xiaozhou-chat 1.0.6 → 1.1.0
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/lib/chat.js +51 -1
- package/package.json +1 -1
package/lib/chat.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { Spinner, StreamPrinter } from "./ui.js";
|
|
3
3
|
import { sleep } from "./utils.js";
|
|
4
|
+
import { updateConfig } from "./config.js";
|
|
4
5
|
|
|
5
6
|
// 尝试加载 Markdown 渲染库
|
|
6
7
|
let marked;
|
|
@@ -98,8 +99,13 @@ export async function chatStream(context, userInput = null, options = {}) {
|
|
|
98
99
|
|
|
99
100
|
const printer = new StreamPrinter();
|
|
100
101
|
|
|
102
|
+
let requestUrl = `${config.baseUrl}/chat/completions`;
|
|
103
|
+
|
|
104
|
+
// 自动尝试逻辑
|
|
105
|
+
let shouldRetryWithV1 = false;
|
|
106
|
+
|
|
101
107
|
try {
|
|
102
|
-
|
|
108
|
+
let res = await requestWithRetry(requestUrl, {
|
|
103
109
|
method: "POST",
|
|
104
110
|
headers: {
|
|
105
111
|
"Content-Type": "application/json",
|
|
@@ -109,9 +115,53 @@ export async function chatStream(context, userInput = null, options = {}) {
|
|
|
109
115
|
signal: signal
|
|
110
116
|
});
|
|
111
117
|
|
|
118
|
+
// 智能检测:如果返回的是 HTML (通常是 404 页或首页),且 URL 没带 v1,可能是用户配错了
|
|
119
|
+
const contentType = res.headers.get("content-type");
|
|
120
|
+
if (contentType && contentType.includes("text/html")) {
|
|
121
|
+
if (!config.baseUrl.endsWith("/v1") && !config.baseUrl.endsWith("/v1/")) {
|
|
122
|
+
console.log("\n⚠️ 检测到 API 返回 HTML,Base URL 可能缺少 '/v1'。");
|
|
123
|
+
console.log("🔄 正在尝试自动追加 '/v1' 重试...");
|
|
124
|
+
requestUrl = `${config.baseUrl}/v1/chat/completions`;
|
|
125
|
+
shouldRetryWithV1 = true;
|
|
126
|
+
|
|
127
|
+
// 重试请求
|
|
128
|
+
res = await requestWithRetry(requestUrl, {
|
|
129
|
+
method: "POST",
|
|
130
|
+
headers: {
|
|
131
|
+
"Content-Type": "application/json",
|
|
132
|
+
Authorization: `Bearer ${config.apiKey}`
|
|
133
|
+
},
|
|
134
|
+
body: JSON.stringify(body),
|
|
135
|
+
signal: signal
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
112
140
|
// 停止 Spinner,准备流式输出
|
|
113
141
|
spinner.stop();
|
|
114
142
|
|
|
143
|
+
if (shouldRetryWithV1 && res.ok && !res.headers.get("content-type")?.includes("text/html")) {
|
|
144
|
+
console.log(`✅ 自动修复成功!`);
|
|
145
|
+
|
|
146
|
+
// 自动保存配置
|
|
147
|
+
try {
|
|
148
|
+
const correctBaseUrl = config.baseUrl.endsWith("/")
|
|
149
|
+
? config.baseUrl + "v1"
|
|
150
|
+
: config.baseUrl + "/v1";
|
|
151
|
+
|
|
152
|
+
// 1. 更新内存配置
|
|
153
|
+
config.baseUrl = correctBaseUrl;
|
|
154
|
+
|
|
155
|
+
// 2. 永久保存配置
|
|
156
|
+
updateConfig("baseUrl", correctBaseUrl);
|
|
157
|
+
|
|
158
|
+
console.log(`✅ 已自动将 Base URL 更新为: ${correctBaseUrl}`);
|
|
159
|
+
console.log(` (配置已保存,无需手动修改)`);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
console.error("⚠️ 自动保存配置失败:", e.message);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
115
165
|
if (!res.body) throw new Error("Response body is empty");
|
|
116
166
|
|
|
117
167
|
const reader = res.body.getReader();
|