159 lines
6.5 KiB
Plaintext
159 lines
6.5 KiB
Plaintext
<!--- process_v2.cfm — v2 pipeline: LLM-интерпретация ДС → apply_events --->
|
||
<cftry>
|
||
<cfquery name="supps" datasource="baza">
|
||
SELECT s.id as supp_id, s.type, d.id as doc_id, d.filename, d.elements_json
|
||
FROM supplements s
|
||
JOIN documents d ON s.document_id = d.id
|
||
WHERE s.contract_id = <cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">
|
||
AND d.elements_json IS NOT NULL
|
||
ORDER BY s.created_at
|
||
</cfquery>
|
||
|
||
<cfif supps.recordCount EQ 0>
|
||
<cfoutput>data: #serializeJSON({type:"error",message:"Нет распарсенных файлов"})#
|
||
|
||
</cfoutput><cfflush>
|
||
<cfabort>
|
||
</cfif>
|
||
|
||
<cfset totalUnresolved = 0>
|
||
<cfset llmStart = getTickCount()>
|
||
|
||
<cfloop query="supps">
|
||
<cfset sid = supps.supp_id>
|
||
|
||
<!--- Текущая спецификация из spec_current --->
|
||
<cfquery name="curSpec" datasource="baza">
|
||
SELECT name_hash, name, price, qty, sum, date_start
|
||
FROM spec_current
|
||
WHERE contract_id = <cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">
|
||
ORDER BY name
|
||
</cfquery>
|
||
<cfset currentSpec = []>
|
||
<cfloop query="curSpec">
|
||
<cfset arrayAppend(currentSpec, {
|
||
hash: curSpec.name_hash,
|
||
name: curSpec.name,
|
||
price: curSpec.price,
|
||
qty: curSpec.qty,
|
||
sum: curSpec.sum,
|
||
date_start: curSpec.date_start
|
||
})>
|
||
</cfloop>
|
||
|
||
<!--- textify elements_json → doc_text --->
|
||
<cfset elements = deserializeJSON(supps.elements_json)>
|
||
<cfset textLines = []>
|
||
<cfloop array="#elements#" index="el">
|
||
<cfif el.type EQ "paragraph">
|
||
<cfset prefix = len(el.style) ? "[#el.style#] " : "">
|
||
<cfset arrayAppend(textLines, prefix & el.text)>
|
||
<cfelseif el.type EQ "table">
|
||
<cfset rows = el.rows>
|
||
<cfif arrayLen(rows) GT 0>
|
||
<cfset ncols = arrayLen(rows[1])>
|
||
<cfset arrayAppend(textLines, "--- Таблица (" & arrayLen(rows) & "×" & ncols & ") ---")>
|
||
<cfloop array="#rows#" index="row">
|
||
<cfset cells = []>
|
||
<cfloop from="1" to="#ncols#" index="ci">
|
||
<cfset val = "">
|
||
<cfif ci LTE arrayLen(row)>
|
||
<cfset val = replace(replace(toString(row[ci]), chr(10), " ", "ALL"), "|", "\|", "ALL")>
|
||
</cfif>
|
||
<cfset arrayAppend(cells, val)>
|
||
</cfloop>
|
||
<cfset arrayAppend(textLines, "| " & arrayToList(cells, " | ") & " |")>
|
||
</cfloop>
|
||
<cfset arrayAppend(textLines, "")>
|
||
</cfif>
|
||
</cfif>
|
||
</cfloop>
|
||
<cfset docText = arrayToList(textLines, chr(10))>
|
||
|
||
<!--- SSE: начинаем LLM --->
|
||
<cfoutput>data: #serializeJSON({type:"extract_start",supplement_id:sid,filename:supps.filename})#
|
||
|
||
</cfoutput><cfflush>
|
||
|
||
<!--- Вызов ВМ /llm-ops --->
|
||
<cfset t0 = getTickCount()>
|
||
<cfset llmPayload = {
|
||
contract_id: url.contract_id,
|
||
supplement_id: sid,
|
||
current_spec: currentSpec,
|
||
doc_text: docText
|
||
}>
|
||
|
||
<cfhttp url="https://contracts.kube5s.ru/llm-ops" method="POST" timeout="130">
|
||
<cfhttpparam type="header" name="Content-Type" value="application/json">
|
||
<cfhttpparam type="body" value="#serializeJSON(llmPayload)#">
|
||
</cfhttp>
|
||
|
||
<cfset elapsed = int((getTickCount() - t0) / 1000 * 10 + 0.5) / 10>
|
||
|
||
<cfif NOT (cfhttp.statusCode EQ 200 OR left(cfhttp.statusCode, 3) EQ "200")>
|
||
<cfoutput>data: #serializeJSON({type:"extract_error",supplement_id:sid,filename:supps.filename,error:"LLM HTTP #cfhttp.statusCode#",time_s:elapsed})#
|
||
|
||
</cfoutput><cfflush>
|
||
<cfcontinue>
|
||
</cfif>
|
||
|
||
<cftry>
|
||
<cfset llmResult = deserializeJSON(cfhttp.fileContent)>
|
||
<cfset ops = structKeyExists(llmResult, "ops") ? llmResult.ops : []>
|
||
<cfset mode = structKeyExists(llmResult, "mode") ? llmResult.mode : "partial">
|
||
|
||
<cfoutput>data: #serializeJSON({type:"llm_done",supplement_id:sid,filename:supps.filename,ops_count:arrayLen(ops),mode:mode,time_s:elapsed})#
|
||
|
||
</cfoutput><cfflush>
|
||
|
||
<!--- Применить операции --->
|
||
<cfset applyPayload = {
|
||
supplement_id: sid,
|
||
ops: ops
|
||
}>
|
||
|
||
<cfhttp url="https://contractor.luceek8s.dev.nubes.ru/apply_events.cfm?contract_id=#url.contract_id#&mode=#mode#" method="POST" timeout="30">
|
||
<cfhttpparam type="header" name="Content-Type" value="application/json">
|
||
<cfhttpparam type="body" value="#serializeJSON(applyPayload)#">
|
||
</cfhttp>
|
||
|
||
<cfif cfhttp.statusCode EQ 200 OR left(cfhttp.statusCode, 3) EQ "200">
|
||
<cfset applyResult = deserializeJSON(cfhttp.fileContent)>
|
||
<cfif structKeyExists(applyResult, "summary")>
|
||
<cfset totalUnresolved += applyResult.summary.unresolved>
|
||
<cfoutput>data: #serializeJSON({type:"applied",supplement_id:sid,summary:applyResult.summary})#
|
||
|
||
</cfoutput><cfflush>
|
||
<cfelse>
|
||
<cfoutput>data: #serializeJSON({type:"apply_error",supplement_id:sid,error:structKeyExists(applyResult,'error')?applyResult.error:'unknown'})#
|
||
|
||
</cfoutput><cfflush>
|
||
</cfif>
|
||
<cfelse>
|
||
<cfoutput>data: #serializeJSON({type:"apply_error",supplement_id:sid,error:"apply HTTP #cfhttp.statusCode#"})#
|
||
|
||
</cfoutput><cfflush>
|
||
</cfif>
|
||
|
||
<cfcatch>
|
||
<cfoutput>data: #serializeJSON({type:"extract_error",supplement_id:sid,filename:supps.filename,error:"JSON parse: " & cfcatch.message,time_s:elapsed})#
|
||
|
||
</cfoutput><cfflush>
|
||
</cfcatch>
|
||
</cftry>
|
||
</cfloop>
|
||
|
||
<!--- Финальное событие --->
|
||
<cfset totalTime = int((getTickCount() - llmStart) / 1000 * 10 + 0.5) / 10>
|
||
<cfoutput>data: #serializeJSON({type:"done",total_time_s:totalTime,total_unresolved:totalUnresolved})#
|
||
|
||
</cfoutput><cfflush>
|
||
|
||
<cfcatch>
|
||
<cfoutput>data: #serializeJSON({type:"error",message:cfcatch.message,detail:cfcatch.detail})#
|
||
|
||
</cfoutput><cfflush>
|
||
</cfcatch>
|
||
</cftry>
|