feat: Support edit last question

This commit is contained in:
zhangzhanwei 2025-12-26 13:53:27 +08:00 committed by zhanweizhang7
parent fcaac9c11a
commit 592e429e3b
7 changed files with 105 additions and 15 deletions

View File

@ -69,6 +69,7 @@ class IChatStep(IBaseChatPipelineStep):
# 是否使用流的形式输出
stream = serializers.BooleanField(required=False, label=_("Streaming Output"))
chat_user_id = serializers.CharField(required=True, label=_("Chat user id"))
chat_record_id = serializers.CharField(required=False, label=_("Chat record id"))
chat_user_type = serializers.CharField(required=True, label=_("Chat user Type"))
# 未查询到引用分段

View File

@ -351,7 +351,7 @@ class BaseChatStep(IChatStep):
mcp_servers, mcp_source, tool_enable, tool_ids,
application_enable, application_ids,
mcp_output_enable)
chat_record_id = uuid.uuid7()
chat_record_id = self.context.get('step_args',{}).get('chat_record_id') if self.context.get('step_args',{}).get('chat_record_id') else uuid.uuid7()
r = StreamingHttpResponse(
streaming_content=event_content(chat_result, chat_id, chat_record_id, paragraph_list,
post_response_handler, manage, self, chat_model, message_list, problem_text,

View File

@ -64,6 +64,7 @@ class WorkFlowPostHandler:
answer_text_list)
if workflow.chat_record is not None:
chat_record = workflow.chat_record
chat_record.problem_text = question
chat_record.answer_text = answer_text
chat_record.details = details
chat_record.message_tokens = message_tokens

View File

@ -563,7 +563,7 @@ class WorkflowManage:
details_result = {}
for index in range(len(self.node_context)):
node = self.node_context[index]
if self.chat_record is not None and self.chat_record.details is not None:
if self.chat_record is not None and self.chat_record.details is not None and self.start_node:
details = self.chat_record.details.get(node.runtime_node_id)
if details is not None and self.start_node.runtime_node_id != node.runtime_node_id:
details_result[node.runtime_node_id] = details

View File

@ -327,6 +327,7 @@ class ChatSerializers(serializers.Serializer):
chat_user_id = self.data.get('chat_user_id')
chat_user_type = self.data.get('chat_user_type')
form_data = instance.get("form_data")
chat_record_id = instance.get('chat_record_id')
pipeline_manage_builder = PipelineManage.builder()
# 如果开启了问题优化,则添加上问题优化步骤
if chat_info.application.problem_optimization:
@ -350,6 +351,8 @@ class ChatSerializers(serializers.Serializer):
# 构建运行参数
params = chat_info.to_pipeline_manage_params(message, get_post_handler(chat_info), exclude_paragraph_id_list,
chat_user_id, chat_user_type, stream, form_data)
if chat_record_id:
params['chat_record_id'] = chat_record_id
chat_info.set_chat(message)
# 运行流水线作业
pipeline_message.run(params)

View File

@ -1,7 +1,7 @@
<template>
<!-- 问题内容 -->
<div class="question-content item-content mb-16 lighter">
<div class="content p-12-16 border-r-8" :class="getClassName">
<div class="question-content item-content mb-4 lighter">
<div v-if="!isReQuestion" class="content p-12-16 border-r-8" :class="getClassName">
<div class="text break-all pre-wrap">
<div class="mb-8" v-if="document_list.length">
<el-space wrap class="w-full media-file-width">
@ -9,12 +9,12 @@
<el-card shadow="never" style="--el-card-padding: 8px" class="download-file cursor">
<div class="download-button flex align-center" @click="downloadFile(item)">
<el-icon class="mr-4">
<Download/>
<Download />
</el-icon>
{{ $t('chat.download') }}
</div>
<div class="show flex align-center">
<img :src="getImgUrl(item && item?.name)" alt="" width="24"/>
<img :src="getImgUrl(item && item?.name)" alt="" width="24" />
<div class="ml-4 ellipsis-1" :title="item && item?.name">
{{ item && item?.name }}
</div>
@ -78,12 +78,12 @@
<el-card shadow="never" style="--el-card-padding: 8px" class="download-file cursor">
<div class="download-button flex align-center" @click="downloadFile(item)">
<el-icon class="mr-4">
<Download/>
<Download />
</el-icon>
{{ $t('chat.download') }}
</div>
<div class="show flex align-center">
<img :src="getImgUrl(item && item?.name)" alt="" width="24"/>
<img :src="getImgUrl(item && item?.name)" alt="" width="24" />
<div class="ml-4 ellipsis-1" :title="item && item?.name">
{{ item && item?.name }}
</div>
@ -95,6 +95,20 @@
<span> {{ chatRecord.problem_text }}</span>
</div>
</div>
<el-input v-else v-model="editText">
<template #append>
<div class="flex" style="gap: 8px">
<el-button-group class="flex ml-8 mr-8">
<el-button class="flex mr-8" text @click="cancelReQuestion"
><el-icon><Close /></el-icon
></el-button>
<el-button :disabled="!editText.trim()" text @click="sendReQuestionMessage(chatRecord)">
<el-icon><Comment /></el-icon>
</el-button>
</el-button-group>
</div>
</template>
</el-input>
<div class="avatar ml-8" v-if="showAvatar">
<el-image
v-if="application.user_avatar"
@ -104,23 +118,51 @@
style="width: 28px; height: 28px; display: block"
/>
<el-avatar v-else :size="28">
<img src="@/assets/user-icon.svg" style="width: 50%" alt=""/>
<img src="@/assets/user-icon.svg" style="width: 50%" alt="" />
</el-avatar>
</div>
</div>
<div
class="text-right mb-8"
:style="{
'padding-right': showAvatar ? '36px' : '0',
}"
v-if="!isReQuestion"
>
<div class="text-right">
<el-tooltip effect="dark" :content="$t('common.edit')" placement="top" v-if="props.isLast">
<el-button text @click="handleEdit(chatRecord)">
<AppIcon iconName="app-edit"></AppIcon>
</el-button>
</el-tooltip>
<el-tooltip effect="dark" :content="$t('common.copy')" placement="top">
<el-button text @click="copyClick(chatRecord?.problem_text)">
<AppIcon iconName="app-copy"></AppIcon>
</el-button>
</el-tooltip>
</div>
</div>
</template>
<script setup lang="ts">
import {type chatType} from '@/api/type/application'
import {getImgUrl, downloadByURL} from '@/utils/common'
import {getAttrsArray} from '@/utils/array'
import {onMounted, computed} from 'vue'
import { type chatType } from '@/api/type/application'
import { getImgUrl, downloadByURL } from '@/utils/common'
import { getAttrsArray } from '@/utils/array'
import { onMounted, computed, ref } from 'vue'
import { copyClick } from '@/utils/clipboard'
const props = defineProps<{
application: any
chatRecord: chatType
chatManagement: any
sendMessage: (question: string, other_params_data?: any, chat?: chatType) => Promise<boolean>
type: 'log' | 'ai-chat' | 'debug-ai-chat'
isLast: boolean
}>()
const isReQuestion = ref<boolean>(false)
const editText = ref<string>('')
const direction = ref<'horizontal' | 'vertical'>('horizontal')
const showAvatar = computed(() => {
return props.application.show_user_avatar == undefined ? true : props.application.show_user_avatar
})
@ -184,8 +226,48 @@ function downloadFile(item: any) {
downloadByURL(item.url, item.name)
}
onMounted(() => {
})
function handleEdit(chatRecord: any) {
isReQuestion.value = true
editText.value = chatRecord.problem_text
}
const cancelReQuestion = () => {
isReQuestion.value = false
}
const emit = defineEmits(['reQuestion'])
function sendReQuestionMessage(chat: chatType) {
const container = props.chatRecord?.upload_meta
? props.chatRecord.upload_meta
: props.chatRecord.execution_details?.find((detail) => detail.type === 'start-node')
props.chatRecord.problem_text = editText.value
reset_answer_text_list(props.chatRecord.answer_text_list)
props.chatRecord.write_ed = false
isReQuestion.value = false
props.sendMessage(
editText.value,
{
re_chat: true,
image_list: container?.image_list || [],
document_list: container?.document_list || [],
audio_list: container?.audio_list || [],
video_list: container?.video_list || [],
other_list: container?.other_list || [],
chat_record_id: props.chatRecord.record_id ? props.chatRecord.record_id : props.chatRecord.id,
},
{ ...props.chatRecord, problem_text: editText.value },
)
}
const reset_answer_text_list = (answer_text_list: any) => {
answer_text_list.splice(0, answer_text_list.length)
answer_text_list.push([])
}
onMounted(() => {})
</script>
<style lang="scss" scoped>
.question-content {

View File

@ -36,9 +36,12 @@
<template v-for="(item, index) in chatList" :key="index">
<!-- 问题 -->
<QuestionContent
:chat-management="ChatManagement"
:type="type"
:application="applicationDetails"
:send-message="sendMessage"
:chat-record="item"
:is-last="index >= chatList.length - 1"
></QuestionContent>
<!-- 回答 -->
<AnswerContent