@3-/aiapi 0.1.4 → 0.1.5
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 +22 -0
- package/TOPIC_SCHEMA.js +40 -0
- package/TYPE.js +1 -0
- package/gemini.js +91 -0
- package/lib.js +3 -0
- package/package.json +5 -2
- package/partition.js +26 -0
- package/refmt.js +25 -0
- package/seg.js +35 -0
package/README.md
CHANGED
|
@@ -110,6 +110,28 @@ output :
|
|
|
110
110
|
```
|
|
111
111
|
标签不超过7个,用词要简短;
|
|
112
112
|
摘要不超过450字,纯文本格式,分多段。
|
|
113
|
+
{
|
|
114
|
+
role: 'assistant',
|
|
115
|
+
content: '\n' +
|
|
116
|
+
'\n' +
|
|
117
|
+
'```\n' +
|
|
118
|
+
'{"tags":[],"summary":"新能源汽车电池寿命研究\\n\\n英国Geotab报告指出,新能源车电池平均每年衰减约1.8%,20年后仍保留64%容量,续航下降但不影响日常使用。而中汽研测试显示部分车型在11.6万公里后电池健康度仅剩89.3%。两份报告存在差异,电车通认为Geotab样本量更大,结果更具代表性。车企普遍提供8-10年或15万公里三电质保,保障电池衰减风险。\\n\\n新能源车渗透率瓶颈\\n\\n尽管电池寿命问题缓解,但新能源车渗透率难以持续突破50%。主要受限于续航焦虑(CLTC测试数据与实际能耗存在差距)、购入成本(B级车新能源产品较少)及购置税政策(减半增加负担)。燃油车在驾驶体验、空间实用性上仍有优势,短期内难以被全面取代。\\n\\n固态电池的未来与挑战\\n\\n固态电池因高能量密度(600Wh/kg)被视为突破方向,奇瑞计划2026年量产,但成本高昂(100kWh电池约20万元),仅适用于高端车型。钠离子电池虽成本低,但能量密度不足。技术升级需时间,短期仍难实现长续航与低成本的平衡。\\n\\n二手车市场发展趋势\\n\\n新能源汽车保值率低于燃油车(45% vs 52%),主要因用户担忧失去质保和换代风险。但随着电池寿命保障,二手新能源车交易量同比增长32.3%,政策支持(如2025年千县万镇消费季)将推动市场发展。"}\n' +
|
|
119
|
+
'```',
|
|
120
|
+
reasoning_content: '\n' +
|
|
121
|
+
'好的,我现在需要处理用户的查询。用户给了一篇关于新能源车电池寿命和燃油车竞争的文章,然后要求生成标签和摘要,格式是JSON,并且用```包裹。标签不超过7个,用词简短;摘要不超过450字,分多段。\n' +
|
|
122
|
+
'\n' +
|
|
123
|
+
'首先,我要仔细阅读文章内容,理解主要讨论的点。文章主要比较了新能源汽车和燃油车的电池寿命,提到Geotab和中汽研的报告结果,分析了电池衰减的原因,以及车企提供的质保服务。接着讨论了新能源汽车渗透率的问题,续航焦虑和成本因素,最后提到固态电池的发展但认为它不会立即取代燃油车。\n' +
|
|
124
|
+
'\n' +
|
|
125
|
+
'接下来生成标签。标签需要简短且涵盖文章关键点。可能包括:新能源汽车、电池寿命、燃油车、续航焦虑、固态电池、二手车市场、三电质保。检查一下是否超过7个,这里正好7个,符合要求。\n' +
|
|
126
|
+
'\n' +
|
|
127
|
+
'然后是摘要。需要分多段,每段讲不同的内容。第一段可以介绍电池寿命的研究结果,Geotab和中汽研的数据对比,以及质保情况。第二段讨论新能源汽车渗透率的问题,提到销量数据、政策支持和成本因素。第三段讲固态电池的前景和成本问题,以及钠离子电池的局限。最后总结竞争的持久性和未来发展。要确保摘要不超过450字,所以每段要简洁。\n' +
|
|
128
|
+
'\n' +
|
|
129
|
+
'需要注意用户可能的深层需求,比如他们可能想了解新能源车是否真的比燃油车更好,或者两者之间的市场前景。因此摘要需要客观,既指出电池寿命的改善,也提到续航焦虑和成本问题,以及固态电池的挑战,最后强调竞争持久。这样用户能全面了解文章内容,做出自己的判断。\n' +
|
|
130
|
+
'\n' +
|
|
131
|
+
'检查标签是否准确,是否有重复或冗余。例如,是否应该将“三电质保”和“电池寿命”分开,但用户要求最多7个标签,所以保持现有结构。\n' +
|
|
132
|
+
'\n' +
|
|
133
|
+
'最后,确保JSON格式正确,没有语法错误,标签是数组,摘要是一个字符串,分段用换行符隔开。确认字数限制,避免超过。\n'
|
|
134
|
+
}
|
|
113
135
|
```
|
|
114
136
|
|
|
115
137
|
## About
|
package/TOPIC_SCHEMA.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import TYPE from './TYPE.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
type: TYPE.ARRAY,
|
|
5
|
+
description: '讨论话题的数组,每个话题都包含相关的问答对',
|
|
6
|
+
items: {
|
|
7
|
+
type: TYPE.OBJECT,
|
|
8
|
+
properties: {
|
|
9
|
+
话题: {
|
|
10
|
+
type: TYPE.STRING,
|
|
11
|
+
description: '将多个问答合并为一个组,用简短的标题描述'
|
|
12
|
+
},
|
|
13
|
+
问答: {
|
|
14
|
+
type: TYPE.ARRAY,
|
|
15
|
+
description: '与该话题相关的一系列问答对',
|
|
16
|
+
minItems: 1,
|
|
17
|
+
items: {
|
|
18
|
+
type: TYPE.OBJECT,
|
|
19
|
+
properties: {
|
|
20
|
+
题: {
|
|
21
|
+
type: TYPE.STRING,
|
|
22
|
+
description: '问答的短标题'
|
|
23
|
+
},
|
|
24
|
+
问: {
|
|
25
|
+
type: TYPE.STRING,
|
|
26
|
+
description: '提问'
|
|
27
|
+
},
|
|
28
|
+
答: {
|
|
29
|
+
type: TYPE.STRING,
|
|
30
|
+
description: '针对该问题的回答,重新分段,方便阅读'
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
required: ['题', '问', '答'],
|
|
34
|
+
propertyOrdering: ['问', '答']
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
required: ['话题', '问答']
|
|
39
|
+
}
|
|
40
|
+
};
|
package/TYPE.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {'ARRAY': 'ARRAY', 'OBJECT': 'OBJECT', 'STRING': 'STRING', 'NUMBER': 'NUMBER', 'INTEGER': 'INTEGER'};
|
package/gemini.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --trace-uncaught --expose-gc --unhandled-rejections=strict --experimental-wasm-modules
|
|
2
|
+
import sleep from '@3-/sleep';
|
|
3
|
+
|
|
4
|
+
export default (token_li) => {
|
|
5
|
+
var _NEXT_TOKEN, _nextToken, nextToken;
|
|
6
|
+
token_li.sort(() => {
|
|
7
|
+
return Math.random() - 0.5;
|
|
8
|
+
});
|
|
9
|
+
_nextToken = function*() {
|
|
10
|
+
var i;
|
|
11
|
+
while (true) {
|
|
12
|
+
for (i of token_li) {
|
|
13
|
+
yield i;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
_NEXT_TOKEN = _nextToken();
|
|
18
|
+
nextToken = () => {
|
|
19
|
+
return _NEXT_TOKEN.next().value;
|
|
20
|
+
};
|
|
21
|
+
return async(text, schema, system) => {
|
|
22
|
+
var body, err, error, r, status;
|
|
23
|
+
body = {
|
|
24
|
+
generationConfig: {
|
|
25
|
+
responseMimeType: 'application/json',
|
|
26
|
+
responseJsonSchema: schema
|
|
27
|
+
},
|
|
28
|
+
contents: [
|
|
29
|
+
{
|
|
30
|
+
parts: [{text}]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
};
|
|
34
|
+
if (system) {
|
|
35
|
+
body.system_instruction = {
|
|
36
|
+
parts: [
|
|
37
|
+
{
|
|
38
|
+
text: system
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// console.log JSON.stringify body,null,2
|
|
44
|
+
body = JSON.stringify(body);
|
|
45
|
+
while (true) {
|
|
46
|
+
try {
|
|
47
|
+
r = (await fetch('https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent', {
|
|
48
|
+
headers: {
|
|
49
|
+
'X-goog-api-key': nextToken(),
|
|
50
|
+
'Content-Type': 'application/json'
|
|
51
|
+
},
|
|
52
|
+
method: 'POST',
|
|
53
|
+
body
|
|
54
|
+
}));
|
|
55
|
+
({status} = r);
|
|
56
|
+
} catch (error1) {
|
|
57
|
+
err = error1;
|
|
58
|
+
console.error(err);
|
|
59
|
+
await sleep(1000);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (status !== 200) {
|
|
63
|
+
text = (await r.text());
|
|
64
|
+
if (status === 429) {
|
|
65
|
+
try {
|
|
66
|
+
({error} = JSON.parse(text));
|
|
67
|
+
console.warn(error.status, error.message);
|
|
68
|
+
} catch (error1) {
|
|
69
|
+
console.warn(text);
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (status === 503) {
|
|
74
|
+
console.warn(text);
|
|
75
|
+
await sleep(1000);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
throw new Error(text);
|
|
79
|
+
}
|
|
80
|
+
r = ((await r.json())).candidates[0].content.parts[0].text;
|
|
81
|
+
try {
|
|
82
|
+
r = JSON.parse(r);
|
|
83
|
+
} catch (error1) {
|
|
84
|
+
err = error1;
|
|
85
|
+
console.error(r);
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
return r;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
};
|
package/lib.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@3-/aiapi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://atomgit.com/i18n/lib.git"
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
"@3-/read": "^0.1.4"
|
|
20
20
|
},
|
|
21
21
|
"type": "module",
|
|
22
|
-
"dependencies": {
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@3-/sleep": "^0.0.4",
|
|
24
|
+
"@3-/txt_li": "^0.1.4"
|
|
25
|
+
},
|
|
23
26
|
"scripts": {}
|
|
24
27
|
}
|
package/partition.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default (lines, title_number) => {
|
|
2
|
+
let title = ''
|
|
3
|
+
// 对行号进行升序排序
|
|
4
|
+
const order = title_number.sort((a, b) => a[1] - b[1]);
|
|
5
|
+
|
|
6
|
+
// 存储最终结果的数组
|
|
7
|
+
const result = [];
|
|
8
|
+
// 追踪上一个分割点的索引
|
|
9
|
+
let start = 0;
|
|
10
|
+
|
|
11
|
+
// 遍历排序后的行号
|
|
12
|
+
for (const [t, row] of order) {
|
|
13
|
+
// 将行号转换为从0开始的数组索引
|
|
14
|
+
const index = row - 1;
|
|
15
|
+
result.push(title + lines.slice(start, index).join('\n'));
|
|
16
|
+
title = '# ' + t + '\n'
|
|
17
|
+
start = index;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 添加从最后一个分割点到末尾的剩余文本
|
|
21
|
+
if (start < lines.length) {
|
|
22
|
+
result.push(title + lines.slice(start).join('\n'));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return result;
|
|
26
|
+
};
|
package/refmt.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --trace-uncaught --expose-gc --unhandled-rejections=strict --experimental-wasm-modules
|
|
2
|
+
var 笔录转问答;
|
|
3
|
+
|
|
4
|
+
import TOPIC_SCHEMA from './TOPIC_SCHEMA.js';
|
|
5
|
+
|
|
6
|
+
import txtFmt from '@3-/txt_li/txtFmt.js';
|
|
7
|
+
|
|
8
|
+
笔录转问答 = (chat, txt) => {
|
|
9
|
+
return chat(`将以下语音对话转为JSON数组,要确保所有问答都被包含,不要遗漏:\n` + txt, TOPIC_SCHEMA, "你是专业资深的秘书");
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default async(chat, txt) => {
|
|
13
|
+
var md_li, ref, x, y, 答, 话题, 问, 问答, 题;
|
|
14
|
+
md_li = [];
|
|
15
|
+
ref = (await 笔录转问答(chat, txt));
|
|
16
|
+
for (x of ref) {
|
|
17
|
+
({话题, 问答} = x);
|
|
18
|
+
md_li.push('## ' + 话题);
|
|
19
|
+
for (y of 问答) {
|
|
20
|
+
({题, 问, 答} = y);
|
|
21
|
+
md_li.push('### ' + 题 + '\n问: ' + txtFmt(问) + '\n答: ' + txtFmt(答));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return md_li.join('\n');
|
|
25
|
+
};
|
package/seg.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --trace-uncaught --expose-gc --unhandled-rejections=strict --experimental-wasm-modules
|
|
2
|
+
import TYPE from './TYPE.js';
|
|
3
|
+
|
|
4
|
+
export default async(chat, txt_li) => {
|
|
5
|
+
var split_li, 提示词;
|
|
6
|
+
提示词 = `下文第1列为行号,第2列为对话内容,以tab分隔。
|
|
7
|
+
请划分章节,每章以提问开始,包含多组问答。
|
|
8
|
+
输出章节标题和每章首个问题的行号及原文,输出格式为JSON数组:\n` + txt_li.map((i, pos) => {
|
|
9
|
+
return (pos + 1) + '\t' + i.trim();
|
|
10
|
+
}).join('\n');
|
|
11
|
+
return split_li = (await chat(提示词, {
|
|
12
|
+
type: TYPE.ARRAY,
|
|
13
|
+
description: '章节和行号的列表',
|
|
14
|
+
items: {
|
|
15
|
+
type: TYPE.ARRAY,
|
|
16
|
+
items: false,
|
|
17
|
+
minItems: 3,
|
|
18
|
+
maxItems: 3,
|
|
19
|
+
prefixItems: [
|
|
20
|
+
{
|
|
21
|
+
description: '章节标题,1-2个词即可',
|
|
22
|
+
type: TYPE.STRING
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
description: '该章首行行号',
|
|
26
|
+
type: TYPE.INTEGER
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
description: '该章首行提问的原文',
|
|
30
|
+
type: TYPE.STRING
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}, '你是专业资深的秘书'));
|
|
35
|
+
};
|