5 lines
11 KiB
JavaScript
5 lines
11 KiB
JavaScript
import{a,j as e}from"./react-vendor-BVoutfaX.js";import{u as O}from"./index-D20cy_yX.js";import"./xyflow-CYMCcsWN.js";import"./graph-layout-7tFr_anw.js";import"./elk-CXeXGyKz.js";import"./graphology-BgTy_cc3.js";const A="ua-rag-llm-settings-v2";function R(){if(typeof window>"u")return{enabled:!1,endpoint:"http://localhost:11434/v1",model:"qwen2.5:7b",apiKey:""};try{const n=window.localStorage.getItem(A);if(n)return{enabled:!1,endpoint:"http://localhost:11434/v1",model:"qwen2.5:7b",apiKey:"",...JSON.parse(n)}}catch{}return{enabled:!1,endpoint:"http://localhost:11434/v1",model:"qwen2.5:7b",apiKey:""}}function Q(n){typeof window>"u"||window.localStorage.setItem(A,JSON.stringify(n))}function G(n){switch(n){case"search":return"本地检索中";case"evidence_rejected":return"证据不足,未调用模型";case"local_answer":return"本地回答";case"llm_done":return"模型回答完成";case"llm_failed":return"模型调用失败";default:return n||"待请求"}}async function P(n,o){const g=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)}),c=await g.text();let u;try{u=c?JSON.parse(c):{}}catch{u={ok:!1,error:{message:c||"响应不是 JSON"}}}return{status:g.status,data:u}}function ee({onClose:n}){const o=O(t=>t.graph),g=O(t=>t.navigateToNodeInLayer),[c,u]=a.useState(""),[j,D]=a.useState(""),[i,w]=a.useState("search"),[d,z]=a.useState(R),[S,b]=a.useState(""),[k,C]=a.useState([]),[v,T]=a.useState(null),[h,l]=a.useState({}),[_,I]=a.useState(!1),[M,E]=a.useState(!1),[K,x]=a.useState(null),[f,N]=a.useState(!1),[p,$]=a.useState(null),F=(o==null?void 0:o.nodes.length)??0,J=a.useMemo(()=>(o==null?void 0:o.nodes.filter(t=>t.id.startsWith("doc:")).length)??0,[o]),y=t=>{const r={...d,...t};z(r),Q(r)},q=async()=>{var r;const t=c.trim();if(D(t),x(null),b(""),C([]),$(null),T(null),l({stage:"search",startedAt:new Date().toISOString()}),!t){b("请输入要检索或提问的内容。");return}I(!0);try{const s=i==="llm"?"/api/rag/answer":"/api/rag/search",{status:H,data:m}=await P(s,{query:t,topK:16,llm:d});if(l(m.requestStatus||{stage:i==="llm"?"llm_done":"local_answer"}),T(m.decision||null),C(m.hits||[]),b(m.answer||"暂无该需求描述。"),!m.ok){const L=((r=m.error)==null?void 0:r.message)||`请求失败:HTTP ${H}`;x(L)}}catch(s){x(s instanceof Error?s.message:String(s)),l({stage:"llm_failed"}),b("请求失败,未能获取检索结果。")}finally{I(!1)}},B=async()=>{var t;E(!0),x(null),l({stage:"模型连接测试中",startedAt:new Date().toISOString()});try{const{status:r,data:s}=await P("/api/llm/test",d);s.ok?(l({stage:"llm_done",endpoint:s.endpoint,elapsedMs:s.elapsedMs}),b(`模型连接成功。
|
||
Endpoint:${s.endpoint||d.endpoint}
|
||
耗时:${s.elapsedMs??"?"} ms
|
||
返回:${s.answer||""}`)):(l({stage:"llm_failed",endpoint:s.endpoint,elapsedMs:s.elapsedMs}),x(((t=s.error)==null?void 0:t.message)||`模型连接测试失败:HTTP ${r}`))}catch(r){l({stage:"llm_failed"}),x(r instanceof Error?r.message:String(r))}finally{E(!1)}};return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/65 backdrop-blur-sm p-4 sm:p-6",onMouseDown:n,children:e.jsxs("div",{className:"w-[calc(100vw-32px)] max-w-[1180px] h-[calc(100vh-64px)] max-h-[860px] rounded-lg border border-border-medium bg-surface shadow-2xl overflow-hidden flex flex-col",onMouseDown:t=>t.stopPropagation(),children:[e.jsxs("div",{className:"flex items-center justify-between px-5 py-4 border-b border-border-subtle bg-elevated/40",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"font-heading text-lg text-text-primary",children:"知识库混合 RAG 检索 / 问答"}),e.jsx("p",{className:"text-xs text-text-muted mt-1",children:"前端只发请求到本地后端;后端先检索证据,再代理调用模型并返回明确错误。"})]}),e.jsx("button",{type:"button",onClick:n,className:"text-text-muted hover:text-accent transition-colors text-xl leading-none",children:"×"})]}),e.jsxs("div",{className:"p-5 border-b border-border-subtle space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",onClick:()=>{w("search"),N(!1)},className:`px-3 py-1.5 rounded-md border text-xs font-semibold ${i==="search"&&!f?"border-accent/50 bg-accent/20 text-accent":"border-border-subtle text-text-muted hover:text-text-primary"}`,children:"本地检索"}),e.jsx("button",{type:"button",onClick:()=>{w("llm"),N(!1)},className:`px-3 py-1.5 rounded-md border text-xs font-semibold ${i==="llm"&&!f?"border-accent/50 bg-accent/20 text-accent":"border-border-subtle text-text-muted hover:text-text-primary"}`,children:"大模型回答"}),e.jsx("button",{type:"button",onClick:()=>N(t=>!t),className:`px-3 py-1.5 rounded-md border text-xs font-semibold ${f?"border-accent/50 bg-accent/20 text-accent":"border-border-subtle text-text-muted hover:text-text-primary"}`,children:"模型设置"}),e.jsxs("div",{className:"text-[11px] text-text-muted",children:["图谱节点:",F,",文档节点:",J]})]}),f&&e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-[120px_1fr_160px_100px] gap-2 border border-border-subtle rounded-lg p-3 bg-elevated/30",children:[e.jsxs("label",{className:"flex items-center gap-2 text-xs text-text-secondary",children:[e.jsx("input",{type:"checkbox",checked:d.enabled,onChange:t=>y({enabled:t.target.checked})}),"启用模型"]}),e.jsx("input",{value:d.endpoint,onChange:t=>y({endpoint:t.target.value}),placeholder:"Base URL,例如 https://.../v1 或完整 /chat/completions",className:"bg-surface text-text-primary text-xs rounded px-2 py-1.5 border border-border-subtle focus:outline-none focus:border-accent/50"}),e.jsx("input",{value:d.model,onChange:t=>y({model:t.target.value}),placeholder:"model",className:"bg-surface text-text-primary text-xs rounded px-2 py-1.5 border border-border-subtle focus:outline-none focus:border-accent/50"}),e.jsx("button",{type:"button",onClick:()=>void B(),disabled:M,className:"px-2 py-1.5 rounded border border-accent/30 text-xs text-accent disabled:opacity-60",children:M?"测试中":"测试连接"}),e.jsx("div",{className:"hidden md:block"}),e.jsx("input",{type:"password",value:d.apiKey,onChange:t=>y({apiKey:t.target.value}),placeholder:"API Key;通过本地后端代理发送,不从浏览器直连模型",className:"md:col-span-3 bg-surface text-text-primary text-xs rounded px-2 py-1.5 border border-border-subtle focus:outline-none focus:border-accent/50"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("textarea",{value:c,onChange:t=>u(t.target.value),onKeyDown:t=>{(t.ctrlKey||t.metaKey)&&t.key==="Enter"&&q()},placeholder:"例如:黑名单是什么?回评是什么?对外 API 契约(草案);风险与反欺诈有哪些接口?",className:"flex-1 min-h-[76px] resize-none bg-elevated text-text-primary text-sm rounded-lg px-3 py-2 border border-border-subtle focus:outline-none focus:border-accent/50 placeholder-text-muted"}),e.jsx("button",{type:"button",onClick:()=>void q(),disabled:_,className:"px-4 py-2 rounded-lg bg-accent/20 text-accent hover:text-accent-bright border border-accent/30 text-sm font-semibold transition-colors disabled:opacity-60",children:_?"处理中":i==="llm"?"问答":"检索"})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-[11px] text-text-muted",children:[e.jsx("span",{children:"快捷键:Ctrl + Enter 提交。"}),e.jsxs("span",{children:["状态:",e.jsx("span",{className:"text-accent",children:G(h.stage)})]}),h.endpoint&&e.jsxs("span",{children:["Endpoint:",h.endpoint]}),typeof h.elapsedMs=="number"&&e.jsxs("span",{children:["耗时:",h.elapsedMs," ms"]})]})]}),e.jsxs("div",{className:"flex-1 min-h-0 overflow-auto p-5 grid grid-cols-1 lg:grid-cols-[1fr_440px] gap-5",children:[e.jsxs("section",{className:"min-w-0 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("h3",{className:"text-[11px] font-semibold text-accent uppercase tracking-wider",children:"回答 / 请求状态"}),j&&v&&e.jsxs("span",{className:`text-[11px] ${v.allowed?"text-accent":"text-text-muted"}`,children:["证据判断:",v.reason]})]}),K&&e.jsxs("div",{className:"text-xs text-red-300 border border-red-400/30 bg-red-500/10 rounded p-2",children:["错误:",K]}),e.jsx("pre",{className:"whitespace-pre-wrap text-sm leading-relaxed text-text-secondary bg-elevated/50 border border-border-subtle rounded-lg p-4 font-sans min-h-[260px]",children:j||S?S||"等待后端返回。":"输入问题后点击“检索”或“问答”。"}),p&&e.jsxs("div",{className:"border border-border-subtle rounded-lg bg-elevated/40 p-3",children:[e.jsx("div",{className:"text-xs text-accent mb-1",children:"当前证据内容"}),e.jsxs("div",{className:"text-sm text-text-primary",children:[p.docTitle," / ",p.sectionTitle]}),e.jsx("div",{className:"text-[11px] text-text-muted mt-1",children:p.docPath}),e.jsx("pre",{className:"mt-2 max-h-[260px] overflow-auto whitespace-pre-wrap text-xs leading-relaxed text-text-secondary font-sans",children:p.evidenceContent||p.snippet})]})]}),e.jsxs("section",{className:"min-w-0",children:[e.jsx("h3",{className:"text-[11px] font-semibold text-accent uppercase tracking-wider mb-2",children:"本地命中证据与排序依据"}),e.jsxs("div",{className:"space-y-2",children:[k.length===0&&j&&e.jsx("div",{className:"text-sm text-text-muted border border-border-subtle rounded-lg p-3",children:"暂无命中。"}),k.slice(0,12).map(t=>e.jsxs("div",{className:"border border-border-subtle bg-elevated/40 hover:border-accent/40 rounded-lg p-3 transition-colors",children:[e.jsxs("button",{type:"button",onClick:()=>g(t.nodeId),className:"w-full text-left",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm text-text-primary truncate",children:t.docTitle}),e.jsx("div",{className:"text-[11px] text-accent mt-1 truncate",children:t.sectionTitle})]}),e.jsx("div",{className:"text-[11px] text-accent shrink-0",children:t.score.toFixed(1)})]}),e.jsx("div",{className:"text-[11px] text-text-muted mt-1 truncate",children:t.docPath})]}),e.jsx("button",{type:"button",onClick:()=>$(t),className:"mt-2 text-left text-xs text-text-secondary line-clamp-4 hover:text-text-primary",children:t.snippet}),e.jsxs("div",{className:"mt-2 grid grid-cols-4 gap-1 text-[10px] text-text-muted",children:[e.jsxs("span",{children:["exact ",t.scores.exact.toFixed(0)]}),e.jsxs("span",{children:["fuzzy ",t.scores.fuzzy.toFixed(0)]}),e.jsxs("span",{children:["semantic ",t.scores.semantic.toFixed(0)]}),e.jsxs("span",{children:["boost ",(t.scores.titleBoost+t.scores.sectionBoost+t.scores.directoryBoost+t.scores.chunkTypeBoost).toFixed(0)]})]}),e.jsx("div",{className:"mt-2 flex flex-wrap gap-1",children:t.reasons.slice(0,5).map((r,s)=>e.jsxs("span",{className:"text-[10px] text-text-muted border border-border-subtle rounded px-1.5 py-0.5",children:[r.message," +",r.score.toFixed(0)]},`${t.chunkId}-${s}`))})]},t.chunkId))]})]})]})]})})}export{ee as default};
|