Skip to content

Commit 9d057f5

Browse files
authored
feat: support display thought chain for deepseek r1 (#597)
Signed-off-by: Bob Du <[email protected]>
1 parent c5795f3 commit 9d057f5

File tree

9 files changed

+60
-1
lines changed

9 files changed

+60
-1
lines changed

service/src/chatgpt/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,16 @@ async function chatReplyProcess(options: RequestOptions) {
126126
})
127127

128128
// Process the stream
129+
let responseReasoning = ''
129130
let responseText = ''
130131
let responseId = ''
131132
const usage = new UsageResponse()
132133

133134
for await (const chunk of stream) {
134135
// Extract the content from the chunk
136+
// @ts-expect-error For deepseek-reasoner model only. The reasoning contents of the assistant message, before the final answer.
137+
const reasoningContent = chunk.choices[0]?.delta?.reasoning_content || ''
138+
responseReasoning += reasoningContent
135139
const content = chunk.choices[0]?.delta?.content || ''
136140
responseText += content
137141
responseId = chunk.id
@@ -141,6 +145,7 @@ async function chatReplyProcess(options: RequestOptions) {
141145
// Build response object similar to the original implementation
142146
const responseChunk = {
143147
id: chunk.id,
148+
reasoning: responseReasoning,
144149
text: responseText,
145150
role: 'assistant',
146151
finish_reason,
@@ -159,6 +164,7 @@ async function chatReplyProcess(options: RequestOptions) {
159164
// Final response object
160165
const response = {
161166
id: responseId || messageId,
167+
reasoning: responseReasoning,
162168
text: responseText,
163169
role: 'assistant',
164170
detail: {

service/src/chatgpt/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface ChatMessage {
1414
export interface ResponseChunk {
1515
id: string
1616
text: string
17+
reasoning: string
1718
role: string
1819
finish_reason: string
1920
}

service/src/routes/chat.ts

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ router.get('/chat-history', auth, async (req, res) => {
8383
result.push({
8484
uuid: c.uuid,
8585
dateTime: new Date(c.dateTime).toLocaleString(),
86+
reasoning: c.reasoning,
8687
text: c.response,
8788
inversion: false,
8889
error: false,
@@ -143,6 +144,7 @@ router.get('/chat-response-history', auth, async (req, res) => {
143144
data: {
144145
uuid: chat.uuid,
145146
dateTime: new Date(chat.dateTime).toLocaleString(),
147+
reasoning: chat.reasoning,
146148
text: response.response,
147149
inversion: false,
148150
error: false,
@@ -295,6 +297,7 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
295297
const previousResponse = message.previousResponse || []
296298
previousResponse.push({ response: message.response, options: message.options })
297299
await updateChat(message._id as unknown as string,
300+
result.data.reasoning,
298301
result.data.text,
299302
result.data.id,
300303
model,
@@ -303,6 +306,7 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
303306
}
304307
else {
305308
await updateChat(message._id as unknown as string,
309+
result.data.reasoning,
306310
result.data.text,
307311
result.data.id,
308312
model,

service/src/storage/model.ts

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export class ChatInfo {
121121
dateTime: number
122122
prompt: string
123123
images?: string[]
124+
reasoning?: string
124125
response?: string
125126
status: Status = Status.Normal
126127
options: ChatOptions

service/src/storage/mongo.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ export async function getChatByMessageId(messageId: string) {
9393
return await chatCol.findOne({ 'options.messageId': messageId })
9494
}
9595

96-
export async function updateChat(chatId: string, response: string, messageId: string, model: string, usage: UsageResponse, previousResponse?: []) {
96+
export async function updateChat(chatId: string, reasoning: string, response: string, messageId: string, model: string, usage: UsageResponse, previousResponse?: []) {
9797
const query = { _id: new ObjectId(chatId) }
9898
const update = {
9999
$set: {
100+
'reasoning': reasoning,
100101
'response': response,
101102
'model': model || '',
102103
'options.messageId': messageId,

src/typings/chat.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ declare namespace Chat {
22
interface Chat {
33
uuid?: number
44
dateTime: string
5+
reasoning?: string
56
text: string
67
images?: string[]
78
inversion?: boolean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<script lang="ts" setup>
2+
import { computed, ref } from 'vue'
3+
import { useBasicLayout } from '@/hooks/useBasicLayout'
4+
5+
interface Props {
6+
reasoning?: string
7+
loading?: boolean
8+
}
9+
10+
defineProps<Props>()
11+
12+
const { isMobile } = useBasicLayout()
13+
14+
const textRef = ref<HTMLElement>()
15+
16+
const wrapClass = computed(() => {
17+
return [
18+
'text-wrap',
19+
'min-w-[20px]',
20+
'rounded-md',
21+
isMobile.value ? 'p-2' : 'px-3 py-2',
22+
]
23+
})
24+
</script>
25+
26+
<template>
27+
<div class="text-black" :class="wrapClass">
28+
<div ref="textRef" class="leading-relaxed break-words">
29+
<div class="flex items-end">
30+
<div class="w-full dark:text-gray-50 text-xs" v-text="reasoning" />
31+
</div>
32+
</div>
33+
</div>
34+
</template>
35+
36+
<style lang="less">
37+
@import url(./style.less);
38+
</style>

src/views/chat/components/Message/index.vue

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { computed, ref } from 'vue'
33
import { NButton, NButtonGroup, NDropdown, NPopover, NSpace, useMessage } from 'naive-ui'
44
import AvatarComponent from './Avatar.vue'
55
import TextComponent from './Text.vue'
6+
import Reasoning from './Reasoning.vue'
67
import { SvgIcon } from '@/components/common'
78
import { useIconRender } from '@/hooks/useIconRender'
89
import { t } from '@/locales'
@@ -21,6 +22,7 @@ interface Props {
2122
currentNavIndex: number
2223
dateTime?: string
2324
model?: string
25+
reasoning?: string
2426
text?: string
2527
images?: string[]
2628
isRecord?: boolean
@@ -223,6 +225,7 @@ function isEventTargetValid(event: any) {
223225
</template>
224226
</NSpace>
225227
</p>
228+
<Reasoning v-if="reasoning" :reasoning="reasoning" :loading="loading" />
226229
<div
227230
class="flex items-end gap-1 mt-2"
228231
:class="[inversion ? 'flex-row-reverse' : 'flex-row']"

src/views/chat/index.vue

+4
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ async function onConversation() {
171171
dataSources.value.length - 1,
172172
{
173173
dateTime: new Date().toLocaleString(),
174+
reasoning: data?.reasoning,
174175
text: lastText + (data.text ?? ''),
175176
inversion: false,
176177
error: false,
@@ -318,6 +319,7 @@ async function onRegenerate(index: number) {
318319
index,
319320
{
320321
dateTime: new Date().toLocaleString(),
322+
reasoning: data?.reasoning,
321323
text: lastText + (data.text ?? ''),
322324
inversion: false,
323325
responseCount,
@@ -386,6 +388,7 @@ async function onResponseHistory(index: number, historyIndex: number) {
386388
index,
387389
{
388390
dateTime: chat.dateTime,
391+
reasoning: chat?.reasoning,
389392
text: chat.text,
390393
inversion: false,
391394
responseCount: chat.responseCount,
@@ -683,6 +686,7 @@ onUnmounted(() => {
683686
:index="index"
684687
:current-nav-index="currentNavIndexRef"
685688
:date-time="item.dateTime"
689+
:reasoning="item?.reasoning"
686690
:text="item.text"
687691
:images="item.images"
688692
:inversion="item.inversion"

0 commit comments

Comments
 (0)