24 lines
18 KiB
JavaScript
24 lines
18 KiB
JavaScript
import{a as b,j as i}from"./react-vendor-BVoutfaX.js";import{u as P}from"./index-DGED3sP8.js";import"./xyflow-CYMCcsWN.js";import"./graph-layout-7tFr_anw.js";import"./elk-CXeXGyKz.js";import"./graphology-BgTy_cc3.js";const B="ua-rag-llm-settings-v1",F={回评:["评价提交","评价展示","客服邀评","评价结果追踪","review submission","review display","review follow-up"],测评:["评价计划","review plan","评价提交","额度统计","测评单"],免评:["KOC","KOL","内容发布","引流","带货","exemption"],真实人:["person","person_profiles","跨账号归并","身份归并","真实人归并"],额度:["4/4/12","person_quota_ledgers","额度台账","预占","额度与频控"],对外API:["对外 API 契约","接口契约","API 草案","接口说明","对外接口"],工单:["客服工单","support_tickets","客服跟进","support_followups"],风险:["风险与反欺诈","risk_signals","risk_cases","黑名单","反欺诈"]};function E(t){return Array.isArray(t)?t.join(" "):typeof t=="string"?t:""}function q(t){return t.replace(/<script[\s\S]*?<\/script>/gi," ").replace(/<style[\s\S]*?<\/style>/gi," ").replace(/<[^>]+>/g," ").replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function Q(t){const e=t.split(`
|
||
`);let n=0;const a=e.map(s=>{const o=s.match(/^\s*\d+\|(.+)$/);return o?(n+=1,o[1]):s});return n>=Math.max(3,Math.floor(e.length/4))?a.join(`
|
||
`):t}function f(t){return t.toLowerCase().replace(/[\s`*_>#|\-\[\]()()【】《》“”"',。、::;;,.\/\\!?!?]+/g,"")}function j(t){return q(Q(t)).toLowerCase().replace(/[\t\r]+/g," ").replace(/[()]/g," ").replace(/[【】《》“”]/g," ").replace(/[_*`>#|\[\]]/g," ").replace(/\s+/g," ").trim()}function T(t){return Array.from(new Set(t.map(e=>e.trim()).filter(Boolean)))}function M(t){const e=j(t),n=e.match(/[a-z0-9_./+-]{2,}/g)??[],a=e.match(/[\u4e00-\u9fa5]{2,}/g)??[],s=e.match(/[\u4e00-\u9fa5]/g)??[],o=[];for(let c=0;c<s.length-1;c+=1)o.push(`${s[c]}${s[c+1]}`);for(let c=0;c<s.length-2;c+=1)o.push(`${s[c]}${s[c+1]}${s[c+2]}`);return T([...n,...a,...o,...s.filter(c=>!/[是什么吗呢的了和与及或在中为]/.test(c))])}function H(t){const e=j(t);return/api|接口|契约|endpoint|对外/.test(e)?"api":/数据|字段|表|对象|模型|schema|建表/.test(e)?"data_model":/流程|怎么走|如何|步骤|流转|处理/.test(e)?"process":/规则|限制|口径|额度|频控|条件/.test(e)?"rule":/谁|负责|职责|owner|角色/.test(e)?"responsibility":/测试|验收|用例|缺陷|上线/.test(e)?"test":/里程碑|阶段|计划|节点/.test(e)?"milestone":/是什么|定义|含义|意思|解释/.test(e)?"definition":"general"}function R(t,e){const n=f(e),a=[];for(const[s,o]of Object.entries(F)){const c=f(s);(n.includes(c)||t.some(r=>f(r).includes(c)||c.includes(f(r))))&&a.push(s,...o)}return T(a)}function J(t){const e=j(t),n=f(t),a=M(t),s=R(a,t),o=T([t.trim(),e,n,...a.filter(c=>c.length>=2)]);return{raw:t,normalized:e,compact:n,tokens:a,coreTerms:o,expandedTerms:s,questionType:H(t)}}function Y(t){var e;return q(Q(E((e=t.knowledgeMeta)==null?void 0:e.content)))}function G(t){var e;return E((e=t.knowledgeMeta)==null?void 0:e.category)||t.tags.find(n=>n.includes("需求")||n.includes("技术")||n.includes("测试")||n.includes("里程碑"))||""}function U(t,e){const n=`${t}
|
||
${e}`.toLowerCase();return/api|接口|契约|endpoint|对外/.test(n)?"api_contract":/数据模型|字段|表结构|对象|schema|建表/.test(n)?"data_model":/业务规则|规则|口径|额度|频控|限制/.test(n)?"business_rule":/流程|流转|步骤|时序|处理/.test(n)?"process":/faq|常见问题|是什么|问答/.test(n)?"faq":"general"}function V(t){var o,c;const e=t.trim();if(!e)return[];const n=[];let a="全文",s=[];for(const r of e.split(`
|
||
`)){const u=(c=(o=r.match(/^\s{0,3}#{1,6}\s+(.+)$/))==null?void 0:o[1])==null?void 0:c.trim();u?(s.length>0&&n.push({heading:a,text:s.join(`
|
||
`)}),a=u,s=[r]):s.push(r)}return s.length>0&&n.push({heading:a,text:s.join(`
|
||
`)}),n.length>0?n:[{heading:"全文",text:e}]}function W(t){return t.flatMap(e=>{const n=Y(e),a=[e.name,e.summary,e.filePath,e.tags.join(" ")].join(`
|
||
`);return V(n||a).map((o,c)=>{const r=o.text.trim()||a,u=j(r);return{chunkId:`${e.id}#${c}`,node:e,docTitle:e.name,docPath:e.filePath??e.id,sectionTitle:o.heading,content:r,normalizedContent:u,compactContent:f(r),chunkType:U(o.heading,r),layer:G(e)}})})}function K(t,e){return e?t.split(e).length-1:0}function C(t,e,n,a=1){const s=j(t),o=f(t),c=[];let r=0;const u=T([e.normalized,e.raw.toLowerCase()].filter(p=>p.length>=2));for(const p of u)if(s.includes(p)){const m=70*a;r+=m,c.push({type:"exact",field:n,message:`${n} 原文命中:${p}`,score:m})}if(e.compact&&o.includes(e.compact)){const p=80*a;r+=p,c.push({type:"compact",field:n,message:`${n} 去标点命中`,score:p})}let d=0;for(const p of e.coreTerms){const m=j(p),x=f(p);if(!m&&!x)continue;const h=Math.max(K(s,m),K(o,x));h>0&&(d+=1,r+=Math.min(h,4)*Math.min(Math.max(x.length,m.length),10)*a)}return d>0&&c.push({type:"token",field:n,message:`${n} 关键词覆盖 ${d} 项`,score:d*a}),{score:r,reasons:c}}function X(t,e){const n=[],a=T([...e.tokens,...e.expandedTerms.flatMap(M)]).filter(u=>u.length>=2);if(a.length===0)return{score:0,reasons:n};const s=new Set(M(`${t.docTitle} ${t.sectionTitle} ${t.normalizedContent}`));let o=0;for(const u of a)(s.has(u)||t.compactContent.includes(f(u))||f(`${t.docTitle}${t.sectionTitle}`).includes(f(u)))&&(o+=1);const c=o/Math.max(a.length,1),r=c*90;return r>0&&n.push({type:"semantic",message:`语义/同义词覆盖 ${(c*100).toFixed(0)}%`,score:r}),{score:r,reasons:n}}function Z(t,e){const n=t.docPath,a=n.includes("05_需求文档")?15:n.includes("01_业务流程")?12:n.includes("07_技术文档")?10:n.includes("08_测试相关")?8:n.includes("06_里程碑")?6:n.includes("02_项目管理流程")?5:n.includes("04_Agent检索")?4:n.includes("03_规范与模板")?1:0;return e.questionType==="api"&&n.includes("07_技术文档")?a+8:(e.questionType==="definition"||e.questionType==="rule")&&n.includes("05_需求文档")?a+5:e.questionType==="test"&&n.includes("08_测试相关")?a+12:a}function ee(t,e){return e.questionType==="api"&&t.chunkType==="api_contract"||e.questionType==="data_model"&&t.chunkType==="data_model"?18:e.questionType==="process"&&t.chunkType==="process"||e.questionType==="rule"&&t.chunkType==="business_rule"?14:e.questionType==="definition"&&(t.chunkType==="faq"||t.sectionTitle.includes("概述")||t.sectionTitle.includes("目标"))?10:0}function te(t,e){const n=t.replace(/\s+/g," ").trim();if(!n)return"";const a=n.toLowerCase(),s=f(n),c=T([e.normalized,e.raw,e.compact,...e.coreTerms,...e.expandedTerms]).map(d=>{const p=a.indexOf(j(d));if(p>=0)return p;const m=s.indexOf(f(d));return m>=0?Math.min(m,n.length-1):-1}).filter(d=>d>=0).sort((d,p)=>d-p)[0],r=Math.max(0,(c??0)-110),u=n.slice(r,r+320);return`${r>0?"…":""}${u}${r+320<n.length?"…":""}`}function O(t,e){const n=J(e);if(!n.normalized&&!n.compact)return[];const a=n.questionType==="api"?{exact:.45,fuzzy:.25,semantic:.1}:n.questionType==="definition"||n.questionType==="process"?{exact:.25,fuzzy:.2,semantic:.3}:{exact:.3,fuzzy:.2,semantic:.25};return t.map(s=>{const o=C(`${s.docTitle}
|
||
${s.docPath}`,n,"docTitle",4),c=C(s.sectionTitle,n,"sectionTitle",6),r=C(s.normalizedContent,n,"content",1),u=C(s.node.tags.join(" "),n,"tags",3),d=X(s,n),p=o.score+c.score+u.score+r.score,m=(s.compactContent.includes(n.compact)?80:0)+r.score*.2,x=o.score>0?12:0,h=c.score>0?18:0,g=Z(s,n),w=ee(s,n),k=p*a.exact+m*a.fuzzy+d.score*a.semantic+x+h+g+w,v=[...o.reasons,...c.reasons,...u.reasons,...r.reasons.slice(0,3),...d.reasons];return g&&v.push({type:"directory",message:`目录权重:${s.docPath.split("/")[0]??""}`,score:g}),w&&v.push({type:"chunkType",message:`章节类型匹配:${s.chunkType}`,score:w}),{chunk:s,score:k,scores:{exact:p,fuzzy:m,semantic:d.score,titleBoost:x,sectionBoost:h,directoryBoost:g,chunkTypeBoost:w},snippet:te(s.content,n),reasons:v}}).filter(s=>s.score>10&&s.snippet).sort((s,o)=>o.score-s.score).reduce((s,o)=>{const c=`${o.chunk.node.id}:${o.chunk.sectionTitle}`;return s.some(r=>`${r.chunk.node.id}:${r.chunk.sectionTitle}`===c)||s.push(o),s},[]).slice(0,16)}function I(t,e){var n;return t.trim()?e.length===0?{allowed:!1,reason:"没有检索到相关证据。"}:e[0].score>=75?{allowed:!0,reason:"Top1 证据分数达到阈值。"}:e[0].score>=60&&(((n=e[1])==null?void 0:n.score)??0)>=50?{allowed:!0,reason:"多个证据片段达到中等相关。"}:{allowed:!1,reason:"证据分数不足。"}:{allowed:!1,reason:"请输入问题。"}}function z(t,e){if(!t.trim())return"请输入要检索或提问的内容。";const n=I(t,e);if(!n.allowed)return"暂无该需求描述。";const a=e.slice(0,5);return[`结论:已基于本地知识库检索到可用证据。${n.reason}`,"","相关依据:",...a.map((s,o)=>`${o+1}. ${s.chunk.docTitle}${s.chunk.sectionTitle?` / ${s.chunk.sectionTitle}`:""}
|
||
${s.snippet}
|
||
来源:${s.chunk.docPath}`),"","说明:当前本地模式不调用大模型,只返回可追溯证据摘要。切换到“大模型回答”可基于这些证据生成解释性回答。"].join(`
|
||
`)}function ne(){if(typeof window>"u")return{enabled:!1,endpoint:"http://localhost:11434/v1/chat/completions",model:"qwen2.5:7b",apiKey:""};try{const t=window.localStorage.getItem(B);if(t)return{enabled:!1,endpoint:"http://localhost:11434/v1/chat/completions",model:"qwen2.5:7b",apiKey:"",...JSON.parse(t)}}catch{}return{enabled:!1,endpoint:"http://localhost:11434/v1/chat/completions",model:"qwen2.5:7b",apiKey:""}}function se(t){typeof window>"u"||window.localStorage.setItem(B,JSON.stringify(t))}async function oe(t,e,n){var d,p,m,x;if(!I(e,n).allowed)return"暂无该需求描述。";if(!t.enabled||!t.endpoint||!t.model)return z(e,n);const s=n.slice(0,8).map((h,g)=>`[${g+1}]
|
||
来源:${h.chunk.docPath}
|
||
章节:${h.chunk.sectionTitle}
|
||
内容:${h.snippet}`).join(`
|
||
|
||
`),o=[{role:"system",content:"你是如愿知识库问答助手。你只能基于提供的知识库片段回答,不得使用外部知识,不得编造文档中没有的内容。如果证据不足,请只回答:暂无该需求描述。回答末尾必须列出来源文件。"},{role:"user",content:`用户问题:
|
||
${e}
|
||
|
||
检索证据:
|
||
${s}
|
||
|
||
请用中文结构化回答。`}],c=await fetch(t.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...t.apiKey?{Authorization:`Bearer ${t.apiKey}`}:{}},body:JSON.stringify({model:t.model,messages:o,temperature:.1,stream:!1})});if(!c.ok)throw new Error(`LLM request failed: ${c.status} ${c.statusText}`);const r=await c.json(),u=((m=(p=(d=r==null?void 0:r.choices)==null?void 0:d[0])==null?void 0:p.message)==null?void 0:m.content)??((x=r==null?void 0:r.message)==null?void 0:x.content)??(r==null?void 0:r.response);return typeof u=="string"&&u.trim()?u.trim():"暂无该需求描述。"}function ue({onClose:t}){const e=P(l=>l.graph),n=P(l=>l.navigateToNodeInLayer),[a,s]=b.useState(""),[o,c]=b.useState(""),[r,u]=b.useState("search"),[d,p]=b.useState(ne),[m,x]=b.useState(""),[h,g]=b.useState(!1),[w,k]=b.useState(null),[v,D]=b.useState(!1),S=b.useMemo(()=>W((e==null?void 0:e.nodes)??[]),[e]),$=b.useMemo(()=>O(S,o),[S,o]),A=b.useMemo(()=>I(o,$),[o,$]),_=l=>{const y={...d,...l};p(y),se(y)},L=async()=>{const l=a.trim();if(c(l),k(null),!l){x("请输入要检索或提问的内容。");return}const y=O(S,l);if(r==="search"){x(z(l,y));return}g(!0);try{x(await oe(d,l,y))}catch(N){k(N instanceof Error?N.message:String(N)),x(z(l,y))}finally{g(!1)}};return i.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:t,children:i.jsxs("div",{className:"w-[calc(100vw-32px)] max-w-[1120px] h-[calc(100vh-64px)] max-h-[820px] rounded-lg border border-border-medium bg-surface shadow-2xl overflow-hidden flex flex-col",onMouseDown:l=>l.stopPropagation(),children:[i.jsxs("div",{className:"flex items-center justify-between px-5 py-4 border-b border-border-subtle bg-elevated/40",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"font-heading text-lg text-text-primary",children:"知识库混合 RAG 检索 / 问答"}),i.jsx("p",{className:"text-xs text-text-muted mt-1",children:"先精确匹配标题、章节和原文,再做模糊/语义补充,并展示排序依据。"})]}),i.jsx("button",{type:"button",onClick:t,className:"text-text-muted hover:text-accent transition-colors text-xl leading-none",children:"×"})]}),i.jsxs("div",{className:"p-5 border-b border-border-subtle space-y-3",children:[i.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[i.jsx("button",{type:"button",onClick:()=>u("search"),className:`px-3 py-1.5 rounded-md border text-xs font-semibold ${r==="search"?"border-accent/50 bg-accent/20 text-accent":"border-border-subtle text-text-muted hover:text-text-primary"}`,children:"本地检索"}),i.jsx("button",{type:"button",onClick:()=>u("llm"),className:`px-3 py-1.5 rounded-md border text-xs font-semibold ${r==="llm"?"border-accent/50 bg-accent/20 text-accent":"border-border-subtle text-text-muted hover:text-text-primary"}`,children:"大模型回答"}),i.jsx("button",{type:"button",onClick:()=>D(l=>!l),className:"px-3 py-1.5 rounded-md border border-border-subtle text-xs text-text-muted hover:text-text-primary",children:"模型设置"}),i.jsxs("div",{className:"text-[11px] text-text-muted",children:["文档节点:",(e==null?void 0:e.nodes.length)??0,",切片:",S.length]})]}),v&&i.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-[120px_1fr_160px] gap-2 border border-border-subtle rounded-lg p-3 bg-elevated/30",children:[i.jsxs("label",{className:"flex items-center gap-2 text-xs text-text-secondary",children:[i.jsx("input",{type:"checkbox",checked:d.enabled,onChange:l=>_({enabled:l.target.checked})}),"启用模型"]}),i.jsx("input",{value:d.endpoint,onChange:l=>_({endpoint:l.target.value}),placeholder:"OpenAI/Ollama compatible endpoint",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"}),i.jsx("input",{value:d.model,onChange:l=>_({model:l.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"}),i.jsx("div",{className:"hidden md:block"}),i.jsx("input",{value:d.apiKey,onChange:l=>_({apiKey:l.target.value}),placeholder:"API Key,可空;仅保存在浏览器本地",className:"md:col-span-2 bg-surface text-text-primary text-xs rounded px-2 py-1.5 border border-border-subtle focus:outline-none focus:border-accent/50"})]}),i.jsxs("div",{className:"flex gap-2",children:[i.jsx("textarea",{value:a,onChange:l=>s(l.target.value),onKeyDown:l=>{(l.ctrlKey||l.metaKey)&&l.key==="Enter"&&L()},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"}),i.jsx("button",{type:"button",onClick:()=>void L(),disabled:h,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:h?"处理中":r==="llm"?"问答":"检索"})]}),i.jsx("div",{className:"text-[11px] text-text-muted",children:"快捷键:Ctrl + Enter 提交。大模型模式会先执行本地混合检索;证据不足返回“暂无该需求描述”。"})]}),i.jsxs("div",{className:"flex-1 min-h-0 overflow-auto p-5 grid grid-cols-1 lg:grid-cols-[1fr_420px] gap-5",children:[i.jsxs("section",{className:"min-w-0",children:[i.jsxs("div",{className:"flex items-center justify-between mb-2",children:[i.jsx("h3",{className:"text-[11px] font-semibold text-accent uppercase tracking-wider",children:"回答"}),o&&i.jsxs("span",{className:`text-[11px] ${A.allowed?"text-accent":"text-text-muted"}`,children:["证据判断:",A.reason]})]}),i.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:o?m||z(o,$):"输入问题后点击“检索”或“问答”。"}),w&&i.jsxs("div",{className:"mt-2 text-xs text-red-300 border border-red-400/30 bg-red-500/10 rounded p-2",children:["模型调用失败,已回退到本地检索:",w]})]}),i.jsxs("section",{className:"min-w-0",children:[i.jsx("h3",{className:"text-[11px] font-semibold text-accent uppercase tracking-wider mb-2",children:"命中文档与排序依据"}),i.jsxs("div",{className:"space-y-2",children:[$.length===0&&o&&i.jsx("div",{className:"text-sm text-text-muted border border-border-subtle rounded-lg p-3",children:"暂无命中。"}),$.slice(0,12).map(l=>i.jsxs("button",{type:"button",onClick:()=>n(l.chunk.node.id),className:"w-full text-left border border-border-subtle bg-elevated/40 hover:border-accent/40 rounded-lg p-3 transition-colors",children:[i.jsxs("div",{className:"flex items-start justify-between gap-2",children:[i.jsxs("div",{className:"min-w-0",children:[i.jsx("div",{className:"text-sm text-text-primary truncate",children:l.chunk.docTitle}),i.jsx("div",{className:"text-[11px] text-accent mt-1 truncate",children:l.chunk.sectionTitle})]}),i.jsx("div",{className:"text-[11px] text-accent shrink-0",children:l.score.toFixed(1)})]}),i.jsx("div",{className:"text-[11px] text-text-muted mt-1 truncate",children:l.chunk.docPath}),i.jsx("div",{className:"text-xs text-text-secondary mt-2 line-clamp-3",children:l.snippet}),i.jsx("div",{className:"mt-2 flex flex-wrap gap-1",children:l.reasons.slice(0,4).map((y,N)=>i.jsxs("span",{className:"text-[10px] text-text-muted border border-border-subtle rounded px-1.5 py-0.5",children:[y.message," +",y.score.toFixed(0)]},`${l.chunk.chunkId}-${N}`))})]},l.chunk.chunkId))]})]})]})]})})}export{ue as default};
|