diff --git a/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py b/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py index f695340e3..135c314d3 100644 --- a/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py +++ b/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py @@ -307,10 +307,9 @@ class BaseChatStep(IChatStep): else: reasoning_content = reasoning_result.get('reasoning_content') + reasoning_result_end.get( 'reasoning_content') - asker = manage.context.get('form_data', {}).get('asker', None) post_response_handler.handler(chat_id, chat_record_id, paragraph_list, problem_text, - chat_id, manage, self, padding_problem_text, - reasoning_content=reasoning_content if reasoning_content_enable else '') + content, manage, self, padding_problem_text, + reasoning_content=reasoning_content) add_access_num(client_id, client_type, manage.context.get('application_id')) return manage.get_base_to_response().to_block_response(str(chat_id), str(chat_record_id), content, True, @@ -324,10 +323,8 @@ class BaseChatStep(IChatStep): except Exception as e: all_text = 'Exception:' + str(e) write_context(self, manage, 0, 0, all_text) - asker = manage.context.get('form_data', {}).get('asker', None) post_response_handler.handler(chat_id, chat_record_id, paragraph_list, problem_text, - chat_id, manage, self, padding_problem_text, - reasoning_content='') + all_text, manage, self, padding_problem_text, reasoning_content='') add_access_num(client_id, client_type, manage.context.get('application_id')) return manage.get_base_to_response().to_block_response(str(chat_id), str(chat_record_id), all_text, True, 0, 0, _status=status.HTTP_500_INTERNAL_SERVER_ERROR) diff --git a/apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py b/apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py index dac0370f8..b1cb3efc2 100644 --- a/apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py +++ b/apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py @@ -61,7 +61,7 @@ def file_id_to_base64(file_id: str): file = QuerySet(File).filter(id=file_id).first() file_bytes = file.get_bytes() base64_image = base64.b64encode(file_bytes).decode("utf-8") - return [base64_image, what(None, file_bytes.tobytes())] + return [base64_image, what(None, file_bytes)] class BaseImageUnderstandNode(IImageUnderstandNode): @@ -173,7 +173,7 @@ class BaseImageUnderstandNode(IImageUnderstandNode): file = QuerySet(File).filter(id=file_id).first() image_bytes = file.get_bytes() base64_image = base64.b64encode(image_bytes).decode("utf-8") - image_format = what(None, image_bytes.tobytes()) + image_format = what(None, image_bytes) images.append( {'type': 'image_url', 'image_url': {'url': f'data:image/{image_format};base64,{base64_image}'}}) messages = [HumanMessage( diff --git a/apps/application/flow/step_node/start_node/impl/base_start_node.py b/apps/application/flow/step_node/start_node/impl/base_start_node.py index 24b968471..64bf81bd3 100644 --- a/apps/application/flow/step_node/start_node/impl/base_start_node.py +++ b/apps/application/flow/step_node/start_node/impl/base_start_node.py @@ -22,12 +22,16 @@ def get_default_global_variable(input_field_list: List): def get_global_variable(node): + body = node.workflow_manage.get_body() history_chat_record = node.flow_params_serializer.data.get('history_chat_record', []) history_context = [{'question': chat_record.problem_text, 'answer': chat_record.answer_text} for chat_record in history_chat_record] chat_id = node.flow_params_serializer.data.get('chat_id') return {'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'start_time': time.time(), - 'history_context': history_context, 'chat_id': str(chat_id), **node.workflow_manage.form_data} + 'history_context': history_context, 'chat_id': str(chat_id), **node.workflow_manage.form_data, + 'chat_user_id': body.get('chat_user_id'), + 'chat_user_type': body.get('chat_user_type'), + 'chat_user': body.get('chat_user')} class BaseStartStepNode(IStarNode): @@ -64,6 +68,7 @@ class BaseStartStepNode(IStarNode): 'document': self.workflow_manage.document_list, 'audio': self.workflow_manage.audio_list, 'other': self.workflow_manage.other_list, + } return NodeResult(node_variable, workflow_variable) diff --git a/apps/application/flow/workflow_manage.py b/apps/application/flow/workflow_manage.py index e0065e6f4..2f4c1586d 100644 --- a/apps/application/flow/workflow_manage.py +++ b/apps/application/flow/workflow_manage.py @@ -154,8 +154,8 @@ class WorkflowManage: if global_fields is not None: for global_field in global_fields: global_field_list.append({**global_field, 'node_id': node_id, 'node_name': node_name}) - field_list.sort(key=lambda f: len(f.get('node_name')), reverse=True) - global_field_list.sort(key=lambda f: len(f.get('node_name')), reverse=True) + field_list.sort(key=lambda f: len(f.get('node_name') + f.get('value')), reverse=True) + global_field_list.sort(key=lambda f: len(f.get('node_name') + f.get('value')), reverse=True) self.field_list = field_list self.global_field_list = global_field_list diff --git a/apps/application/migrations/0005_chat_chat_record_count_chat_mark_sum_chat_star_num_and_more.py b/apps/application/migrations/0005_chat_chat_record_count_chat_mark_sum_chat_star_num_and_more.py new file mode 100644 index 000000000..fcb788af6 --- /dev/null +++ b/apps/application/migrations/0005_chat_chat_record_count_chat_mark_sum_chat_star_num_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.3 on 2025-07-07 02:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('application', '0004_application_publish_time_applicationversion_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='chat', + name='chat_record_count', + field=models.IntegerField(default=0, verbose_name='对话次数'), + ), + migrations.AddField( + model_name='chat', + name='mark_sum', + field=models.IntegerField(default=0, verbose_name='标记数量'), + ), + migrations.AddField( + model_name='chat', + name='star_num', + field=models.IntegerField(default=0, verbose_name='点赞数量'), + ), + migrations.AddField( + model_name='chat', + name='trample_num', + field=models.IntegerField(default=0, verbose_name='点踩数量'), + ), + ] diff --git a/apps/application/models/application_chat.py b/apps/application/models/application_chat.py index f66c5c946..3e475a5bf 100644 --- a/apps/application/models/application_chat.py +++ b/apps/application/models/application_chat.py @@ -39,6 +39,10 @@ class Chat(AppModelMixin): is_deleted = models.BooleanField(verbose_name="逻辑删除", default=False) asker = models.JSONField(verbose_name="访问者", default=default_asker, encoder=SystemEncoder) meta = models.JSONField(verbose_name="元数据", default=dict) + star_num = models.IntegerField(verbose_name="点赞数量", default=0) + trample_num = models.IntegerField(verbose_name="点踩数量", default=0) + chat_record_count = models.IntegerField(verbose_name="对话次数", default=0) + mark_sum = models.IntegerField(verbose_name="标记数量", default=0) class Meta: db_table = "application_chat" diff --git a/apps/application/serializers/application_chat.py b/apps/application/serializers/application_chat.py index a8b0fce7e..e88e7cab2 100644 --- a/apps/application/serializers/application_chat.py +++ b/apps/application/serializers/application_chat.py @@ -22,12 +22,12 @@ from django.utils.translation import gettext_lazy as _, gettext from openpyxl.cell.cell import ILLEGAL_CHARACTERS_RE from rest_framework import serializers -from application.models import Chat, Application +from application.models import Chat, Application, ChatRecord from common.db.search import get_dynamics_model, native_search, native_page_search from common.exception.app_exception import AppApiException from common.utils.common import get_file_content from maxkb.conf import PROJECT_DIR -from maxkb.settings import TIME_ZONE +from maxkb.settings import TIME_ZONE, edition class ApplicationChatResponseSerializers(serializers.Serializer): @@ -120,12 +120,8 @@ class ApplicationChatQuerySerializers(serializers.Serializer): condition = base_condition & min_trample_query else: condition = base_condition - inner_queryset = QuerySet(Chat).filter(application_id=self.data.get("application_id")) - if 'abstract' in self.data and self.data.get('abstract') is not None: - inner_queryset = inner_queryset.filter(abstract__icontains=self.data.get('abstract')) return { - 'inner_queryset': inner_queryset, 'default_queryset': query_set.filter(condition).order_by("-application_chat.update_time") } @@ -133,7 +129,8 @@ class ApplicationChatQuerySerializers(serializers.Serializer): if with_valid: self.is_valid(raise_exception=True) return native_search(self.get_query_set(), select_string=get_file_content( - os.path.join(PROJECT_DIR, "apps", "application", 'sql', 'list_application_chat.sql')), + os.path.join(PROJECT_DIR, "apps", "application", 'sql', ('list_application_chat_ee.sql' if ['PE', 'EE'].__contains__( + edition) else 'list_application_chat.sql'))), with_table_name=False) @staticmethod @@ -144,7 +141,7 @@ class ApplicationChatQuerySerializers(serializers.Serializer): @staticmethod def to_row(row: Dict): - details = row.get('details') + details = row.get('details') or {} padding_problem_text = ' '.join(node.get("answer", "") for key, node in details.items() if node.get("type") == 'question-node') search_dataset_node_list = [(key, node) for key, node in details.items() if @@ -161,7 +158,7 @@ class ApplicationChatQuerySerializers(serializers.Serializer): 'name') + ':\n' + ApplicationChatQuerySerializers.paragraph_list_to_string(node.get('paragraph_list', [])) for key, node in search_dataset_node_list]) - improve_paragraph_list = row.get('improve_paragraph_list') + improve_paragraph_list = row.get('improve_paragraph_list') or [] vote_status_map = {'-1': '未投票', '0': '赞同', '1': '反对'} return [str(row.get('chat_id')), row.get('abstract'), row.get('problem_text'), padding_problem_text, row.get('answer_text'), vote_status_map.get(row.get('vote_status')), reference_paragraph_len, @@ -169,18 +166,20 @@ class ApplicationChatQuerySerializers(serializers.Serializer): "\n".join([ f"{improve_paragraph_list[index].get('title')}\n{improve_paragraph_list[index].get('content')}" for index in range(len(improve_paragraph_list))]), - row.get('message_tokens') + row.get('answer_tokens'), row.get('run_time'), + (row.get('message_tokens') or 0) + (row.get('answer_tokens') or 0), row.get('run_time'), str(row.get('create_time').astimezone(pytz.timezone(TIME_ZONE)).strftime('%Y-%m-%d %H:%M:%S') - )] + if row.get('create_time') is not None else None)] def export(self, data, with_valid=True): if with_valid: self.is_valid(raise_exception=True) ApplicationChatRecordExportRequest(data=data).is_valid(raise_exception=True) + data_list = native_search(self.get_query_set(data.get('select_ids')), select_string=get_file_content( os.path.join(PROJECT_DIR, "apps", "application", 'sql', - 'export_application_chat.sql')), + ('export_application_chat_ee.sql' if ['PE', 'EE'].__contains__( + edition) else 'export_application_chat.sql'))), with_table_name=False) batch_size = 500 @@ -232,5 +231,26 @@ class ApplicationChatQuerySerializers(serializers.Serializer): if with_valid: self.is_valid(raise_exception=True) return native_page_search(current_page, page_size, self.get_query_set(), select_string=get_file_content( - os.path.join(PROJECT_DIR, "apps", "application", 'sql', 'list_application_chat.sql')), + os.path.join(PROJECT_DIR, "apps", "application", 'sql', + ('list_application_chat_ee.sql' if ['PE', 'EE'].__contains__( + edition) else 'list_application_chat.sql'))), with_table_name=False) + + +class ChatCountSerializer(serializers.Serializer): + chat_id = serializers.UUIDField(required=True, label=_("Conversation ID")) + + def get_query_set(self): + return QuerySet(ChatRecord).filter(chat_id=self.data.get('chat_id')) + + def update_chat(self): + self.is_valid(raise_exception=True) + count_chat_record = native_search(self.get_query_set(), get_file_content( + os.path.join(PROJECT_DIR, "apps", "application", 'sql', 'count_chat_record.sql')), with_search_one=True) + QuerySet(Chat).filter(id=self.data.get('chat_id')).update(star_num=count_chat_record.get('star_num', 0) or 0, + trample_num=count_chat_record.get('trample_num', + 0) or 0, + chat_record_count=count_chat_record.get( + 'chat_record_count', 0) or 0, + mark_sum=count_chat_record.get('mark_sum', 0) or 0) + return True diff --git a/apps/application/serializers/application_chat_record.py b/apps/application/serializers/application_chat_record.py index d5d50dc04..324aaa934 100644 --- a/apps/application/serializers/application_chat_record.py +++ b/apps/application/serializers/application_chat_record.py @@ -18,6 +18,7 @@ from rest_framework import serializers from rest_framework.utils.formatting import lazy_format from application.models import ChatRecord, ApplicationAccessToken, Application +from application.serializers.application_chat import ChatCountSerializer from application.serializers.common import ChatInfo from common.db.search import page_search from common.exception.app_exception import AppApiException @@ -359,6 +360,7 @@ class ApplicationChatRecordImproveSerializer(serializers.Serializer): update_document_char_length(document_id) # 添加标注 chat_record.save() + ChatCountSerializer(data={'chat_id': chat_id}).update_chat() return ChatRecordSerializerModel(chat_record).data, paragraph.id, knowledge_id class Operate(serializers.Serializer): diff --git a/apps/application/serializers/common.py b/apps/application/serializers/common.py index f602c78bf..1574b0d4b 100644 --- a/apps/application/serializers/common.py +++ b/apps/application/serializers/common.py @@ -14,8 +14,9 @@ from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ from application.chat_pipeline.step.chat_step.i_chat_step import PostResponseHandler -from application.models import Application, ChatRecord, Chat, ApplicationVersion +from application.models import Application, ChatRecord, Chat, ApplicationVersion, ChatUserType from common.constants.cache_version import Cache_Version +from common.database_model_manage.database_model_manage import DatabaseModelManage from common.exception.app_exception import ChatException from models_provider.models import Model from models_provider.tools import get_model_credential @@ -47,6 +48,7 @@ class ChatInfo: self.application_id = application_id self.chat_record_list: List[ChatRecord] = [] self.application = None + self.chat_user = None self.debug = debug @staticmethod @@ -73,8 +75,30 @@ class ChatInfo: self.application = application return application + def get_chat_user(self, asker=None): + if self.chat_user: + return self.chat_user + if self.chat_user_type == ChatUserType.CHAT_USER.value: + chat_user_model = DatabaseModelManage.get_model("chat_user") + chat_user = QuerySet(chat_user_model).filter(id=self.chat_user_id).first() + return { + 'id': chat_user.id, + 'email': chat_user.email, + 'phone': chat_user.phone, + 'nick_name': chat_user.nick_name, + 'username': chat_user.username, + 'source': chat_user.source + } + else: + if asker: + self.chat_user = asker + else: + self.chat_user = {'username': '游客'} + return self.chat_user + def to_base_pipeline_manage_params(self): self.get_application() + self.get_chat_user() knowledge_setting = self.application.knowledge_setting model_setting = self.application.model_setting model_id = self.application.model_id @@ -139,7 +163,8 @@ class ChatInfo: if not self.debug: if not QuerySet(Chat).filter(id=self.chat_id).exists(): Chat(id=self.chat_id, application_id=self.application_id, abstract=chat_record.problem_text[0:1024], - chat_user_id=self.chat_user_id, chat_user_type=self.chat_user_type).save() + chat_user_id=self.chat_user_id, chat_user_type=self.chat_user_type, + asker=self.get_chat_user()).save() else: QuerySet(Chat).filter(id=self.chat_id).update(update_time=datetime.now()) # 插入会话记录 diff --git a/apps/application/sql/count_chat_record.sql b/apps/application/sql/count_chat_record.sql new file mode 100644 index 000000000..5d4b9a333 --- /dev/null +++ b/apps/application/sql/count_chat_record.sql @@ -0,0 +1,7 @@ +SELECT COUNT + ( "id" ) AS chat_record_count, + SUM ( CASE WHEN "vote_status" = '0' THEN 1 ELSE 0 END ) AS star_num, + SUM ( CASE WHEN "vote_status" = '1' THEN 1 ELSE 0 END ) AS trample_num, + SUM ( CASE WHEN array_length( application_chat_record.improve_paragraph_id_list, 1 ) IS NULL THEN 0 ELSE array_length( application_chat_record.improve_paragraph_id_list, 1 ) END ) AS mark_sum +FROM + application_chat_record \ No newline at end of file diff --git a/apps/application/sql/export_application_chat.sql b/apps/application/sql/export_application_chat.sql index cc83a2396..2a607cd55 100644 --- a/apps/application/sql/export_application_chat.sql +++ b/apps/application/sql/export_application_chat.sql @@ -10,24 +10,11 @@ SELECT application_chat_record_temp."index" as "index", application_chat_record_temp.improve_paragraph_list as improve_paragraph_list, application_chat_record_temp.vote_status as vote_status, - application_chat_record_temp.create_time as create_time + application_chat_record_temp.create_time as create_time, + application_chat.asker::json AS asker FROM application_chat application_chat LEFT JOIN ( - SELECT COUNT - ( "id" ) AS chat_record_count, - SUM ( CASE WHEN "vote_status" = '0' THEN 1 ELSE 0 END ) AS star_num, - SUM ( CASE WHEN "vote_status" = '1' THEN 1 ELSE 0 END ) AS trample_num, - SUM ( CASE WHEN array_length( application_chat_record.improve_paragraph_id_list, 1 ) IS NULL THEN 0 ELSE array_length( application_chat_record.improve_paragraph_id_list, 1 ) END ) AS mark_sum, - chat_id - FROM - application_chat_record - WHERE chat_id IN ( - SELECT id FROM application_chat ${inner_queryset}) - GROUP BY - application_chat_record.chat_id - ) chat_record_temp ON application_chat."id" = chat_record_temp.chat_id - LEFT JOIN ( SELECT *, CASE diff --git a/apps/application/sql/export_application_chat_ee.sql b/apps/application/sql/export_application_chat_ee.sql new file mode 100644 index 000000000..a77350a40 --- /dev/null +++ b/apps/application/sql/export_application_chat_ee.sql @@ -0,0 +1,28 @@ +SELECT + application_chat."id" as chat_id, + application_chat.abstract as abstract, + application_chat_record_temp.problem_text as problem_text, + application_chat_record_temp.answer_text as answer_text, + application_chat_record_temp.message_tokens as message_tokens, + application_chat_record_temp.answer_tokens as answer_tokens, + application_chat_record_temp.run_time as run_time, + application_chat_record_temp.details::JSON as details, + application_chat_record_temp."index" as "index", + application_chat_record_temp.improve_paragraph_list as improve_paragraph_list, + application_chat_record_temp.vote_status as vote_status, + application_chat_record_temp.create_time as create_time, + (CASE WHEN "chat_user".id is NULL THEN application_chat.asker ELSE jsonb_build_object('id',chat_user.id,'user_name',chat_user.username) END)::json AS asker +FROM + application_chat application_chat + left join chat_user chat_user on chat_user.id::varchar = application_chat.chat_user_id + LEFT JOIN ( + SELECT + *, + CASE + WHEN array_length( application_chat_record.improve_paragraph_id_list, 1 ) IS NULL THEN + '{}' ELSE ( SELECT ARRAY_AGG ( row_to_json ( paragraph ) ) FROM paragraph WHERE "id" = ANY ( application_chat_record.improve_paragraph_id_list ) ) + END as improve_paragraph_list + FROM + application_chat_record application_chat_record + ) application_chat_record_temp ON application_chat_record_temp.chat_id = application_chat."id" + ${default_queryset} \ No newline at end of file diff --git a/apps/application/sql/list_application_chat.sql b/apps/application/sql/list_application_chat.sql index f5b6d3e57..a2b0ace27 100644 --- a/apps/application/sql/list_application_chat.sql +++ b/apps/application/sql/list_application_chat.sql @@ -1,19 +1,3 @@ -SELECT - * -FROM - application_chat application_chat - LEFT JOIN ( - SELECT COUNT - ( "id" ) AS chat_record_count, - SUM ( CASE WHEN "vote_status" = '0' THEN 1 ELSE 0 END ) AS star_num, - SUM ( CASE WHEN "vote_status" = '1' THEN 1 ELSE 0 END ) AS trample_num, - SUM ( CASE WHEN array_length( application_chat_record.improve_paragraph_id_list, 1 ) IS NULL THEN 0 ELSE array_length( application_chat_record.improve_paragraph_id_list, 1 ) END ) AS mark_sum, - chat_id - FROM - application_chat_record - WHERE chat_id IN ( - SELECT id FROM application_chat ${inner_queryset}) - GROUP BY - application_chat_record.chat_id - ) chat_record_temp ON application_chat."id" = chat_record_temp.chat_id +select application_chat.*,application_chat.asker::json AS asker +from application_chat application_chat ${default_queryset} \ No newline at end of file diff --git a/apps/application/sql/list_application_chat_ee.sql b/apps/application/sql/list_application_chat_ee.sql new file mode 100644 index 000000000..0943c561b --- /dev/null +++ b/apps/application/sql/list_application_chat_ee.sql @@ -0,0 +1,4 @@ +select application_chat.*,(CASE WHEN "chat_user".id is NULL THEN application_chat.asker ELSE jsonb_build_object('id',chat_user.id,'user_name',chat_user.username) END)::json AS asker +from application_chat application_chat + left join chat_user chat_user on chat_user.id::varchar = application_chat.chat_user_id +${default_queryset} \ No newline at end of file diff --git a/apps/chat/serializers/chat.py b/apps/chat/serializers/chat.py index d14741be3..44ef94566 100644 --- a/apps/chat/serializers/chat.py +++ b/apps/chat/serializers/chat.py @@ -236,7 +236,8 @@ class ChatSerializers(serializers.Serializer): 'chat_user_id': chat_user_id, 'chat_user_type': chat_user_type, 'workspace_id': workspace_id, - 'debug': debug}, + 'debug': debug, + 'chat_user': chat_info.get_chat_user()}, WorkFlowPostHandler(chat_info), base_to_response, form_data, image_list, document_list, audio_list, other_list, @@ -250,6 +251,7 @@ class ChatSerializers(serializers.Serializer): ChatMessageSerializers(data=instance).is_valid(raise_exception=True) chat_info = self.get_chat_info() chat_info.get_application() + chat_info.get_chat_user() self.is_valid_chat_id(chat_info) if chat_info.application.type == ApplicationTypeChoices.SIMPLE: self.is_valid_application_simple(raise_exception=True, chat_info=chat_info) diff --git a/apps/chat/serializers/chat_record.py b/apps/chat/serializers/chat_record.py index 02570a9ad..4239e5b20 100644 --- a/apps/chat/serializers/chat_record.py +++ b/apps/chat/serializers/chat_record.py @@ -14,6 +14,7 @@ from django.utils.translation import gettext_lazy as _, gettext from rest_framework import serializers from application.models import VoteChoices, ChatRecord, Chat +from application.serializers.application_chat import ChatCountSerializer from application.serializers.application_chat_record import ChatRecordSerializerModel from common.db.search import page_search from common.exception.app_exception import AppApiException @@ -74,6 +75,7 @@ class VoteSerializer(serializers.Serializer): raise AppApiException(500, gettext("Already voted, please cancel first and then vote again")) finally: un_lock(self.data.get('chat_record_id')) + ChatCountSerializer(data={'chat_id': self.data.get('chat_id')}).update_chat() return True diff --git a/apps/knowledge/migrations/0003_alter_file_source_id_alter_file_source_type.py b/apps/knowledge/migrations/0003_alter_file_source_id_alter_file_source_type.py new file mode 100644 index 000000000..19288938f --- /dev/null +++ b/apps/knowledge/migrations/0003_alter_file_source_id_alter_file_source_type.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.3 on 2025-07-07 02:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('knowledge', '0002_alter_document_status_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='file', + name='source_id', + field=models.CharField(default='TEMPORARY_120_MINUTE', verbose_name='资源id'), + ), + migrations.AlterField( + model_name='file', + name='source_type', + field=models.CharField(choices=[('KNOWLEDGE', 'Knowledge'), ('APPLICATION', 'Application'), ('TOOL', 'Tool'), ('DOCUMENT', 'Document'), ('CHAT', 'Chat'), ('TEMPORARY_30_MINUTE', 'Temporary 30 Minute'), ('TEMPORARY_120_MINUTE', 'Temporary 120 Minute'), ('TEMPORARY_1_DAY', 'Temporary 1 Day')], default='TEMPORARY_120_MINUTE', verbose_name='资源类型'), + ), + ] diff --git a/ui/src/locales/lang/zh-CN/ai-chat.ts b/ui/src/locales/lang/zh-CN/ai-chat.ts index b518c03e5..0fb7d4b57 100644 --- a/ui/src/locales/lang/zh-CN/ai-chat.ts +++ b/ui/src/locales/lang/zh-CN/ai-chat.ts @@ -9,6 +9,9 @@ export default { question_count: '条提问', exportRecords: '导出聊天记录', chatId: '对话 ID', + chatUserId: '对话用户 ID', + chatUserType: '对话用户类型', + chatUser: '对话用户', userInput: '用户输入', quote: '引用', download: '点击下载文件', @@ -16,7 +19,7 @@ export default { passwordValidator: { title: '请输入密码打开链接', errorMessage1: '密码不能为空', - errorMessage2: '密码错误' + errorMessage2: '密码错误', }, operation: { play: '点击播放', @@ -28,7 +31,7 @@ export default { cancelOppose: '取消反对', continue: '继续', stopChat: '停止回答', - startChat: '开始对话' + startChat: '开始对话', }, tip: { error500Message: '抱歉,当前正在维护,无法提供服务,请稍后再试!', @@ -47,12 +50,12 @@ export default { requiredMessage: '请填写所有必填字段', inputParamMessage1: '请在URL中填写参数', inputParamMessage2: '的值', - prologueMessage: '抱歉,当前正在维护,无法提供服务,请稍后再试!' + prologueMessage: '抱歉,当前正在维护,无法提供服务,请稍后再试!', }, inputPlaceholder: { speaking: '说话中', recorderLoading: '转文字中', - default: '请输入问题' + default: '请输入问题', }, uploadFile: { label: '上传文件', @@ -64,7 +67,7 @@ export default { limitMessage2: '个文件', sizeLimit: '单个文件大小不能超过', imageMessage: '请解析图片内容', - errorMessage: '上传失败' + errorMessage: '上传失败', }, executionDetails: { title: '执行详情', @@ -83,18 +86,18 @@ export default { rerankerResult: '重排结果', paragraph: '分段', noSubmit: '用户未提交', - errMessage: '错误日志' + errMessage: '错误日志', }, KnowledgeSource: { title: '知识来源', referenceParagraph: '引用分段', consume: '消耗tokens', - consumeTime: '耗时' + consumeTime: '耗时', }, paragraphSource: { title: '知识库引用', question: '用户问题', - optimizationQuestion: '优化后问题' + optimizationQuestion: '优化后问题', }, - editTitle: '编辑标题' + editTitle: '编辑标题', } diff --git a/ui/src/workflow/common/data.ts b/ui/src/workflow/common/data.ts index 51b75553e..f9e1420e7 100644 --- a/ui/src/workflow/common/data.ts +++ b/ui/src/workflow/common/data.ts @@ -13,27 +13,27 @@ export const startNode = { fields: [ { label: t('views.applicationWorkflow.nodes.startNode.question'), - value: 'question' - } + value: 'question', + }, ], globalFields: [ { label: t('views.applicationWorkflow.nodes.startNode.currentTime'), value: 'time' }, { label: t('views.application.form.historyRecord.label'), - value: 'history_context' + value: 'history_context', }, { label: t('chat.chatId'), - value: 'chat_id' - } - ] + value: 'chat_id', + }, + ], }, fields: [{ label: t('views.applicationWorkflow.nodes.startNode.question'), value: 'question' }], globalFields: [ - { label: t('views.applicationWorkflow.nodes.startNode.currentTime'), value: 'time' } + { label: t('views.applicationWorkflow.nodes.startNode.currentTime'), value: 'time' }, ], - showNode: true - } + showNode: true, + }, } export const baseNode = { id: WorkflowType.Base, @@ -50,13 +50,13 @@ export const baseNode = { desc: '', // @ts-ignore prologue: t('views.application.form.defaultPrologue'), - tts_type: 'BROWSER' + tts_type: 'BROWSER', }, config: {}, showNode: true, user_input_config: { title: t('chat.userInput') }, - user_input_field_list: [] - } + user_input_field_list: [], + }, } /** * 说明 @@ -77,15 +77,15 @@ export const aiChatNode = { fields: [ { label: t('views.applicationWorkflow.nodes.aiChatNode.answer'), - value: 'answer' + value: 'answer', }, { label: t('views.applicationWorkflow.nodes.aiChatNode.think'), - value: 'reasoning_content' - } - ] - } - } + value: 'reasoning_content', + }, + ], + }, + }, } /** * 知识库检索配置数据 @@ -101,23 +101,25 @@ export const searchKnowledgeNode = { fields: [ { label: t('views.applicationWorkflow.nodes.searchKnowledgeNode.paragraph_list'), - value: 'paragraph_list' + value: 'paragraph_list', }, { - label: t('views.applicationWorkflow.nodes.searchKnowledgeNode.is_hit_handling_method_list'), - value: 'is_hit_handling_method_list' + label: t( + 'views.applicationWorkflow.nodes.searchKnowledgeNode.is_hit_handling_method_list', + ), + value: 'is_hit_handling_method_list', }, { label: t('views.applicationWorkflow.nodes.searchKnowledgeNode.result'), - value: 'data' + value: 'data', }, { label: t('views.applicationWorkflow.nodes.searchKnowledgeNode.directly_return'), - value: 'directly_return' - } - ] - } - } + value: 'directly_return', + }, + ], + }, + }, } export const questionNode = { type: WorkflowType.Question, @@ -130,11 +132,11 @@ export const questionNode = { fields: [ { label: t('views.applicationWorkflow.nodes.questionNode.result'), - value: 'answer' - } - ] - } - } + value: 'answer', + }, + ], + }, + }, } export const conditionNode = { type: WorkflowType.Condition, @@ -148,11 +150,11 @@ export const conditionNode = { fields: [ { label: t('views.applicationWorkflow.nodes.conditionNode.branch_name'), - value: 'branch_name' - } - ] - } - } + value: 'branch_name', + }, + ], + }, + }, } export const replyNode = { type: WorkflowType.Reply, @@ -165,11 +167,11 @@ export const replyNode = { fields: [ { label: t('views.applicationWorkflow.nodes.replyNode.content'), - value: 'answer' - } - ] - } - } + value: 'answer', + }, + ], + }, + }, } export const rerankerNode = { type: WorkflowType.RrerankerNode, @@ -182,15 +184,15 @@ export const rerankerNode = { fields: [ { label: t('views.applicationWorkflow.nodes.rerankerNode.result_list'), - value: 'result_list' + value: 'result_list', }, { label: t('views.applicationWorkflow.nodes.rerankerNode.result'), - value: 'result' - } - ] - } - } + value: 'result', + }, + ], + }, + }, } export const formNode = { type: WorkflowType.FormNode, @@ -205,17 +207,17 @@ export const formNode = { form_field_list: [], form_content_format: `${t('views.applicationWorkflow.nodes.formNode.form_content_format1')} {{form}} -${t('views.applicationWorkflow.nodes.formNode.form_content_format2')}` +${t('views.applicationWorkflow.nodes.formNode.form_content_format2')}`, }, config: { fields: [ { label: t('views.applicationWorkflow.nodes.formNode.form_data'), - value: 'form_data' - } - ] - } - } + value: 'form_data', + }, + ], + }, + }, } export const documentExtractNode = { type: WorkflowType.DocumentExtractNode, @@ -228,11 +230,11 @@ export const documentExtractNode = { fields: [ { label: t('views.applicationWorkflow.nodes.documentExtractNode.content'), - value: 'content' - } - ] - } - } + value: 'content', + }, + ], + }, + }, } export const imageUnderstandNode = { type: WorkflowType.ImageUnderstandNode, @@ -245,11 +247,11 @@ export const imageUnderstandNode = { fields: [ { label: t('views.applicationWorkflow.nodes.imageUnderstandNode.answer'), - value: 'answer' - } - ] - } - } + value: 'answer', + }, + ], + }, + }, } export const variableAssignNode = { @@ -259,8 +261,8 @@ export const variableAssignNode = { height: 252, properties: { stepName: t('views.applicationWorkflow.nodes.variableAssignNode.label'), - config: {} - } + config: {}, + }, } export const mcpNode = { @@ -274,11 +276,11 @@ export const mcpNode = { fields: [ { label: t('common.result'), - value: 'result' - } - ] - } - } + value: 'result', + }, + ], + }, + }, } export const imageGenerateNode = { @@ -292,15 +294,15 @@ export const imageGenerateNode = { fields: [ { label: t('views.applicationWorkflow.nodes.imageGenerateNode.answer'), - value: 'answer' + value: 'answer', }, { label: t('common.fileUpload.image'), - value: 'image' - } - ] - } - } + value: 'image', + }, + ], + }, + }, } export const speechToTextNode = { @@ -314,11 +316,11 @@ export const speechToTextNode = { fields: [ { label: t('common.result'), - value: 'result' - } - ] - } - } + value: 'result', + }, + ], + }, + }, } export const textToSpeechNode = { type: WorkflowType.TextToSpeechNode, @@ -331,17 +333,33 @@ export const textToSpeechNode = { fields: [ { label: t('common.result'), - value: 'result' - } - ] - } - } + value: 'result', + }, + ], + }, + }, } export const menuNodes = [ - { label: t('views.applicationWorkflow.nodes.classify.aiCapability'), list: [aiChatNode, questionNode, imageGenerateNode, imageUnderstandNode, textToSpeechNode, speechToTextNode] }, + { + label: t('views.applicationWorkflow.nodes.classify.aiCapability'), + list: [ + aiChatNode, + questionNode, + imageGenerateNode, + imageUnderstandNode, + textToSpeechNode, + speechToTextNode, + ], + }, { label: t('views.knowledge.title'), list: [searchKnowledgeNode, rerankerNode] }, - { label: t('views.applicationWorkflow.nodes.classify.businessLogic'), list: [conditionNode, formNode, variableAssignNode, replyNode] }, - { label: t('views.applicationWorkflow.nodes.classify.other'), list: [mcpNode, documentExtractNode] }, + { + label: t('views.applicationWorkflow.nodes.classify.businessLogic'), + list: [conditionNode, formNode, variableAssignNode, replyNode], + }, + { + label: t('views.applicationWorkflow.nodes.classify.other'), + list: [mcpNode, documentExtractNode], + }, ] /** @@ -358,11 +376,11 @@ export const toolNode = { fields: [ { label: t('common.result'), - value: 'result' - } - ] - } - } + value: 'result', + }, + ], + }, + }, } export const toolLibNode = { type: WorkflowType.ToolLib, @@ -375,11 +393,11 @@ export const toolLibNode = { fields: [ { label: t('common.result'), - value: 'result' - } - ] - } - } + value: 'result', + }, + ], + }, + }, } export const applicationNode = { @@ -393,11 +411,11 @@ export const applicationNode = { fields: [ { label: t('common.result'), - value: 'result' - } - ] - } - } + value: 'result', + }, + ], + }, + }, } export const compareList = [ @@ -416,7 +434,7 @@ export const compareList = [ { value: 'len_le', label: t('views.applicationWorkflow.compare.len_le') }, { value: 'len_lt', label: t('views.applicationWorkflow.compare.len_lt') }, { value: 'is_true', label: t('views.applicationWorkflow.compare.is_true') }, - { value: 'is_not_true', label: t('views.applicationWorkflow.compare.is_not_true') } + { value: 'is_not_true', label: t('views.applicationWorkflow.compare.is_not_true') }, ] export const nodeDict: any = { @@ -438,7 +456,7 @@ export const nodeDict: any = { [WorkflowType.SpeechToTextNode]: speechToTextNode, [WorkflowType.ImageGenerateNode]: imageGenerateNode, [WorkflowType.VariableAssignNode]: variableAssignNode, - [WorkflowType.McpNode]: mcpNode + [WorkflowType.McpNode]: mcpNode, } export function isWorkFlow(type: string | undefined) { return type === 'WORK_FLOW' diff --git a/ui/src/workflow/nodes/start-node/index.vue b/ui/src/workflow/nodes/start-node/index.vue index 0b3a52b40..30a72e2cb 100644 --- a/ui/src/workflow/nodes/start-node/index.vue +++ b/ui/src/workflow/nodes/start-node/index.vue @@ -26,7 +26,7 @@ import { cloneDeep, set } from 'lodash' import NodeContainer from '@/workflow/common/NodeContainer.vue' import { copyClick } from '@/utils/clipboard' -import { ref, computed, onMounted } from 'vue' +import { ref, onMounted } from 'vue' import { t } from '@/locales' const props = defineProps<{ nodeModel: any }>() @@ -35,9 +35,21 @@ const globalFields = [ { label: t('views.applicationWorkflow.nodes.startNode.currentTime'), value: 'time' }, { label: t('views.application.form.historyRecord.label'), - value: 'history_context' + value: 'history_context', + }, + { label: t('chat.chatId'), value: 'chat_id' }, + { + label: t('chat.chatUserId'), + value: 'chat_user_id', + }, + { + label: t('chat.chatUserType'), + value: 'chat_user_type', + }, + { + label: t('chat.chatUser'), + value: 'chat_user', }, - { label: t('chat.chatId'), value: 'chat_id' } ] const getRefreshFieldList = () => { @@ -79,7 +91,7 @@ const refreshFileUploadConfig = () => { item.value !== 'document' && item.value !== 'audio' && item.value !== 'video' && - item.value !== 'other' + item.value !== 'other', ) if (form_data.length === 0) {