11import traceback
2- from typing import List
32
43import orjson
54from fastapi import APIRouter , HTTPException
65from fastapi .responses import StreamingResponse
7- from sqlmodel import select
86
97from apps .chat .curd .chat import list_chats , get_chat_with_records , create_chat , rename_chat , \
10- delete_chat , list_records
11- from apps .chat .models .chat_model import CreateChat , ChatRecord , RenameChat , Chat , ChatQuestion , ChatMcp
12- from apps .chat .task .llm import LLMService
13- from apps .datasource .crud .datasource import get_table_schema
14- from apps .datasource .models .datasource import CoreDatasource
15- from apps .system .crud .user import get_user_info
16- from apps .system .models .system_model import AiModelDetail
17- from common .core .deps import SessionDep , CurrentUser , get_current_user
8+ delete_chat
9+ from apps .chat .models .chat_model import CreateChat , ChatRecord , RenameChat , ChatQuestion
10+ from apps .chat .task .llm import LLMService , run_task
11+ from common .core .deps import SessionDep , CurrentUser
1812
1913router = APIRouter (tags = ["Data Q&A" ], prefix = "/chat" )
2014
@@ -81,107 +75,17 @@ async def stream_sql(session: SessionDep, current_user: CurrentUser, request_que
8175 Streaming response with analysis results
8276 """
8377
84- chat = session .query (Chat ).filter (Chat .id == request_question .chat_id ).first ()
85- if not chat :
86- raise HTTPException (
87- status_code = 400 ,
88- detail = f"Chat with id { request_question .chat_id } not found"
89- )
90- ds : CoreDatasource | None = None
91- if chat .datasource :
92- # Get available datasource
93- ds = session .query (CoreDatasource ).filter (CoreDatasource .id == chat .datasource ).first ()
94- if not ds :
95- raise HTTPException (
96- status_code = 500 ,
97- detail = "No available datasource configuration found"
98- )
99-
100- request_question .engine = ds .type_name if ds .type != 'excel' else 'PostgreSQL'
101-
102- # Get available AI model
103- aimodel = session .exec (select (AiModelDetail ).where (
104- AiModelDetail .status == True ,
105- AiModelDetail .api_key .is_not (None )
106- )).first ()
107- if not aimodel :
78+ try :
79+ llm_service = LLMService (session , current_user , request_question )
80+ llm_service .init_record ()
81+ except Exception as e :
82+ traceback .print_exc ()
10883 raise HTTPException (
10984 status_code = 500 ,
110- detail = "No available AI model configuration found"
85+ detail = str ( e )
11186 )
11287
113- history_records : List [ChatRecord ] = list (filter (lambda r : True if r .first_chat != True else False ,
114- list_records (session = session , current_user = current_user ,
115- chart_id = request_question .chat_id )))
116- # get schema
117- if ds :
118- request_question .db_schema = get_table_schema (session = session , ds = ds )
119-
120- db_user = get_user_info (session = session , user_id = current_user .id )
121- request_question .lang = db_user .language
122-
123- llm_service = LLMService (request_question , aimodel , history_records ,
124- CoreDatasource (** ds .model_dump ()) if ds else None )
125-
126- llm_service .init_record (session = session , current_user = current_user )
127-
128- def run_task ():
129- try :
130- # return id
131- yield orjson .dumps ({'type' : 'id' , 'id' : llm_service .get_record ().id }).decode () + '\n \n '
132-
133- # select datasource if datasource is none
134- if not ds :
135- ds_res = llm_service .select_datasource (session = session )
136- for chunk in ds_res :
137- yield orjson .dumps ({'content' : chunk , 'type' : 'datasource-result' }).decode () + '\n \n '
138- yield orjson .dumps ({'id' : llm_service .ds .id , 'datasource_name' : llm_service .ds .name ,
139- 'engine_type' : llm_service .ds .type_name , 'type' : 'datasource' }).decode () + '\n \n '
140-
141- llm_service .chat_question .db_schema = get_table_schema (session = session , ds = llm_service .ds )
142-
143- # generate sql
144- sql_res = llm_service .generate_sql (session = session )
145- full_sql_text = ''
146- for chunk in sql_res :
147- full_sql_text += chunk
148- yield orjson .dumps ({'content' : chunk , 'type' : 'sql-result' }).decode () + '\n \n '
149- yield orjson .dumps ({'type' : 'info' , 'msg' : 'sql generated' }).decode () + '\n \n '
150-
151- # filter sql
152- print (full_sql_text )
153- sql = llm_service .check_save_sql (session = session , res = full_sql_text )
154- print (sql )
155- yield orjson .dumps ({'content' : sql , 'type' : 'sql' }).decode () + '\n \n '
156-
157- # execute sql
158- result = llm_service .execute_sql (sql = sql )
159- llm_service .save_sql_data (session = session , data_obj = result )
160- yield orjson .dumps ({'content' : orjson .dumps (result ).decode (), 'type' : 'sql-data' }).decode () + '\n \n '
161-
162- # generate chart
163- chart_res = llm_service .generate_chart (session = session )
164- full_chart_text = ''
165- for chunk in chart_res :
166- full_chart_text += chunk
167- yield orjson .dumps ({'content' : chunk , 'type' : 'chart-result' }).decode () + '\n \n '
168- yield orjson .dumps ({'type' : 'info' , 'msg' : 'chart generated' }).decode () + '\n \n '
169-
170- # filter chart
171- print (full_chart_text )
172- chart = llm_service .check_save_chart (session = session , res = full_chart_text )
173- print (chart )
174- yield orjson .dumps ({'content' : orjson .dumps (chart ).decode (), 'type' : 'chart' }).decode () + '\n \n '
175-
176- llm_service .finish (session = session )
177- yield orjson .dumps ({'type' : 'finish' }).decode () + '\n \n '
178-
179- except Exception as e :
180- traceback .print_exc ()
181- llm_service .save_error (session = session , message = str (e ))
182- yield orjson .dumps ({'content' : str (e ), 'type' : 'error' }).decode () + '\n \n '
183-
184- return StreamingResponse (run_task (), media_type = "text/event-stream" )
88+ return StreamingResponse (run_task (llm_service , session ), media_type = "text/event-stream" )
18589
18690
18791@router .post ("/record/{chart_record_id}/{action_type}" )
@@ -205,35 +109,9 @@ async def analysis_or_predict(session: SessionDep, current_user: CurrentUser, ch
205109 detail = f"Chat record with id { chart_record_id } has not generated chart, do not support to analyze it"
206110 )
207111
208- chat = session .query (Chat ).filter (Chat .id == record .chat_id ).first ()
209- if not chat :
210- raise HTTPException (
211- status_code = 400 ,
212- detail = f"Chat with id { record .chart_id } not found"
213- )
214-
215- if chat .create_by != current_user .id :
216- raise HTTPException (
217- status_code = 401 ,
218- detail = f"You cannot use the chat with id { record .chart_id } "
219- )
220-
221- # Get available AI model
222- aimodel = session .exec (select (AiModelDetail ).where (
223- AiModelDetail .status == True ,
224- AiModelDetail .api_key .is_not (None )
225- )).first ()
226- if not aimodel :
227- raise HTTPException (
228- status_code = 500 ,
229- detail = "No available AI model configuration found"
230- )
231-
232- request_question = ChatQuestion (chat_id = chat .id , question = '' )
233- db_user = get_user_info (session = session , user_id = current_user .id )
234- request_question .lang = db_user .language
112+ request_question = ChatQuestion (chat_id = record .chat_id , question = '' )
235113
236- llm_service = LLMService (request_question , aimodel )
114+ llm_service = LLMService (session , current_user , request_question )
237115 llm_service .set_record (record )
238116
239117 def run_task ():
@@ -249,14 +127,14 @@ def run_task():
249127
250128 elif action_type == 'predict' :
251129 # generate predict
252- analysis_res = llm_service .generate_predict (session = session )
130+ analysis_res = llm_service .generate_predict ()
253131 full_text = ''
254132 for chunk in analysis_res :
255133 yield orjson .dumps ({'content' : chunk , 'type' : 'predict-result' }).decode () + '\n \n '
256134 full_text += chunk
257135 yield orjson .dumps ({'type' : 'info' , 'msg' : 'predict generated' }).decode () + '\n \n '
258136
259- _data = llm_service .check_save_predict_data (session = session , res = full_text )
137+ _data = llm_service .check_save_predict_data (res = full_text )
260138 yield orjson .dumps ({'type' : 'predict' , 'content' : _data }).decode () + '\n \n '
261139
262140 yield orjson .dumps ({'type' : 'predict_finish' }).decode () + '\n \n '
0 commit comments