feat: 强制停止AI回复 - 真正中止Ollama接口请求

- ollama-api.js: chatStream 新增 AbortController 参数,同时中止 fetch 和 reader
- input-area.js: 发送按钮流式时变为停止按钮(红色方块),点击立即 abort
- abort 时保留已生成内容,标记 [已停止]
- 停止按钮带脉冲动画,视觉反馈明确
- 真正的接口级别终止:fetch abort + reader.cancel 双重保险
This commit is contained in:
thzxx
2026-04-03 12:31:04 +08:00
parent 6088ea4629
commit f80dd7f390
3 changed files with 101 additions and 9 deletions
+19 -3
View File
@@ -69,8 +69,10 @@ export class OllamaAPI {
* 使用 ReadableStream + TextDecoder 解析 NDJSON 流
* Ollama 流式响应格式 (NDJSON):
* {"model":"xxx","message":{"role":"assistant","content":"Hello"},"done":false}
*
* @param {AbortController} [abortController] - 可选,用于强制终止流
*/
async chatStream(params, onChunk) {
async chatStream(params, onChunk, abortController) {
const body = {
model: params.model,
messages: params.messages,
@@ -81,15 +83,29 @@ export class OllamaAPI {
...(params.options && { options: params.options })
};
const response = await this._request('/api/chat', {
const fetchOptions = {
method: 'POST',
body: JSON.stringify(body)
});
};
// 注入 abort 信号,同时中止 fetch 和 reader
if (abortController) {
fetchOptions.signal = abortController.signal;
}
const response = await this._request('/api/chat', fetchOptions);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
// 如果外部触发 abort,立即取消 reader(双重保险:fetch abort + reader.cancel
if (abortController) {
abortController.signal.addEventListener('abort', () => {
reader.cancel();
}, { once: true });
}
while (true) {
const { done, value } = await reader.read();
if (done) break;