Skip to content

Commit 5e6656e

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 0c6d885 + ffe6a61 commit 5e6656e

4 files changed

Lines changed: 65 additions & 47 deletions

File tree

backend/apps/chat/models/chat_model.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
from datetime import datetime
22
from typing import List, Optional
33

4+
from fastapi import Body
45
from pydantic import BaseModel
56
from sqlalchemy import Column, Integer, Text, BigInteger, DateTime, Identity, Boolean
67
from sqlmodel import SQLModel, Field
78

9+
from apps.template.filter.generator import get_permissions_template
810
from apps.template.generate_analysis.generator import get_analysis_template
911
from apps.template.generate_chart.generator import get_chart_template
1012
from apps.template.generate_guess_question.generator import get_guess_question_template
1113
from apps.template.generate_predict.generator import get_predict_template
1214
from apps.template.generate_sql.generator import get_sql_template
1315
from apps.template.select_datasource.generator import get_datasource_template
14-
from apps.template.filter.generator import get_permissions_template
1516

1617

1718
class Chat(SQLModel, table=True):
@@ -104,63 +105,63 @@ class AiModelQuestion(BaseModel):
104105
rule: str = ""
105106
fields: str = ""
106107
data: str = ""
107-
lang: str = "zh-CN"
108+
lang: str = "简体中文"
108109
filter: str = []
109110

110111
def sql_sys_question(self):
111-
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question)
112+
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question, lang=self.lang)
112113

113114
def sql_user_question(self):
114115
return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=self.question,
115-
rule=self.rule, lang=self.lang)
116+
rule=self.rule)
116117

117118
def chart_sys_question(self):
118-
return get_chart_template()['system'].format(sql=self.sql, question=self.question)
119+
return get_chart_template()['system'].format(sql=self.sql, question=self.question, lang=self.lang)
119120

120121
def chart_user_question(self):
121-
return get_chart_template()['user'].format(sql=self.sql, question=self.question, rule=self.rule, lang=self.lang)
122+
return get_chart_template()['user'].format(sql=self.sql, question=self.question, rule=self.rule)
122123

123124
def analysis_sys_question(self):
124-
return get_analysis_template()['system']
125+
return get_analysis_template()['system'].format(lang=self.lang)
125126

126127
def analysis_user_question(self):
127-
return get_analysis_template()['user'].format(fields=self.fields, data=self.data, lang=self.lang)
128+
return get_analysis_template()['user'].format(fields=self.fields, data=self.data)
128129

129130
def predict_sys_question(self):
130-
return get_predict_template()['system']
131+
return get_predict_template()['system'].format(lang=self.lang)
131132

132133
def predict_user_question(self):
133-
return get_predict_template()['user'].format(fields=self.fields, data=self.data, lang=self.lang)
134+
return get_predict_template()['user'].format(fields=self.fields, data=self.data)
134135

135136
def datasource_sys_question(self):
136-
return get_datasource_template()['system']
137+
return get_datasource_template()['system'].format(lang=self.lang)
137138

138139
def datasource_user_question(self, datasource_list: str = "[]"):
139-
return get_datasource_template()['user'].format(question=self.question, data=datasource_list, lang=self.lang)
140+
return get_datasource_template()['user'].format(question=self.question, data=datasource_list)
140141

141142
def guess_sys_question(self):
142-
return get_guess_question_template()['system']
143+
return get_guess_question_template()['system'].format(lang=self.lang)
143144

144145
def guess_user_question(self, old_questions: str = "[]"):
145146
return get_guess_question_template()['user'].format(question=self.question, schema=self.db_schema,
146-
old_questions=old_questions, lang=self.lang)
147+
old_questions=old_questions)
147148

148149
def filter_sys_question(self):
149-
return get_permissions_template()['system']
150+
return get_permissions_template()['system'].format(lang=self.lang)
150151

151152
def filter_user_question(self):
152-
return get_permissions_template()['user'].format(sql=self.sql, filter=self.filter, lang=self.lang)
153+
return get_permissions_template()['user'].format(sql=self.sql, filter=self.filter)
153154

154155

155156
class ChatQuestion(AiModelQuestion):
156-
question: str
157-
chat_id: int
157+
question: str = Body(description='用户提问')
158+
chat_id: int = Body(description='会话ID')
158159

159160

160161
class ChatMcp(ChatQuestion):
161-
token: str
162+
token: str = Body(description='token')
162163

163164

164165
class ChatStart(BaseModel):
165-
username: str = ''
166-
password: str = ''
166+
username: str = Body(description='用户名')
167+
password: str = Body(description='密码')

backend/apps/chat/task/llm.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def __init__(self, session: SessionDep, current_user: CurrentUser, chat_question
9999
chart_id=chat_id))))
100100
self.change_title = len(history_records) == 0
101101

102-
chat_question.lang = current_user.language
102+
chat_question.lang = get_lang_name(current_user.language)
103103

104104
self.ds = (ds if isinstance(ds, AssistantOutDsSchema) else CoreDatasource(**ds.model_dump())) if ds else None
105105
self.chat_question = chat_question
@@ -1044,3 +1044,8 @@ def get_token_usage(chunk: BaseMessageChunk, token_usage: dict = {}):
10441044
token_usage['total_tokens'] = chunk.usage_metadata.get('total_tokens')
10451045
except Exception:
10461046
pass
1047+
1048+
def get_lang_name(lang: str):
1049+
if lang and lang == 'en':
1050+
return '英文'
1051+
return '简体中文'

backend/template.yaml

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
template:
22
sql:
33
system: |
4+
### 请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
5+
46
任务:
57
根据表结构和问题生成符合{engine}数据库引擎规范的sql语句,以及sql中所用到的表名(不要包含schema和database,用数组返回)。
68
你必须遵守以下规则:
@@ -42,29 +44,29 @@ template:
4244
### 问题:
4345
{question}
4446
45-
### 请使用 i18n: {lang} 对应的语言输出你的结果
46-
4747
### 其他规则:
4848
{rule}
4949
chart:
5050
system: |
51+
### 请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
52+
5153
### 说明:
5254
您的任务是通过给定的问题和SQL生成 JSON 以进行数据可视化。
5355
请遵守以下规则:
5456
- 如果需要表格,则生成的 JSON 格式应为:
55-
{{"type":"table", "title": "标题", "columns": [{{"name":"中文字段名1", "value": "SQL 查询列 1(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, {{"name": "中文字段名 2", "value": "SQL 查询列 2(有别名用别名,去掉外层的反引号、双引号、方括号)"}}]}}
57+
{{"type":"table", "title": "标题", "columns": [{{"name":"{lang}字段名1", "value": "SQL 查询列 1(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, {{"name": "{lang}字段名 2", "value": "SQL 查询列 2(有别名用别名,去掉外层的反引号、双引号、方括号)"}}]}}
5658
必须从 SQL 查询列中提取“columns”。
5759
- 如果需要柱状图,则生成的 JSON 格式应为(如果有分类则在JSON中返回series):
58-
{{"type":"column", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
60+
{{"type":"column", "title": "标题", "axis": {{"x": {{"name":"x轴的{lang}名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的{lang}名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的{lang}名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
5961
必须从 SQL 查询列中提取“x”和“y”。
6062
- 如果需要条形图,则生成的 JSON 格式应为(如果有分类则在JSON中返回series),条形图相当于是旋转后的柱状图,因此 x 轴仍为维度轴,y 轴仍为指标轴:
61-
{{"type":"bar", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
63+
{{"type":"bar", "title": "标题", "axis": {{"x": {{"name":"x轴的{lang}名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的{lang}名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的{lang}名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
6264
必须从 SQL 查询列中提取“x”和“y”。
6365
- 如果需要折线图,则生成的 JSON 格式应为(如果有分类则在JSON中返回series):
64-
{{"type":"line", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称","value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
66+
{{"type":"line", "title": "标题", "axis": {{"x": {{"name":"x轴的{lang}名称","value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的{lang}名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的{lang}名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
6567
其中“x”和“y”必须从SQL查询列中提取。
6668
- 如果需要饼图,则生成的 JSON 格式应为:
67-
{{"type":"pie", "title": "标题", "axis": {{"y": {{"name":"值轴的中文名称","value":"SQL 查询数值的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
69+
{{"type":"pie", "title": "标题", "axis": {{"y": {{"name":"值轴的{lang}名称","value":"SQL 查询数值的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的{lang}名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}}}
6870
其中“y”和“series”必须从SQL查询列中提取。
6971
- 如果答案未知或者与生成JSON无关,则生成的 JSON 格式应为:
7072
{{"type":"error", "reason": "抱歉,我无法回答您的问题。"}}
@@ -85,12 +87,12 @@ template:
8587
### 问题:
8688
{question}
8789
88-
### 请使用 i18n: {lang} 对应的语言输出你的结果
89-
9090
### 其他规则:
9191
{rule}
9292
guess:
9393
system: |
94+
### 请使用语言:{lang} 回答,不需要输出深度思考过程
95+
9496
### 说明:
9597
您的任务是根据给定的表结构,用户问题以及以往用户提问,推测用户接下来可能提问的1-4个问题。
9698
请遵循以下规则:
@@ -106,14 +108,12 @@ template:
106108
- 最多返回4个你推测出的结果
107109
- 若无法推测,则返回空数据JSON:
108110
[]
109-
- 不需要思考过程,或者尽量精简思考过程(重要)
111+
- 若你的给出的JSON不是{lang}的,则必须翻译为{lang}
110112
111113
### 响应, 请直接返回JSON结果:
112114
```json
113115
114116
user: |
115-
### 请使用 i18n: {lang} 对应的语言输出你的结果
116-
117117
### 表结构:
118118
{schema}
119119
@@ -124,36 +124,36 @@ template:
124124
{old_questions}
125125
analysis:
126126
system: |
127+
### 请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
128+
127129
### 说明:
128130
你是一个数据分析师,你的任务是根据给定的数据分析数据,并给出你的分析结果。
129-
130131
user: |
131-
### 请使用 i18n: {lang} 对应的语言输出你的结果
132-
133132
### 字段(字段别名):
134133
{fields}
135134
136135
### 数据:
137136
{data}
138137
predict:
139138
system: |
139+
### 请使用语言:{lang} 回答,若有深度思考过程,则思考过程也需要使用 {lang} 输出
140+
140141
### 说明:
141-
你是一个数据分析师,你的任务是根据给定的数据进行数据预测,我将以json格式给你一组数据,你帮我预测之后的数据(一段可以展示趋势的数据,至少2个周期),用json数组的格式返回,返回的格式需要与传入的数据格式保持一致。
142+
你是一个数据分析师,你的任务是根据给定的数据进行数据预测,我将以JSON格式给你一组数据,你帮我预测之后的数据(一段可以展示趋势的数据,至少2个周期),用json数组的格式返回,返回的格式需要与传入的数据格式保持一致。
142143
```json
143144
144-
无法预测或者不支持预测的数据请直接返回(不需要返回JSON格式):"抱歉,该数据无法进行预测。(有原因则返回无法预测的原因)"
145+
无法预测或者不支持预测的数据请直接返回(不需要返回JSON格式,需要翻译为 {lang} 输出):"抱歉,该数据无法进行预测。(有原因则返回无法预测的原因)"
145146
如果可以预测,则不需要返回原有数据,直接返回预测的部份
146-
147147
user: |
148-
### 请使用 i18n: {lang} 对应的语言输出你的结果
149-
150148
### 字段(字段别名):
151149
{fields}
152150
153151
### 数据:
154152
{data}
155153
datasource:
156154
system: |
155+
### 请使用语言:{lang} 回答
156+
157157
### 说明:
158158
你是一个数据分析师,你需要根据用户的提问,以及提供的数据源列表(格式为JSON数组:[{{"id": 数据源ID1,"name":"数据源名称1","description":"数据源描述1"}},{{"id": 数据源ID2,"name":"数据源名称2","description":"数据源描述2"}}]),根据名称和描述找出最符合用户提问的数据源,这个数据源后续将被用来进行数据的分析
159159
@@ -166,15 +166,15 @@ template:
166166
### 响应, 请直接返回JSON结果:
167167
```json
168168
user: |
169-
### 请使用 i18n: {lang} 对应的语言输出你的结果
170-
171169
### 数据源列表:
172170
{data}
173171
174172
### 问题:
175173
{question}
176174
permissions:
177175
system: |
176+
### 请使用语言:{lang} 回答
177+
178178
### 说明:
179179
提供给你一句SQL和一组表的过滤条件,从这组表的过滤条件中找出SQL中用到的表所对应的过滤条件,将用到的表所对应的过滤条件添加到提供给你的SQL中(不要替换SQL中原有的条件),生成符合{engine}数据库引擎规范的新SQL语句(如果过滤条件为空则无需处理)。
180180
表的过滤条件json格式如下:
@@ -197,8 +197,6 @@ template:
197197
```json
198198
199199
user: |
200-
### 请使用 i18n: {lang} 对应的语言输出你的结果
201-
202200
### sql:
203201
{sql}
204202

frontend/src/views/chat/index.vue

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,8 @@
292292
:disabled="isTyping"
293293
clearable
294294
class="input-area"
295+
:class="isAssistant && 'is-assistant'"
295296
type="textarea"
296-
:rows="1"
297297
:autosize="{ minRows: 1, maxRows: 8.583 }"
298298
:placeholder="t('qa.question_placeholder')"
299299
@keydown.enter.exact.prevent="sendMessage"
@@ -935,6 +935,20 @@ onMounted(() => {
935935
border-radius: 16px;
936936
line-height: 24px;
937937
}
938+
939+
&.is-assistant {
940+
:deep(.ed-textarea__inner) {
941+
padding: 12px 12px 52px 12px;
942+
font-weight: 400;
943+
font-size: 16px;
944+
line-height: 24px;
945+
border-radius: 16px;
946+
947+
&::placeholder {
948+
color: #8f959e;
949+
}
950+
}
951+
}
938952
}
939953
940954
.input-icon {

0 commit comments

Comments
 (0)