fix: queue monitor tasks and recover doubao dom answers
Desktop Client Build / Resolve Build Metadata (push) Successful in 26s
Backend CI / Backend (push) Successful in 15m54s
Desktop Client Build / Build Desktop Client (push) Successful in 22m56s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 28s
Desktop Client Build / Resolve Build Metadata (push) Successful in 26s
Backend CI / Backend (push) Successful in 15m54s
Desktop Client Build / Build Desktop Client (push) Successful in 22m56s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 28s
This commit is contained in:
@@ -251,10 +251,42 @@ describe('doubao adapter helpers', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('does not submit a success answer when the SSE stream has no answer text', () => {
|
||||
it('uses DOM answer when Doubao finishes the stream without SSE answer text', () => {
|
||||
expect(
|
||||
resolveDoubaoSubmissionAnswer({
|
||||
answer: null,
|
||||
domAnswer:
|
||||
'口袋门墙体预埋件通常需要确认墙体厚度、轨道承重、缓冲阻尼和检修口位置。选购时建议优先核对门扇重量、轨道长度和五金兼容性。',
|
||||
allowDomAnswer: true,
|
||||
}),
|
||||
).toEqual({
|
||||
answer:
|
||||
'口袋门墙体预埋件通常需要确认墙体厚度、轨道承重、缓冲阻尼和检修口位置。选购时建议优先核对门扇重量、轨道长度和五金兼容性。',
|
||||
source: 'dom',
|
||||
})
|
||||
})
|
||||
|
||||
it('does not submit DOM answer before a finish signal allows DOM recovery', () => {
|
||||
expect(
|
||||
resolveDoubaoSubmissionAnswer({
|
||||
answer: null,
|
||||
domAnswer:
|
||||
'口袋门墙体预埋件通常需要确认墙体厚度、轨道承重、缓冲阻尼和检修口位置。选购时建议优先核对门扇重量、轨道长度和五金兼容性。',
|
||||
allowDomAnswer: false,
|
||||
}),
|
||||
).toEqual({
|
||||
answer: null,
|
||||
source: null,
|
||||
})
|
||||
})
|
||||
|
||||
it('does not submit a weak history-title DOM fragment as a success answer', () => {
|
||||
expect(
|
||||
resolveDoubaoSubmissionAnswer({
|
||||
answer: null,
|
||||
domAnswer:
|
||||
'口袋门墙体预埋件全解析 卧室口袋门阻尼缓冲导轨选购安装指南 口袋门防夹手缓冲方案 隐形门合页选购指南',
|
||||
allowDomAnswer: true,
|
||||
}),
|
||||
).toEqual({
|
||||
answer: null,
|
||||
|
||||
@@ -469,14 +469,45 @@ function selectBestDoubaoText(primary: string | null, secondary: string | null):
|
||||
return secondaryScore > primaryScore ? secondaryText : primaryText
|
||||
}
|
||||
|
||||
function resolveDoubaoSubmissionAnswer(input: { answer: string | null }): {
|
||||
function isDoubaoSSESubmissionCandidate(value: string | null): boolean {
|
||||
const answer = normalizeOptionalString(value)
|
||||
if (!answer || containsDoubaoMojibakeSignal(answer)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function isDoubaoDOMSubmissionCandidate(value: string | null): boolean {
|
||||
const answer = normalizeOptionalString(value)
|
||||
if (!answer || containsDoubaoMojibakeSignal(answer)) {
|
||||
return false
|
||||
}
|
||||
if (answer.length < 48) {
|
||||
return false
|
||||
}
|
||||
const punctuationCount = countDoubaoMatches(answer, /[。!?;:,、,.!?;:]/g)
|
||||
if (punctuationCount < 2 && !doubaoHasStructuredAnswerMarkers(answer) && !/\n/.test(answer)) {
|
||||
return false
|
||||
}
|
||||
return doubaoTextQualityScore(answer) >= 180
|
||||
}
|
||||
|
||||
function resolveDoubaoSubmissionAnswer(input: {
|
||||
answer: string | null
|
||||
source: 'sse' | null
|
||||
domAnswer?: string | null
|
||||
allowDomAnswer?: boolean
|
||||
}): {
|
||||
answer: string | null
|
||||
source: 'sse' | 'dom' | null
|
||||
} {
|
||||
const answer = normalizeOptionalString(input.answer)
|
||||
if (answer && !containsDoubaoMojibakeSignal(answer)) {
|
||||
if (isDoubaoSSESubmissionCandidate(answer)) {
|
||||
return { answer, source: 'sse' }
|
||||
}
|
||||
const domAnswer = normalizeOptionalString(input.domAnswer)
|
||||
if (input.allowDomAnswer === true && isDoubaoDOMSubmissionCandidate(domAnswer)) {
|
||||
return { answer: domAnswer, source: 'dom' }
|
||||
}
|
||||
|
||||
return { answer: null, source: null }
|
||||
}
|
||||
@@ -2505,7 +2536,8 @@ const doubaoQueryInPage = async (
|
||||
return
|
||||
}
|
||||
seen.add(href)
|
||||
const visibleText = normalize(element.innerText) ?? normalize(element.textContent) ?? fallbackText
|
||||
const visibleText =
|
||||
normalize(element.innerText) ?? normalize(element.textContent) ?? fallbackText
|
||||
links.push({
|
||||
url: href,
|
||||
title:
|
||||
@@ -2643,9 +2675,7 @@ const doubaoQueryInPage = async (
|
||||
/搜索\s*\d+\s*个关键词|参考\s*\d+\s*篇资料|查看\d+篇资料|参考资料|资料来源/.test(line)
|
||||
|
||||
const isReferenceQueryLine = (line: string): boolean =>
|
||||
/[“"「].+[”"」]/.test(line) ||
|
||||
/、/.test(line) ||
|
||||
/关键词|搜索词|查询词/.test(line)
|
||||
/[“"「].+[”"」]/.test(line) || /、/.test(line) || /关键词|搜索词|查询词/.test(line)
|
||||
|
||||
const isReferenceItemLine = (line: string): boolean =>
|
||||
/^\d+[.、]\s*\S+/.test(line) &&
|
||||
@@ -3240,6 +3270,8 @@ export const doubaoAdapter: MonitorAdapter = {
|
||||
pageResult.ok === false && isDoubaoRecoverablePageError(pageResult.error)
|
||||
const submission = resolveDoubaoSubmissionAnswer({
|
||||
answer,
|
||||
domAnswer: pageResult.domAnswer,
|
||||
allowDomAnswer: streamSawAnswerFinish || pageResult.ok === true,
|
||||
})
|
||||
const hasRecoveredAnswer = Boolean(submission.answer)
|
||||
const hasRecoveredContent = hasRecoveredAnswer || searchResults.length > 0
|
||||
|
||||
Reference in New Issue
Block a user