dsh-form-fill-agent 0.2.18 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/lib/diagnostics.js +1 -1
- package/lib/http.js +2 -2
- package/lib/mapping-recommendations.js +3 -0
- package/lib/ui.html +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
AI填表智能体:支持自动填表、表格填充、表格补全、Excel填表与 Excel回填;使用企查查 MCP 填写 XLSX 空白字段,预览确认后导出新副本。
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
dsh plugin --profile web add dsh-form-fill-agent@0.2.
|
|
8
|
+
dsh plugin --profile web add dsh-form-fill-agent@0.2.19
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
请先满足下文的 DSH、连接器及侧边栏依赖要求;安装后完整停止并重启对应 Profile。
|
|
@@ -64,7 +64,7 @@ dsh plugin --profile web add dsh-form-fill-agent@latest
|
|
|
64
64
|
|
|
65
65
|
## 使用边界与数据保存
|
|
66
66
|
|
|
67
|
-
补充要求为模型可读文本;字段或工作表范围请通过向导/工作台修改,不能仅改文字后假定执行范围已同步。任务 schema 5 可读取 schema 1–5;回退旧版本请使用升级前目录副本或独立任务目录。主包为 0.2.
|
|
67
|
+
补充要求为模型可读文本;字段或工作表范围请通过向导/工作台修改,不能仅改文字后假定执行范围已同步。任务 schema 5 可读取 schema 1–5;回退旧版本请使用升级前目录副本或独立任务目录。主包为 0.2.19,共享内核为 0.2.10,Provider 为 0.2.1,共享字段契约为 0.1.0。
|
|
68
68
|
|
|
69
69
|
支持企业完整登记名称或 18 位信用代码;简称、主体不一致或多候选不会自动猜选。仅有信用代码的表格也可作为查询锚点。连接候选检索工具时可检索简称,仍需人工确认;缺少工具时降级人工输入。字段映射采用确定性规则及人工确认,不让模型编造事实。支持普通内部公式、固定区域下拉、基础条件格式和普通表格对象;复杂 Excel 结构和 Word 暂不支持,保真边界见下方安全说明。
|
|
70
70
|
|
|
@@ -72,7 +72,7 @@ dsh plugin --profile web add dsh-form-fill-agent@latest
|
|
|
72
72
|
|
|
73
73
|
显式设置 DSH_HOME 时,任务保存至其 form-fill-tasks 目录,默认 24 小时过期;未设置时使用内存。任务保存输入表格和归一化预览,不持久化原始 MCP 响应,可主动删除任务。模型及 MCP 凭据由宿主管理。
|
|
74
74
|
|
|
75
|
-
0.2.
|
|
75
|
+
0.2.19 保存任务 schema 5,兼容读取旧 schema 1–4;回退旧版本须使用升级前任务目录副本或新目录,防止丢失已确认的字段/主体设置。
|
|
76
76
|
|
|
77
77
|
## 文档与反馈
|
|
78
78
|
|
package/lib/diagnostics.js
CHANGED
|
@@ -44,5 +44,5 @@ export function renderEnrichmentResult(value) {
|
|
|
44
44
|
const reasons=value.diagnostics?.reasons||[];
|
|
45
45
|
return 'AI填表:可填写 '+value.filled+' 格,未完成 '+value.incomplete+' 项。'
|
|
46
46
|
+(reasons.length?'原因分类:'+reasons.map(r=>r.label+' '+r.count+r.unit).join(';')+'。':'')
|
|
47
|
-
+'
|
|
47
|
+
+'可填写仅代表预览,尚未写入副本;必须在工作台确认后下载。未完成包含范围排除、映射或查询问题,不可统一解释为企查查查不到,也不能仅凭可填写为 0 推断授权异常;请依据具体错误记录。预览:'+value.previewPath;
|
|
48
48
|
}
|
package/lib/http.js
CHANGED
|
@@ -7,7 +7,7 @@ import { createTaskStore } from './task-store.js';
|
|
|
7
7
|
import { allCandidates, selectCandidates } from './task-model.js';
|
|
8
8
|
import { gridPage } from './grid.js';
|
|
9
9
|
import { diagnostics } from './diagnostics.js';
|
|
10
|
-
import { mappingRecommendations } from './mapping-recommendations.js';
|
|
10
|
+
import { mappingRecommendations, mappingSearchAliases } from './mapping-recommendations.js';
|
|
11
11
|
const XLSX_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
12
12
|
const FIXTURES = ['客户台账', '供应商准入表', '合同主体信息表'];
|
|
13
13
|
export function createFormFillHandler({ basePath = '', getPort, now = Date.now, ttlMs = 15 * 60 * 1000, maxTasks = 10, taskDirectory, getQccStatus = () => false } = {}) {
|
|
@@ -26,7 +26,7 @@ export function createFormFillHandler({ basePath = '', getPort, now = Date.now,
|
|
|
26
26
|
progress: task.progress,
|
|
27
27
|
candidates: allCandidates(task).changes,
|
|
28
28
|
selectedIds: task.preview.changeSet.changes.map(c=>c.id),
|
|
29
|
-
catalog: FIELD_CATALOG,
|
|
29
|
+
catalog: FIELD_CATALOG.map(field=>({...field,searchAliases:mappingSearchAliases(field.key)})),
|
|
30
30
|
catalogGroups: [...QCC_FIELD_CATALOG,ACTUAL_CONTROLLER_GROUP].map(g=>({id:g.id,label:g.label,fields:g.fields.flatMap(item=>FIELD_CATALOG.filter(f=>f.key===item.id||f.aliases?.includes(item.id)).map(f=>f.key))})),
|
|
31
31
|
structure: parseWorkbook(task.bytes).sheets.filter(s => !s.hidden).map(s => ({
|
|
32
32
|
name: s.name,
|
|
@@ -23,6 +23,9 @@ const ambiguous = {
|
|
|
23
23
|
所属行业:['industry_category','qcc_industry'],行业:['industry_category','qcc_industry'],法人:['legal_person'],
|
|
24
24
|
};
|
|
25
25
|
const normalize=value=>String(value??'').normalize('NFKC').toLowerCase().replace(/[\s_\-·]/g,'');
|
|
26
|
+
export function mappingSearchAliases(key){
|
|
27
|
+
return [...(aliases[key]||[]),...Object.entries(ambiguous).filter(([,keys])=>keys.includes(key)).map(([label])=>label)];
|
|
28
|
+
}
|
|
26
29
|
export function mappingRecommendations(header,catalog){
|
|
27
30
|
const label=normalize(String(header??'').normalize('NFKC').replace(/\s*\(?\s*YYYY[-/]MM[-/]DD\s*\)?\s*$/i,''));
|
|
28
31
|
if(!label)return [];
|
package/lib/ui.html
CHANGED
|
@@ -68,14 +68,14 @@ function syncActions(){
|
|
|
68
68
|
const running=current?.state==='enriching';$('cancel-run').hidden=!running;$('cancel-run').disabled=busy||!running;
|
|
69
69
|
$('retry-run').hidden=!current||current.confirmed||!current.changeSet.incomplete.some(i=>['provider-error','cancelled','not-started'].includes(i.reason));
|
|
70
70
|
$('retry-run').disabled=busy||!current||current.confirmed||running||!current.changeSet.incomplete.some(i=>['provider-error','cancelled','not-started'].includes(i.reason));
|
|
71
|
-
$('execution-progress').textContent=running?(current.progress?.total?'
|
|
71
|
+
$('execution-progress').textContent=running?(current.progress?.total?'已处理查询计划项 '+(current.progress?.completed||0)+' / '+current.progress.total+'(含失败,不代表填写成功)':'正在准备查询…'):current?.state==='cancelled'?'已取消,成功结果保留。':current?.state==='interrupted'?'上次查询中断,已保存进度,可重试剩余部分。':'';
|
|
72
72
|
for(const id of ['confirm','selection','configure'])$(id).disabled=busy||!current||current.confirmed||running;
|
|
73
73
|
}
|
|
74
74
|
$('cancel-run').onclick=async()=>{try{await api('/cancel',{id:current.id});$('status').textContent='已请求取消。已发出的请求可能已在远端执行,本地不再继续后续查询。';await restore()}catch(e){$('status').textContent=e.message}};
|
|
75
75
|
$('retry-run').onclick=()=>{openWizard(true);wizardStep=3;renderWizard()};
|
|
76
76
|
async function api(path,body){if(current&&body?.id===current.id)body={...body,expectedRevision:current.revision};const response=await fetch(basePath+path,{...(body===undefined?{}:{method:'POST',body:JSON.stringify(body)}),headers:{'Content-Type':'application/json','X-Form-Fill-Owner':owner}});const data=await response.json();if(!response.ok)throw Error(data.message);return data}
|
|
77
77
|
function navigate(target){if(target==='wizard'){openWizard();return}if(target!=='import'&&!current){$('status').textContent='请先导入表格。';return}step=target;$('history').hidden=true;$('current').hidden=false;$('current-tab').setAttribute('aria-pressed','true');$('history-tab').setAttribute('aria-pressed','false');document.querySelectorAll('[data-pane]').forEach(p=>p.hidden=p.dataset.pane!==target);document.querySelectorAll('[data-step]').forEach(b=>b.setAttribute('aria-current',String(b.dataset.step===target)))}
|
|
78
|
-
function downloads(){ $('downloads').replaceChildren();for(const [kind,label,suffix] of [['xlsx','下载已填副本','-已填副本.xlsx'],['changes','下载变更清单','-变更.json'],['incomplete','下载未完成项','-未完成.json']]){const a=document.createElement('a');Object.assign(a,{className:'download',href:basePath+'/download/'+current.id+'/'+kind,download:filename+suffix,textContent:label});$('downloads').append(a)}}
|
|
78
|
+
function downloads(){ $('downloads').replaceChildren();for(const [kind,label,suffix] of [['xlsx','下载已填副本','-已填副本.xlsx'],['changes','下载变更清单','-变更.json'],['incomplete','下载未完成项','-未完成.json']]){if(kind==='incomplete'&&!current.changeSet.incomplete.length)continue;const a=document.createElement('a');Object.assign(a,{className:'download',href:basePath+'/download/'+current.id+'/'+kind,download:filename+suffix,textContent:label});$('downloads').append(a)}}
|
|
79
79
|
function businessSummary(){return current?(retryIntent?'仅重试失败、取消或未执行的部分,保留成功结果。':'')+'填写文件“'+current.filename+'”中的空白字段。共 '+current.analysis.tables.length+' 个工作表,'+wizardFields.size+' 个填写字段,'+current.analysis.opportunities.filter(p=>wizardFields.has(p.field)).length+' 个待补空位置。字段范围以本次保存的映射为准。保留已有值、公式与未确认位置,核验预览后生成新副本。':'请先上传 XLSX 文件。'}
|
|
80
80
|
function command(){return current?businessSummary()+'\n'+$('requirements').value+'\n执行关联:调用 form_fill_enrich:taskId='+current.id+',expectedRevision='+current.revision+(retryIntent?',mode=retry':'')+'。字段范围以工作台确认设置为准。':''}
|
|
81
81
|
function mappingVersion(){return JSON.stringify({tables:current?.analysis.tables.map(t=>({sheet:t.sheet,headerRow:t.headerRow,anchors:t.anchors,mappings:t.mappings.map(m=>[m.column,m.field,m.role,m.evidence])})),scope:current?.selectedFields??null})}
|
|
@@ -196,7 +196,7 @@ function renderSettings(data){
|
|
|
196
196
|
for(const [value,text] of [['input','用于定位企业'],['output','仅接收填写']]){const o=document.createElement('option');o.value=value;o.textContent=text;role.append(o)}
|
|
197
197
|
role.value=override?.role||'input';
|
|
198
198
|
const normalize=s=>String(s).normalize('NFKC').toLowerCase().replace(/[\s_()()·-]/g,'');
|
|
199
|
-
const matches=(field,query)=>{const text=normalize([field.label,field.key,...(field.aliases||[])].join(' '));return query.trim().split(/\s+/).every(word=>{const q=normalize(word);if(text.includes(q))return true;if(q.length<2)return false;let i=0;for(const c of text)if(c===q[i])i++;return i===q.length})};
|
|
199
|
+
const matches=(field,query)=>{const text=normalize([field.label,field.key,...(field.aliases||[]),...(field.searchAliases||[])].join(' '));return query.trim().split(/\s+/).every(word=>{const q=normalize(word);if(text.includes(q))return true;if(q.length<2)return false;let i=0;for(const c of text)if(c===q[i])i++;return i===q.length})};
|
|
200
200
|
const search=document.createElement('input');search.type='search';search.placeholder='关键词,例如:电话、信用代码';search.setAttribute('aria-label',sheet.name+' 搜索目标字段 '+cell.label);
|
|
201
201
|
const dimension=document.createElement('select');dimension.setAttribute('aria-label',sheet.name+' 字段维度 '+cell.label);
|
|
202
202
|
const groups=[{id:'',label:'全部维度'},...(data.catalogGroups||[]),{id:'other',label:'其他字段'}];
|
|
@@ -266,7 +266,7 @@ function render(data){
|
|
|
266
266
|
current=data;directScope();$('direct-command').hidden=true;filename=(data.filename||'已填表格.xlsx').replace(/\.xlsx$/i,'');location.hash='task='+data.id;
|
|
267
267
|
if(gridTask!==data.id){gridTask=data.id;gridPageNumber=1;gridColumn=1;$('grid-sheet').replaceChildren();$('grid-query').value=''}$('grid').hidden=false;loadGrid();
|
|
268
268
|
if(parent!==window)parent.postMessage({type:'ff-task',taskId:data.id},location.origin);
|
|
269
|
-
$('changes').replaceChildren();$('incomplete').replaceChildren();$('downloads').replaceChildren();
|
|
269
|
+
$('incomplete').closest('.card').style.display=data.changeSet.incomplete.length?'':'none';$('changes').replaceChildren();$('incomplete').replaceChildren();$('downloads').replaceChildren();
|
|
270
270
|
$('task-meta').dataset.state=data.state;
|
|
271
271
|
$('task-meta').textContent=(data.filename||'表格')+' · '+({'enriching':'查询中','completed':'已生成副本'+(data.changeSet.incomplete.length?',仍有 '+data.changeSet.incomplete.length+' 项未完成':''),'interrupted':'查询中断,请重新核验','partial':'部分完成','preview_ready':'可核验'}[data.state]||data.state)+' · 有效期至 '+new Date(data.expiresAt).toLocaleString();
|
|
272
272
|
$('summary').textContent='可填写 '+data.changeSet.changes.length+' 格 · '+(data.plan.paidCalls?'企查查来源':'本地分析 / 合成示例 · 费用 0')+' · 未完成 '+data.changeSet.incomplete.length+' 项';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-form-fill-agent",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "AI form filling and spreadsheet autofill for XLSX in DeepSeek Harness, using authorized Qichacha MCP facts with cell previews, user confirmation and export to a new copy.",
|
|
6
6
|
"repository": {
|