yuangs 1.3.9 → 1.3.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/README.md +9 -9
- package/cli.js +51 -7
- package/index.js +50 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,7 @@ yuangs ai
|
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
## 应用列表
|
|
46
|
+
|
|
46
47
|
以下是 CLI 中可以通过相应命令直接打开的应用程序链接:
|
|
47
48
|
|
|
48
49
|
古诗词 PWA: https://wealth.want.biz/shici/index.html
|
|
@@ -55,18 +56,16 @@ Pong 游戏: https://wealth.want.biz/pages/pong.html
|
|
|
55
56
|
|
|
56
57
|
### v1.3.6 (2025-11-29)
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
- **新增** AI 命令交互模式:直接输入 `yuangs ai` 即可进入一问一答模式,无需每次输入问题,quit 或 exit 可退出。
|
|
60
|
+
- **新增** AI 命令模型参数 `-m` 简写:支持 `-m <模型名称>` 代替 `--model <模型名称>`。
|
|
61
|
+
- **新增** `help` 命令显示仓库地址:方便用户直接访问项目仓库。
|
|
62
|
+
- **优化** AI 请求错误提示:在处理 AI 请求出错时,提供更清晰的错误信息。
|
|
62
63
|
|
|
63
64
|
### v1.1.x (之前版本,主要更新点)
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
- **新增** `ai` 命令:集成 AI 问答功能 (`yuangs ai "你的问题"`)。
|
|
67
|
+
- **新增** `help` 命令显示当前版本号:方便用户了解工具版本。
|
|
68
|
+
- **优化** AI 请求加载动画:在请求过程中显示加载动画和已耗时秒数,并在请求结束后显示总耗时。
|
|
70
69
|
|
|
71
70
|
## 自动发布(CI/CD)
|
|
72
71
|
|
|
@@ -78,6 +77,7 @@ Pong 游戏: https://wealth.want.biz/pages/pong.html
|
|
|
78
77
|
- 自动运行 `npm publish --provenance` 发布到 npm。
|
|
79
78
|
|
|
80
79
|
这样日常开发只需要专注写代码和推送到 `main`,发布和版本管理都由 CI 自动完成。
|
|
80
|
+
本地开发前务必先:`git pull`,确保本地代码与远程仓库一致。
|
|
81
81
|
|
|
82
82
|
## 维护者
|
|
83
83
|
|
package/cli.js
CHANGED
|
@@ -20,6 +20,9 @@ function printHelp() {
|
|
|
20
20
|
console.log(` ${chalk.green('ai')} "<问题>" 向 AI 提问(不写问题进入交互模式)`);
|
|
21
21
|
console.log(` ${chalk.gray('--model, -m <模型名称>')} 指定 AI 模型 (可选)`);
|
|
22
22
|
console.log(` ${chalk.green('help')} 显示帮助信息\n`);
|
|
23
|
+
console.log(chalk.bold('AI 交互模式命令:'));
|
|
24
|
+
console.log(` ${chalk.gray('/clear')} 清空对话历史`);
|
|
25
|
+
console.log(` ${chalk.gray('/history')} 查看对话历史\n`);
|
|
23
26
|
console.log(chalk.gray('AI 示例: yuangs ai "你好" --model gemini-pro-latest'));
|
|
24
27
|
console.log(chalk.gray('普通示例: yuangs shici\n'));
|
|
25
28
|
}
|
|
@@ -35,14 +38,23 @@ async function askOnce(question, model) {
|
|
|
35
38
|
const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
36
39
|
const interval = setInterval(() => {
|
|
37
40
|
const elapsedTime = Math.floor((Date.now() - startTime) / 1000); // Calculate elapsed time in seconds
|
|
38
|
-
process.stdout.write(chalk.cyan(`\r${spinner[i++ % spinner.length]} 正在请求 AI,请稍候... (${elapsedTime}s
|
|
41
|
+
process.stdout.write(chalk.cyan(`\r${spinner[i++ % spinner.length]} 正在请求 AI,请稍候... (${elapsedTime}s}`));
|
|
39
42
|
}, 100);
|
|
40
43
|
|
|
41
44
|
try {
|
|
42
|
-
|
|
45
|
+
// For single requests (non-interactive mode), we may want to include history
|
|
46
|
+
// For now, use history for all requests, but we could make this configurable
|
|
47
|
+
const answer = await yuangs.getAIAnswer(question, model, true);
|
|
43
48
|
clearInterval(interval);
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
|
|
50
|
+
// Clear the spinner line if possible
|
|
51
|
+
if (process.stdout.clearLine) {
|
|
52
|
+
process.stdout.clearLine(0);
|
|
53
|
+
process.stdout.cursorTo(0);
|
|
54
|
+
} else {
|
|
55
|
+
process.stdout.write('\r'); // Fallback to just carriage return
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
const totalElapsedTime = (Date.now() - startTime) / 1000; // Calculate total elapsed time
|
|
47
59
|
if (answer && answer.explanation) {
|
|
48
60
|
console.log(chalk.bold.green('🤖 AI 回答:\n'));
|
|
@@ -53,8 +65,15 @@ async function askOnce(question, model) {
|
|
|
53
65
|
console.log(chalk.gray(`\n请求耗时: ${totalElapsedTime.toFixed(2)}s\n`)); // Display total elapsed time
|
|
54
66
|
} catch (error) {
|
|
55
67
|
clearInterval(interval);
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
|
|
69
|
+
// Clear the spinner line if possible
|
|
70
|
+
if (process.stdout.clearLine) {
|
|
71
|
+
process.stdout.clearLine(0);
|
|
72
|
+
process.stdout.cursorTo(0);
|
|
73
|
+
} else {
|
|
74
|
+
process.stdout.write('\r'); // Fallback to just carriage return
|
|
75
|
+
}
|
|
76
|
+
|
|
58
77
|
const totalElapsedTime = (Date.now() - startTime) / 1000; // Calculate total elapsed time on error
|
|
59
78
|
console.error(chalk.red('处理 AI 请求时出错:'), error.message || error);
|
|
60
79
|
console.log(chalk.gray(`\n请求耗时: ${totalElapsedTime.toFixed(2)}s\n`)); // Display total elapsed time on error
|
|
@@ -84,6 +103,9 @@ async function handleAICommand() {
|
|
|
84
103
|
if (!question) {
|
|
85
104
|
console.log(chalk.bold.cyan('\n🤖 进入 AI 交互模式 (输入 exit 退出)\n'));
|
|
86
105
|
console.log(chalk.gray('直接输入你的问题,每回车一次提一个问题。\n'));
|
|
106
|
+
console.log(chalk.gray('支持的命令:'));
|
|
107
|
+
console.log(chalk.gray(' /clear - 清空对话历史'));
|
|
108
|
+
console.log(chalk.gray(' /history - 查看对话历史\n'));
|
|
87
109
|
|
|
88
110
|
const readline = require('readline');
|
|
89
111
|
const rl = readline.createInterface({
|
|
@@ -103,10 +125,32 @@ async function handleAICommand() {
|
|
|
103
125
|
process.exit(0);
|
|
104
126
|
}
|
|
105
127
|
|
|
128
|
+
// Handle special commands
|
|
129
|
+
if (trimmed === '/clear') {
|
|
130
|
+
yuangs.clearConversationHistory();
|
|
131
|
+
console.log(chalk.yellow('✓ 对话历史已清空\n'));
|
|
132
|
+
return askLoop();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (trimmed === '/history') {
|
|
136
|
+
const history = yuangs.getConversationHistory();
|
|
137
|
+
if (history.length === 0) {
|
|
138
|
+
console.log(chalk.gray('暂无对话历史\n'));
|
|
139
|
+
} else {
|
|
140
|
+
console.log(chalk.bold('📋 对话历史:\n'));
|
|
141
|
+
history.forEach((msg, index) => {
|
|
142
|
+
const prefix = msg.role === 'user' ? chalk.green('你: ') : chalk.blue('AI: ');
|
|
143
|
+
console.log(prefix + msg.content);
|
|
144
|
+
});
|
|
145
|
+
console.log('');
|
|
146
|
+
}
|
|
147
|
+
return askLoop();
|
|
148
|
+
}
|
|
149
|
+
|
|
106
150
|
if (!trimmed) {
|
|
107
151
|
return askLoop(); // 空输入则重新询问
|
|
108
152
|
}
|
|
109
|
-
|
|
153
|
+
|
|
110
154
|
// 等待回答完成后,再开启下一轮询问
|
|
111
155
|
await askOnce(trimmed, model);
|
|
112
156
|
askLoop();
|
package/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const { exec } = require('child_process');
|
|
2
2
|
const axios = require('axios');
|
|
3
3
|
|
|
4
|
+
// Store conversation history
|
|
5
|
+
let conversationHistory = [];
|
|
6
|
+
|
|
4
7
|
const APPS = {
|
|
5
8
|
shici: 'https://wealth.want.biz/shici/index.html',
|
|
6
9
|
dict: 'https://wealth.want.biz/pages/dict.html',
|
|
@@ -17,9 +20,39 @@ function openUrl(url) {
|
|
|
17
20
|
exec(command);
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
// Function to add a message to the conversation history
|
|
24
|
+
function addToConversationHistory(role, content) {
|
|
25
|
+
conversationHistory.push({ role, content });
|
|
26
|
+
|
|
27
|
+
// Keep only the last 20 messages to prevent history from growing too large
|
|
28
|
+
if (conversationHistory.length > 20) {
|
|
29
|
+
conversationHistory = conversationHistory.slice(-20);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Function to clear conversation history
|
|
34
|
+
function clearConversationHistory() {
|
|
35
|
+
conversationHistory = [];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Function to get conversation history
|
|
39
|
+
function getConversationHistory() {
|
|
40
|
+
return conversationHistory;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getAIAnswer(question, model, includeHistory = true) {
|
|
21
44
|
const url = 'https://aiproxy.want.biz/ai/explain';
|
|
22
|
-
|
|
45
|
+
|
|
46
|
+
// Prepare the prompt with conversation history if enabled
|
|
47
|
+
let prompt = question;
|
|
48
|
+
if (includeHistory && conversationHistory.length > 0) {
|
|
49
|
+
// Create a context with the current question added to history
|
|
50
|
+
const contextWithHistory = [...conversationHistory, { role: 'user', content: question }];
|
|
51
|
+
prompt = contextWithHistory.map(msg => `${msg.role}: ${msg.content}`).join('\n\n');
|
|
52
|
+
} else {
|
|
53
|
+
// If not including history, just use the question directly
|
|
54
|
+
prompt = question;
|
|
55
|
+
}
|
|
23
56
|
|
|
24
57
|
const headers = {
|
|
25
58
|
'Referer': 'https://wealth.want.biz/',
|
|
@@ -35,7 +68,17 @@ async function getAIAnswer(question, model) {
|
|
|
35
68
|
|
|
36
69
|
try {
|
|
37
70
|
const response = await axios.post(url, data, { headers });
|
|
38
|
-
|
|
71
|
+
const answer = response.data;
|
|
72
|
+
|
|
73
|
+
// Add the user's question to the conversation history
|
|
74
|
+
addToConversationHistory('user', question);
|
|
75
|
+
|
|
76
|
+
// Add the AI response to the conversation history
|
|
77
|
+
if (answer && answer.explanation) {
|
|
78
|
+
addToConversationHistory('assistant', answer.explanation);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return answer;
|
|
39
82
|
} catch (error) {
|
|
40
83
|
console.error('AI 请求失败:', error.response?.data?.message || error.message || '未知错误');
|
|
41
84
|
return null;
|
|
@@ -51,5 +94,8 @@ module.exports = {
|
|
|
51
94
|
console.log('--- YGS Apps ---');
|
|
52
95
|
Object.entries(APPS).forEach(([key, url]) => console.log(`${key}: ${url}`));
|
|
53
96
|
},
|
|
54
|
-
getAIAnswer
|
|
97
|
+
getAIAnswer,
|
|
98
|
+
addToConversationHistory,
|
|
99
|
+
clearConversationHistory,
|
|
100
|
+
getConversationHistory
|
|
55
101
|
};
|