Initial commit — kb-app RAG server
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""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 ""
|
||||
Reference in New Issue
Block a user