Skip to content

Commit 0069f76

Browse files
committed
Merge branch 'main' of https://github.com/dataease/SQLBot
2 parents 2bdbd2b + aeee30e commit 0069f76

File tree

14 files changed

+213
-39
lines changed

14 files changed

+213
-39
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""033_chat_origin_ddl
2+
3+
Revision ID: 3cb5d6a54f2e
4+
Revises: 6549e47f9adc
5+
Create Date: 2025-07-22 22:00:48.599729
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlmodel.sql.sqltypes
11+
from sqlalchemy.dialects import postgresql
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '3cb5d6a54f2e'
15+
down_revision = '6549e47f9adc'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.add_column('chat', sa.Column('origin', sa.Integer(), nullable=True, default=0)) # 0: default, 1: mcp, 2: assistant
23+
op.execute('UPDATE chat SET origin = 0 WHERE origin IS NULL')
24+
# ### end Alembic commands ###
25+
26+
27+
def downgrade():
28+
# ### commands auto generated by Alembic - please adjust! ###
29+
op.drop_column('chat', 'origin')
30+
# ### end Alembic commands ###

backend/apps/chat/api/chat.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ async def chats(session: SessionDep, current_user: CurrentUser):
1818

1919

2020
@router.get("/get/{chart_id}")
21-
async def get_chat(session: SessionDep, current_user: CurrentUser, chart_id: int):
21+
async def get_chat(session: SessionDep, current_user: CurrentUser, chart_id: int, current_assistant: CurrentAssistant):
2222
try:
23-
return get_chat_with_records(chart_id=chart_id, session=session, current_user=current_user)
23+
return get_chat_with_records(chart_id=chart_id, session=session, current_user=current_user, current_assistant=current_assistant)
2424
except Exception as e:
2525
raise HTTPException(
2626
status_code=500,
@@ -85,7 +85,7 @@ async def start_chat(session: SessionDep, current_user: CurrentUser, create_chat
8585
@router.post("/assistant/start")
8686
async def start_chat(session: SessionDep, current_user: CurrentUser):
8787
try:
88-
return create_chat(session, current_user, CreateChat(), False)
88+
return create_chat(session, current_user, CreateChat(origin=2), False)
8989
except Exception as e:
9090
raise HTTPException(
9191
status_code=500,

backend/apps/chat/curd/chat.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
from apps.chat.models.chat_model import Chat, ChatRecord, CreateChat, ChatInfo, RenameChat, ChatQuestion
1010
from apps.datasource.models.datasource import CoreDatasource
11-
from common.core.deps import SessionDep, CurrentUser
11+
from apps.system.crud.assistant import AssistantOutDsFactory
12+
from common.core.deps import CurrentAssistant, SessionDep, CurrentUser
1213
from common.utils.utils import extract_nested_json
1314

1415

@@ -20,7 +21,7 @@ def list_chats(session: SessionDep, current_user: CurrentUser) -> List[Chat]:
2021

2122

2223
def rename_chat(session: SessionDep, rename_object: RenameChat) -> str:
23-
chat = session.query(Chat).filter(Chat.id == rename_object.id).first()
24+
chat = session.get(Chat, rename_object.id)
2425
if not chat:
2526
raise Exception(f"Chat with id {rename_object.id} not found")
2627

@@ -65,14 +66,19 @@ def get_chat_predict_data(session: SessionDep, chart_record_id: int):
6566
return ''
6667

6768

68-
def get_chat_with_records(session: SessionDep, chart_id: int, current_user: CurrentUser) -> ChatInfo:
69-
chat = session.query(Chat).filter(Chat.id == chart_id).first()
69+
def get_chat_with_records(session: SessionDep, chart_id: int, current_user: CurrentUser, current_assistant: CurrentAssistant) -> ChatInfo:
70+
chat = session.get(Chat, chart_id)
7071
if not chat:
7172
raise Exception(f"Chat with id {chart_id} not found")
7273

7374
chat_info = ChatInfo(**chat.model_dump())
7475

75-
ds = session.query(CoreDatasource).filter(CoreDatasource.id == chat.datasource).first()
76+
if current_assistant and current_assistant.type == 1:
77+
out_ds_instance = AssistantOutDsFactory.get_instance(current_assistant)
78+
ds = out_ds_instance.get_ds(chat.datasource)
79+
else:
80+
ds = session.get(CoreDatasource, chat.datasource) if chat.datasource else None
81+
7682
if not ds:
7783
chat_info.datasource_exists = False
7884
chat_info.datasource_name = 'Datasource not exist'
@@ -157,11 +163,12 @@ def create_chat(session: SessionDep, current_user: CurrentUser, create_chat_obj:
157163
chat = Chat(create_time=datetime.datetime.now(),
158164
create_by=current_user.id,
159165
oid=current_user.oid if current_user.oid is not None else 1,
160-
brief=create_chat_obj.question.strip()[:20])
166+
brief=create_chat_obj.question.strip()[:20],
167+
origin=create_chat_obj.origin if create_chat_obj.origin is not None else 0)
161168
ds: CoreDatasource | None = None
162169
if create_chat_obj.datasource:
163170
chat.datasource = create_chat_obj.datasource
164-
ds = session.query(CoreDatasource).filter(CoreDatasource.id == create_chat_obj.datasource).first()
171+
ds = session.get(CoreDatasource, create_chat_obj.datasource)
165172

166173
if not ds:
167174
raise Exception(f"Datasource with id {create_chat_obj.datasource} not found")

backend/apps/chat/models/chat_model.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import List, Optional
33

44
from pydantic import BaseModel
5-
from sqlalchemy import Column, Text, BigInteger, DateTime, Identity, Boolean
5+
from sqlalchemy import Column, Integer, Text, BigInteger, DateTime, Identity, Boolean
66
from sqlmodel import SQLModel, Field
77

88
from apps.template.generate_analysis.generator import get_analysis_template
@@ -24,6 +24,7 @@ class Chat(SQLModel, table=True):
2424
chat_type: str = Field(max_length=20, default="chat") # chat, datasource
2525
datasource: int = Field(sa_column=Column(BigInteger, nullable=True))
2626
engine_type: str = Field(max_length=64)
27+
origin: Optional[int] = Field(sa_column=Column(Integer, nullable=False, default=0)) # 0: default, 1: mcp, 2: assistant
2728

2829

2930
class ChatRecord(SQLModel, table=True):
@@ -72,6 +73,7 @@ class CreateChat(BaseModel):
7273
id: int = None
7374
question: str = None
7475
datasource: int = None
76+
origin: Optional[int] = 0
7577

7678

7779
class RenameChat(BaseModel):

backend/apps/chat/task/llm.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
from apps.datasource.crud.row_permission import transFilterTree
3232
from apps.datasource.models.datasource import CoreDatasource, CoreTable
3333
from apps.db.db import exec_sql
34-
from apps.system.crud.assistant import AssistantOutDs, get_assistant_ds
34+
from apps.system.crud.assistant import AssistantOutDs, AssistantOutDsFactory, get_assistant_ds
35+
from apps.system.schemas.system_schema import AssistantOutDsSchema
3536
from common.core.config import settings
3637
from common.core.deps import CurrentAssistant, SessionDep, CurrentUser
3738
from common.utils.utils import extract_nested_json
@@ -67,15 +68,23 @@ def __init__(self, session: SessionDep, current_user: CurrentUser, chat_question
6768
chat: Chat = self.session.get(Chat, chat_id)
6869
if not chat:
6970
raise Exception(f"Chat with id {chat_id} not found")
70-
ds: CoreDatasource | None = None
71+
ds: CoreDatasource | AssistantOutDsSchema | None = None
7172
if chat.datasource:
7273
# Get available datasource
7374
# ds = self.session.query(CoreDatasource).filter(CoreDatasource.id == chat.datasource).first()
74-
ds = self.session.get(CoreDatasource, chat.datasource)
75-
if not ds:
76-
raise Exception("No available datasource configuration found")
77-
78-
chat_question.engine = ds.type_name if ds.type != 'excel' else 'PostgreSQL'
75+
if current_assistant and current_assistant.type == 1:
76+
self.out_ds_instance = AssistantOutDsFactory.get_instance(current_assistant)
77+
ds = self.out_ds_instance.get_ds(chat.datasource)
78+
if not ds:
79+
raise Exception("No available datasource configuration found")
80+
chat_question.engine = ds.type
81+
chat_question.db_schema = self.out_ds_instance.get_db_schema(ds.id)
82+
else:
83+
ds = self.session.get(CoreDatasource, chat.datasource)
84+
if not ds:
85+
raise Exception("No available datasource configuration found")
86+
chat_question.engine = ds.type_name if ds.type != 'excel' else 'PostgreSQL'
87+
chat_question.db_schema = get_table_schema(session=self.session, current_user=current_user, ds=ds)
7988

8089
history_records: List[ChatRecord] = list(
8190
map(lambda x: ChatRecord(**x.model_dump()), filter(lambda r: True if r.first_chat != True else False,
@@ -84,13 +93,9 @@ def __init__(self, session: SessionDep, current_user: CurrentUser, chat_question
8493
chart_id=chat_id))))
8594
self.change_title = len(history_records) == 0
8695

87-
# get schema
88-
if ds:
89-
chat_question.db_schema = get_table_schema(session=self.session, current_user=current_user, ds=ds)
90-
9196
chat_question.lang = current_user.language
9297

93-
self.ds = CoreDatasource(**ds.model_dump()) if ds else None
98+
self.ds = (ds if isinstance(ds, AssistantOutDsSchema) else CoreDatasource(**ds.model_dump())) if ds else None
9499
self.chat_question = chat_question
95100
self.config = get_default_config()
96101
self.chat_question.ai_modal_id = self.config.model_id
@@ -298,7 +303,7 @@ def generate_recommend_questions_task(self):
298303

299304
# get schema
300305
if self.ds and not self.chat_question.db_schema:
301-
self.chat_question.db_schema = get_table_schema(session=self.session, current_user=self.current_user, ds=self.ds)
306+
self.chat_question.db_schema = self.out_ds_instance.get_db_schema(self.ds.id) if self.out_ds_instance else get_table_schema(session=self.session, current_user=self.current_user, ds=self.ds)
302307

303308
guess_msg: List[Union[BaseMessage, dict[str, Any]]] = []
304309
guess_msg.append(SystemMessage(content=self.chat_question.guess_sys_question()))

backend/apps/mcp/mcp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ async def mcp_start(session: SessionDep, chat: ChatStart):
7171
t = Token(access_token=create_access_token(
7272
user_dict, expires_delta=access_token_expires
7373
))
74-
c = create_chat(session, user, CreateChat(), False)
74+
c = create_chat(session, user, CreateChat(origin=1), False)
7575
return {"access_token": t.access_token, "chat_id": c.id}
7676

7777

backend/apps/system/crud/assistant.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from common.core.db import engine
1616
from starlette.middleware.cors import CORSMiddleware
1717
from common.core.config import settings
18+
from common.utils.utils import string_to_numeric_hash
1819

1920
@cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="assistant_id")
2021
async def get_assistant_info(*, session: Session, assistant_id: int) -> AssistantModel | None:
@@ -100,7 +101,7 @@ def get_ds_from_api(self):
100101
header = {}
101102
cookies = {}
102103
for item in certificateList:
103-
if item['target'] == 'head':
104+
if item['target'] == 'header':
104105
header[item['key']] = item['value']
105106
if item['target'] == 'cookie':
106107
cookies[item['key']] = item['value']
@@ -111,8 +112,8 @@ def get_ds_from_api(self):
111112
if result_json.get('code') == 0:
112113
temp_list = result_json.get('data', [])
113114
self.ds_list = [
114-
AssistantOutDsSchema(**{**item, "id": idx})
115-
for idx, item in enumerate(temp_list, start=1)
115+
self.convert2schema(item)
116+
for item in temp_list
116117
]
117118

118119
return self.ds_list
@@ -151,6 +152,14 @@ def get_ds(self, ds_id: int):
151152
raise Exception("Datasource list is not found.")
152153
raise Exception(f"Datasource with id {ds_id} not found.")
153154

155+
def convert2schema(self, ds_dict: dict) -> AssistantOutDsSchema:
156+
id_marker: str = ''
157+
attr_list = ['name', 'type', 'host', 'port', 'user', 'dataBase', 'schema']
158+
for attr in attr_list:
159+
if attr in ds_dict:
160+
id_marker += str(ds_dict.get(attr, '')) + '--sqlbot--'
161+
id = string_to_numeric_hash(id_marker)
162+
return AssistantOutDsSchema(**{**ds_dict, "id": id})
154163

155164
class AssistantOutDsFactory:
156165
@staticmethod

backend/common/utils/utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import hashlib
12
import logging
23
from datetime import datetime, timedelta, timezone
4+
from typing import Optional
35

46
import jwt
57
import orjson
@@ -70,3 +72,7 @@ def extract_nested_json(text):
7072
if len(results) > 0 and results[0]:
7173
return results[0]
7274
return None
75+
76+
def string_to_numeric_hash(text: str, bits: Optional[int] = 64) -> int:
77+
hash_bytes = hashlib.sha256(text.encode()).digest()
78+
return int.from_bytes(hash_bytes[:bits//8], byteorder='big')

frontend/src/views/chat/RecommendQuestion.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ const props = withDefaults(
1010
currentChat?: ChatInfo
1111
questions?: string
1212
firstChat?: boolean
13+
disabled?: boolean
1314
}>(),
1415
{
1516
recordId: undefined,
1617
currentChat: () => new ChatInfo(),
1718
questions: '[]',
1819
firstChat: false,
20+
disabled: false,
1921
}
2022
)
2123
@@ -47,7 +49,9 @@ const computedQuestions = computed<string>(() => {
4749
const { t } = useI18n()
4850
4951
function clickQuestion(question: string): void {
50-
emits('clickQuestion', question)
52+
if (!props.disabled) {
53+
emits('clickQuestion', question)
54+
}
5155
}
5256
5357
const stopFlag = ref(false)
@@ -160,6 +164,7 @@ defineExpose({ getRecommendQuestions, id: () => props.recordId, stop })
160164
v-for="(question, index) in computedQuestions"
161165
:key="index"
162166
class="question"
167+
:class="{ disabled: disabled }"
163168
@click="clickQuestion(question)"
164169
>
165170
{{ question }}
@@ -199,6 +204,10 @@ defineExpose({ getRecommendQuestions, id: () => props.recordId, stop })
199204
&:hover {
200205
background: rgba(31, 35, 41, 0.1);
201206
}
207+
&.disabled {
208+
cursor: not-allowed;
209+
background: rgba(245, 246, 247, 1);
210+
}
202211
}
203212
}
204213
</style>

frontend/src/views/chat/component/BaseG2Chart.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export abstract class BaseG2Chart extends BaseChart {
99
this.chart = new Chart({
1010
container: id,
1111
autoFit: true,
12+
padding: 'auto',
1213
})
1314

1415
this.chart.theme({

0 commit comments

Comments
 (0)