fix: 撤回 typewriter 改动,novel 改用直接累加 delta 保证流式输出
之前用 useTypewriterStream.writer.push + 同步读 visibleText 有时序问题: writer 的 visibleText 由内部 setInterval 异步推进,push 后立即同步读得到空串, 气泡一直空白。 撤回 typewriter 改动,恢复 novel_delta 直接 lastNovel.content += delta, SSE 本身就是流式推送,每次到达即显示。 保留 confirmOutline / modifyOutline 的 pendingNextResponse = true 修复(loading)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -290,8 +290,6 @@ const currentVersionMessageId = ref('')
|
|||||||
const novelSessionId = ref('')
|
const novelSessionId = ref('')
|
||||||
const novelFullText = ref('')
|
const novelFullText = ref('')
|
||||||
const novelOutline = ref(null)
|
const novelOutline = ref(null)
|
||||||
// novel 消息 id → typewriter writer 实例映射(用于真正的逐字流式输出)
|
|
||||||
const novelWriters = new Map()
|
|
||||||
const clarificationCard = ref(null)
|
const clarificationCard = ref(null)
|
||||||
const currentStreamTask = ref(null)
|
const currentStreamTask = ref(null)
|
||||||
const answeringClarification = ref(false)
|
const answeringClarification = ref(false)
|
||||||
@@ -1707,27 +1705,16 @@ const handleShortNovelEvent = (event) => {
|
|||||||
generationStatus.value = 'idle'
|
generationStatus.value = 'idle'
|
||||||
pendingNextResponse.value = false
|
pendingNextResponse.value = false
|
||||||
break
|
break
|
||||||
case 'novel_start': {
|
case 'novel_start':
|
||||||
const novelMsg = addResultMessage({ role: 'assistant', kind: 'novel', content: '', pending: true })
|
addResultMessage({ role: 'assistant', kind: 'novel', content: '', pending: true })
|
||||||
// 为这条 novel 消息创建独立的 typewriter writer,实现逐字流式输出
|
|
||||||
novelWriters.set(novelMsg.id, useTypewriterStream({ interval: 32, step: 1 }))
|
|
||||||
generationStatus.value = 'streaming'
|
generationStatus.value = 'streaming'
|
||||||
pendingNextResponse.value = false
|
pendingNextResponse.value = false
|
||||||
break
|
break
|
||||||
}
|
|
||||||
case 'novel_delta': {
|
case 'novel_delta': {
|
||||||
// 往最后一条 pending novel 消息推送 delta 到 typewriter writer
|
// 往最后一条 pending novel 消息直接累加 delta,保证流式显示
|
||||||
const lastNovel = [...resultMessages.value].reverse().find(m => m.kind === 'novel' && m.pending)
|
const lastNovel = [...resultMessages.value].reverse().find(m => m.kind === 'novel' && m.pending)
|
||||||
if (lastNovel) {
|
if (lastNovel) {
|
||||||
const writer = novelWriters.get(lastNovel.id)
|
lastNovel.content += payload.delta || ''
|
||||||
const delta = payload.delta || ''
|
|
||||||
if (writer) {
|
|
||||||
writer.push((writer.targetText?.value || '') + delta)
|
|
||||||
lastNovel.content = writer.visibleText.value
|
|
||||||
// writer 的 visibleText 是 reactive,需用 watch;但这里直接读取值即可
|
|
||||||
} else {
|
|
||||||
lastNovel.content += delta
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
keepResultAtBottom()
|
keepResultAtBottom()
|
||||||
break
|
break
|
||||||
@@ -1736,17 +1723,7 @@ const handleShortNovelEvent = (event) => {
|
|||||||
// 标记最后一条 novel 消息完成
|
// 标记最后一条 novel 消息完成
|
||||||
const lastNovel = [...resultMessages.value].reverse().find(m => m.kind === 'novel')
|
const lastNovel = [...resultMessages.value].reverse().find(m => m.kind === 'novel')
|
||||||
if (lastNovel) {
|
if (lastNovel) {
|
||||||
const writer = novelWriters.get(lastNovel.id)
|
if (payload.full_text) lastNovel.content = payload.full_text
|
||||||
const finalText = payload.full_text || ''
|
|
||||||
if (writer) {
|
|
||||||
writer.finish(finalText)
|
|
||||||
// finish 后 typewriter 会逐字排空到 targetText,等排空完成再写回 content
|
|
||||||
// 但为了持久化和立即显示,这里直接同步设值
|
|
||||||
lastNovel.content = finalText
|
|
||||||
novelWriters.delete(lastNovel.id)
|
|
||||||
} else if (finalText) {
|
|
||||||
lastNovel.content = finalText
|
|
||||||
}
|
|
||||||
lastNovel.pending = false
|
lastNovel.pending = false
|
||||||
}
|
}
|
||||||
scriptId.value = payload.scriptId || ''
|
scriptId.value = payload.scriptId || ''
|
||||||
|
|||||||
Reference in New Issue
Block a user