Files

73 lines
3.3 KiB
Python

"""Дистилляция чанка в типизированные атомы (LLM)."""
from __future__ import annotations
import json
import httpx
from . import config
_client = httpx.Client(timeout=600)
SYSTEM = """Ты — экстрактор знаний. Преврати текст в атомарные, типизированные утверждения.
Верни ТОЛЬКО JSON-массив без пояснений. Каждый элемент:
{
"type": "text|definition|logical_rule|code|table|fact",
"claim": "короткое каноническое утверждение (одно предложение)",
"content": "полное значение атома",
"confidence": 0.0-1.0
}
Правила:
- definition: термин и его точное определение.
- logical_rule: правило "если X то Y" (content = JSON со ключами if/then).
- code: фрагмент кода или сигнатура функции (content = сам код).
- table: табличные данные (content = JSON или markdown-таблица).
- fact: проверяемый факт с числом или датой.
- text: всё остальное ценное.
- Отбрасывай воду, повторы, навигацию, рекламу. Только новое и ценное.
- Если ничего ценного — верни []. No markdown fences."""
def distill_chunk(chunk_text: str, model: str | None = None) -> list[dict]:
"""Вернуть список атомов (dict) из чанка."""
m = model or config.LLM_MODEL
r = _client.post(f"{config.OLLAMA_URL}/api/chat", json={
"model": m,
"messages": [
{"role": "system", "content": SYSTEM},
{"role": "user", "content": chunk_text[:6000]},
],
"stream": False,
"options": {"temperature": 0.1},
})
r.raise_for_status()
content = r.json()["message"]["content"]
start = content.find("[")
end = content.rfind("]")
if start == -1 or end == -1:
return []
try:
arr = json.loads(content[start:end + 1])
except json.JSONDecodeError:
return []
return [a for a in arr if isinstance(a, dict) and a.get("type") and a.get("content")]
def verify_atom(atom: dict, context_atoms: list[dict], model: str | None = None) -> float:
"""Оценить новизну/ценность атома против существующих (0..1)."""
m = model or config.LLM_MODEL
ctx = "\n".join(f"- {a.get('claim','')}" for a in context_atoms[:8])
prompt = (
f"Существующие знания:\n{ctx}\n\n"
f"Новый атом ({atom.get('type')}): {atom.get('claim')}\n{atom.get('content','')[:500]}\n\n"
f"Оцени от 0 до 1, насколько это НОВОЕ и ценное знание (0=дубль/вода, 1=уникальное важное). "
f"Верни только число."
)
r = _client.post(f"{config.OLLAMA_URL}/api/chat", json={
"model": m,
"messages": [{"role": "user", "content": prompt}],
"stream": False,
"options": {"temperature": 0.0},
})
r.raise_for_status()
out = r.json()["message"]["content"].strip()
try:
return float(out)
except ValueError:
return 0.5