Skip to content

Commit 787d392

Browse files
committed
feat: chat view
1 parent d2b7b0c commit 787d392

File tree

10 files changed

+164
-91
lines changed

10 files changed

+164
-91
lines changed

backend/apps/chat/api/chat.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def run_task():
135135
# execute sql
136136
result = llm_service.execute_sql(sql=sql)
137137
llm_service.save_sql_data(session=session, data_obj=result)
138-
yield json.dumps({'content': result, 'type': 'sql-data'}, ensure_ascii=False) + '\n\n'
138+
yield json.dumps({'content': json.dumps(result, ensure_ascii=False), 'type': 'sql-data'}) + '\n\n'
139139

140140
# generate chart
141141
chart_res = llm_service.generate_chart(session=session)
@@ -149,7 +149,8 @@ def run_task():
149149
print(full_chart_text)
150150
chart = llm_service.check_save_chart(session=session, res=full_chart_text)
151151
print(chart)
152-
yield json.dumps({'content': chart, 'type': 'chart'}, ensure_ascii=False) + '\n\n'
152+
yield json.dumps({'content': json.dumps(chart, ensure_ascii=False), 'type': 'chart'},
153+
ensure_ascii=False) + '\n\n'
153154

154155
llm_service.finish(session=session)
155156
yield json.dumps({'type': 'finish'})

backend/apps/chat/models/chat_model.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
from sqlmodel import SQLModel, Field
2-
from sqlalchemy import Column, Text, BigInteger, DateTime, Integer, Identity, Boolean
31
from datetime import datetime
2+
from typing import List, Optional
3+
44
from pydantic import BaseModel
5-
from typing import List, Optional, Any
5+
from sqlalchemy import Column, Text, BigInteger, DateTime, Integer, Identity, Boolean
6+
from sqlmodel import SQLModel, Field
67

78
from apps.template.generate_chart.generator import get_chart_template
89
from apps.template.generate_sql.generator import get_sql_template
@@ -70,19 +71,14 @@ class AiModelQuestion(BaseModel):
7071
engine: str = ""
7172
db_schema: str = ""
7273
sql: str = ""
73-
rule: str = """
74-
请逐步推理后给出答案:
75-
推理过程中不需要输出JSON,仅在最终结果内输出符合要求的JSON
76-
步骤1: [思考内容]
77-
步骤2: [思考内容]
78-
最终答案: [结果]
79-
"""
74+
rule: str = ""
8075

8176
def sql_sys_question(self):
8277
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question)
8378

8479
def sql_user_question(self):
85-
return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=self.question, rule=self.rule)
80+
return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=self.question,
81+
rule=self.rule)
8682

8783
def chart_sys_question(self):
8884
return get_chart_template()['system'].format(sql=self.sql, question=self.question)

backend/template.yaml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ template:
1818
- 如果问题是图表展示相关且与生成SQL查询无关时,请参考上一次回答的SQL来生成SQL
1919
- 如果问题是图表展示相关,可参考的图表类型为表格(table)、条形图(bar)、折线图(line)或饼图(pie),返回的JSON:
2020
{{"success":true,"sql":"生成的SQL语句","chart-type":"选择的图表类型(table/bar/line/pie)"}}
21+
22+
### 请遵守以下输出要求:
23+
请逐步推理后给出答案
24+
推理过程中不需要输出JSON,仅在最终结果内输出符合要求的JSON
25+
步骤1: [思考内容]
26+
步骤2: [思考内容]
27+
……
28+
最终答案: [结果]
2129
user: |
2230
### 表结构:
2331
{schema}
@@ -26,6 +34,7 @@ template:
2634
{question}
2735
2836
### 其他规则:
37+
请使用英语(English)回答
2938
{rule}
3039
chart:
3140
system: |
@@ -55,12 +64,21 @@ template:
5564
### 响应:
5665
根据您的指示,这是我生成的与 问题 和 sql 匹配的 JSON:
5766
```json
58-
user: |
67+
68+
### 请遵守以下输出要求:
69+
请逐步推理后给出答案
70+
推理过程中不需要输出JSON,仅在最终结果内输出符合要求的JSON
71+
步骤1: [思考内容]
72+
步骤2: [思考内容]
73+
……
74+
最终答案: [结果]
75+
user: |
5976
### SQL:
6077
{sql}
6178
6279
### 问题:
6380
{question}
6481
6582
### 其他规则:
83+
请使用英语(English)回答
6684
{rule}

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"@npkg/tinymce-plugins": "^0.0.7",
1313
"@tinymce/tinymce-vue": "^5.1.0",
1414
"dayjs": "^1.11.13",
15+
"element-plus": "^2.9.11",
1516
"lodash": "^4.17.21",
1617
"snowflake-id": "^1.1.0",
1718
"tinymce": "^5.8.2",

frontend/src/views/chat/ChatAnswer.vue

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const props = defineProps<{
1010
}>()
1111
1212
const settings = ref<{
13-
type: "chart" | "sql" | "data"
13+
type: "chart" | "sql"
1414
showAnswer: boolean
1515
}>({
1616
type: "chart",
@@ -74,11 +74,11 @@ const chartType = computed<"table" | "bar" | "line" | "pie">({
7474
<div v-if="message">
7575
<div>
7676
<div v-if="message.isTyping">Thinking ...</div>
77-
<div v-if="chartObject.title">{{ chartObject.title }}</div>
77+
<div v-if="chartObject.title && !message.isTyping">{{ chartObject.title }}</div>
7878
<el-tabs v-model="settings.type" class="demo-tabs" @tab-click="handleClick" tab-position="top">
7979
<el-tab-pane label="Chart" name="chart">
8080
<template #label>
81-
<el-select v-model="chartType" style="width: 80px">
81+
<el-select v-model="chartType" style="width: 80px" :disabled="settings.type!== 'chart'">
8282
<el-option value="table">table</el-option>
8383
<el-option value="bar">bar</el-option>
8484
<el-option value="line">line</el-option>
@@ -87,15 +87,14 @@ const chartType = computed<"table" | "bar" | "line" | "pie">({
8787
</template>
8888
</el-tab-pane>
8989
<el-tab-pane label="SQL" name="sql"></el-tab-pane>
90-
<el-tab-pane label="Data" name="data"></el-tab-pane>
9190
</el-tabs>
9291
</div>
9392
<template v-if="message.record">
9493
<el-collapse expand-icon-position="left">
9594
<el-collapse-item name="1">
9695
<template #title>
9796
Inference process
98-
<el-icon v-if="props.message.isTyping">
97+
<el-icon v-if="props.message?.isTyping">
9998
<Loading/>
10099
</el-icon>
101100
</template>
@@ -112,7 +111,7 @@ const chartType = computed<"table" | "bar" | "line" | "pie">({
112111
</div>
113112
</el-collapse-item>
114113
</el-collapse>
115-
<div>
114+
<div class="answer-content">
116115
<template v-if="settings.type === 'sql'">
117116
<div>
118117
<div v-if="message.record.sql">
@@ -149,4 +148,8 @@ const chartType = computed<"table" | "bar" | "line" | "pie">({
149148
display: flex;
150149
justify-content: flex-end;
151150
}
151+
152+
.answer-content {
153+
padding: 12px;
154+
}
152155
</style>

frontend/src/views/chat/ChatBlock.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ defineProps<{
1212
<div class="chat-block-outer">
1313
<div class="chat-block">
1414
<slot>
15-
<div v-html="msg?.content"></div>
15+
<div class="chat-block-content">
16+
<div v-html="msg?.content"></div>
17+
</div>
1618
</slot>
1719
</div>
1820
<div class="chat-block-footer">
@@ -26,9 +28,13 @@ defineProps<{
2628
.chat-block {
2729
border-radius: 2px;
2830
background-color: white;
29-
padding: 12px;
3031
word-wrap: break-word;
3132
white-space: pre-wrap;
33+
34+
.chat-block-content {
35+
padding: 12px;
36+
}
37+
3238
}
3339
3440
.chat-block-footer {

frontend/src/views/chat/ChatList.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import {MoreFilled, EditPen, Delete} from '@element-plus/icons-vue'
2+
import {Delete, EditPen, MoreFilled} from '@element-plus/icons-vue'
33
import {type Chat, chatApi} from "@/api/chat.ts";
44
import {computed} from "vue";
55
@@ -105,10 +105,11 @@ function handleCommand(command: string | number | object, chat: Chat) {
105105
}
106106
}
107107
108+
108109
</script>
109110

110111
<template>
111-
<el-scrollbar>
112+
<el-scrollbar ref="chatListRef">
112113
<div class="chat-list-inner">
113114
<template v-for="chat in chatList" :key="chat.id">
114115
<div class="chat-list-item" :class="{'active': currentChatId === chat.id}" @click="onClickHistory(chat)">

frontend/src/views/chat/ChatRow.vue

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ChatBlock from './ChatBlock.vue'
33
import WelcomeBlock from './WelcomeBlock.vue'
44
import {ChatInfo, type ChatMessage} from "@/api/chat.ts";
55
import {computed} from "vue";
6+
import {UserFilled} from "@element-plus/icons-vue"
67
78
const props = withDefaults(defineProps<{
89
msg: ChatMessage
@@ -27,8 +28,12 @@ const _datasource = computed({
2728

2829
<template>
2930
<div class="chat-row" :class="{'right-to-left': msg.role === 'user'}">
30-
<el-avatar shape="square" v-if="msg.role === 'assistant'">SQLBot</el-avatar>
31-
<el-avatar shape="square" v-if="msg.role === 'user'"/>
31+
<el-avatar class="ai-avatar" shape="square" v-if="msg.role === 'assistant'">SQLBot</el-avatar>
32+
<el-avatar class="user-avatar" shape="square" v-if="msg.role === 'user'">
33+
<el-icon>
34+
<UserFilled/>
35+
</el-icon>
36+
</el-avatar>
3237
<ChatBlock v-if="!msg.isWelcome" :msg="msg" :class="{'row-full': msg.role === 'assistant'}">
3338
<slot></slot>
3439
<template #footer>
@@ -58,5 +63,13 @@ const _datasource = computed({
5863
}
5964
}
6065
66+
.ai-avatar {
67+
background: var(--el-color-primary);
68+
}
69+
70+
.user-avatar {
71+
background: var(--ed-color-primary)
72+
}
73+
6174
6275
</style>

frontend/src/views/chat/WelcomeBlock.vue

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -63,37 +63,43 @@ onMounted(() => {
6363

6464
<template>
6565
<ChatBlock>
66-
<div>你好,我是SQLBot,很高兴为你服务</div>
67-
<div class="sub">我可以帮忙查询数据、生成图表、检测数据异常、预测数据等,请选择一个数据源,开启智能问数吧~</div>
68-
<template v-if="editable">
69-
<template v-if="dsList.length>0">
66+
<div class="welcome-content">
67+
<div>你好,我是SQLBot,很高兴为你服务</div>
68+
<div class="sub">我可以帮忙查询数据、生成图表、检测数据异常、预测数据等,请选择一个数据源,开启智能问数吧~</div>
69+
<template v-if="editable">
70+
<template v-if="dsList.length>0">
71+
<div class="ds-select-row">
72+
<div>选择数据源</div>
73+
<el-button @click="showDs" link type="primary">查看更多</el-button>
74+
</div>
75+
<div class="ds-row-container">
76+
<template v-for="(item, _index) in dsList" :key="_index">
77+
<DatasourceItemCard :ds="item" @click="selectDs(item)" v-if="_index<3 || item?.id===modelValue"
78+
class="ds-card" :class="[item?.id===modelValue? 'ds-card-selected': '']"/>
79+
</template>
80+
</div>
81+
</template>
82+
<div v-else>
83+
数据源为空,请新建后再开启智能问数!
84+
</div>
85+
</template>
86+
<template v-else>
7087
<div class="ds-select-row">
71-
<div>选择数据源</div>
72-
<el-button @click="showDs" link type="primary">查看更多</el-button>
88+
<div>已选择数据源</div>
7389
</div>
7490
<div class="ds-row-container">
75-
<template v-for="(item, _index) in dsList" :key="_index">
76-
<DatasourceItemCard :ds="item" @click="selectDs(item)" v-if="_index<3 || item?.id===modelValue"
77-
class="ds-card" :class="[item?.id===modelValue? 'ds-card-selected': '']"/>
78-
</template>
91+
<DatasourceItemCard :ds="ds"/>
7992
</div>
8093
</template>
81-
<div v-else>
82-
数据源为空,请新建后再开启智能问数!
83-
</div>
84-
</template>
85-
<template v-else>
86-
<div class="ds-select-row">
87-
<div>已选择数据源</div>
88-
</div>
89-
<div class="ds-row-container">
90-
<DatasourceItemCard :ds="ds"/>
91-
</div>
92-
</template>
94+
</div>
9395
</ChatBlock>
9496
</template>
9597

9698
<style scoped lang="less">
99+
.welcome-content {
100+
padding: 12px;
101+
}
102+
97103
.sub {
98104
color: grey;
99105
font-size: 0.8em;
@@ -118,7 +124,7 @@ onMounted(() => {
118124
}
119125
120126
.ds-card-selected {
121-
border-color: var(--ed-color-primary-light-5);
127+
box-shadow: 0 1px 3px var(--ed-color-primary-light-5);
122128
}
123129
124130

0 commit comments

Comments
 (0)