CatPtain commited on
Commit
8dd0381
·
verified ·
1 Parent(s): 7254052

Upload 68 files

Browse files
app/config/__pycache__/config.cpython-311.pyc ADDED
Binary file (29.8 kB). View file
 
app/config/config.py CHANGED
@@ -10,6 +10,41 @@ from pydantic import ValidationError, ValidationInfo, field_validator
10
  from pydantic_settings import BaseSettings
11
  from sqlalchemy import insert, select, update
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  from app.core.constants import (
14
  API_VERSION,
15
  DEFAULT_CREATE_IMAGE_MODEL,
@@ -29,7 +64,7 @@ from app.log.logger import Logger
29
 
30
  class Settings(BaseSettings):
31
  # 数据库配置
32
- DATABASE_TYPE: str = "mysql" # sqlite 或 mysql
33
  SQLITE_DATABASE: str = "default_db"
34
  MYSQL_HOST: str = ""
35
  MYSQL_PORT: int = 3306
@@ -51,8 +86,25 @@ class Settings(BaseSettings):
51
  return v
52
 
53
  # API相关配置
54
- API_KEYS: List[str]
55
- ALLOWED_TOKENS: List[str]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  BASE_URL: str = f"https://generativelanguage.googleapis.com/{API_VERSION}"
57
  AUTH_TOKEN: str = ""
58
  MAX_FAILURES: int = 3
@@ -72,6 +124,13 @@ class Settings(BaseSettings):
72
  IMAGE_MODELS: List[str] = ["gemini-2.0-flash-exp"]
73
  FILTERED_MODELS: List[str] = DEFAULT_FILTER_MODELS
74
  TOOLS_CODE_EXECUTION_ENABLED: bool = False
 
 
 
 
 
 
 
75
  SHOW_SEARCH_LINK: bool = True
76
  SHOW_THINKING_PROCESS: bool = True
77
  THINKING_MODELS: List[str] = []
@@ -90,7 +149,6 @@ class Settings(BaseSettings):
90
  PICGO_API_KEY: str = ""
91
  CLOUDFLARE_IMGBED_URL: str = ""
92
  CLOUDFLARE_IMGBED_AUTH_CODE: str = ""
93
- CLOUDFLARE_IMGBED_UPLOAD_FOLDER: str = ""
94
 
95
  # 流式输出优化器配置
96
  STREAM_OPTIMIZER_ENABLED: bool = False
@@ -125,12 +183,18 @@ class Settings(BaseSettings):
125
  super().__init__(**kwargs)
126
  # 设置默认AUTH_TOKEN(如果未提供)
127
  if not self.AUTH_TOKEN and self.ALLOWED_TOKENS:
128
- self.AUTH_TOKEN = self.ALLOWED_TOKENS[0]
 
 
129
 
130
 
131
  # 创建全局配置实例
132
  settings = Settings()
133
 
 
 
 
 
134
 
135
  def _parse_db_value(key: str, db_value: str, target_type: Type) -> Any:
136
  """尝试将数据库字符串值解析为目标 Python 类型"""
@@ -477,4 +541,4 @@ async def sync_initial_settings():
477
  except Exception as e:
478
  logger.error(f"Error disconnecting database after initial sync: {e}")
479
 
480
- logger.info("Initial settings synchronization finished.")
 
10
  from pydantic_settings import BaseSettings
11
  from sqlalchemy import insert, select, update
12
 
13
+
14
+ def parse_comma_separated_string(v: Any) -> List[str]:
15
+ """解析逗号分隔的字符串为字符串列表"""
16
+ # Handle None or empty values
17
+ if v is None or v == "":
18
+ return []
19
+
20
+ if isinstance(v, list):
21
+ return [str(item).strip() for item in v if str(item).strip()]
22
+
23
+ if isinstance(v, str):
24
+ # Handle empty string or whitespace-only string
25
+ if not v.strip():
26
+ return []
27
+
28
+ try:
29
+ # Attempt to parse as JSON list first, in case it's provided as such
30
+ parsed = json.loads(v)
31
+ if isinstance(parsed, list):
32
+ return [str(item).strip() for item in parsed if str(item).strip()]
33
+ except json.JSONDecodeError:
34
+ pass # Not a JSON string, proceed to comma split
35
+
36
+ # Split by comma and filter out empty strings
37
+ return [token.strip() for token in v.split(',') if token.strip()]
38
+
39
+ # For any other type, try to convert to string and process
40
+ try:
41
+ str_val = str(v)
42
+ if not str_val or str_val.strip() == "":
43
+ return []
44
+ return [token.strip() for token in str_val.split(',') if token.strip()]
45
+ except Exception:
46
+ return []
47
+
48
  from app.core.constants import (
49
  API_VERSION,
50
  DEFAULT_CREATE_IMAGE_MODEL,
 
64
 
65
  class Settings(BaseSettings):
66
  # 数据库配置
67
+ DATABASE_TYPE: str = "sqlite" # sqlite 或 mysql
68
  SQLITE_DATABASE: str = "default_db"
69
  MYSQL_HOST: str = ""
70
  MYSQL_PORT: int = 3306
 
86
  return v
87
 
88
  # API相关配置
89
+ API_KEYS: str = ""
90
+ ALLOWED_TOKENS: str = ""
91
+
92
+ @field_validator("API_KEYS")
93
+ @classmethod
94
+ def validate_api_keys(cls, v: str) -> str:
95
+ if not v or v.strip() == "":
96
+ raise ValueError("API_KEYS cannot be empty. Please provide at least one API key.")
97
+ return v
98
+
99
+ @property
100
+ def api_keys_list(self) -> List[str]:
101
+ """将API_KEYS字符串转换为列表"""
102
+ return parse_comma_separated_string(self.API_KEYS)
103
+
104
+ @property
105
+ def allowed_tokens_list(self) -> List[str]:
106
+ """将ALLOWED_TOKENS字符串转换为列表"""
107
+ return parse_comma_separated_string(self.ALLOWED_TOKENS)
108
  BASE_URL: str = f"https://generativelanguage.googleapis.com/{API_VERSION}"
109
  AUTH_TOKEN: str = ""
110
  MAX_FAILURES: int = 3
 
124
  IMAGE_MODELS: List[str] = ["gemini-2.0-flash-exp"]
125
  FILTERED_MODELS: List[str] = DEFAULT_FILTER_MODELS
126
  TOOLS_CODE_EXECUTION_ENABLED: bool = False
127
+
128
+ @field_validator("TOOLS_CODE_EXECUTION_ENABLED", mode="before")
129
+ @classmethod
130
+ def parse_boolean(cls, v: Any) -> bool:
131
+ if isinstance(v, str):
132
+ return v.lower() == "true"
133
+ return v
134
  SHOW_SEARCH_LINK: bool = True
135
  SHOW_THINKING_PROCESS: bool = True
136
  THINKING_MODELS: List[str] = []
 
149
  PICGO_API_KEY: str = ""
150
  CLOUDFLARE_IMGBED_URL: str = ""
151
  CLOUDFLARE_IMGBED_AUTH_CODE: str = ""
 
152
 
153
  # 流式输出优化器配置
154
  STREAM_OPTIMIZER_ENABLED: bool = False
 
183
  super().__init__(**kwargs)
184
  # 设置默认AUTH_TOKEN(如果未提供)
185
  if not self.AUTH_TOKEN and self.ALLOWED_TOKENS:
186
+ tokens_list = self.allowed_tokens_list
187
+ if tokens_list:
188
+ self.AUTH_TOKEN = tokens_list[0]
189
 
190
 
191
  # 创建全局配置实例
192
  settings = Settings()
193
 
194
+ def get_settings() -> Settings:
195
+ """获取配置实例"""
196
+ return settings
197
+
198
 
199
  def _parse_db_value(key: str, db_value: str, target_type: Type) -> Any:
200
  """尝试将数据库字符串值解析为目标 Python 类型"""
 
541
  except Exception as e:
542
  logger.error(f"Error disconnecting database after initial sync: {e}")
543
 
544
+ logger.info("Initial settings synchronization finished.")
app/core/__pycache__/constants.cpython-311.pyc ADDED
Binary file (2.19 kB). View file
 
app/core/application.py CHANGED
@@ -43,7 +43,7 @@ async def _setup_database_and_config(app_settings):
43
  logger.info("Database initialized successfully")
44
  await connect_to_db()
45
  await sync_initial_settings()
46
- await get_key_manager_instance(app_settings.API_KEYS, app_settings.VERTEX_API_KEYS)
47
  logger.info("Database, config sync, and KeyManager initialized successfully")
48
 
49
 
 
43
  logger.info("Database initialized successfully")
44
  await connect_to_db()
45
  await sync_initial_settings()
46
+ await get_key_manager_instance(app_settings.api_keys_list, app_settings.VERTEX_API_KEYS)
47
  logger.info("Database, config sync, and KeyManager initialized successfully")
48
 
49
 
app/core/security.py CHANGED
@@ -15,7 +15,7 @@ def verify_auth_token(token: str) -> bool:
15
  class SecurityService:
16
 
17
  async def verify_key(self, key: str):
18
- if key not in settings.ALLOWED_TOKENS and key != settings.AUTH_TOKEN:
19
  logger.error("Invalid key")
20
  raise HTTPException(status_code=401, detail="Invalid key")
21
  return key
@@ -34,7 +34,7 @@ class SecurityService:
34
  )
35
 
36
  token = authorization.replace("Bearer ", "")
37
- if token not in settings.ALLOWED_TOKENS and token != settings.AUTH_TOKEN:
38
  logger.error("Invalid token")
39
  raise HTTPException(status_code=401, detail="Invalid token")
40
 
@@ -49,7 +49,7 @@ class SecurityService:
49
  raise HTTPException(status_code=401, detail="Missing x-goog-api-key header")
50
 
51
  if (
52
- x_goog_api_key not in settings.ALLOWED_TOKENS
53
  and x_goog_api_key != settings.AUTH_TOKEN
54
  ):
55
  logger.error("Invalid x-goog-api-key")
@@ -75,7 +75,7 @@ class SecurityService:
75
  ) -> str:
76
  """验证URL中的key或请求头中的x-goog-api-key"""
77
  # 如果URL中的key有效,直接返回
78
- if key in settings.ALLOWED_TOKENS or key == settings.AUTH_TOKEN:
79
  return key
80
 
81
  # 否则检查请求头中的x-goog-api-key
@@ -83,7 +83,7 @@ class SecurityService:
83
  logger.error("Invalid key and missing x-goog-api-key header")
84
  raise HTTPException(status_code=401, detail="Invalid key and missing x-goog-api-key header")
85
 
86
- if x_goog_api_key not in settings.ALLOWED_TOKENS and x_goog_api_key != settings.AUTH_TOKEN:
87
  logger.error("Invalid key and invalid x-goog-api-key")
88
  raise HTTPException(status_code=401, detail="Invalid key and invalid x-goog-api-key")
89
 
 
15
  class SecurityService:
16
 
17
  async def verify_key(self, key: str):
18
+ if key not in settings.allowed_tokens_list and key != settings.AUTH_TOKEN:
19
  logger.error("Invalid key")
20
  raise HTTPException(status_code=401, detail="Invalid key")
21
  return key
 
34
  )
35
 
36
  token = authorization.replace("Bearer ", "")
37
+ if token not in settings.allowed_tokens_list and token != settings.AUTH_TOKEN:
38
  logger.error("Invalid token")
39
  raise HTTPException(status_code=401, detail="Invalid token")
40
 
 
49
  raise HTTPException(status_code=401, detail="Missing x-goog-api-key header")
50
 
51
  if (
52
+ x_goog_api_key not in settings.allowed_tokens_list
53
  and x_goog_api_key != settings.AUTH_TOKEN
54
  ):
55
  logger.error("Invalid x-goog-api-key")
 
75
  ) -> str:
76
  """验证URL中的key或请求头中的x-goog-api-key"""
77
  # 如果URL中的key有效,直接返回
78
+ if key in settings.allowed_tokens_list or key == settings.AUTH_TOKEN:
79
  return key
80
 
81
  # 否则检查请求头中的x-goog-api-key
 
83
  logger.error("Invalid key and missing x-goog-api-key header")
84
  raise HTTPException(status_code=401, detail="Invalid key and missing x-goog-api-key header")
85
 
86
+ if x_goog_api_key not in settings.allowed_tokens_list and x_goog_api_key != settings.AUTH_TOKEN:
87
  logger.error("Invalid key and invalid x-goog-api-key")
88
  raise HTTPException(status_code=401, detail="Invalid key and invalid x-goog-api-key")
89
 
app/log/__pycache__/logger.cpython-311.pyc ADDED
Binary file (10.7 kB). View file
 
app/service/config/config_service.py CHANGED
@@ -115,7 +115,7 @@ class ConfigService:
115
  # 重置并重新初始化 KeyManager
116
  try:
117
  await reset_key_manager_instance()
118
- await get_key_manager_instance(settings.API_KEYS, settings.VERTEX_API_KEYS)
119
  logger.info("KeyManager instance re-initialized with updated settings.")
120
  except Exception as e:
121
  logger.error(f"Failed to re-initialize KeyManager: {str(e)}")
@@ -125,17 +125,15 @@ class ConfigService:
125
  @staticmethod
126
  async def delete_key(key_to_delete: str) -> Dict[str, Any]:
127
  """删除单个API密钥"""
128
- # 确保 settings.API_KEYS 是一个列表
129
- if not isinstance(settings.API_KEYS, list):
130
- settings.API_KEYS = []
131
-
132
- original_keys_count = len(settings.API_KEYS)
133
  # 创建一个不包含待删除密钥的新列表
134
- updated_api_keys = [k for k in settings.API_KEYS if k != key_to_delete]
135
 
136
  if len(updated_api_keys) < original_keys_count:
137
- # 密钥已找到并从列表中移除
138
- settings.API_KEYS = updated_api_keys # 首先更新内存中的 settings
139
  # 使用 update_config 持久化更改,它同时处理数据库和 KeyManager
140
  await ConfigService.update_config({"API_KEYS": settings.API_KEYS})
141
  logger.info(f"密钥 '{key_to_delete}' 已成功删除。")
@@ -148,13 +146,10 @@ class ConfigService:
148
  @staticmethod
149
  async def delete_selected_keys(keys_to_delete: List[str]) -> Dict[str, Any]:
150
  """批量删除选定的API密钥"""
151
- if not isinstance(settings.API_KEYS, list):
152
- settings.API_KEYS = []
153
-
154
  deleted_count = 0
155
  not_found_keys: List[str] = []
156
-
157
- current_api_keys = list(settings.API_KEYS)
158
  keys_actually_removed: List[str] = []
159
 
160
  for key_to_del in keys_to_delete:
@@ -166,7 +161,8 @@ class ConfigService:
166
  not_found_keys.append(key_to_del)
167
 
168
  if deleted_count > 0:
169
- settings.API_KEYS = current_api_keys
 
170
  await ConfigService.update_config({"API_KEYS": settings.API_KEYS})
171
  logger.info(
172
  f"成功删除 {deleted_count} 个密钥。密钥: {keys_actually_removed}"
@@ -213,7 +209,7 @@ class ConfigService:
213
  try:
214
  await reset_key_manager_instance()
215
  # 确保使用更新后的 settings 中的 API_KEYS
216
- await get_key_manager_instance(settings.API_KEYS)
217
  logger.info("KeyManager instance re-initialized with reloaded settings.")
218
  except Exception as e:
219
  logger.error(f"Failed to re-initialize KeyManager during reset: {str(e)}")
 
115
  # 重置并重新初始化 KeyManager
116
  try:
117
  await reset_key_manager_instance()
118
+ await get_key_manager_instance(settings.api_keys_list, settings.VERTEX_API_KEYS)
119
  logger.info("KeyManager instance re-initialized with updated settings.")
120
  except Exception as e:
121
  logger.error(f"Failed to re-initialize KeyManager: {str(e)}")
 
125
  @staticmethod
126
  async def delete_key(key_to_delete: str) -> Dict[str, Any]:
127
  """删除单个API密钥"""
128
+ # 获取当前API密钥列表
129
+ current_api_keys = settings.api_keys_list
130
+ original_keys_count = len(current_api_keys)
 
 
131
  # 创建一个不包含待删除密钥的新列表
132
+ updated_api_keys = [k for k in current_api_keys if k != key_to_delete]
133
 
134
  if len(updated_api_keys) < original_keys_count:
135
+ # 密钥已找到并从列表中移除,更新为逗号分隔的字符串
136
+ settings.API_KEYS = ",".join(updated_api_keys)
137
  # 使用 update_config 持久化更改,它同时处理数据库和 KeyManager
138
  await ConfigService.update_config({"API_KEYS": settings.API_KEYS})
139
  logger.info(f"密钥 '{key_to_delete}' 已成功删除。")
 
146
  @staticmethod
147
  async def delete_selected_keys(keys_to_delete: List[str]) -> Dict[str, Any]:
148
  """批量删除选定的API密钥"""
149
+ # 获取当前API密钥列表
150
+ current_api_keys = settings.api_keys_list.copy()
 
151
  deleted_count = 0
152
  not_found_keys: List[str] = []
 
 
153
  keys_actually_removed: List[str] = []
154
 
155
  for key_to_del in keys_to_delete:
 
161
  not_found_keys.append(key_to_del)
162
 
163
  if deleted_count > 0:
164
+ # 更新为逗号分隔的字符串
165
+ settings.API_KEYS = ",".join(current_api_keys)
166
  await ConfigService.update_config({"API_KEYS": settings.API_KEYS})
167
  logger.info(
168
  f"成功删除 {deleted_count} 个密钥。密钥: {keys_actually_removed}"
 
209
  try:
210
  await reset_key_manager_instance()
211
  # 确保使用更新后的 settings 中的 API_KEYS
212
+ await get_key_manager_instance(settings.api_keys_list)
213
  logger.info("KeyManager instance re-initialized with reloaded settings.")
214
  except Exception as e:
215
  logger.error(f"Failed to re-initialize KeyManager during reset: {str(e)}")