diff --git a/apply_events.cfm b/apply_events.cfm index 35ac362..0b5a1e0 100644 --- a/apply_events.cfm +++ b/apply_events.cfm @@ -7,6 +7,15 @@ + + + + + + ALTER TABLE spec_events ADD COLUMN IF NOT EXISTS prompt_version UUID + + + @@ -44,7 +53,7 @@ - INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, comment, status) + INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, comment, status, prompt_version) SELECT , , @@ -52,7 +61,8 @@ 'DELETE', name_hash, 'full_replace', - 'applied' + 'applied', + ::uuidNULL FROM spec_current WHERE contract_id = @@ -101,7 +111,7 @@ - INSERT INTO spec_events (contract_id, supplement_id, seq, action, new_values, comment, status) + INSERT INTO spec_events (contract_id, supplement_id, seq, action, new_values, comment, status, prompt_version) VALUES ( , , @@ -109,7 +119,8 @@ 'ADD', ::jsonb, , - 'applied' + 'applied', + ::uuidNULL ) RETURNING id @@ -134,7 +145,7 @@ - INSERT INTO spec_events (contract_id, supplement_id, seq, action, new_values, comment, status) + INSERT INTO spec_events (contract_id, supplement_id, seq, action, new_values, comment, status, prompt_version) VALUES ( , , @@ -142,7 +153,8 @@ 'UNRESOLVED', ::jsonb, , - 'pending' + 'pending', + ::uuidNULL ) @@ -155,7 +167,7 @@ - INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, new_values, comment, status) + INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, new_values, comment, status, prompt_version) VALUES ( , , @@ -164,7 +176,8 @@ , ::jsonb, , - 'applied' + 'applied', + ::uuidNULL ) RETURNING id @@ -186,7 +199,7 @@ - INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, comment, status) + INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, comment, status, prompt_version) VALUES ( , , @@ -194,7 +207,8 @@ 'DELETE', , , - 'applied' + 'applied', + ::uuidNULL ) @@ -206,7 +220,7 @@ - INSERT INTO spec_events (contract_id, supplement_id, seq, action, new_values, comment, status) + INSERT INTO spec_events (contract_id, supplement_id, seq, action, new_values, comment, status, prompt_version) VALUES ( , , @@ -214,7 +228,8 @@ 'UNRESOLVED', ::jsonb, , - 'pending' + 'pending', + ::uuidNULL ) diff --git a/deploy/convert_server.py b/deploy/convert_server.py index bdc852f..e584e3a 100755 --- a/deploy/convert_server.py +++ b/deploy/convert_server.py @@ -19,8 +19,8 @@ LUCEE_URL = "https://contractor.luceek8s.dev.nubes.ru" def call_llm(current_spec, doc_text): - """Вызов LLM API. Возвращает {mode, ops} или кидает исключение.""" - prompt = build_prompt(current_spec, doc_text) + """Вызов LLM API. Возвращает ({mode, ops}, prompt_id) или кидает исключение.""" + prompt, prompt_id = build_prompt(current_spec, doc_text) payload = { "model": LLM_MODEL, "messages": [{"role": "user", "content": prompt}], @@ -39,7 +39,7 @@ def call_llm(current_spec, doc_text): json_text = json_text.split("```json")[1].split("```")[0] elif "```" in json_text: json_text = json_text.split("```")[1].split("```")[0] - return json.loads(json_text.strip()) + return json.loads(json_text.strip()), prompt_id class Handler(BaseHTTPRequestHandler): @@ -215,7 +215,7 @@ class Handler(BaseHTTPRequestHandler): "error": error[0], "time_s": elapsed}) continue - llm_result = result[0] + llm_result, prompt_id = result[0] ops = llm_result.get("ops", []) mode = llm_result.get("mode", "partial") @@ -237,7 +237,7 @@ class Handler(BaseHTTPRequestHandler): # Применить apply_resp = httpx.post( f"{LUCEE_URL}/apply_events.cfm?contract_id={cid}&mode={mode}", - json={"supplement_id": sid, "ops": ops}, timeout=30 + json={"supplement_id": sid, "ops": ops, "prompt_id": prompt_id}, timeout=30 ) if apply_resp.status_code == 200: ar = apply_resp.json() @@ -258,7 +258,7 @@ class Handler(BaseHTTPRequestHandler): length = int(self.headers.get("Content-Length", 0)) body = json.loads(self.rfile.read(length)) try: - result = call_llm(body.get("current_spec", []), body.get("doc_text", "")) + result, prompt_id = call_llm(body.get("current_spec", []), body.get("doc_text", "")) self.send_response(200) self.send_header("Content-Type", "application/json") self.end_headers() diff --git a/deploy/llm_prompt.py b/deploy/llm_prompt.py index 650ae36..0d3751e 100644 --- a/deploy/llm_prompt.py +++ b/deploy/llm_prompt.py @@ -101,12 +101,13 @@ def _build_spec_text(current_spec: list) -> str: return "\n".join(lines) -def build_prompt(current_spec: list, doc_text: str) -> str: +def build_prompt(current_spec: list, doc_text: str) -> tuple: """ Формирует промпт для LLM. 1. Пробует получить активный промпт из БД (Lucee API). 2. При неудаче — fallback на хардкод. - Возвращает готовый текст промпта. + Возвращает (текст_промпта, prompt_id). + prompt_id — UUID версии промпта из БД, или "" если fallback. """ is_first = len(current_spec) == 0 role = "extract" if is_first else "diff" @@ -114,11 +115,13 @@ def build_prompt(current_spec: list, doc_text: str) -> str: db = _fetch_prompt(role) if db: template = db["body"] + prompt_id = db.get("id", "") else: template = FALLBACK_EXTRACT if is_first else FALLBACK_DIFF + prompt_id = "" # Подстановка плейсхолдеров result = template.replace("{doc_text}", doc_text) result = result.replace("{spec_current}", _build_spec_text(current_spec)) - return result + return result, prompt_id diff --git a/index.cfm b/index.cfm index a1ea686..be255a5 100644 --- a/index.cfm +++ b/index.cfm @@ -75,7 +75,7 @@
Nubes - Сверка договоров — LLM AI-driven Event Sourcing v1.0.112 — Lucee + Сверка договоров — LLM AI-driven Event Sourcing v1.0.113 — Lucee