fix: 移除损坏的 Claude gitlink 并同步业务与文档更新
- 从索引移除误记录的 .claude/worktrees gitlink(旧绝对路径会导致 git 命令失败) - 新增根目录 .gitignore 忽略 .claude/worktrees 与 .DS_Store - 后端:Coze/知识库、ResultAdvice、应用配置 - 前端 uniapp:AI 营养、食物百科等页面与 API - 更新 README、测试文档与 shop-msh.sql Made-with: Cursor
This commit is contained in:
@@ -353,6 +353,114 @@ function cozeChat(data) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Coze - 流式对话 (Chat Stream via SSE + enableChunked)
|
||||
* 使用微信小程序 enableChunked 能力消费 SSE 事件流
|
||||
* @param {object} data 请求参数(与 cozeChat 一致)
|
||||
* @returns {object} 控制器 { onMessage, onError, onComplete, abort, getTask }
|
||||
*/
|
||||
function cozeChatStream(data) {
|
||||
let _onMessage = () => {}
|
||||
let _onError = () => {}
|
||||
let _onComplete = () => {}
|
||||
let _buffer = ''
|
||||
let _task = null
|
||||
let _gotChunks = false
|
||||
|
||||
const controller = {
|
||||
onMessage(fn) { _onMessage = fn; return controller },
|
||||
onError(fn) { _onError = fn; return controller },
|
||||
onComplete(fn) { _onComplete = fn; return controller },
|
||||
abort() { if (_task) _task.abort() },
|
||||
getTask() { return _task }
|
||||
}
|
||||
|
||||
const parseSseLines = (text) => {
|
||||
_buffer += text
|
||||
const lines = _buffer.split('\n')
|
||||
_buffer = lines.pop() || ''
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim()
|
||||
if (!trimmed || trimmed.startsWith(':')) continue
|
||||
if (trimmed.startsWith('data:')) {
|
||||
const jsonStr = trimmed.slice(5).trim()
|
||||
if (!jsonStr) continue
|
||||
try {
|
||||
const evt = JSON.parse(jsonStr)
|
||||
_onMessage(evt)
|
||||
} catch (e) {
|
||||
// skip malformed JSON fragments
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const parseSseResponseBody = (body) => {
|
||||
if (!body || typeof body !== 'string') return
|
||||
const lines = body.split('\n')
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim()
|
||||
if (!trimmed || trimmed.startsWith(':')) continue
|
||||
if (trimmed.startsWith('data:')) {
|
||||
const jsonStr = trimmed.slice(5).trim()
|
||||
if (!jsonStr) continue
|
||||
try {
|
||||
const evt = JSON.parse(jsonStr)
|
||||
_onMessage(evt)
|
||||
} catch (e) {
|
||||
// skip malformed JSON fragments
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const token = uni.getStorageSync('LOGIN_STATUS_TOKEN') || ''
|
||||
_task = uni.request({
|
||||
url: `${API_BASE_URL}/api/front/coze/chat/stream`,
|
||||
method: 'POST',
|
||||
data: data,
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { 'Authori-zation': token } : {})
|
||||
},
|
||||
enableChunked: true,
|
||||
responseType: 'text',
|
||||
success: (res) => {
|
||||
if (_buffer.trim()) {
|
||||
parseSseLines('\n')
|
||||
}
|
||||
if (!_gotChunks && res && res.data) {
|
||||
const body = typeof res.data === 'string' ? res.data : JSON.stringify(res.data)
|
||||
parseSseResponseBody(body)
|
||||
}
|
||||
_onComplete()
|
||||
},
|
||||
fail: (err) => {
|
||||
_onError(err)
|
||||
}
|
||||
})
|
||||
|
||||
if (_task && _task.onChunkReceived) {
|
||||
_task.onChunkReceived((res) => {
|
||||
_gotChunks = true
|
||||
try {
|
||||
const bytes = new Uint8Array(res.data)
|
||||
let text = ''
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
text += String.fromCharCode(bytes[i])
|
||||
}
|
||||
text = decodeURIComponent(escape(text))
|
||||
parseSseLines(text)
|
||||
} catch (e) {
|
||||
// chunk decode error, skip
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Coze - 检索对话详情 (Retrieve Chat)
|
||||
* @param {object} params 请求参数
|
||||
@@ -471,6 +579,7 @@ export default {
|
||||
kieaiGeminiChat,
|
||||
// Coze API
|
||||
cozeChat,
|
||||
cozeChatStream,
|
||||
cozeRetrieveChat,
|
||||
cozeMessageList,
|
||||
cozeWorkflowRun,
|
||||
|
||||
Reference in New Issue
Block a user