diff --git a/backend/alembic/env.py b/backend/alembic/env.py index a01ac836..0ae300dd 100755 --- a/backend/alembic/env.py +++ b/backend/alembic/env.py @@ -24,7 +24,7 @@ # from apps.system.models.user import SQLModel # noqa # from apps.settings.models.setting_models import SQLModel -# from apps.chat.models.chat_model import SQLModel +from apps.chat.models.chat_model import SQLModel from apps.terminology.models.terminology_model import SQLModel #from apps.custom_prompt.models.custom_prompt_model import SQLModel from apps.data_training.models.data_training_model import SQLModel diff --git a/backend/alembic/versions/054_update_chat_record_dll.py b/backend/alembic/versions/054_update_chat_record_dll.py new file mode 100644 index 00000000..76647f54 --- /dev/null +++ b/backend/alembic/versions/054_update_chat_record_dll.py @@ -0,0 +1,29 @@ +"""054_update_chat_record_dll + +Revision ID: 24e961f6326b +Revises: 5755c0b95839 +Create Date: 2025-12-04 15:51:42.900778 + +""" +from alembic import op +import sqlalchemy as sa +import sqlmodel.sql.sqltypes +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '24e961f6326b' +down_revision = '5755c0b95839' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('chat_record', sa.Column('regenerate_record_id', sa.BigInteger(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('chat_record', 'regenerate_record_id') + # ### end Alembic commands ### diff --git a/backend/apps/chat/api/chat.py b/backend/apps/chat/api/chat.py index 8e672a46..22887994 100644 --- a/backend/apps/chat/api/chat.py +++ b/backend/apps/chat/api/chat.py @@ -12,9 +12,10 @@ from apps.chat.curd.chat import list_chats, get_chat_with_records, create_chat, rename_chat, \ delete_chat, get_chat_chart_data, get_chat_predict_data, get_chat_with_records_with_data, get_chat_record_by_id, \ format_json_data, format_json_list_data, get_chart_config, list_recent_questions -from apps.chat.models.chat_model import CreateChat, ChatRecord, RenameChat, ChatQuestion, AxisObj +from apps.chat.models.chat_model import CreateChat, ChatRecord, RenameChat, ChatQuestion, AxisObj, QuickCommand from apps.chat.task.llm import LLMService from common.core.deps import CurrentAssistant, SessionDep, CurrentUser, Trans +from common.utils.command_utils import parse_quick_command from common.utils.data_format import DataFormat router = APIRouter(tags=["Data Q&A"], prefix="/chat") @@ -141,20 +142,99 @@ async def recommend_questions(session: SessionDep, current_user: CurrentUser, da return list_recent_questions(session=session, current_user=current_user, datasource_id=datasource_id) +def find_base_question(record_id: int, session: SessionDep): + stmt = select(ChatRecord.question, ChatRecord.regenerate_record_id).where( + and_(ChatRecord.id == record_id)) + _record = session.execute(stmt).fetchone() + if not _record: + raise Exception(f'Cannot find base chat record') + rec_question, rec_regenerate_record_id = _record + if rec_regenerate_record_id: + return find_base_question(rec_regenerate_record_id, session) + else: + return rec_question + + @router.post("/question") +async def question_answer(session: SessionDep, current_user: CurrentUser, request_question: ChatQuestion, + current_assistant: CurrentAssistant): + try: + command, text_before_command, record_id, warning_info = parse_quick_command(request_question.question) + if command: + # todo 暂不支持分析和预测,需要改造前端 + if command == QuickCommand.ANALYSIS or command == QuickCommand.PREDICT_DATA: + raise Exception(f'Command: {command.value} temporary not supported') + + if record_id is not None: + # 排除analysis和predict + stmt = select(ChatRecord.id, ChatRecord.chat_id, ChatRecord.analysis_record_id, + ChatRecord.predict_record_id, ChatRecord.regenerate_record_id, + ChatRecord.first_chat).where( + and_(ChatRecord.id == record_id)) + _record = session.execute(stmt).fetchone() + if not _record: + raise Exception(f'Record id: {record_id} does not exist') + + rec_id, rec_chat_id, rec_analysis_record_id, rec_predict_record_id, rec_regenerate_record_id, rec_first_chat = _record + + if rec_chat_id != request_question.chat_id: + raise Exception(f'Record id: {record_id} does not belong to this chat') + if rec_first_chat: + raise Exception(f'Record id: {record_id} does not support this operation') + + if command == QuickCommand.REGENERATE: + if rec_analysis_record_id: + raise Exception('Analysis record does not support this operation') + if rec_predict_record_id: + raise Exception('Predict data record does not support this operation') + + else: # get last record id + stmt = select(ChatRecord.id, ChatRecord.chat_id, ChatRecord.regenerate_record_id).where( + and_(ChatRecord.chat_id == request_question.chat_id, + ChatRecord.first_chat == False, + ChatRecord.analysis_record_id.is_(None), + ChatRecord.predict_record_id.is_(None))).order_by( + ChatRecord.create_time.desc()).limit(1) + _record = session.execute(stmt).fetchone() + + if not _record: + raise Exception(f'You have not ask any question') + + rec_id, rec_chat_id, rec_regenerate_record_id = _record + + # 没有指定的,就查询上一个 + if not rec_regenerate_record_id: + rec_regenerate_record_id = rec_id + + # 针对已经是重新生成的提问,需要找到原来的提问是什么 + base_question_text = find_base_question(rec_regenerate_record_id, session) + text_before_command = text_before_command + ("\n" if text_before_command else "") + base_question_text + + if command == QuickCommand.REGENERATE: + request_question.question = text_before_command + request_question.regenerate_record_id = rec_id + return await stream_sql(session, current_user, request_question, current_assistant) + + elif command == QuickCommand.ANALYSIS: + return await analysis_or_predict(session, current_user, rec_id, 'analysis', current_assistant) + + elif command == QuickCommand.PREDICT_DATA: + return await analysis_or_predict(session, current_user, rec_id, 'predict', current_assistant) + else: + raise Exception(f'Unknown command: {command.value}') + else: + return await stream_sql(session, current_user, request_question, current_assistant) + except Exception as e: + traceback.print_exc() + + def _err(_e: Exception): + yield 'data:' + orjson.dumps({'content': str(_e), 'type': 'error'}).decode() + '\n\n' + + return StreamingResponse(_err(e), media_type="text/event-stream") + + async def stream_sql(session: SessionDep, current_user: CurrentUser, request_question: ChatQuestion, current_assistant: CurrentAssistant): - """Stream SQL analysis results - - Args: - session: Database session - current_user: CurrentUser - request_question: User question model - - Returns: - Streaming response with analysis results - """ - try: llm_service = await LLMService.create(session, current_user, request_question, current_assistant, embedding=True) @@ -172,6 +252,12 @@ def _err(_e: Exception): @router.post("/record/{chat_record_id}/{action_type}") +async def analysis_or_predict_question(session: SessionDep, current_user: CurrentUser, chat_record_id: int, + action_type: str, + current_assistant: CurrentAssistant): + return await analysis_or_predict(session, current_user, chat_record_id, action_type, current_assistant) + + async def analysis_or_predict(session: SessionDep, current_user: CurrentUser, chat_record_id: int, action_type: str, current_assistant: CurrentAssistant): try: diff --git a/backend/apps/chat/curd/chat.py b/backend/apps/chat/curd/chat.py index 9ff45ea4..f5c2c4e3 100644 --- a/backend/apps/chat/curd/chat.py +++ b/backend/apps/chat/curd/chat.py @@ -1,16 +1,16 @@ import datetime from typing import List -from sqlalchemy import desc, func import orjson import sqlparse from sqlalchemy import and_, select, update +from sqlalchemy import desc, func from sqlalchemy.orm import aliased from apps.chat.models.chat_model import Chat, ChatRecord, CreateChat, ChatInfo, RenameChat, ChatQuestion, ChatLog, \ TypeEnum, OperationEnum, ChatRecordResult -from apps.datasource.crud.recommended_problem import get_datasource_recommended, get_datasource_recommended_chart -from apps.datasource.models.datasource import CoreDatasource, DsRecommendedProblem +from apps.datasource.crud.recommended_problem import get_datasource_recommended_chart +from apps.datasource.models.datasource import CoreDatasource from apps.system.crud.assistant import AssistantOutDsFactory from common.core.deps import CurrentAssistant, SessionDep, CurrentUser, Trans from common.utils.utils import extract_nested_json @@ -28,11 +28,13 @@ def get_chat_record_by_id(session: SessionDep, record_id: int): engine_type=r.engine_type, ai_modal_id=r.ai_modal_id, create_by=r.create_by) return record + def get_chat(session: SessionDep, chat_id: int) -> Chat: statement = select(Chat).where(Chat.id == chat_id) chat = session.exec(statement).scalars().first() return chat + def list_chats(session: SessionDep, current_user: CurrentUser) -> List[Chat]: oid = current_user.oid if current_user.oid is not None else 1 chart_list = session.query(Chat).filter(and_(Chat.create_by == current_user.id, Chat.oid == oid)).order_by( @@ -57,6 +59,7 @@ def list_recent_questions(session: SessionDep, current_user: CurrentUser, dataso ) return [record[0] for record in chat_records] if chat_records else [] + def rename_chat(session: SessionDep, rename_object: RenameChat) -> str: chat = session.get(Chat, rename_object.id) if not chat: @@ -191,7 +194,8 @@ def get_chat_with_records_with_data(session: SessionDep, chart_id: int, current_ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: CurrentUser, - current_assistant: CurrentAssistant, with_data: bool = False,trans: Trans = None) -> ChatInfo: + current_assistant: CurrentAssistant, with_data: bool = False, + trans: Trans = None) -> ChatInfo: chat = session.get(Chat, chart_id) if not chat: raise Exception(f"Chat with id {chart_id} not found") @@ -200,7 +204,7 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr if current_assistant and current_assistant.type in dynamic_ds_types: out_ds_instance = AssistantOutDsFactory.get_instance(current_assistant) - ds = out_ds_instance.get_ds(chat.datasource,trans) + ds = out_ds_instance.get_ds(chat.datasource, trans) else: ds = session.get(CoreDatasource, chat.datasource) if chat.datasource else None @@ -221,6 +225,7 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr ChatRecord.question, ChatRecord.sql_answer, ChatRecord.sql, ChatRecord.chart_answer, ChatRecord.chart, ChatRecord.analysis, ChatRecord.predict, ChatRecord.datasource_select_answer, ChatRecord.analysis_record_id, ChatRecord.predict_record_id, + ChatRecord.regenerate_record_id, ChatRecord.recommended_question, ChatRecord.first_chat, ChatRecord.finish, ChatRecord.error, sql_alias_log.reasoning_content.label('sql_reasoning_content'), @@ -247,6 +252,7 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr ChatRecord.question, ChatRecord.sql_answer, ChatRecord.sql, ChatRecord.chart_answer, ChatRecord.chart, ChatRecord.analysis, ChatRecord.predict, ChatRecord.datasource_select_answer, ChatRecord.analysis_record_id, ChatRecord.predict_record_id, + ChatRecord.regenerate_record_id, ChatRecord.recommended_question, ChatRecord.first_chat, ChatRecord.finish, ChatRecord.error, ChatRecord.data, ChatRecord.predict_data).where( and_(ChatRecord.create_by == current_user.id, ChatRecord.chat_id == chart_id)).order_by( @@ -264,6 +270,7 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr analysis=row.analysis, predict=row.predict, datasource_select_answer=row.datasource_select_answer, analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id, + regenerate_record_id=row.regenerate_record_id, recommended_question=row.recommended_question, first_chat=row.first_chat, finish=row.finish, error=row.error, sql_reasoning_content=row.sql_reasoning_content, @@ -280,6 +287,7 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr analysis=row.analysis, predict=row.predict, datasource_select_answer=row.datasource_select_answer, analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id, + regenerate_record_id=row.regenerate_record_id, recommended_question=row.recommended_question, first_chat=row.first_chat, finish=row.finish, error=row.error, data=row.data, predict_data=row.predict_data)) @@ -347,8 +355,9 @@ def format_record(record: ChatRecordResult): return _dict + def get_chat_brief_generate(session: SessionDep, chat_id: int): - chat = get_chat(session=session,chat_id=chat_id) + chat = get_chat(session=session, chat_id=chat_id) if chat is not None and chat.brief_generate is not None: return chat.brief_generate else: @@ -468,6 +477,7 @@ def save_question(session: SessionDep, current_user: CurrentUser, question: Chat record.datasource = chat.datasource record.engine_type = chat.engine_type record.ai_modal_id = question.ai_modal_id + record.regenerate_record_id = question.regenerate_record_id result = ChatRecord(**record.model_dump()) diff --git a/backend/apps/chat/models/chat_model.py b/backend/apps/chat/models/chat_model.py index 0786c2f6..dc19b7e8 100644 --- a/backend/apps/chat/models/chat_model.py +++ b/backend/apps/chat/models/chat_model.py @@ -48,6 +48,12 @@ class ChatFinishStep(Enum): GENERATE_CHART = 3 +class QuickCommand(Enum): + REGENERATE = '/regenerate' + ANALYSIS = '/analysis' + PREDICT_DATA = '/predict' + + # TODO choose table / check connection / generate description class ChatLog(SQLModel, table=True): @@ -78,7 +84,7 @@ class Chat(SQLModel, table=True): datasource: int = Field(sa_column=Column(BigInteger, nullable=True)) engine_type: str = Field(max_length=64) origin: Optional[int] = Field( - sa_column=Column(Integer, nullable=False, default=0)) # 0: default, 1: mcp, 2: assistant + sa_column=Column(Integer, nullable=False, default=0)) # 0: default, 1: mcp, 2: assistant brief_generate: bool = Field(default=False) @@ -110,6 +116,7 @@ class ChatRecord(SQLModel, table=True): error: str = Field(sa_column=Column(Text, nullable=True)) analysis_record_id: int = Field(sa_column=Column(BigInteger, nullable=True)) predict_record_id: int = Field(sa_column=Column(BigInteger, nullable=True)) + regenerate_record_id: int = Field(sa_column=Column(BigInteger, nullable=True)) class ChatRecordResult(BaseModel): @@ -134,6 +141,7 @@ class ChatRecordResult(BaseModel): error: Optional[str] = None analysis_record_id: Optional[int] = None predict_record_id: Optional[int] = None + regenerate_record_id: Optional[int] = None sql_reasoning_content: Optional[str] = None chart_reasoning_content: Optional[str] = None analysis_reasoning_content: Optional[str] = None @@ -184,6 +192,7 @@ class AiModelQuestion(BaseModel): data_training: str = "" custom_prompt: str = "" error_msg: str = "" + regenerate_record_id: Optional[int] = None def sql_sys_question(self, db_type: Union[str, DB], enable_query_limit: bool = True): _sql_template = get_sql_example_template(db_type) @@ -213,7 +222,10 @@ def sql_sys_question(self, db_type: Union[str, DB], enable_query_limit: bool = T example_answer_3=_example_answer_3) def sql_user_question(self, current_time: str, change_title: bool): - return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=self.question, + _question = self.question + if self.regenerate_record_id: + _question = get_sql_template()['regenerate_hint'] + self.question + return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=_question, rule=self.rule, current_time=current_time, error_msg=self.error_msg, change_title=change_title) diff --git a/backend/apps/chat/task/llm.py b/backend/apps/chat/task/llm.py index 47ab30a9..4b2c4ebd 100644 --- a/backend/apps/chat/task/llm.py +++ b/backend/apps/chat/task/llm.py @@ -167,6 +167,11 @@ def is_running(self, timeout=0.5): def init_messages(self): last_sql_messages: List[dict[str, Any]] = self.generate_sql_logs[-1].messages if len( self.generate_sql_logs) > 0 else [] + if self.chat_question.regenerate_record_id: + # filter record before regenerate_record_id + _temp_log = next( + filter(lambda obj: obj.pid == self.chat_question.regenerate_record_id, self.generate_sql_logs), None) + last_sql_messages: List[dict[str, Any]] = _temp_log.messages if _temp_log else [] # todo maybe can configure count_limit = 0 - base_message_count_limit @@ -947,6 +952,11 @@ def run_task(self, in_chat: bool = True, stream: bool = True, # return id if in_chat: yield 'data:' + orjson.dumps({'type': 'id', 'id': self.get_record().id}).decode() + '\n\n' + if self.get_record().regenerate_record_id: + yield 'data:' + orjson.dumps({'type': 'regenerate_record_id', + 'regenerate_record_id': self.get_record().regenerate_record_id}).decode() + '\n\n' + yield 'data:' + orjson.dumps( + {'type': 'question', 'question': self.get_record().question}).decode() + '\n\n' if not stream: json_result['record_id'] = self.get_record().id diff --git a/backend/common/utils/command_utils.py b/backend/common/utils/command_utils.py new file mode 100644 index 00000000..7f1b7d80 --- /dev/null +++ b/backend/common/utils/command_utils.py @@ -0,0 +1,99 @@ +import re +from typing import Optional, Tuple + +from apps.chat.models.chat_model import QuickCommand + + +def parse_quick_command(input_str: str) -> Tuple[Optional[QuickCommand], str, Optional[int], Optional[str]]: + """ + 解析字符串中的快速命令 + + Args: + input_str: 输入字符串 + + Returns: + Tuple[Optional[QuickCommand], str, Optional[int], Optional[str]]: + (命令枚举, 去除命令的字符串, 数字参数, 警告信息) + 如果解析成功: (命令, 文本, 数字, None) + 如果解析失败: (None, 原字符串, None, 警告信息) + """ + + # 获取所有命令值 + command_values = [cmd.value for cmd in QuickCommand] + + # 1. 检查字符串中是否包含任何命令 + found_commands = [] + for cmd_value in command_values: + # 使用正则表达式查找独立的命令(前后是单词边界或空格) + pattern = r'(? 1: + return None, input_str, None, f"错误: 字符串中包含多个命令: {', '.join(found_commands)}" + + # 此时只有一个命令 + command_str = found_commands[0] + + # 3. 构建完整匹配模式,匹配命令及其后的可选数字 + # 模式: 命令 + 可选的空格 + 可选的数字 + full_pattern = r'(? 0: + return None, input_str, None, f"错误: 命令与前面的文本没有用空格分隔" + + # 6. 获取命令枚举 + command = None + for cmd in QuickCommand: + if cmd.value == command_part: + command = cmd + break + + if not command: + return None, input_str, None, f"错误: 未识别的命令: {command_part}" + + # 7. 提取去除命令和数字后的文本 + # 获取命令前的文本 + text_before_command = input_str[:match.start()].rstrip() + + # 8. 处理数字参数 + record_id = None + if number_part: + try: + record_id = int(number_part) + except ValueError: + return None, input_str, None, f"错误: 数字参数格式不正确: {number_part}" + + return command, text_before_command, record_id, None + + diff --git a/backend/templates/template.yaml b/backend/templates/template.yaml index 2862a11d..82c990ec 100644 --- a/backend/templates/template.yaml +++ b/backend/templates/template.yaml @@ -6,16 +6,20 @@ template: {data_training} sql: + regenerate_hint: | + 你之前生成的回答不符合预期或者系统出现了其他问题,请再次检查提示词内要求的规则和提供的信息,重新回答: + process_check: | 1. 分析用户问题,确定查询需求 2. 根据表结构生成基础SQL - 3. 强制检查:应用数据量限制规则 - 4. 应用其他规则(引号、别名等) - 5. 强制检查:检查语法是否正确? - 6. 确定图表类型 - 7. 确定对话标题 - 8. 返回JSON结果 + 3. 强制检查:验证SQL中使用的表名和字段名是否在中定义 + 4. 强制检查:应用数据量限制规则(默认限制或用户指定数量) + 5. 应用其他规则(引号、别名、格式化等) + 6. 强制检查:验证SQL语法是否符合规范 + 7. 确定图表类型(根据规则选择table/column/bar/line/pie) + 8. 确定对话标题 + 9. 返回JSON结果 query_limit: | diff --git a/frontend/src/api/chat.ts b/frontend/src/api/chat.ts index 4180ff82..42a7199c 100644 --- a/frontend/src/api/chat.ts +++ b/frontend/src/api/chat.ts @@ -51,6 +51,7 @@ export class ChatRecord { recommended_question?: string analysis_record_id?: number predict_record_id?: number + regenerate_record_id?: number constructor() constructor( @@ -75,7 +76,8 @@ export class ChatRecord { first_chat: boolean, recommended_question: string | undefined, analysis_record_id: number | undefined, - predict_record_id: number | undefined + predict_record_id: number | undefined, + regenerate_record_id: number | undefined ) constructor( id?: number, @@ -99,7 +101,8 @@ export class ChatRecord { first_chat?: boolean, recommended_question?: string, analysis_record_id?: number, - predict_record_id?: number + predict_record_id?: number, + regenerate_record_id?: number ) { this.id = id this.chat_id = chat_id @@ -123,6 +126,7 @@ export class ChatRecord { this.recommended_question = recommended_question this.analysis_record_id = analysis_record_id this.predict_record_id = predict_record_id + this.regenerate_record_id = regenerate_record_id } } @@ -252,7 +256,8 @@ const toChatRecord = (data?: any): ChatRecord | undefined => { data.first_chat, data.recommended_question, data.analysis_record_id, - data.predict_record_id + data.predict_record_id, + data.regenerate_record_id ) } const toChatRecordList = (list: any = []): ChatRecord[] => { diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index f3fe10f4..dca1f835 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -235,6 +235,7 @@ "continue_to_ask": "Continue asking:", "data_analysis": "Data Analysis", "data_predict": "Data Prediction", + "data_regenerated": "Regenerate", "chat_search": "Search", "thinking": "Thinking", "thinking_step": "Thought Process", diff --git a/frontend/src/i18n/ko-KR.json b/frontend/src/i18n/ko-KR.json index 92b2d63d..e77a7fe0 100644 --- a/frontend/src/i18n/ko-KR.json +++ b/frontend/src/i18n/ko-KR.json @@ -235,6 +235,7 @@ "continue_to_ask": "계속 질문하기:", "data_analysis": "데이터 분석", "data_predict": "데이터 예측", + "data_regenerated": "재생성", "chat_search": "검색", "thinking": "생각 중", "thinking_step": "사고 과정", diff --git a/frontend/src/i18n/zh-CN.json b/frontend/src/i18n/zh-CN.json index 02a803dc..2ec825a7 100644 --- a/frontend/src/i18n/zh-CN.json +++ b/frontend/src/i18n/zh-CN.json @@ -236,6 +236,7 @@ "continue_to_ask": "继续提问:", "data_analysis": "数据分析", "data_predict": "数据预测", + "data_regenerated": "重新生成", "chat_search": "搜索", "thinking": "思考中", "thinking_step": "思考过程", diff --git a/frontend/src/views/chat/answer/ChartAnswer.vue b/frontend/src/views/chat/answer/ChartAnswer.vue index 1f1f4504..68c74059 100644 --- a/frontend/src/views/chat/answer/ChartAnswer.vue +++ b/frontend/src/views/chat/answer/ChartAnswer.vue @@ -163,6 +163,15 @@ const sendMessage = async () => { currentRecord.id = data.id _currentChat.value.records[index.value].id = data.id break + case 'regenerate_record_id': + currentRecord.regenerate_record_id = data.regenerate_record_id + _currentChat.value.records[index.value].regenerate_record_id = + data.regenerate_record_id + break + case 'question': + currentRecord.question = data.question + _currentChat.value.records[index.value].question = data.question + break case 'info': console.info(data.msg) break diff --git a/frontend/src/views/chat/chat-block/UserChat.vue b/frontend/src/views/chat/chat-block/UserChat.vue index 6be1c3f2..2bf8e226 100644 --- a/frontend/src/views/chat/chat-block/UserChat.vue +++ b/frontend/src/views/chat/chat-block/UserChat.vue @@ -3,9 +3,11 @@ import type { ChatMessage } from '@/api/chat.ts' import icon_copy_outlined from '@/assets/embedded/icon_copy_outlined.svg' import { useI18n } from 'vue-i18n' import { useClipboard } from '@vueuse/core' +import { computed } from 'vue' const props = defineProps<{ message?: ChatMessage + allMessages?: ChatMessage[] }>() const { t } = useI18n() const { copy } = useClipboard({ legacy: true }) @@ -16,6 +18,13 @@ function clickAnalysis() { function clickPredict() { console.info('predict_record_id: ' + props.message?.record?.predict_record_id) } +function clickRegenerated() { + console.info('regenerate_record_id: ' + props.message?.record?.regenerate_record_id) +} + +const isRegenerated = computed(() => { + return !!props.message?.record?.regenerate_record_id +}) const copyCode = () => { const str = props.message?.content || '' @@ -37,6 +46,9 @@ const copyCode = () => { {{ t('qa.data_predict') }} + + {{ t('qa.data_regenerated') }} + {{ message?.content }}
diff --git a/frontend/src/views/chat/index.vue b/frontend/src/views/chat/index.vue index f351727f..da20796b 100644 --- a/frontend/src/views/chat/index.vue +++ b/frontend/src/views/chat/index.vue @@ -211,7 +211,11 @@ - +