chaimi-keep-mcp 3.3.3-beta.10 → 3.3.3-beta.12
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/bin/record.js +57 -0
- package/package.json +1 -1
- package/server.js +30 -15
- package/utils/category-mapper.js +15 -0
package/bin/record.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 柴米AI记账 - 直接记账 CLI
|
|
4
|
+
* 一步完成:解析文本 → 分类 → 调用云函数存储
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { callMcpHub } = require('../utils/api');
|
|
8
|
+
const { getToken } = require('../utils/auth');
|
|
9
|
+
const { parseText } = require('../utils/parser');
|
|
10
|
+
|
|
11
|
+
async function record(text, options = {}) {
|
|
12
|
+
try {
|
|
13
|
+
// 1. 解析文本
|
|
14
|
+
const parsed = await parseText(text);
|
|
15
|
+
|
|
16
|
+
// 2. 确定类型(收入/支出)
|
|
17
|
+
const type = options.type || parsed.type || 'expense';
|
|
18
|
+
|
|
19
|
+
// 3. 获取 token
|
|
20
|
+
const token = await getToken();
|
|
21
|
+
|
|
22
|
+
// 4. 调用云函数存储
|
|
23
|
+
const result = await callMcpHub(type === 'income' ? 'addIncome' : 'addExpense', {
|
|
24
|
+
...parsed,
|
|
25
|
+
type,
|
|
26
|
+
rawInput: text
|
|
27
|
+
}, token);
|
|
28
|
+
|
|
29
|
+
if (result.success) {
|
|
30
|
+
console.log('✅ 记账成功!');
|
|
31
|
+
console.log(`金额:¥${parsed.amount}`);
|
|
32
|
+
console.log(`分类:${parsed.category}`);
|
|
33
|
+
console.log(`商品:${parsed.name}`);
|
|
34
|
+
} else {
|
|
35
|
+
console.error('❌ 记账失败:', result.error);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('❌ 错误:', error.message);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 解析命令行参数
|
|
45
|
+
const args = process.argv.slice(2);
|
|
46
|
+
const text = args[0];
|
|
47
|
+
const typeFlag = args.find(arg => arg.startsWith('--type='));
|
|
48
|
+
const type = typeFlag ? typeFlag.split('=')[1] : null;
|
|
49
|
+
|
|
50
|
+
if (!text) {
|
|
51
|
+
console.log('用法: chaimi-keep record "<记账文本>" [--type=income|expense]');
|
|
52
|
+
console.log('示例: chaimi-keep record "中午吃饭花了35元"');
|
|
53
|
+
console.log('示例: chaimi-keep record "工资收入5000" --type=income');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
record(text, { type });
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -259,7 +259,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
259
259
|
},
|
|
260
260
|
{
|
|
261
261
|
name: 'save_expense',
|
|
262
|
-
description: '【文本记账-支出】用户提及支出/消费时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt
|
|
262
|
+
description: '【文本记账-支出】用户提及支出/消费时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt获取凭证和解析模板。用法:mcporter call 柴米AI记账.save_expense _flowmate="SOLINWANG..." name="午餐" amount=35 category="餐饮" rawInput="午餐35元"。注意:上传图片请用save_receipt',
|
|
263
263
|
inputSchema: {
|
|
264
264
|
type: 'object',
|
|
265
265
|
properties: {
|
|
@@ -275,13 +275,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
275
275
|
agentType: { type: 'string', description: '【必填】Agent类型,如:claude-desktop、cursor、openclaw、workbuddy、trae' },
|
|
276
276
|
apiProvider: { type: 'string', description: '【必填】AI服务提供商,如:anthropic、openai、doubao、aliyun' },
|
|
277
277
|
rawInput: { type: 'string', description: '【必填】用户的原始输入内容,用于记录用户原始请求' },
|
|
278
|
+
_flowmate: { type: 'string', description: '【必填】流程凭证,从get_text_parse_prompt获取的myflowmate值' },
|
|
278
279
|
},
|
|
279
|
-
required: ['name', 'amount', 'category', 'agentType', 'apiProvider', 'rawInput'],
|
|
280
|
+
required: ['name', 'amount', 'category', 'agentType', 'apiProvider', 'rawInput', '_flowmate'],
|
|
280
281
|
},
|
|
281
282
|
},
|
|
282
283
|
{
|
|
283
284
|
name: 'save_receipt',
|
|
284
|
-
description: '【图片记账-小票】用户上传小票/发票/收据图片时用此工具。前置:必须先调用get_skill获取规范,再调用get_parse_prompt
|
|
285
|
+
description: '【图片记账-小票】用户上传小票/发票/收据图片时用此工具。前置:必须先调用get_skill获取规范,再调用get_parse_prompt获取凭证和解析模板。用法:mcporter call 柴米AI记账.save_receipt _flowmate="SOLINWANG..." store="超市" totalAmount=156.5 items="[...]"。注意:文字描述请用save_expense/save_income',
|
|
285
286
|
inputSchema: {
|
|
286
287
|
type: 'object',
|
|
287
288
|
properties: {
|
|
@@ -322,8 +323,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
322
323
|
agentType: { type: 'string', description: '【必填】Agent类型:claude-desktop、cursor、openclaw、workbuddy、trae' },
|
|
323
324
|
apiProvider: { type: 'string', description: '【必填】AI服务提供商:anthropic、openai、doubao、aliyun' },
|
|
324
325
|
rawInput: { type: 'string', description: '【必填】用户的原始输入内容' },
|
|
326
|
+
_flowmate: { type: 'string', description: '【必填】流程凭证,从get_parse_prompt获取的myflowmate值' },
|
|
325
327
|
},
|
|
326
|
-
required: ['store', 'items', 'storeCategory', 'storeSubCategory', 'agentType', 'apiProvider', 'rawInput'],
|
|
328
|
+
required: ['store', 'items', 'storeCategory', 'storeSubCategory', 'agentType', 'apiProvider', 'rawInput', '_flowmate'],
|
|
327
329
|
},
|
|
328
330
|
},
|
|
329
331
|
{
|
|
@@ -409,7 +411,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
409
411
|
},
|
|
410
412
|
{
|
|
411
413
|
name: 'save_income',
|
|
412
|
-
description: '【文本记账-收入】用户提及收入关键词(工资、红包、转账、退款等)时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt
|
|
414
|
+
description: '【文本记账-收入】用户提及收入关键词(工资、红包、转账、退款等)时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt获取凭证和解析模板。用法:mcporter call 柴米AI记账.save_income _flowmate="SOLINWANG..." name="红包" amount=100 category="礼金" rawInput="收红包100元"',
|
|
413
415
|
inputSchema: {
|
|
414
416
|
type: 'object',
|
|
415
417
|
properties: {
|
|
@@ -422,13 +424,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
422
424
|
agentType: { type: 'string', description: '【必填】Agent类型,如:claude-desktop、cursor、openclaw、workbuddy、trae' },
|
|
423
425
|
apiProvider: { type: 'string', description: '【必填】AI服务提供商,如:anthropic、openai、doubao、aliyun' },
|
|
424
426
|
rawInput: { type: 'string', description: '【必填】用户的原始输入内容,用于记录用户原始请求' },
|
|
427
|
+
_flowmate: { type: 'string', description: '【必填】流程凭证,从get_text_parse_prompt获取的myflowmate值' },
|
|
425
428
|
},
|
|
426
|
-
required: ['name', 'amount', 'category', 'agentType', 'apiProvider', 'rawInput'],
|
|
429
|
+
required: ['name', 'amount', 'category', 'agentType', 'apiProvider', 'rawInput', '_flowmate'],
|
|
427
430
|
},
|
|
428
431
|
},
|
|
429
432
|
{
|
|
430
433
|
name: 'get_text_parse_prompt',
|
|
431
|
-
description: '【不调用100%失败】获取文字记账解析的Prompt
|
|
434
|
+
description: '【不调用100%失败】获取文字记账解析的Prompt模板和流程凭证。⚠️ 文字/语音记账必须先调用此工具获取凭证,AI解析时必须返回_flowmate字段,否则save_expense/save_income会报MISSING_TOKEN错误!',
|
|
432
435
|
inputSchema: {
|
|
433
436
|
type: 'object',
|
|
434
437
|
properties: {
|
|
@@ -439,7 +442,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
439
442
|
},
|
|
440
443
|
{
|
|
441
444
|
name: 'get_parse_prompt',
|
|
442
|
-
description: '【不调用100%失败】获取小票图片解析的Prompt
|
|
445
|
+
description: '【不调用100%失败】获取小票图片解析的Prompt模板和流程凭证。⚠️ 小票记账必须先调用此工具获取凭证,AI解析时必须返回_flowmate字段,否则save_receipt会报MISSING_TOKEN错误!',
|
|
443
446
|
inputSchema: {
|
|
444
447
|
type: 'object',
|
|
445
448
|
properties: {
|
|
@@ -1047,6 +1050,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1047
1050
|
}
|
|
1048
1051
|
}
|
|
1049
1052
|
|
|
1053
|
+
// 添加 agentType 和 apiProvider 到 processedArgs,确保 convertParams 能获取到
|
|
1054
|
+
processedArgs.agentType = agentType || '';
|
|
1055
|
+
processedArgs.apiProvider = apiProvider || '';
|
|
1056
|
+
|
|
1050
1057
|
const mcpParams = convertParams('save_expense', processedArgs);
|
|
1051
1058
|
result = await callMcpHubWithLogging('addExpense', mcpParams, token, traceId, startTime, osInfo, agentType, apiProvider);
|
|
1052
1059
|
|
|
@@ -1326,6 +1333,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1326
1333
|
};
|
|
1327
1334
|
}
|
|
1328
1335
|
|
|
1336
|
+
// 添加 agentType 和 apiProvider 到 processedArgs,确保 convertParams 能获取到
|
|
1337
|
+
processedArgs.agentType = agentType || '';
|
|
1338
|
+
processedArgs.apiProvider = apiProvider || '';
|
|
1339
|
+
|
|
1329
1340
|
const mcpParams = convertParams('save_receipt', processedArgs);
|
|
1330
1341
|
result = await callMcpHubWithLogging('addReceipt', mcpParams, token, traceId, startTime, osInfo, agentType, apiProvider);
|
|
1331
1342
|
|
|
@@ -1573,6 +1584,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1573
1584
|
}
|
|
1574
1585
|
}
|
|
1575
1586
|
|
|
1587
|
+
// 添加 agentType 和 apiProvider 到 processedArgs,确保 convertParams 能获取到
|
|
1588
|
+
processedArgs.agentType = agentType || '';
|
|
1589
|
+
processedArgs.apiProvider = apiProvider || '';
|
|
1590
|
+
|
|
1576
1591
|
const mcpParams = convertParams('save_income', processedArgs);
|
|
1577
1592
|
result = await callMcpHubWithLogging('addIncome', mcpParams, token, traceId, startTime, osInfo, agentType, apiProvider);
|
|
1578
1593
|
|
|
@@ -1613,8 +1628,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1613
1628
|
systemPrompt: promptResult.data.systemPrompt,
|
|
1614
1629
|
userPromptTemplate: promptResult.data.userPromptTemplate,
|
|
1615
1630
|
examples: promptResult.data.examples,
|
|
1616
|
-
|
|
1617
|
-
instructions: '请将 systemPrompt 作为 system message,把小票图片作为 user message,调用你的大模型进行解析。解析完成后,调用 save_receipt 工具保存结果。⚠️ 注意:AI解析结果必须包含
|
|
1631
|
+
myflowmate: promptResult.data.myflowmate,
|
|
1632
|
+
instructions: '请将 systemPrompt 作为 system message,把小票图片作为 user message,调用你的大模型进行解析。解析完成后,调用 save_receipt 工具保存结果。⚠️ 注意:AI解析结果必须包含 _flowmate 字段!'
|
|
1618
1633
|
}
|
|
1619
1634
|
};
|
|
1620
1635
|
// 【新增】返回模板位置信息(Server只返回原始数据,Agent使用模板渲染)
|
|
@@ -1641,7 +1656,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1641
1656
|
prompt: promptResult.data.prompt,
|
|
1642
1657
|
currentDate: promptResult.data.currentDate,
|
|
1643
1658
|
currentTime: promptResult.data.currentTime,
|
|
1644
|
-
|
|
1659
|
+
myflowmate: promptResult.data.myflowmate,
|
|
1645
1660
|
instructions: promptResult.data.instructions
|
|
1646
1661
|
}
|
|
1647
1662
|
};
|
|
@@ -2109,7 +2124,7 @@ function convertParams(toolName, args) {
|
|
|
2109
2124
|
apiProvider: sanitizeString(args.apiProvider, 50) || '',
|
|
2110
2125
|
mcpVersion: MCP_VERSION,
|
|
2111
2126
|
source: 'mcp_txt_expense',
|
|
2112
|
-
|
|
2127
|
+
_flowmate: args._flowmate,
|
|
2113
2128
|
};
|
|
2114
2129
|
}
|
|
2115
2130
|
|
|
@@ -2166,11 +2181,11 @@ function convertParams(toolName, args) {
|
|
|
2166
2181
|
source: 'mcp_receipt',
|
|
2167
2182
|
storeCategory: sanitizeString(args.storeCategory, 50) || '其他',
|
|
2168
2183
|
storeSubCategory: sanitizeString(args.storeSubCategory, 50) || '其他',
|
|
2169
|
-
|
|
2184
|
+
_flowmate: args._flowmate,
|
|
2170
2185
|
};
|
|
2171
2186
|
}
|
|
2172
2187
|
|
|
2173
|
-
case '
|
|
2188
|
+
case 'save_receipt': {
|
|
2174
2189
|
// 【新增】支持 period 参数
|
|
2175
2190
|
const periodDates = args.period ? parsePeriod(args.period) : {};
|
|
2176
2191
|
return {
|
|
@@ -2208,7 +2223,7 @@ function convertParams(toolName, args) {
|
|
|
2208
2223
|
apiProvider: sanitizeString(args.apiProvider, 50) || '',
|
|
2209
2224
|
mcpVersion: MCP_VERSION,
|
|
2210
2225
|
source: 'mcp_txt_income',
|
|
2211
|
-
|
|
2226
|
+
_flowmate: args._flowmate,
|
|
2212
2227
|
};
|
|
2213
2228
|
|
|
2214
2229
|
default:
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分类标准化映射器
|
|
3
|
+
* 将 Agent 提取的关键词映射到标准分类
|
|
4
|
+
* 确保分类一致性,便于后续统计
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// 标准分类列表
|
|
8
|
+
const STANDARD_CATEGORIES = [
|
|
9
|
+
'餐饮', '购物', '交通', '蔬菜', '水果', '零食', '运动', '通讯', '服饰', '美容',
|
|
10
|
+
'住房', '孩子', '长辈', '社交', '旅行', '烟酒', '数码', '汽车', '医疗', '办公',
|
|
11
|
+
'学习', '宠物', '礼金', '亲友', '日用', '休闲娱乐', '维修', '居家', '饮品', '鲜花',
|
|
12
|
+
'追星', '首饰', '借出', '保险', '网络虚拟', '生活缴费', '转账', '书籍', '捐赠', '彩票', '快递', '其他'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
// 关键词到
|