diff --git a/src/hooks/useMessageOption.tsx b/src/hooks/useMessageOption.tsx index 8653776..24d930d 100644 --- a/src/hooks/useMessageOption.tsx +++ b/src/hooks/useMessageOption.tsx @@ -40,6 +40,7 @@ import { pageAssistEmbeddingModel } from "@/models/embedding" import { isReasoningEnded, isReasoningStarted, + mergeReasoningContent, removeReasoning } from "@/libs/reasoning" @@ -652,6 +653,15 @@ export const useMessageOption = () => { for await (const chunk of chunks) { contentToSave += chunk?.content fullText += chunk?.content + // console.log(chunk) + // if (chunk?.reasoning_content) { + // const reasoningContent = mergeReasoningContent( + // fullText, + // chunk?.reasoning_content || "" + // ) + // contentToSave += reasoningContent + // fullText += reasoningContent + // } if (isReasoningStarted(fullText) && !reasoningStartTime) { reasoningStartTime = new Date() diff --git a/src/libs/reasoning.ts b/src/libs/reasoning.ts index cfe41c6..a44dc4c 100644 --- a/src/libs/reasoning.ts +++ b/src/libs/reasoning.ts @@ -1,9 +1,19 @@ -const tags = ["think", "reason", "reasoning", "thought"]; -export function parseReasoning(text: string): { type: 'reasoning' | 'text', content: string, reasoning_running?: boolean }[] { +const tags = ["think", "reason", "reasoning", "thought"] +export function parseReasoning( + text: string +): { + type: "reasoning" | "text" + content: string + reasoning_running?: boolean +}[] { try { - const result: { type: 'reasoning' | 'text', content: string, reasoning_running?: boolean }[] = [] - const tagPattern = new RegExp(`<(${tags.join('|')})>`, 'i') - const closeTagPattern = new RegExp(``, 'i') + const result: { + type: "reasoning" | "text" + content: string + reasoning_running?: boolean + }[] = [] + const tagPattern = new RegExp(`<(${tags.join("|")})>`, "i") + const closeTagPattern = new RegExp(``, "i") let currentIndex = 0 let isReasoning = false @@ -13,9 +23,12 @@ export function parseReasoning(text: string): { type: 'reasoning' | 'text', cont const closeTagMatch = text.slice(currentIndex).match(closeTagPattern) if (!isReasoning && openTagMatch) { - const beforeText = text.slice(currentIndex, currentIndex + openTagMatch.index) + const beforeText = text.slice( + currentIndex, + currentIndex + openTagMatch.index + ) if (beforeText.trim()) { - result.push({ type: 'text', content: beforeText.trim() }) + result.push({ type: "text", content: beforeText.trim() }) } isReasoning = true @@ -24,9 +37,12 @@ export function parseReasoning(text: string): { type: 'reasoning' | 'text', cont } if (isReasoning && closeTagMatch) { - const reasoningContent = text.slice(currentIndex, currentIndex + closeTagMatch.index) + const reasoningContent = text.slice( + currentIndex, + currentIndex + closeTagMatch.index + ) if (reasoningContent.trim()) { - result.push({ type: 'reasoning', content: reasoningContent.trim() }) + result.push({ type: "reasoning", content: reasoningContent.trim() }) } isReasoning = false @@ -37,7 +53,7 @@ export function parseReasoning(text: string): { type: 'reasoning' | 'text', cont if (currentIndex < text.length) { const remainingText = text.slice(currentIndex) result.push({ - type: isReasoning ? 'reasoning' : 'text', + type: isReasoning ? "reasoning" : "text", content: remainingText.trim(), reasoning_running: isReasoning }) @@ -50,7 +66,7 @@ export function parseReasoning(text: string): { type: 'reasoning' | 'text', cont console.error(`Error parsing reasoning: ${e}`) return [ { - type: 'text', + type: "text", content: text } ] @@ -58,16 +74,36 @@ export function parseReasoning(text: string): { type: 'reasoning' | 'text', cont } export function isReasoningStarted(text: string): boolean { - const tagPattern = new RegExp(`<(${tags.join('|')})>`, 'i') + const tagPattern = new RegExp(`<(${tags.join("|")})>`, "i") return tagPattern.test(text) } export function isReasoningEnded(text: string): boolean { - const closeTagPattern = new RegExp(``, 'i') + const closeTagPattern = new RegExp(``, "i") return closeTagPattern.test(text) } export function removeReasoning(text: string): string { - const tagPattern = new RegExp(`<(${tags.join('|')})>.*?`, 'gis') - return text.replace(tagPattern, '').trim() + const tagPattern = new RegExp( + `<(${tags.join("|")})>.*?`, + "gis" + ) + return text.replace(tagPattern, "").trim() } +export function mergeReasoningContent(originalText: string, reasoning: string): string { + const defaultReasoningTag = "think" + const tagPattern = new RegExp(`<(${tags.join("|")})>(.*?)`, "is") + const hasReasoningTag = tagPattern.test(originalText) + + if (hasReasoningTag) { + const match = originalText.match(tagPattern) + if (match) { + const [fullMatch, tag, existingContent] = match + const remainingText = originalText.replace(fullMatch, '').trim() + const newContent = `${existingContent.trim()}${reasoning}` + return `<${tag}>${newContent} ${remainingText}` + } + } + + return `<${defaultReasoningTag}>${reasoning} ${originalText.trim()}`.trim() +} \ No newline at end of file