11import logging
2+ from http import HTTPStatus
23from typing import Optional
34
4- from fastapi import APIRouter , Header , Request
5+ from fastapi import APIRouter , Header , Request , HTTPException
56from fastapi .responses import JSONResponse
67
7- from consts .const import (
8- DEFAULT_APP_DESCRIPTION_ZH ,
9- DEFAULT_APP_DESCRIPTION_EN ,
10- DEFAULT_APP_NAME_EN ,
11- DEFAULT_APP_NAME_ZH ,
12- DEFAULT_APP_ICON_URL
13- )
148from consts .model import GlobalConfig
15- from database . model_management_db import get_model_id_by_display_name
9+ from services . config_sync_service import save_config_impl , load_config_impl
1610from utils .auth_utils import get_current_user_id , get_current_user_info
17- from utils .config_utils import (
18- get_env_key ,
19- safe_value ,
20- tenant_config_manager ,
21- get_model_name_from_config
22- )
2311
2412router = APIRouter (prefix = "/config" )
2513logger = logging .getLogger ("config_sync_app" )
2614
2715
28- def handle_model_config (tenant_id : str , user_id : str , config_key : str , model_id : int , tenant_config_dict : dict ) -> None :
29- """
30- Handle model configuration updates, deletions, and settings operations
31-
32- Args:
33- tenant_id: Tenant ID
34- user_id: User ID
35- config_key: Configuration key name
36- model_id: Model ID
37- tenant_config_dict: Tenant configuration dictionary
38- """
39- if not model_id and config_key in tenant_config_dict :
40- tenant_config_manager .delete_single_config (tenant_id , config_key )
41- elif config_key in tenant_config_dict :
42- try :
43- existing_model_id = int (
44- tenant_config_dict [config_key ]) if tenant_config_dict [config_key ] else None
45- if existing_model_id == model_id :
46- tenant_config_manager .update_single_config (
47- tenant_id , config_key )
48- else :
49- tenant_config_manager .delete_single_config (
50- tenant_id , config_key )
51- if model_id :
52- tenant_config_manager .set_single_config (
53- user_id , tenant_id , config_key , model_id )
54- except (ValueError , TypeError ):
55- tenant_config_manager .delete_single_config (tenant_id , config_key )
56- if model_id :
57- tenant_config_manager .set_single_config (
58- user_id , tenant_id , config_key , model_id )
59- else :
60- if model_id :
61- tenant_config_manager .set_single_config (
62- user_id , tenant_id , config_key , model_id )
63-
64-
6516@router .post ("/save_config" )
6617async def save_config (config : GlobalConfig , authorization : Optional [str ] = Header (None )):
6718 try :
6819 user_id , tenant_id = get_current_user_id (authorization )
6920 logger .info (
7021 f"Start to save config, user_id: { user_id } , tenant_id: { tenant_id } " )
71- config_dict = config .model_dump (exclude_none = False )
72- env_config = {}
73-
74- tenant_config_dict = tenant_config_manager .load_config (tenant_id )
75-
76- # Process app configuration - use key names directly without prefix
77- for key , value in config_dict .get ("app" , {}).items ():
78- env_key = get_env_key (key )
79- env_config [env_key ] = safe_value (value )
80-
81- # Check if the key exists and has the same value in tenant_config_dict
82- if env_key in tenant_config_dict and tenant_config_dict [env_key ] == safe_value (value ):
83- tenant_config_manager .update_single_config (tenant_id , env_key )
84- elif env_key in tenant_config_dict and env_config [env_key ] == '' :
85- tenant_config_manager .delete_single_config (tenant_id , env_key )
86- elif env_key in tenant_config_dict :
87- tenant_config_manager .delete_single_config (tenant_id , env_key )
88- tenant_config_manager .set_single_config (
89- user_id , tenant_id , env_key , safe_value (value ))
90- else :
91- if env_config [env_key ] not in [DEFAULT_APP_NAME_ZH , DEFAULT_APP_NAME_EN , DEFAULT_APP_DESCRIPTION_ZH , DEFAULT_APP_DESCRIPTION_EN ]:
92- tenant_config_manager .set_single_config (
93- user_id , tenant_id , env_key , safe_value (value ))
94-
95- # Process model configuration
96- for model_type , model_config in config_dict .get ("models" , {}).items ():
97- if not model_config :
98- continue
99-
100- model_name = model_config .get ("modelName" )
101- model_display_name = model_config .get ("displayName" )
102-
103- config_key = get_env_key (model_type ) + "_ID"
104- model_id = get_model_id_by_display_name (
105- model_display_name , tenant_id )
106-
107- if not model_name :
108- continue
109-
110- handle_model_config (tenant_id , user_id , config_key ,
111- model_id , tenant_config_dict )
112-
113- model_prefix = get_env_key (model_type )
114-
115- # Still keep EMBEDDING_API_KEY in env
116- if model_type == "embedding" :
117- if model_config and "apiConfig" in model_config :
118- embedding_api_config = model_config .get ("apiConfig" , {})
119- env_config [f"{ model_prefix } _API_KEY" ] = safe_value (
120- embedding_api_config .get ("apiKey" ))
121-
122- logger .info ("Configuration saved successfully" )
22+ await save_config_impl (config , tenant_id , user_id )
12323 return JSONResponse (
124- status_code = 200 ,
24+ status_code = HTTPStatus . OK ,
12525 content = {"message" : "Configuration saved successfully" ,
12626 "status" : "saved" }
12727 )
12828 except Exception as e :
12929 logger .error (f"Failed to save configuration: { str (e )} " )
130- return JSONResponse (
131- status_code = 400 ,
132- content = {
133- "message" : f"Failed to save configuration: { str (e )} " , "status" : "unsaved" }
134- )
30+ raise HTTPException (status_code = HTTPStatus .BAD_REQUEST , detail = "Failed to save configuration." )
13531
13632
13733@router .get ("/load_config" )
@@ -144,116 +40,13 @@ async def load_config(authorization: Optional[str] = Header(None), request: Requ
14440 """
14541 try :
14642 # Build configuration object
147- # TODO: Clean up the default values
14843 user_id , tenant_id , language = get_current_user_info (
14944 authorization , request )
150-
151- llm_model_name = tenant_config_manager .get_model_config (
152- "LLM_ID" , tenant_id = tenant_id )
153- llm_secondary_model_name = tenant_config_manager .get_model_config (
154- "LLM_SECONDARY_ID" , tenant_id = tenant_id )
155- embedding_model_name = tenant_config_manager .get_model_config (
156- "EMBEDDING_ID" , tenant_id = tenant_id )
157- multi_embedding_model_name = tenant_config_manager .get_model_config (
158- "MULTI_EMBEDDING_ID" , tenant_id = tenant_id )
159- rerank_model_name = tenant_config_manager .get_model_config (
160- "RERANK_ID" , tenant_id = tenant_id )
161- vlm_model_name = tenant_config_manager .get_model_config (
162- "VLM_ID" , tenant_id = tenant_id )
163- stt_model_name = tenant_config_manager .get_model_config (
164- "STT_ID" , tenant_id = tenant_id )
165- tts_model_name = tenant_config_manager .get_model_config (
166- "TTS_ID" , tenant_id = tenant_id )
167-
168- default_app_name = DEFAULT_APP_NAME_ZH if language == "zh" else DEFAULT_APP_NAME_EN
169- default_app_description = DEFAULT_APP_DESCRIPTION_ZH if language == "zh" else DEFAULT_APP_DESCRIPTION_EN
170- config = {
171- "app" : {
172- "name" : tenant_config_manager .get_app_config ("APP_NAME" , tenant_id = tenant_id ) or default_app_name ,
173- "description" : tenant_config_manager .get_app_config ("APP_DESCRIPTION" , tenant_id = tenant_id ) or default_app_description ,
174- "icon" : {
175- "type" : tenant_config_manager .get_app_config ("ICON_TYPE" , tenant_id = tenant_id ) or "preset" ,
176- "avatarUri" : tenant_config_manager .get_app_config ("AVATAR_URI" , tenant_id = tenant_id ) or DEFAULT_APP_ICON_URL ,
177- "customUrl" : tenant_config_manager .get_app_config ("CUSTOM_ICON_URL" , tenant_id = tenant_id ) or ""
178- }
179- },
180- "models" : {
181- "llm" : {
182- "name" : get_model_name_from_config (llm_model_name ) if llm_model_name else "" ,
183- "displayName" : llm_model_name .get ("display_name" , "" ),
184- "apiConfig" : {
185- "apiKey" : llm_model_name .get ("api_key" , "" ),
186- "modelUrl" : llm_model_name .get ("base_url" , "" )
187- }
188- },
189- "llmSecondary" : {
190- "name" : get_model_name_from_config (llm_secondary_model_name ) if llm_secondary_model_name else "" ,
191- "displayName" : llm_secondary_model_name .get ("display_name" , "" ),
192- "apiConfig" : {
193- "apiKey" : llm_secondary_model_name .get ("api_key" , "" ),
194- "modelUrl" : llm_secondary_model_name .get ("base_url" , "" )
195- }
196- },
197- "embedding" : {
198- "name" : get_model_name_from_config (embedding_model_name ) if embedding_model_name else "" ,
199- "displayName" : embedding_model_name .get ("display_name" , "" ),
200- "apiConfig" : {
201- "apiKey" : embedding_model_name .get ("api_key" , "" ),
202- "modelUrl" : embedding_model_name .get ("base_url" , "" )
203- },
204- "dimension" : embedding_model_name .get ("max_tokens" , 0 )
205- },
206- "multiEmbedding" : {
207- "name" : get_model_name_from_config (multi_embedding_model_name ) if multi_embedding_model_name else "" ,
208- "displayName" : multi_embedding_model_name .get ("display_name" , "" ),
209- "apiConfig" : {
210- "apiKey" : multi_embedding_model_name .get ("api_key" , "" ),
211- "modelUrl" : multi_embedding_model_name .get ("base_url" , "" )
212- },
213- "dimension" : multi_embedding_model_name .get ("max_tokens" , 0 )
214- },
215- "rerank" : {
216- "name" : get_model_name_from_config (rerank_model_name ) if rerank_model_name else "" ,
217- "displayName" : rerank_model_name .get ("display_name" , "" ),
218- "apiConfig" : {
219- "apiKey" : rerank_model_name .get ("api_key" , "" ),
220- "modelUrl" : rerank_model_name .get ("base_url" , "" )
221- }
222- },
223- "vlm" : {
224- "name" : get_model_name_from_config (vlm_model_name ) if vlm_model_name else "" ,
225- "displayName" : vlm_model_name .get ("display_name" , "" ),
226- "apiConfig" : {
227- "apiKey" : vlm_model_name .get ("api_key" , "" ),
228- "modelUrl" : vlm_model_name .get ("base_url" , "" )
229- }
230- },
231- "stt" : {
232- "name" : get_model_name_from_config (stt_model_name ) if stt_model_name else "" ,
233- "displayName" : stt_model_name .get ("display_name" , "" ),
234- "apiConfig" : {
235- "apiKey" : stt_model_name .get ("api_key" , "" ),
236- "modelUrl" : stt_model_name .get ("base_url" , "" )
237- }
238- },
239- "tts" : {
240- "name" : get_model_name_from_config (tts_model_name ) if tts_model_name else "" ,
241- "displayName" : tts_model_name .get ("display_name" , "" ),
242- "apiConfig" : {
243- "apiKey" : tts_model_name .get ("api_key" , "" ),
244- "modelUrl" : tts_model_name .get ("base_url" , "" )
245- }
246- }
247- }
248- }
249-
45+ config = await load_config_impl (language , tenant_id )
25046 return JSONResponse (
251- status_code = 200 ,
47+ status_code = HTTPStatus . OK ,
25248 content = {"config" : config }
25349 )
25450 except Exception as e :
255- return JSONResponse (
256- status_code = 400 ,
257- content = {
258- "message" : f"Failed to load configuration: { str (e )} " , "status" : "error" }
259- )
51+ logger .error (f"Failed to load configuration: { str (e )} " )
52+ raise HTTPException (status_code = HTTPStatus .BAD_REQUEST , detail = "Failed to load configuration." )
0 commit comments