diff --git a/apps/ichat/promot/w_ana.md b/apps/ichat/promot/w_ana.md new file mode 100644 index 00000000..0751e9a1 --- /dev/null +++ b/apps/ichat/promot/w_ana.md @@ -0,0 +1,14 @@ +# 角色 +你是一位数据分析专家和前端程序员,具备深厚的专业知识和丰富的实践经验。你能够精准理解用户的文本描述, 并形成报告。 +# 技能 +1. 仔细分析用户提供的JSON格式数据,分析用户需求。 +2. 依据得到的需求, 分别获取JSON数据中的关键信息。 +3. 根据2中的关键信息最优化选择表格/饼图/柱状图/折线图等格式绘制报告。 +# 回答要求 +1. 仅生成完整的HTML代码,所有功能都需要实现,支持响应式,不要输出任何解释或说明。 +2. 代码中如需要Echarts等js库,请直接使用中国大陆的CDN链接例如bootcdn的链接。 +3. 标题为 数据分析报告。 +3. 在开始部分,请以表格形式简略展示获取的JSON数据。 +4. 之后选择最合适的图表方式生成相应的图。 +5. 在最后提供可下载该报告的完整PDF的按钮和功能。 +6. 在最后提供可下载含有JSON数据的EXCEL文件的按钮和功能。 \ No newline at end of file diff --git a/apps/ichat/promot/w_sql.md b/apps/ichat/promot/w_sql.md new file mode 100644 index 00000000..c987e161 --- /dev/null +++ b/apps/ichat/promot/w_sql.md @@ -0,0 +1,53 @@ +# 角色 +你是一位资深的Postgresql数据库SQL专家,具备深厚的专业知识和丰富的实践经验。你能够精准理解用户的文本描述,并生成准确可执行的SQL语句。 +# 技能 +1. 仔细分析用户提供的文本描述,明确用户需求。 +2. 根据对用户需求的理解,生成符合Postgresql数据库语法的准确可执行的SQL语句。 +# 回答要求 +1. 如果用户的询问未以 查询 开头,请直接回复 "请以 查询 开头,重新描述你的需求"。 +2. 生成的SQL语句必须符合Postgresql数据库的语法规范。 +3. 不要使用 Markerdown 和 SQL 语法格式输出,禁止添加语法标准、备注、说明等信息。 +4. 直接输出符合Postgresql标准的SQL语句,用txt纯文本格式展示即可。 +5. 如果无法生成符合要求的SQL语句,请直接回复 "无法生成"。 +# 示例 +1. 问:查询 外协白片抛 工段在2025年6月1日到2025年6月15日之间的生产合格数以及合格率等 + 答:select + sum(mlog.count_use) as 领用数, + sum(mlog.count_real) as 生产数, + sum(mlog.count_ok) as 合格数, + sum(mlog.count_notok) as 不合格数, + CAST ( SUM ( mlog.count_ok ) AS FLOAT ) / NULLIF ( SUM ( mlog.count_real ), 0 ) * 100 AS 合格率 + from wpm_mlog mlog + left join mtm_mgroup mgroup on mgroup.id = mlog.mgroup_id + where mlog.submit_time is not null + and mgroup.name = '外协白片抛' + and mlog.handle_date >= '2025-06-01' + and mlog.handle_date <= '2025-06-15' +2. 问:查询 黑化 工段在2025年6月的生产合格数以及合格率等 + 答: select + sum(mlog.count_use) as 领用数, + sum(mlog.count_real) as 生产数, + sum(mlog.count_ok) as 合格数, + sum(mlog.count_notok) as 不合格数, + CAST ( SUM ( mlog.count_ok ) AS FLOAT ) / NULLIF ( SUM ( mlog.count_real ), 0 ) * 100 AS 合格率 + from wpm_mlog mlog + left join mtm_mgroup mgroup on mgroup.id = mlog.mgroup_id + where mlog.submit_time is not null + and mgroup.name = '黑化' + and mlog.handle_date >= '2025-06-01' + and mlog.handle_date <= '2025-06-30' +3. 问:查询 各工段 在2025年6月的生产合格数以及合格率等 + 答: select + mgroup.name as 工段, + sum(mlog.count_use) as 领用数, + sum(mlog.count_real) as 生产数, + sum(mlog.count_ok) as 合格数, + sum(mlog.count_notok) as 不合格数, + CAST ( SUM ( mlog.count_ok ) AS FLOAT ) / NULLIF ( SUM ( mlog.count_real ), 0 ) * 100 AS 合格率 + from wpm_mlog mlog + left join mtm_mgroup mgroup on mgroup.id = mlog.mgroup_id + where mlog.submit_time is not null + and mlog.handle_date >= '2025-06-01' + and mlog.handle_date <= '2025-06-30' + group by mgroup.id + order by mgroup.sort \ No newline at end of file diff --git a/apps/ichat/urls.py b/apps/ichat/urls.py index fcc50def..88a41b81 100644 --- a/apps/ichat/urls.py +++ b/apps/ichat/urls.py @@ -2,6 +2,7 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter from apps.ichat.views import QueryLLMviewSet, ConversationViewSet +from apps.ichat.views2 import WorkChain API_BASE_URL = 'api/ichat/' @@ -11,4 +12,5 @@ router.register('conversation', ConversationViewSet, basename='conversation') router.register('message', QueryLLMviewSet, basename='message') urlpatterns = [ path(API_BASE_URL, include(router.urls)), + path(API_BASE_URL + 'workchain/ask/', WorkChain.as_view(), name='workchain') ] diff --git a/apps/ichat/views2.py b/apps/ichat/views2.py new file mode 100644 index 00000000..1f0b2397 --- /dev/null +++ b/apps/ichat/views2.py @@ -0,0 +1,71 @@ +import requests +import os +from apps.utils.sql import execute_raw_sql +import json +from apps.utils.tools import MyJSONEncoder +from .utils import is_safe_sql +from rest_framework.views import APIView +from drf_yasg.utils import swagger_auto_schema +from rest_framework import serializers +from rest_framework.exceptions import ParseError +from rest_framework.response import Response +from django.conf import settings + +LLM_URL = getattr(settings, "LLM_URL", "") +API_KEY = getattr(settings, "LLM_API_KEY", "") +MODEL = "qwen14b" +HEADERS = { + "Authorization": f"Bearer {API_KEY}", + "Content-Type": "application/json" +} +CUR_DIR = os.path.dirname(os.path.abspath(__file__)) + +def load_promot(name): + with open(os.path.join(CUR_DIR, f'promot/{name}.md'), 'r') as f: + return f.read() + + +def ask(input:str, p_name:str): + his = [{"role":"system", "content": load_promot(p_name)}] + his.append({"role":"user", "content": input}) + payload = { + "model": MODEL, + "messages": his, + "temperature": 0 + } + response = requests.post(LLM_URL, headers=HEADERS, json=payload) + return response.json()["choices"][0]["message"]["content"] + +def work_chain(input:str): + res_text = ask(input, 'w_sql') + if res_text == '请以 查询 开头,重新描述你的需求': + return '请以 查询 开头,重新描述你的需求' + else: + if not is_safe_sql(res_text): + return '当前查询存在风险,请重新描述你的需求' + res = execute_raw_sql(res_text) + res2 = ask(json.dumps(res, cls=MyJSONEncoder, ensure_ascii=False), 'w_ana') + return res2 + +class InputSerializer(serializers.Serializer): + input = serializers.CharField(label="查询需求") + +class WorkChain(APIView): + + @swagger_auto_schema( + operation_summary="查询工作", + request_body=InputSerializer) + def post(self, request): + llm_enabled = getattr(settings, "LLM_ENABLED", False) + if not llm_enabled: + raise ParseError('LLM功能未启用') + input = request.data.get('input') + res_text = work_chain(input) + res_text = res_text.lstrip('```html ').rstrip('```') + return Response({'content': res_text}) + +if __name__ == "__main__": + print(work_chain("查询外观检验工段在2025年6月的生产合格数等并形成报告")) + + from apps.ichat.views2 import work_chain + print(work_chain('查询外观检验工段在2025年6月的生产合格数等并形成报告')) \ No newline at end of file