Skip to content

Commit f0fe44c

Browse files
committed
improve: add lang parameter in mcp chat
1 parent 4aaa2f8 commit f0fe44c

File tree

7 files changed

+46
-18
lines changed

7 files changed

+46
-18
lines changed

backend/apps/chat/models/chat_model.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ class McpQuestion(BaseModel):
293293
chat_id: int = Body(description='会话ID')
294294
token: str = Body(description='token')
295295
stream: Optional[bool] = Body(description='是否流式输出,默认为true开启, 关闭false则返回JSON对象', default=True)
296+
lang: Optional[str] = Body(description='语言:zh-CN|en|ko-KR', default='zh-CN')
296297

297298

298299
class AxisObj(BaseModel):

backend/apps/chat/task/llm.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
from common.core.deps import CurrentAssistant, CurrentUser
5050
from common.error import SingleMessageError, SQLBotDBError, ParseSQLResultError, SQLBotDBConnectionError
5151
from common.utils.data_format import DataFormat
52+
from common.utils.locale import I18n, I18nHelper
5253
from common.utils.utils import SQLBotLogUtil, extract_nested_json, prepare_for_orjson
5354

5455
warnings.filterwarnings("ignore")
@@ -62,6 +63,8 @@
6263

6364
session_maker = scoped_session(sessionmaker(bind=engine, class_=Session))
6465

66+
i18n = I18n()
67+
6568

6669
class LLMService:
6770
ds: CoreDatasource
@@ -86,6 +89,8 @@ class LLMService:
8689
chunk_list: List[str] = []
8790
future: Future
8891

92+
trans: I18nHelper = None
93+
8994
last_execute_sql_error: str = None
9095
articles_number: int = 4
9196

@@ -125,6 +130,7 @@ def __init__(self, session: Session, current_user: CurrentUser, chat_question: C
125130
self.change_title = not get_chat_brief_generate(session=session, chat_id=chat_id)
126131

127132
chat_question.lang = get_lang_name(current_user.language)
133+
self.trans = i18n(lang=current_user.language)
128134

129135
self.ds = (
130136
ds if isinstance(ds, AssistantOutDsSchema) else CoreDatasource(**ds.model_dump())) if ds else None
@@ -972,7 +978,7 @@ def run_task(self, in_chat: bool = True, stream: bool = True,
972978
{'type': 'question', 'question': self.get_record().question}).decode() + '\n\n'
973979
else:
974980
if stream:
975-
yield '> ID: ' + str(self.get_record().id) + '\n'
981+
yield '> ' + self.trans('i18n_chat.record_id_in_mcp') + str(self.get_record().id) + '\n'
976982
yield '> ' + self.get_record().question + '\n\n'
977983
if not stream:
978984
json_result['record_id'] = self.get_record().id
@@ -1173,7 +1179,7 @@ def run_task(self, in_chat: bool = True, stream: bool = True,
11731179
# generate picture
11741180
try:
11751181
if chart.get('type') != 'table':
1176-
yield '### generated chart picture\n\n'
1182+
# yield '### generated chart picture\n\n'
11771183
image_url, error = request_picture(self.record.chat_id, self.record.id, chart,
11781184
format_json_data(result))
11791185
SQLBotLogUtil.info(image_url)
@@ -1185,6 +1191,8 @@ def run_task(self, in_chat: bool = True, stream: bool = True,
11851191
raise error
11861192
except Exception as e:
11871193
if stream:
1194+
if chart.get('type') != 'table':
1195+
yield 'generate or fetch chart picture error.\n\n'
11881196
raise e
11891197

11901198
if not stream:
@@ -1263,7 +1271,7 @@ def run_analysis_or_predict_task(self, action_type: str, in_chat: bool = True, s
12631271
yield 'data:' + orjson.dumps({'type': 'id', 'id': self.get_record().id}).decode() + '\n\n'
12641272
else:
12651273
if stream:
1266-
yield '> ID: ' + str(self.get_record().id) + '\n'
1274+
yield '> ' + self.trans('i18n_chat.record_id_in_mcp') + str(self.get_record().id) + '\n'
12671275
yield '> ' + self.get_record().question + '\n\n'
12681276
if not stream:
12691277
json_result['record_id'] = self.get_record().id
@@ -1331,7 +1339,7 @@ def run_analysis_or_predict_task(self, action_type: str, in_chat: bool = True, s
13311339
# generate picture
13321340
try:
13331341
if chart.get('type') != 'table':
1334-
yield '### generated chart picture\n\n'
1342+
# yield '### generated chart picture\n\n'
13351343

13361344
_data = get_chat_chart_data(_session, self.record.id)
13371345
_data['data'] = _data.get('data') + predict_data
@@ -1347,6 +1355,8 @@ def run_analysis_or_predict_task(self, action_type: str, in_chat: bool = True, s
13471355
raise error
13481356
except Exception as e:
13491357
if stream:
1358+
if chart.get('type') != 'table':
1359+
yield 'generate or fetch chart picture error.\n\n'
13501360
raise e
13511361
else:
13521362
if in_chat:

backend/apps/mcp/mcp.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ async def mcp_question(session: SessionDep, chat: McpQuestion):
9191
db_user: UserModel = get_db_user(session=session, user_id=token_data.id)
9292
session_user = UserInfoDTO.model_validate(db_user.model_dump())
9393
session_user.isAdmin = session_user.id == 1 and session_user.account == 'admin'
94+
session_user.language = chat.lang
9495
if session_user.isAdmin:
9596
session_user = session_user
9697
ws_model: UserWsModel = session.exec(

backend/common/utils/locale.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
from pathlib import Path
21
import json
3-
from typing import Dict, Optional, Any
2+
from pathlib import Path
3+
from typing import Dict, Any
4+
45
from fastapi import Request
56

7+
68
class I18n:
79
def __init__(self, locale_dir: str = "locales"):
810
self.locale_dir = Path(locale_dir)
@@ -18,40 +20,45 @@ def load_translations(self):
1820
with open(lang_file, 'r', encoding='utf-8') as f:
1921
self.translations[lang_file.stem.lower()] = json.load(f)
2022

21-
def get_language(self, request: Request) -> str:
22-
accept_language = request.headers.get('accept-language', 'en')
23-
primary_lang = accept_language.split(',')[0].lower()
24-
23+
def get_language(self, request: Request = None, lang: str = None) -> str:
24+
primary_lang: str | None = None
25+
if lang is not None:
26+
primary_lang = lang.lower()
27+
elif request is not None:
28+
accept_language = request.headers.get('accept-language', 'en')
29+
primary_lang = accept_language.split(',')[0].lower()
30+
2531
return primary_lang if primary_lang in self.translations else 'zh-cn'
2632

27-
def __call__(self, request: Request) -> 'I18nHelper':
28-
return I18nHelper(self, request)
33+
def __call__(self, request: Request = None, lang: str = None) -> 'I18nHelper':
34+
return I18nHelper(self, request, lang)
35+
2936

3037
class I18nHelper:
31-
def __init__(self, i18n: I18n, request: Request):
38+
def __init__(self, i18n: I18n, request: Request = None, lang: str = None):
3239
self.i18n = i18n
3340
self.request = request
34-
self.lang = i18n.get_language(request)
41+
self.lang = i18n.get_language(request, lang)
3542

3643
def _get_nested_translation(self, data: Dict[str, Any], key_path: str) -> str:
3744
keys = key_path.split('.')
3845
current = data
39-
46+
4047
for key in keys:
4148
if isinstance(current, dict) and key in current:
4249
current = current[key]
4350
else:
4451
return key_path # 如果找不到,返回原键
45-
52+
4653
return current if isinstance(current, str) else key_path
4754

4855
def __call__(self, arg_key: str, **kwargs) -> str:
4956
lang_data = self.i18n.translations.get(self.lang, {})
5057
text = self._get_nested_translation(lang_data, arg_key)
51-
58+
5259
if kwargs:
5360
try:
5461
return text.format(**kwargs)
5562
except (KeyError, ValueError):
5663
return text
57-
return text
64+
return text

backend/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
"i18n_embedded": {
4141
"invalid_origin": "Domain name validation failed【{origin}】"
4242
},
43+
"i18n_chat": {
44+
"record_id_in_mcp": "Answer ID: "
45+
},
4346
"i18n_terminology": {
4447
"terminology_not_exists": "This terminology does not exist",
4548
"datasource_cannot_be_none": "Datasource cannot be empty",

backend/locales/ko-KR.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
"i18n_embedded": {
4141
"invalid_origin": "도메인 이름 검증 실패 【{origin}】"
4242
},
43+
"i18n_chat": {
44+
"record_id_in_mcp": "응답 ID: "
45+
},
4346
"i18n_terminology": {
4447
"datasource_list_is_not_found": "데이터 소스 목록을 찾을 수 없습니다",
4548
"datasource_id_not_found": "데이터 소스 ID: {key}를 찾을 수 없습니다",

backend/locales/zh-CN.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
"i18n_embedded": {
4141
"invalid_origin": "域名校验失败【{origin}】"
4242
},
43+
"i18n_chat": {
44+
"record_id_in_mcp": "响应ID: "
45+
},
4346
"i18n_terminology": {
4447
"terminology_not_exists": "该术语不存在",
4548
"datasource_cannot_be_none": "数据源不能为空",

0 commit comments

Comments
 (0)