From 53c7454196eb90eec8df5ad673093ac8a34785d9 Mon Sep 17 00:00:00 2001 From: shaohuzhang1 Date: Mon, 17 Jun 2024 16:24:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BA=94=E7=94=A8=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=B7=A5=E4=BD=9C=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/application/flow/default_workflow.json | 845 ++++++++++++++++++ .../migrations/0010_application_is_ready.py | 18 + apps/application/models/application.py | 1 + .../serializers/application_serializers.py | 66 +- .../serializers/chat_message_serializers.py | 36 +- .../swagger_api/application_api.py | 4 +- 6 files changed, 946 insertions(+), 24 deletions(-) create mode 100644 apps/application/flow/default_workflow.json create mode 100644 apps/application/migrations/0010_application_is_ready.py diff --git a/apps/application/flow/default_workflow.json b/apps/application/flow/default_workflow.json new file mode 100644 index 000000000..6cd820825 --- /dev/null +++ b/apps/application/flow/default_workflow.json @@ -0,0 +1,845 @@ +{ + "edges": [ + { + "id": "21096f2c-d89f-4fb3-b12-61484b0686d4", + "type": "app-edge", + "endPoint": { + "x": 370, + "y": 330 + }, + "pointsList": [ + { + "x": 250, + "y": 330 + }, + { + "x": 360, + "y": 330 + }, + { + "x": 260, + "y": 330 + }, + { + "x": 370, + "y": 330 + } + ], + "properties": { + + }, + "startPoint": { + "x": 250, + "y": 330 + }, + "sourceNodeId": "start-node", + "targetNodeId": "e781559d-e54b-45d8-bcea-d2d426fd58a3", + "sourceAnchorId": "start-node_right", + "targetAnchorId": "e781559d-e54b-45d8-bcea-d2d426fd58a3_left" + }, + { + "id": "6019001b-f9e8-4081-9538-ef1e717eac7b", + "type": "app-edge", + "endPoint": { + "x": 850, + "y": 330 + }, + "pointsList": [ + { + "x": 690, + "y": 330 + }, + { + "x": 800, + "y": 330 + }, + { + "x": 740, + "y": 330 + }, + { + "x": 850, + "y": 330 + } + ], + "properties": { + + }, + "startPoint": { + "x": 690, + "y": 330 + }, + "sourceNodeId": "e781559d-e54b-45d8-bcea-d2d426fd58a3", + "targetNodeId": "c94a8bfb-34b0-4b1b-8456-0a164870d382", + "sourceAnchorId": "e781559d-e54b-45d8-bcea-d2d426fd58a3_right", + "targetAnchorId": "c94a8bfb-34b0-4b1b-8456-0a164870d382_left" + }, + { + "id": "6dba7e71-c14c-427e-b7de-09f3b1064291", + "type": "app-edge", + "endPoint": { + "x": 1510, + "y": -480 + }, + "pointsList": [ + { + "x": 1430, + "y": 172.39999999999998 + }, + { + "x": 1540, + "y": 172.39999999999998 + }, + { + "x": 1400, + "y": -480 + }, + { + "x": 1510, + "y": -480 + } + ], + "properties": { + + }, + "startPoint": { + "x": 1430, + "y": 172.39999999999998 + }, + "sourceNodeId": "c94a8bfb-34b0-4b1b-8456-0a164870d382", + "targetNodeId": "ec6f5581-fef3-45a1-8be1-6611a8c9ccfc", + "sourceAnchorId": "c94a8bfb-34b0-4b1b-8456-0a164870d382_5675_right", + "targetAnchorId": "ec6f5581-fef3-45a1-8be1-6611a8c9ccfc_left" + }, + { + "id": "45a83361-1dfe-499e-8407-8c1670386b04", + "type": "app-edge", + "endPoint": { + "x": 1510, + "y": 60 + }, + "pointsList": [ + { + "x": 1430, + "y": 296.8 + }, + { + "x": 1540, + "y": 296.8 + }, + { + "x": 1400, + "y": 60 + }, + { + "x": 1510, + "y": 60 + } + ], + "properties": { + + }, + "startPoint": { + "x": 1430, + "y": 296.8 + }, + "sourceNodeId": "c94a8bfb-34b0-4b1b-8456-0a164870d382", + "targetNodeId": "2ac57a56-9150-4f04-a7b9-6390bdaade19", + "sourceAnchorId": "c94a8bfb-34b0-4b1b-8456-0a164870d382_9947_right", + "targetAnchorId": "2ac57a56-9150-4f04-a7b9-6390bdaade19_left" + }, + { + "id": "b18a10f9-df1a-415b-b419-cf44229b3345", + "type": "app-edge", + "endPoint": { + "x": 2090, + "y": 60 + }, + "pointsList": [ + { + "x": 1830, + "y": 60 + }, + { + "x": 1940, + "y": 60 + }, + { + "x": 1980, + "y": 60 + }, + { + "x": 2090, + "y": 60 + } + ], + "properties": { + + }, + "startPoint": { + "x": 1830, + "y": 60 + }, + "sourceNodeId": "2ac57a56-9150-4f04-a7b9-6390bdaade19", + "targetNodeId": "bd9dd852-d749-4b42-9b95-80f25b9a606d", + "sourceAnchorId": "2ac57a56-9150-4f04-a7b9-6390bdaade19_right", + "targetAnchorId": "bd9dd852-d749-4b42-9b95-80f25b9a606d_left" + }, + { + "id": "d9b31737-a480-48e5-84b6-a8556d1d68a5", + "type": "app-edge", + "endPoint": { + "x": 1510, + "y": 780 + }, + "pointsList": [ + { + "x": 1430, + "y": 421.2 + }, + { + "x": 1540, + "y": 421.2 + }, + { + "x": 1400, + "y": 780 + }, + { + "x": 1510, + "y": 780 + } + ], + "properties": { + + }, + "startPoint": { + "x": 1430, + "y": 421.2 + }, + "sourceNodeId": "c94a8bfb-34b0-4b1b-8456-0a164870d382", + "targetNodeId": "1cd54877-bfff-4791-b8f5-08c49f8bdf66", + "sourceAnchorId": "c94a8bfb-34b0-4b1b-8456-0a164870d382_5048_right", + "targetAnchorId": "1cd54877-bfff-4791-b8f5-08c49f8bdf66_left" + }, + { + "id": "32d36445-b2b8-4472-9c86-3a9c147ceea2", + "type": "app-edge", + "endPoint": { + "x": 1950, + "y": 780 + }, + "pointsList": [ + { + "x": 1830, + "y": 780 + }, + { + "x": 1940, + "y": 780 + }, + { + "x": 1840, + "y": 780 + }, + { + "x": 1950, + "y": 780 + } + ], + "properties": { + + }, + "startPoint": { + "x": 1830, + "y": 780 + }, + "sourceNodeId": "1cd54877-bfff-4791-b8f5-08c49f8bdf66", + "targetNodeId": "e99869b2-251f-47a7-9966-c54ffb59b381", + "sourceAnchorId": "1cd54877-bfff-4791-b8f5-08c49f8bdf66_right", + "targetAnchorId": "e99869b2-251f-47a7-9966-c54ffb59b381_left" + }, + { + "id": "98c9014f-0bfc-4595-9c79-48ea785dc6cd", + "type": "app-edge", + "endPoint": { + "x": 2640, + "y": 260 + }, + "pointsList": [ + { + "x": 2530, + "y": 684.6 + }, + { + "x": 2640, + "y": 684.6 + }, + { + "x": 2530, + "y": 260 + }, + { + "x": 2640, + "y": 260 + } + ], + "properties": { + + }, + "startPoint": { + "x": 2530, + "y": 684.6 + }, + "sourceNodeId": "e99869b2-251f-47a7-9966-c54ffb59b381", + "targetNodeId": "62ab766b-b218-4bea-895f-b7e83614c8b7", + "sourceAnchorId": "e99869b2-251f-47a7-9966-c54ffb59b381_3014_right", + "targetAnchorId": "62ab766b-b218-4bea-895f-b7e83614c8b7_left" + }, + { + "id": "57e76e75-5c7f-42cb-a120-cc890243bb17", + "type": "app-edge", + "endPoint": { + "x": 2660, + "y": 810 + }, + "pointsList": [ + { + "x": 2530, + "y": 809 + }, + { + "x": 2640, + "y": 809 + }, + { + "x": 2550, + "y": 810 + }, + { + "x": 2660, + "y": 810 + } + ], + "properties": { + + }, + "startPoint": { + "x": 2530, + "y": 809 + }, + "sourceNodeId": "e99869b2-251f-47a7-9966-c54ffb59b381", + "targetNodeId": "04837361-30ea-41bd-96bc-768ee58d69d6", + "sourceAnchorId": "e99869b2-251f-47a7-9966-c54ffb59b381_4658_right", + "targetAnchorId": "04837361-30ea-41bd-96bc-768ee58d69d6_left" + }, + { + "id": "8becdf8e-243a-482a-bdf6-22e947aa9bd2", + "type": "app-edge", + "endPoint": { + "x": 2660, + "y": 1420 + }, + "pointsList": [ + { + "x": 2530, + "y": 895.6000000000001 + }, + { + "x": 2640, + "y": 895.6000000000001 + }, + { + "x": 2550, + "y": 1420 + }, + { + "x": 2660, + "y": 1420 + } + ], + "properties": { + + }, + "startPoint": { + "x": 2530, + "y": 895.6000000000001 + }, + "sourceNodeId": "e99869b2-251f-47a7-9966-c54ffb59b381", + "targetNodeId": "fe4d14fd-9aeb-40ad-b7e0-3d88bf1c5933", + "sourceAnchorId": "e99869b2-251f-47a7-9966-c54ffb59b381_8871_right", + "targetAnchorId": "fe4d14fd-9aeb-40ad-b7e0-3d88bf1c5933_left" + }, + { + "id": "f0277552-0d5a-4642-838f-989e59afe350", + "type": "app-edge", + "endPoint": { + "x": 1510, + "y": 1460 + }, + "pointsList": [ + { + "x": 1430, + "y": 507.8 + }, + { + "x": 1540, + "y": 507.8 + }, + { + "x": 1400, + "y": 1460 + }, + { + "x": 1510, + "y": 1460 + } + ], + "properties": { + + }, + "startPoint": { + "x": 1430, + "y": 507.8 + }, + "sourceNodeId": "c94a8bfb-34b0-4b1b-8456-0a164870d382", + "targetNodeId": "c9b74adb-e219-4d2b-8fd5-ecc2bac8786e", + "sourceAnchorId": "c94a8bfb-34b0-4b1b-8456-0a164870d382_6750_right", + "targetAnchorId": "c9b74adb-e219-4d2b-8fd5-ecc2bac8786e_left" + } + ], + "nodes": [ + { + "x": 2.777777777777601, + "y": -340, + "id": "base-node", + "type": "base-node", + "properties": { + "height": 200, + "stepName": "基本信息", + "node_data": { + "desc": "", + "name": "", + "prologue": "您好,我是 MaxKB 小助手,您可以向我提出 MaxKB 使用问题。\n- MaxKB 主要功能有什么?\n- MaxKB 支持哪些大语言模型?\n- MaxKB 支持哪些文档类型?" + } + } + }, + { + "x": 90, + "y": 330, + "id": "start-node", + "type": "start-node", + "properties": { + "fields": [ + { + "label": "用户问题", + "value": "question", + "globeLabel": "{{开始.question}}", + "globeValue": "{{context['start-node'].question}}" + } + ], + "height": 200, + "stepName": "开始" + } + }, + { + "x": 530, + "y": 330, + "id": "e781559d-e54b-45d8-bcea-d2d426fd58a3", + "type": "ai-chat-node", + "properties": { + "fields": [ + { + "label": "AI 回答内容", + "value": "answer", + "globeLabel": "{{AI 对话.answer}}", + "globeValue": "{{context['e781559d-e54b-45d8-bcea-d2d426fd58a3'].answer}}" + } + ], + "stepName": "AI 对话", + "node_data": { + "prompt": "请直接返回所属的问题分类,不要说推理过程。\n用户问题为:{{开始.question}}\n问题分类是:\n打招呼 \n售前咨询\n售后咨询\n其他咨询", + "system": "你是问题分类大师", + "model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab", + "dialogue_number": 0 + } + } + }, + { + "x": 1140, + "y": 330, + "id": "c94a8bfb-34b0-4b1b-8456-0a164870d382", + "type": "condition-node", + "properties": { + "width": 600, + "stepName": "判断器", + "node_data": { + "branch": [ + { + "id": "5675", + "type": "IF", + "condition": "and", + "conditions": [ + { + "field": [ + "e781559d-e54b-45d8-bcea-d2d426fd58a3", + "answer" + ], + "value": "打招呼 ", + "compare": "contain" + } + ] + }, + { + "id": "9947", + "type": "ELSE IF 1", + "condition": "and", + "conditions": [ + { + "field": [ + "e781559d-e54b-45d8-bcea-d2d426fd58a3", + "answer" + ], + "value": "售前咨询", + "compare": "contain" + } + ] + }, + { + "id": "5048", + "type": "ELSE IF 2", + "condition": "and", + "conditions": [ + { + "field": [ + "e781559d-e54b-45d8-bcea-d2d426fd58a3", + "answer" + ], + "value": "售后咨询", + "compare": "contain" + } + ] + }, + { + "id": "6750", + "type": "ELSE", + "condition": "and", + "conditions": [ + + ] + } + ] + }, + "branch_condition_list": [ + { + "id": "5675", + "index": 0, + "height": 116.4 + }, + { + "id": "9947", + "index": 1, + "height": 116.4 + }, + { + "id": "5048", + "index": 2, + "height": 116.4 + }, + { + "id": "6750", + "index": 3, + "height": 40.8 + } + ] + } + }, + { + "x": 1670, + "y": -480, + "id": "ec6f5581-fef3-45a1-8be1-6611a8c9ccfc", + "type": "reply-node", + "properties": { + "stepName": "指定回复", + "node_data": { + "fields": [ + + ], + "content": "你好我是ai只能机器人,很高兴为你服务", + "reply_type": "content" + } + } + }, + { + "x": 1670, + "y": 60, + "id": "2ac57a56-9150-4f04-a7b9-6390bdaade19", + "type": "search-dataset-node", + "properties": { + "fields": [ + { + "label": "段落列表", + "value": "paragraph_list", + "globeLabel": "{{知识库检索.paragraph_list}}", + "globeValue": "{{context['2ac57a56-9150-4f04-a7b9-6390bdaade19'].paragraph_list}}" + }, + { + "label": "满足直接回答的段落列表", + "value": "is_hit_handling_method_list", + "globeLabel": "{{知识库检索.is_hit_handling_method_list}}", + "globeValue": "{{context['2ac57a56-9150-4f04-a7b9-6390bdaade19'].is_hit_handling_method_list}}" + }, + { + "label": "检索结果", + "value": "data", + "globeLabel": "{{知识库检索.data}}", + "globeValue": "{{context['2ac57a56-9150-4f04-a7b9-6390bdaade19'].data}}" + }, + { + "label": "满足直接回答的分段内容", + "value": "directly_return", + "globeLabel": "{{知识库检索.directly_return}}", + "globeValue": "{{context['2ac57a56-9150-4f04-a7b9-6390bdaade19'].directly_return}}" + } + ], + "stepName": "知识库检索", + "node_data": { + "dataset_id_list": [ + "8ba47817-28a1-11ef-90fd-a8a1595801ab" + ], + "dataset_setting": { + "top_n": 3, + "similarity": 0.6, + "search_mode": "embedding", + "max_paragraph_char_number": 5000 + }, + "question_reference_address": [ + "start-node", + "question" + ] + } + } + }, + { + "x": 2250, + "y": 60, + "id": "bd9dd852-d749-4b42-9b95-80f25b9a606d", + "type": "ai-chat-node", + "properties": { + "fields": [ + { + "label": "AI 回答内容", + "value": "answer", + "globeLabel": "{{AI 对话.answer}}", + "globeValue": "{{context['bd9dd852-d749-4b42-9b95-80f25b9a606d'].answer}}" + } + ], + "stepName": "AI 对话", + "node_data": { + "prompt": "已知信息:\n{{知识库检索.data}}\n问题:\n{{开始.question}}", + "system": "你是售前咨询知识库", + "model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab", + "dialogue_number": 0 + } + } + }, + { + "x": 1670, + "y": 780, + "id": "1cd54877-bfff-4791-b8f5-08c49f8bdf66", + "type": "search-dataset-node", + "properties": { + "fields": [ + { + "label": "段落列表", + "value": "paragraph_list", + "globeLabel": "{{知识库检索.paragraph_list}}", + "globeValue": "{{context['1cd54877-bfff-4791-b8f5-08c49f8bdf66'].paragraph_list}}" + }, + { + "label": "满足直接回答的段落列表", + "value": "is_hit_handling_method_list", + "globeLabel": "{{知识库检索.is_hit_handling_method_list}}", + "globeValue": "{{context['1cd54877-bfff-4791-b8f5-08c49f8bdf66'].is_hit_handling_method_list}}" + }, + { + "label": "检索结果", + "value": "data", + "globeLabel": "{{知识库检索.data}}", + "globeValue": "{{context['1cd54877-bfff-4791-b8f5-08c49f8bdf66'].data}}" + }, + { + "label": "满足直接回答的分段内容", + "value": "directly_return", + "globeLabel": "{{知识库检索.directly_return}}", + "globeValue": "{{context['1cd54877-bfff-4791-b8f5-08c49f8bdf66'].directly_return}}" + } + ], + "stepName": "知识库检索", + "node_data": { + "dataset_id_list": [ + "188c3fa1-28a3-11ef-99e8-a8a1595801ab" + ], + "dataset_setting": { + "top_n": 3, + "similarity": 0.6, + "search_mode": "embedding", + "max_paragraph_char_number": 5000 + }, + "question_reference_address": [ + "start-node", + "question" + ] + } + } + }, + { + "x": 2240, + "y": 780, + "id": "e99869b2-251f-47a7-9966-c54ffb59b381", + "type": "condition-node", + "properties": { + "width": 600, + "stepName": "判断器", + "node_data": { + "branch": [ + { + "id": "3014", + "type": "IF", + "condition": "and", + "conditions": [ + { + "field": [ + "1cd54877-bfff-4791-b8f5-08c49f8bdf66", + "is_hit_handling_method_list" + ], + "value": "1", + "compare": "ge" + } + ] + }, + { + "id": "4658", + "type": "ELSE IF 1", + "condition": "and", + "conditions": [ + { + "field": [ + "1cd54877-bfff-4791-b8f5-08c49f8bdf66", + "paragraph_list" + ], + "value": "1", + "compare": "ge" + } + ] + }, + { + "id": "8871", + "type": "ELSE", + "condition": "and", + "conditions": [ + + ] + } + ] + }, + "branch_condition_list": [ + { + "id": "3014", + "index": 0, + "height": 116.4 + }, + { + "id": "4658", + "index": 1, + "height": 116.4 + }, + { + "id": "8871", + "index": 2, + "height": 40.8 + } + ] + } + }, + { + "x": 2800, + "y": 260, + "id": "62ab766b-b218-4bea-895f-b7e83614c8b7", + "type": "reply-node", + "properties": { + "stepName": "指定回复", + "node_data": { + "fields": [ + "1cd54877-bfff-4791-b8f5-08c49f8bdf66", + "directly_return" + ], + "content": "", + "reply_type": "referencing" + } + } + }, + { + "x": 2820, + "y": 810, + "id": "04837361-30ea-41bd-96bc-768ee58d69d6", + "type": "ai-chat-node", + "properties": { + "fields": [ + { + "label": "AI 回答内容", + "value": "answer", + "globeLabel": "{{AI 对话.answer}}", + "globeValue": "{{context['04837361-30ea-41bd-96bc-768ee58d69d6'].answer}}" + } + ], + "stepName": "AI 对话", + "node_data": { + "prompt": "已知信息:\n{{context['1cd54877-bfff-4791-b8f5-08c49f8bdf66'].data}}\n问题:\n{{context['start-node'].question}}", + "system": "你是售后工程师", + "model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab", + "dialogue_number": 0 + } + } + }, + { + "x": 2820, + "y": 1420, + "id": "fe4d14fd-9aeb-40ad-b7e0-3d88bf1c5933", + "type": "reply-node", + "properties": { + "stepName": "指定回复", + "node_data": { + "fields": [ + + ], + "content": "未找到相关内容", + "reply_type": "content" + } + } + }, + { + "x": 1670, + "y": 1460, + "id": "c9b74adb-e219-4d2b-8fd5-ecc2bac8786e", + "type": "ai-chat-node", + "properties": { + "fields": [ + { + "label": "AI 回答内容", + "value": "answer", + "globeLabel": "{{AI 对话.answer}}", + "globeValue": "{{context['c9b74adb-e219-4d2b-8fd5-ecc2bac8786e'].answer}}" + } + ], + "stepName": "AI 对话", + "node_data": { + "prompt": "{{开始.question}} ", + "system": "", + "model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab", + "dialogue_number": 0 + } + } + } + ] +} \ No newline at end of file diff --git a/apps/application/migrations/0010_application_is_ready.py b/apps/application/migrations/0010_application_is_ready.py new file mode 100644 index 000000000..d6aba10db --- /dev/null +++ b/apps/application/migrations/0010_application_is_ready.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.13 on 2024-06-17 16:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('application', '0009_application_type_application_work_flow'), + ] + + operations = [ + migrations.AddField( + model_name='application', + name='is_ready', + field=models.BooleanField(default=True, verbose_name='是否就绪'), + ), + ] diff --git a/apps/application/models/application.py b/apps/application/models/application.py index 43fb10c50..4623f51ab 100644 --- a/apps/application/models/application.py +++ b/apps/application/models/application.py @@ -51,6 +51,7 @@ class Application(AppModelMixin): work_flow = models.JSONField(verbose_name="工作流数据", default=dict) type = models.CharField(verbose_name="应用类型", choices=ApplicationTypeChoices.choices, default=ApplicationTypeChoices.SIMPLE, max_length=256) + is_ready = models.BooleanField(verbose_name="是否就绪", default=True) @staticmethod def get_default_model_prompt(): diff --git a/apps/application/serializers/application_serializers.py b/apps/application/serializers/application_serializers.py index 47ecb4446..0a60506d9 100644 --- a/apps/application/serializers/application_serializers.py +++ b/apps/application/serializers/application_serializers.py @@ -7,6 +7,7 @@ @desc: """ import hashlib +import json import os import re import uuid @@ -22,7 +23,7 @@ from django.http import HttpResponse from django.template import Template, Context from rest_framework import serializers -from application.models import Application, ApplicationDatasetMapping +from application.models import Application, ApplicationDatasetMapping, ApplicationTypeChoices from application.models.api_key_model import ApplicationAccessToken, ApplicationApiKey from common.config.embedding_config import VectorStore, EmbeddingModel from common.constants.authentication_type import AuthenticationType @@ -105,6 +106,40 @@ class ModelSettingSerializer(serializers.Serializer): prompt = serializers.CharField(required=True, max_length=2048, error_messages=ErrMessage.char("提示词")) +class ApplicationWorkflowSerializer(serializers.Serializer): + name = serializers.CharField(required=True, max_length=64, min_length=1, error_messages=ErrMessage.char("应用名称")) + desc = serializers.CharField(required=False, allow_null=True, allow_blank=True, + max_length=256, min_length=1, + error_messages=ErrMessage.char("应用描述")) + prologue = serializers.CharField(required=False, allow_null=True, allow_blank=True, max_length=4096, + error_messages=ErrMessage.char("开场白")) + + @staticmethod + def to_application_model(user_id: str, application: Dict): + + default_workflow_json = get_file_content( + os.path.join(PROJECT_DIR, "apps", "application", 'flow', 'default_workflow.json')) + default_workflow = json.loads(default_workflow_json) + for node in default_workflow.get('nodes'): + if node.get('id') == 'base-node': + node.get('properties')['node_data'] = {"desc": application.get('desc'), + "name": application.get('name'), + "prologue": application.get('prologue')} + return Application(id=uuid.uuid1(), + name=application.get('name'), + desc=application.get('desc'), + prologue="", + dialogue_number=0, + user_id=user_id, model_id=None, + dataset_setting={}, + model_setting={}, + problem_optimization=False, + type=ApplicationTypeChoices.WORK_FLOW, + work_flow=default_workflow, + is_ready=False + ) + + class ApplicationSerializer(serializers.Serializer): name = serializers.CharField(required=True, max_length=64, min_length=1, error_messages=ErrMessage.char("应用名称")) desc = serializers.CharField(required=False, allow_null=True, allow_blank=True, @@ -123,6 +158,13 @@ class ApplicationSerializer(serializers.Serializer): model_setting = ModelSettingSerializer(required=True) # 问题补全 problem_optimization = serializers.BooleanField(required=True, error_messages=ErrMessage.boolean("问题补全")) + # 应用类型 + type = serializers.CharField(required=True, error_messages=ErrMessage.char("应用类型"), + validators=[ + validators.RegexValidator(regex=re.compile("^SIMPLE|WORK_FLOW$"), + message="应用类型只支持SIMPLE|WORK_FLOW", code=500) + ] + ) def is_valid(self, *, user_id=None, raise_exception=False): super().is_valid(raise_exception=True) @@ -281,6 +323,22 @@ class ApplicationSerializer(serializers.Serializer): @transaction.atomic def insert(self, application: Dict): + application_type = application.get('type') + if 'WORK_FLOW' == application_type: + self.insert_workflow(application) + else: + self.insert_simple(application) + return True + + def insert_workflow(self, application: Dict): + self.is_valid(raise_exception=True) + user_id = self.data.get('user_id') + ApplicationWorkflowSerializer(data=application).is_valid(raise_exception=True) + application_model = ApplicationWorkflowSerializer.to_application_model(user_id, application) + application_model.save() + return True + + def insert_simple(self, application: Dict): self.is_valid(raise_exception=True) user_id = self.data.get('user_id') ApplicationSerializer(data=application).is_valid(user_id=user_id, raise_exception=True) @@ -296,7 +354,6 @@ class ApplicationSerializer(serializers.Serializer): access_token=hashlib.md5(str(uuid.uuid1()).encode()).hexdigest()[8:24]).save() # 插入关联数据 QuerySet(ApplicationDatasetMapping).bulk_create(application_dataset_mapping_model_list) - return True @staticmethod def to_application_model(user_id: str, application: Dict): @@ -306,7 +363,10 @@ class ApplicationSerializer(serializers.Serializer): user_id=user_id, model_id=application.get('model_id'), dataset_setting=application.get('dataset_setting'), model_setting=application.get('model_setting'), - problem_optimization=application.get('problem_optimization') + problem_optimization=application.get('problem_optimization'), + type=ApplicationTypeChoices.SIMPLE, + work_flow={}, + is_ready=True ) @staticmethod diff --git a/apps/application/serializers/chat_message_serializers.py b/apps/application/serializers/chat_message_serializers.py index 41155acd9..6e812b79b 100644 --- a/apps/application/serializers/chat_message_serializers.py +++ b/apps/application/serializers/chat_message_serializers.py @@ -151,13 +151,6 @@ class ChatMessageSerializer(serializers.Serializer): def is_valid_application_workflow(self, *, raise_exception=False): self.is_valid_intraday_access_num() - chat_id = self.data.get('chat_id') - chat_info: ChatInfo = chat_cache.get(chat_id) - if chat_info is None: - chat_info = self.re_open_chat(chat_id) - chat_cache.set(chat_id, - chat_info, timeout=60 * 30) - return chat_info def is_valid_intraday_access_num(self): if self.data.get('client_type') == AuthenticationType.APPLICATION_ACCESS_TOKEN.value: @@ -174,14 +167,8 @@ class ChatMessageSerializer(serializers.Serializer): if application_access_token.access_num <= access_client.intraday_access_num: raise AppChatNumOutOfBoundsFailed(1002, "访问次数超过今日访问量") - def is_valid_application_simple(self, *, raise_exception=False): + def is_valid_application_simple(self, *, chat_info: ChatInfo, raise_exception=False): self.is_valid_intraday_access_num() - chat_id = self.data.get('chat_id') - chat_info: ChatInfo = chat_cache.get(chat_id) - if chat_info is None: - chat_info = self.re_open_chat(chat_id) - chat_cache.set(chat_id, - chat_info, timeout=60 * 30) model = chat_info.application.model if model is None: return chat_info @@ -194,7 +181,7 @@ class ChatMessageSerializer(serializers.Serializer): raise AppApiException(500, "模型正在下载中,请稍后再发起对话") return chat_info - def chat_simple(self, chat_info): + def chat_simple(self, chat_info: ChatInfo): message = self.data.get('message') re_chat = self.data.get('re_chat') stream = self.data.get('stream') @@ -241,15 +228,24 @@ class ChatMessageSerializer(serializers.Serializer): def chat(self): super().is_valid(raise_exception=True) - application = QuerySet(Application).filter(id=self.data.get('application_id')).first() - if application.type == ApplicationTypeChoices.SIMPLE: - chat_info = self.is_valid_application_simple(raise_exception=True) + chat_info = self.get_chat_info() + if chat_info.application.type == ApplicationTypeChoices.SIMPLE: + self.is_valid_application_simple(raise_exception=True, chat_info=chat_info), return self.chat_simple(chat_info) - else: - chat_info = self.is_valid_application_workflow(raise_exception=True) + self.is_valid_application_workflow(raise_exception=True) return self.chat_work_flow(chat_info) + def get_chat_info(self): + self.is_valid(raise_exception=True) + chat_id = self.data.get('chat_id') + chat_info: ChatInfo = chat_cache.get(chat_id) + if chat_info is None: + chat_info: ChatInfo = self.re_open_chat(chat_id) + chat_cache.set(chat_id, + chat_info, timeout=60 * 30) + return chat_info + @staticmethod def re_open_chat(chat_id: str): chat = QuerySet(Chat).filter(id=chat_id).first() diff --git a/apps/application/swagger_api/application_api.py b/apps/application/swagger_api/application_api.py index 4bacc5831..75cdbd0ab 100644 --- a/apps/application/swagger_api/application_api.py +++ b/apps/application/swagger_api/application_api.py @@ -239,7 +239,9 @@ class ApplicationApi(ApiMixin): 'dataset_setting': ApplicationApi.DatasetSetting.get_request_body_api(), 'model_setting': ApplicationApi.ModelSetting.get_request_body_api(), 'problem_optimization': openapi.Schema(type=openapi.TYPE_BOOLEAN, title="问题优化", - description="是否开启问题优化", default=True) + description="是否开启问题优化", default=True), + 'type': openapi.Schema(type=openapi.TYPE_STRING, title="应用类型", + description="应用类型 简易:SIMPLE|工作流:WORK_FLOW") } )