Merge remote-tracking branch 'origin/main'

This commit is contained in:
wangjiahao
2025-07-28 18:53:41 +08:00
4 changed files with 65 additions and 47 deletions
+22 -21
View File
@@ -1,17 +1,18 @@
from datetime import datetime
from typing import List, Optional
from fastapi import Body
from pydantic import BaseModel
from sqlalchemy import Column, Integer, Text, BigInteger, DateTime, Identity, Boolean
from sqlmodel import SQLModel, Field
from apps.template.filter.generator import get_permissions_template
from apps.template.generate_analysis.generator import get_analysis_template
from apps.template.generate_chart.generator import get_chart_template
from apps.template.generate_guess_question.generator import get_guess_question_template
from apps.template.generate_predict.generator import get_predict_template
from apps.template.generate_sql.generator import get_sql_template
from apps.template.select_datasource.generator import get_datasource_template
from apps.template.filter.generator import get_permissions_template
class Chat(SQLModel, table=True):
@@ -104,63 +105,63 @@ class AiModelQuestion(BaseModel):
rule: str = ""
fields: str = ""
data: str = ""
lang: str = "zh-CN"
lang: str = "简体中文"
filter: str = []
def sql_sys_question(self):
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question)
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question, lang=self.lang)
def sql_user_question(self):
return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=self.question,
rule=self.rule, lang=self.lang)
rule=self.rule)
def chart_sys_question(self):
return get_chart_template()['system'].format(sql=self.sql, question=self.question)
return get_chart_template()['system'].format(sql=self.sql, question=self.question, lang=self.lang)
def chart_user_question(self):
return get_chart_template()['user'].format(sql=self.sql, question=self.question, rule=self.rule, lang=self.lang)
return get_chart_template()['user'].format(sql=self.sql, question=self.question, rule=self.rule)
def analysis_sys_question(self):
return get_analysis_template()['system']
return get_analysis_template()['system'].format(lang=self.lang)
def analysis_user_question(self):
return get_analysis_template()['user'].format(fields=self.fields, data=self.data, lang=self.lang)
return get_analysis_template()['user'].format(fields=self.fields, data=self.data)
def predict_sys_question(self):
return get_predict_template()['system']
return get_predict_template()['system'].format(lang=self.lang)
def predict_user_question(self):
return get_predict_template()['user'].format(fields=self.fields, data=self.data, lang=self.lang)
return get_predict_template()['user'].format(fields=self.fields, data=self.data)
def datasource_sys_question(self):
return get_datasource_template()['system']
return get_datasource_template()['system'].format(lang=self.lang)
def datasource_user_question(self, datasource_list: str = "[]"):
return get_datasource_template()['user'].format(question=self.question, data=datasource_list, lang=self.lang)
return get_datasource_template()['user'].format(question=self.question, data=datasource_list)
def guess_sys_question(self):
return get_guess_question_template()['system']
return get_guess_question_template()['system'].format(lang=self.lang)
def guess_user_question(self, old_questions: str = "[]"):
return get_guess_question_template()['user'].format(question=self.question, schema=self.db_schema,
old_questions=old_questions, lang=self.lang)
old_questions=old_questions)
def filter_sys_question(self):
return get_permissions_template()['system']
return get_permissions_template()['system'].format(lang=self.lang)
def filter_user_question(self):
return get_permissions_template()['user'].format(sql=self.sql, filter=self.filter, lang=self.lang)
return get_permissions_template()['user'].format(sql=self.sql, filter=self.filter)
class ChatQuestion(AiModelQuestion):
question: str
chat_id: int
question: str = Body(description='用户提问')
chat_id: int = Body(description='会话ID')
class ChatMcp(ChatQuestion):
token: str
token: str = Body(description='token')
class ChatStart(BaseModel):
username: str = ''
password: str = ''
username: str = Body(description='用户名')
password: str = Body(description='密码')
+6 -1
View File
@@ -99,7 +99,7 @@ class LLMService:
chart_id=chat_id))))
self.change_title = len(history_records) == 0
chat_question.lang = current_user.language
chat_question.lang = get_lang_name(current_user.language)
self.ds = (ds if isinstance(ds, AssistantOutDsSchema) else CoreDatasource(**ds.model_dump())) if ds else None
self.chat_question = chat_question
@@ -1044,3 +1044,8 @@ def get_token_usage(chunk: BaseMessageChunk, token_usage: dict = {}):
token_usage['total_tokens'] = chunk.usage_metadata.get('total_tokens')
except Exception:
pass
def get_lang_name(lang: str):
if lang and lang == 'en':
return '英文'
return '简体中文'
+22 -24
View File
@@ -1,6 +1,8 @@
template:
sql:
system: |
### 请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
任务:
根据表结构和问题生成符合{engine}数据库引擎规范的sql语句,以及sql中所用到的表名(不要包含schema和database,用数组返回)。
你必须遵守以下规则:
@@ -42,29 +44,29 @@ template:
### 问题:
{question}
### 请使用 i18n: {lang} 对应的语言输出你的结果
### 其他规则:
{rule}
chart:
system: |
### 请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
### 说明:
您的任务是通过给定的问题和SQL生成 JSON 以进行数据可视化。
请遵守以下规则:
- 如果需要表格,则生成的 JSON 格式应为:
{{"type":"table", "title": "标题", "columns": [{{"name":"中文字段名1", "value": "SQL 查询列 1(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, {{"name": "中文字段名 2", "value": "SQL 查询列 2(有别名用别名,去掉外层的反引号、双引号、方括号)"}}]}}
{{"type":"table", "title": "标题", "columns": [{{"name":"{lang}字段名1", "value": "SQL 查询列 1(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, {{"name": "{lang}字段名 2", "value": "SQL 查询列 2(有别名用别名,去掉外层的反引号、双引号、方括号)"}}]}}
必须从 SQL 查询列中提取“columns”。
- 如果需要柱状图,则生成的 JSON 格式应为(如果有分类则在JSON中返回series):
{{"type":"column", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
{{"type":"column", "title": "标题", "axis": {{"x": {{"name":"x轴的{lang}名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的{lang}名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的{lang}名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
必须从 SQL 查询列中提取“x”和“y”。
- 如果需要条形图,则生成的 JSON 格式应为(如果有分类则在JSON中返回series),条形图相当于是旋转后的柱状图,因此 x 轴仍为维度轴,y 轴仍为指标轴:
{{"type":"bar", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
{{"type":"bar", "title": "标题", "axis": {{"x": {{"name":"x轴的{lang}名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的{lang}名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的{lang}名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
必须从 SQL 查询列中提取“x”和“y”。
- 如果需要折线图,则生成的 JSON 格式应为(如果有分类则在JSON中返回series):
{{"type":"line", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称","value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
{{"type":"line", "title": "标题", "axis": {{"x": {{"name":"x轴的{lang}名称","value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的{lang}名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的{lang}名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
其中“x”和“y”必须从SQL查询列中提取。
- 如果需要饼图,则生成的 JSON 格式应为:
{{"type":"pie", "title": "标题", "axis": {{"y": {{"name":"值轴的中文名称","value":"SQL 查询数值的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
{{"type":"pie", "title": "标题", "axis": {{"y": {{"name":"值轴的{lang}名称","value":"SQL 查询数值的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的{lang}名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
其中“y”和“series”必须从SQL查询列中提取。
- 如果答案未知或者与生成JSON无关,则生成的 JSON 格式应为:
{{"type":"error", "reason": "抱歉,我无法回答您的问题。"}}
@@ -85,12 +87,12 @@ template:
### 问题:
{question}
### 请使用 i18n: {lang} 对应的语言输出你的结果
### 其他规则:
{rule}
guess:
system: |
### 请使用语言:{lang} 回答,不需要输出深度思考过程
### 说明:
您的任务是根据给定的表结构,用户问题以及以往用户提问,推测用户接下来可能提问的1-4个问题。
请遵循以下规则:
@@ -106,14 +108,12 @@ template:
- 最多返回4个你推测出的结果
- 若无法推测,则返回空数据JSON:
[]
- 不需要思考过程,或者尽量精简思考过程(重要)
- 若你的给出的JSON不是{lang}的,则必须翻译为{lang}
### 响应, 请直接返回JSON结果:
```json
user: |
### 请使用 i18n: {lang} 对应的语言输出你的结果
### 表结构:
{schema}
@@ -124,12 +124,11 @@ template:
{old_questions}
analysis:
system: |
### 请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
### 说明:
你是一个数据分析师,你的任务是根据给定的数据分析数据,并给出你的分析结果。
user: |
### 请使用 i18n: {lang} 对应的语言输出你的结果
### 字段(字段别名):
{fields}
@@ -137,16 +136,15 @@ template:
{data}
predict:
system: |
### 请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
### 说明:
你是一个数据分析师,你的任务是根据给定的数据进行数据预测,我将以json格式给你一组数据,你帮我预测之后的数据(一段可以展示趋势的数据,至少2个周期),用json数组的格式返回,返回的格式需要与传入的数据格式保持一致。
你是一个数据分析师,你的任务是根据给定的数据进行数据预测,我将以JSON格式给你一组数据,你帮我预测之后的数据(一段可以展示趋势的数据,至少2个周期),用json数组的格式返回,返回的格式需要与传入的数据格式保持一致。
```json
无法预测或者不支持预测的数据请直接返回(不需要返回JSON格式):"抱歉,该数据无法进行预测。(有原因则返回无法预测的原因)"
无法预测或者不支持预测的数据请直接返回(不需要返回JSON格式,需要翻译为 {lang} 输出):"抱歉,该数据无法进行预测。(有原因则返回无法预测的原因)"
如果可以预测,则不需要返回原有数据,直接返回预测的部份
user: |
### 请使用 i18n: {lang} 对应的语言输出你的结果
### 字段(字段别名):
{fields}
@@ -154,6 +152,8 @@ template:
{data}
datasource:
system: |
### 请使用语言:{lang} 回答
### 说明:
你是一个数据分析师,你需要根据用户的提问,以及提供的数据源列表(格式为JSON数组:[{{"id": 数据源ID1,"name":"数据源名称1","description":"数据源描述1"}},{{"id": 数据源ID2,"name":"数据源名称2","description":"数据源描述2"}}]),根据名称和描述找出最符合用户提问的数据源,这个数据源后续将被用来进行数据的分析
@@ -166,8 +166,6 @@ template:
### 响应, 请直接返回JSON结果:
```json
user: |
### 请使用 i18n: {lang} 对应的语言输出你的结果
### 数据源列表:
{data}
@@ -175,6 +173,8 @@ template:
{question}
permissions:
system: |
### 请使用语言:{lang} 回答
### 说明:
提供给你一句SQL和一组表的过滤条件,从这组表的过滤条件中找出SQL中用到的表所对应的过滤条件,将用到的表所对应的过滤条件添加到提供给你的SQL中(不要替换SQL中原有的条件),生成符合{engine}数据库引擎规范的新SQL语句(如果过滤条件为空则无需处理)。
表的过滤条件json格式如下:
@@ -197,8 +197,6 @@ template:
```json
user: |
### 请使用 i18n: {lang} 对应的语言输出你的结果
### sql:
{sql}
+15 -1
View File
@@ -292,8 +292,8 @@
:disabled="isTyping"
clearable
class="input-area"
:class="isAssistant && 'is-assistant'"
type="textarea"
:rows="1"
:autosize="{ minRows: 1, maxRows: 8.583 }"
:placeholder="t('qa.question_placeholder')"
@keydown.enter.exact.prevent="sendMessage"
@@ -935,6 +935,20 @@ onMounted(() => {
border-radius: 16px;
line-height: 24px;
}
&.is-assistant {
:deep(.ed-textarea__inner) {
padding: 12px 12px 52px 12px;
font-weight: 400;
font-size: 16px;
line-height: 24px;
border-radius: 16px;
&::placeholder {
color: #8f959e;
}
}
}
}
.input-icon {