"""Extract topic labels for chunks using a local LLM.""" import requests import os from .config import CONFIG # Use a fast model — chosen at config time TOPIC_MODEL = os.getenv("KB_TOPIC_MODEL", "qwen2.5-coder:7b") def extract_topic(chunk_text, doc_title=None, doc_category=None): """Generate a brief topic label for a chunk. Returns a single-line description of what specific entities, concepts, and topics this chunk discusses. """ # Truncate very long chunks for the LLM if len(chunk_text) > 3000: chunk_text = chunk_text[:3000] + "..." context_hint = "" if doc_title: context_hint += f"\nThe broader document is titled: {doc_title}" if doc_category: context_hint += f"\nThe document category: {doc_category}" prompt = ( f"<|im_start|>system\n" f"You extract topic labels for retrieval. Given a passage, identify the specific " f"entities, concepts, names, and topics it discusses. Output a single concise line " f"of 10-30 words listing what this passage is specifically about. Include proper " f"nouns, technical terms, and metric values. Do not summarize the content; just " f"label what it covers.<|im_end|>\n" f"<|im_start|>user\n" f"Passage:{context_hint}\n\n{chunk_text}<|im_end|>\n" f"<|im_start|>assistant\n" ) try: resp = requests.post( f"{CONFIG.ollama_url}/api/generate", json={ "model": TOPIC_MODEL, "prompt": prompt, "stream": False, "options": { "num_predict": 60, "temperature": 0.0, "top_p": 1.0, }, "raw": True, }, timeout=60, ) resp.raise_for_status() text = resp.json().get("response", "").strip() # Take only the first line, drop any "Labels:" prefix first_line = text.split("\n")[0].strip() for prefix in ("Topics:", "Topic:", "Labels:", "Label:", "Subject:"): if first_line.lower().startswith(prefix.lower()): first_line = first_line[len(prefix):].strip() return first_line[:300] # cap length except Exception as e: print(f"Topic extraction error: {e}", flush=True) return ""