botrun-flow-lang 5.10.82__py3-none-any.whl → 5.10.83__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. botrun_flow_lang/api/auth_api.py +39 -39
  2. botrun_flow_lang/api/auth_utils.py +183 -183
  3. botrun_flow_lang/api/botrun_back_api.py +65 -65
  4. botrun_flow_lang/api/flow_api.py +3 -3
  5. botrun_flow_lang/api/hatch_api.py +481 -481
  6. botrun_flow_lang/api/langgraph_api.py +796 -796
  7. botrun_flow_lang/api/line_bot_api.py +1357 -1357
  8. botrun_flow_lang/api/model_api.py +300 -300
  9. botrun_flow_lang/api/rate_limit_api.py +32 -32
  10. botrun_flow_lang/api/routes.py +79 -79
  11. botrun_flow_lang/api/search_api.py +53 -53
  12. botrun_flow_lang/api/storage_api.py +316 -316
  13. botrun_flow_lang/api/subsidy_api.py +290 -290
  14. botrun_flow_lang/api/subsidy_api_system_prompt.txt +109 -109
  15. botrun_flow_lang/api/user_setting_api.py +70 -70
  16. botrun_flow_lang/api/version_api.py +31 -31
  17. botrun_flow_lang/api/youtube_api.py +26 -26
  18. botrun_flow_lang/constants.py +13 -13
  19. botrun_flow_lang/langgraph_agents/agents/agent_runner.py +174 -174
  20. botrun_flow_lang/langgraph_agents/agents/agent_tools/step_planner.py +77 -77
  21. botrun_flow_lang/langgraph_agents/agents/checkpointer/firestore_checkpointer.py +666 -666
  22. botrun_flow_lang/langgraph_agents/agents/gov_researcher/GOV_RESEARCHER_PRD.md +192 -192
  23. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gov_researcher_2_graph.py +1002 -1002
  24. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gov_researcher_graph.py +822 -822
  25. botrun_flow_lang/langgraph_agents/agents/langgraph_react_agent.py +591 -548
  26. botrun_flow_lang/langgraph_agents/agents/search_agent_graph.py +864 -864
  27. botrun_flow_lang/langgraph_agents/agents/tools/__init__.py +4 -4
  28. botrun_flow_lang/langgraph_agents/agents/tools/gemini_code_execution.py +376 -376
  29. botrun_flow_lang/langgraph_agents/agents/util/gemini_grounding.py +66 -66
  30. botrun_flow_lang/langgraph_agents/agents/util/html_util.py +316 -316
  31. botrun_flow_lang/langgraph_agents/agents/util/img_util.py +294 -294
  32. botrun_flow_lang/langgraph_agents/agents/util/local_files.py +345 -345
  33. botrun_flow_lang/langgraph_agents/agents/util/mermaid_util.py +86 -86
  34. botrun_flow_lang/langgraph_agents/agents/util/model_utils.py +143 -143
  35. botrun_flow_lang/langgraph_agents/agents/util/pdf_analyzer.py +160 -160
  36. botrun_flow_lang/langgraph_agents/agents/util/perplexity_search.py +464 -464
  37. botrun_flow_lang/langgraph_agents/agents/util/plotly_util.py +59 -59
  38. botrun_flow_lang/langgraph_agents/agents/util/tavily_search.py +199 -199
  39. botrun_flow_lang/langgraph_agents/agents/util/youtube_util.py +90 -90
  40. botrun_flow_lang/langgraph_agents/cache/langgraph_botrun_cache.py +197 -197
  41. botrun_flow_lang/llm_agent/llm_agent.py +19 -19
  42. botrun_flow_lang/llm_agent/llm_agent_util.py +83 -83
  43. botrun_flow_lang/log/.gitignore +2 -2
  44. botrun_flow_lang/main.py +61 -61
  45. botrun_flow_lang/main_fast.py +51 -51
  46. botrun_flow_lang/mcp_server/__init__.py +10 -10
  47. botrun_flow_lang/mcp_server/default_mcp.py +711 -711
  48. botrun_flow_lang/models/nodes/utils.py +205 -205
  49. botrun_flow_lang/models/token_usage.py +34 -34
  50. botrun_flow_lang/requirements.txt +21 -21
  51. botrun_flow_lang/services/base/firestore_base.py +30 -30
  52. botrun_flow_lang/services/hatch/hatch_factory.py +11 -11
  53. botrun_flow_lang/services/hatch/hatch_fs_store.py +372 -372
  54. botrun_flow_lang/services/storage/storage_cs_store.py +202 -202
  55. botrun_flow_lang/services/storage/storage_factory.py +12 -12
  56. botrun_flow_lang/services/storage/storage_store.py +65 -65
  57. botrun_flow_lang/services/user_setting/user_setting_factory.py +9 -9
  58. botrun_flow_lang/services/user_setting/user_setting_fs_store.py +66 -66
  59. botrun_flow_lang/static/docs/tools/index.html +926 -926
  60. botrun_flow_lang/tests/api_functional_tests.py +1525 -1525
  61. botrun_flow_lang/tests/api_stress_test.py +357 -357
  62. botrun_flow_lang/tests/shared_hatch_tests.py +333 -333
  63. botrun_flow_lang/tests/test_botrun_app.py +46 -46
  64. botrun_flow_lang/tests/test_html_util.py +31 -31
  65. botrun_flow_lang/tests/test_img_analyzer.py +190 -190
  66. botrun_flow_lang/tests/test_img_util.py +39 -39
  67. botrun_flow_lang/tests/test_local_files.py +114 -114
  68. botrun_flow_lang/tests/test_mermaid_util.py +103 -103
  69. botrun_flow_lang/tests/test_pdf_analyzer.py +104 -104
  70. botrun_flow_lang/tests/test_plotly_util.py +151 -151
  71. botrun_flow_lang/tests/test_run_workflow_engine.py +65 -65
  72. botrun_flow_lang/tools/generate_docs.py +133 -133
  73. botrun_flow_lang/tools/templates/tools.html +153 -153
  74. botrun_flow_lang/utils/__init__.py +7 -7
  75. botrun_flow_lang/utils/botrun_logger.py +344 -344
  76. botrun_flow_lang/utils/clients/rate_limit_client.py +209 -209
  77. botrun_flow_lang/utils/clients/token_verify_client.py +153 -153
  78. botrun_flow_lang/utils/google_drive_utils.py +654 -654
  79. botrun_flow_lang/utils/langchain_utils.py +324 -324
  80. botrun_flow_lang/utils/yaml_utils.py +9 -9
  81. {botrun_flow_lang-5.10.82.dist-info → botrun_flow_lang-5.10.83.dist-info}/METADATA +3 -2
  82. botrun_flow_lang-5.10.83.dist-info/RECORD +99 -0
  83. botrun_flow_lang-5.10.82.dist-info/RECORD +0 -99
  84. {botrun_flow_lang-5.10.82.dist-info → botrun_flow_lang-5.10.83.dist-info}/WHEEL +0 -0
@@ -1,300 +1,300 @@
1
- import os
2
- import pandas as pd
3
- from fastapi import APIRouter, HTTPException
4
- from pydantic import BaseModel
5
- from typing import List, Optional
6
- from google.oauth2 import service_account
7
- from googleapiclient.discovery import build
8
-
9
- router = APIRouter()
10
-
11
-
12
- class ModelInfo(BaseModel):
13
- """Model information structure"""
14
-
15
- display_name: str
16
- model_name: str
17
- provider: str
18
-
19
-
20
- class ModelsResponse(BaseModel):
21
- """Response model for listing supported models"""
22
-
23
- models: List[ModelInfo]
24
- total_count: int
25
-
26
-
27
- class AgentModelsResponse(BaseModel):
28
- """Response model for listing supported agent models"""
29
-
30
- models: List[str]
31
- total_count: int
32
-
33
-
34
- def read_google_sheet(
35
- credentials_path: str, spreadsheet_id: str, sheet_name: str
36
- ) -> pd.DataFrame:
37
- """
38
- 讀取 Google Spreadsheet 指定 sheet,回傳 pandas DataFrame。
39
- """
40
- try:
41
- scopes = ["https://www.googleapis.com/auth/spreadsheets.readonly"]
42
- credentials = service_account.Credentials.from_service_account_file(
43
- credentials_path, scopes=scopes
44
- )
45
- service = build("sheets", "v4", credentials=credentials)
46
- sheet = service.spreadsheets()
47
- result = (
48
- sheet.values().get(spreadsheetId=spreadsheet_id, range=sheet_name).execute()
49
- )
50
- values = result.get("values", [])
51
- if not values:
52
- return pd.DataFrame()
53
- # 第一列為欄位名稱
54
- df = pd.DataFrame(values[1:], columns=values[0])
55
- return df
56
- except Exception:
57
- import traceback
58
-
59
- traceback.print_exc()
60
- return pd.DataFrame()
61
-
62
-
63
- def get_models_from_google_sheet() -> List[ModelInfo]:
64
- """
65
- 從 Google Sheets 讀取模型列表
66
- 優先順序:ENV_NAME sheet -> default sheet -> DEFAULT_SUPPORTED_MODELS
67
- """
68
- credentials_path = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_FOR_MODELS_SHEET")
69
- spreadsheet_id = os.getenv("MODELS_GSPREAD_ID")
70
- env_name = os.getenv("ENV_NAME", "")
71
-
72
- if not credentials_path or not spreadsheet_id:
73
- return DEFAULT_SUPPORTED_MODELS
74
-
75
- # 首先嘗試使用 ENV_NAME 作為 sheet_name
76
- if env_name:
77
- df = read_google_sheet(credentials_path, spreadsheet_id, env_name)
78
- if not df.empty and all(
79
- col in df.columns for col in ["display_name", "model_name", "provider"]
80
- ):
81
- try:
82
- return [
83
- ModelInfo(
84
- display_name=row["display_name"],
85
- model_name=row["model_name"],
86
- provider=row["provider"],
87
- )
88
- for _, row in df.iterrows()
89
- ]
90
- except Exception:
91
- pass
92
-
93
- # 如果 ENV_NAME sheet 找不到或有問題,嘗試 default sheet
94
- df = read_google_sheet(credentials_path, spreadsheet_id, "default")
95
- if not df.empty and all(
96
- col in df.columns for col in ["display_name", "model_name", "provider"]
97
- ):
98
- try:
99
- return [
100
- ModelInfo(
101
- display_name=row["display_name"],
102
- model_name=row["model_name"],
103
- provider=row["provider"],
104
- )
105
- for _, row in df.iterrows()
106
- ]
107
- except Exception:
108
- pass
109
-
110
- # 如果都失敗,回退到 DEFAULT_SUPPORTED_MODELS
111
- return DEFAULT_SUPPORTED_MODELS
112
-
113
-
114
- def get_agent_models_from_google_sheet() -> List[str]:
115
- """
116
- 從 Google Sheets 讀取 agent 模型列表
117
- 優先順序:ENV_NAME-agents sheet -> default-agents sheet -> DEFAULT_AGENT_MODELS
118
- """
119
- credentials_path = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_FOR_MODELS_SHEET")
120
- spreadsheet_id = os.getenv("MODELS_GSPREAD_ID")
121
- env_name = os.getenv("ENV_NAME", "")
122
-
123
- if not credentials_path or not spreadsheet_id:
124
- return DEFAULT_AGENT_MODELS
125
-
126
- # 首先嘗試使用 ENV_NAME-agents 作為 sheet_name
127
- if env_name:
128
- sheet_name = f"{env_name}-agents"
129
- df = read_google_sheet(credentials_path, spreadsheet_id, sheet_name)
130
- if not df.empty and "model_name" in df.columns:
131
- try:
132
- return [
133
- row["model_name"] for _, row in df.iterrows() if row["model_name"]
134
- ]
135
- except Exception:
136
- pass
137
-
138
- # 如果 ENV_NAME-agents sheet 找不到或有問題,嘗試 default-agents sheet
139
- df = read_google_sheet(credentials_path, spreadsheet_id, "default-agents")
140
- if not df.empty and "model_name" in df.columns:
141
- try:
142
- return [row["model_name"] for _, row in df.iterrows() if row["model_name"]]
143
- except Exception:
144
- pass
145
-
146
- # 如果都失敗,回退到 DEFAULT_AGENT_MODELS
147
- return DEFAULT_AGENT_MODELS
148
-
149
-
150
- # 定義支援的 LLM models
151
- DEFAULT_SUPPORTED_MODELS = [
152
- ModelInfo(
153
- display_name="gemini-2.5-flash",
154
- model_name="gemini-2.5-flash",
155
- provider="gemini",
156
- ),
157
- ModelInfo(
158
- display_name="claude-sonnet-4-5-20250929",
159
- model_name="claude-sonnet-4-5-20250929",
160
- provider="anthropic",
161
- ),
162
- ModelInfo(
163
- display_name="gemini-2.5-pro",
164
- model_name="gemini-2.5-pro",
165
- provider="gemini",
166
- ),
167
- ModelInfo(
168
- display_name="gpt-4.1-2025-04-14",
169
- model_name="gpt-4.1-2025-04-14",
170
- provider="openai",
171
- ),
172
- ModelInfo(
173
- display_name="o4-mini-2025-04-16",
174
- model_name="o4-mini-2025-04-16",
175
- provider="openai",
176
- ),
177
- ModelInfo(
178
- display_name="claude-3-5-haiku-latest",
179
- model_name="claude-3-5-haiku-latest",
180
- provider="anthropic",
181
- ),
182
- ModelInfo(display_name="gpt-4o-mini", model_name="gpt-4o-mini", provider="openai"),
183
- ModelInfo(
184
- display_name="gpt-4o-2024-08-06",
185
- model_name="gpt-4o-2024-08-06",
186
- provider="openai",
187
- ),
188
- ModelInfo(
189
- display_name="Meta-Llama-3.1-8B-Instruct",
190
- model_name="meta-llama/Meta-Llama-3.1-8B-Instruct",
191
- provider="deepinfra",
192
- ),
193
- ModelInfo(
194
- display_name="Meta-Llama-3.1-70B-Instruct-Turbo",
195
- model_name="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
196
- provider="deepinfra",
197
- ),
198
- ModelInfo(
199
- display_name="Meta-Llama-3.1-405B-Instruct-Turbo",
200
- model_name="meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo",
201
- provider="together_ai",
202
- ),
203
- ModelInfo(
204
- display_name="Llama-3.1-Nemotron-70B-Instruct",
205
- model_name="nvidia/Llama-3.1-Nemotron-70B-Instruct",
206
- provider="deepinfra",
207
- ),
208
- ModelInfo(
209
- display_name="Llama-3.2-11B-Vision-Instruct-Turbo",
210
- model_name="meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo",
211
- provider="together_ai",
212
- ),
213
- ModelInfo(
214
- display_name="Llama-3.2-90B-Vision-Instruct-Turbo",
215
- model_name="meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo",
216
- provider="together_ai",
217
- ),
218
- ModelInfo(
219
- display_name="gemma-2-9b-it",
220
- model_name="google/gemma-2-9b-it",
221
- provider="deepinfra",
222
- ),
223
- ModelInfo(
224
- display_name="gemma-2-27b-it",
225
- model_name="google/gemma-2-27b-it",
226
- provider="deepinfra",
227
- ),
228
- ModelInfo(
229
- display_name="Mixtral-8x7B-Instruct-v0.1",
230
- model_name="mistralai/Mixtral-8x7B-Instruct-v0.1",
231
- provider="deepinfra",
232
- ),
233
- ModelInfo(
234
- display_name="Mixtral-8x22B-Instruct-v0.1",
235
- model_name="mistralai/Mixtral-8x22B-Instruct-v0.1",
236
- provider="deepinfra",
237
- ),
238
- ModelInfo(
239
- display_name="WizardLM-2-8x22B",
240
- model_name="microsoft/WizardLM-2-8x22B",
241
- provider="deepinfra",
242
- ),
243
- ModelInfo(
244
- display_name="Meta-Llama-Guard-3-8B",
245
- model_name="meta-llama/Meta-Llama-Guard-3-8B",
246
- provider="together_ai",
247
- ),
248
- ModelInfo(display_name="o1-mini", model_name="o1-mini", provider="openai"),
249
- ModelInfo(display_name="o1-preview", model_name="o1-preview", provider="openai"),
250
- ]
251
-
252
- # 定義支援 agent 的 LLM models
253
- DEFAULT_AGENT_MODELS = [
254
- "claude-sonnet-4-5-20250929",
255
- "gemini-2.5-pro",
256
- "gemini-2.5-flash",
257
- ]
258
-
259
-
260
- @router.get("/models", response_model=ModelsResponse)
261
- async def list_models():
262
- """
263
- 列出所有支援的 LLM models
264
- 優先從 Google Sheets 讀取,回退到預設列表
265
-
266
- Args:
267
- provider: 可選的提供商篩選 (openai, anthropic, google, perplexity, etc.)
268
-
269
- Returns:
270
- ModelsResponse: 包含 models 清單和總數
271
- """
272
- try:
273
- # 從 Google Sheets 或預設列表獲取模型
274
- all_models = get_models_from_google_sheet()
275
-
276
- return ModelsResponse(models=all_models, total_count=len(all_models))
277
- except Exception as e:
278
- raise HTTPException(
279
- status_code=500, detail=f"Failed to retrieve models: {str(e)}"
280
- )
281
-
282
-
283
- @router.get("/models/agent-models", response_model=AgentModelsResponse)
284
- async def list_agent_models():
285
- """
286
- 列出所有支援的 agent models
287
- 優先從 Google Sheets 讀取,回退到預設列表
288
-
289
- Returns:
290
- AgentModelsResponse: 包含 models 清單和總數
291
- """
292
- try:
293
- # 從 Google Sheets 或預設列表獲取模型
294
- all_models = get_agent_models_from_google_sheet()
295
-
296
- return AgentModelsResponse(models=all_models, total_count=len(all_models))
297
- except Exception as e:
298
- raise HTTPException(
299
- status_code=500, detail=f"Failed to retrieve agent models: {str(e)}"
300
- )
1
+ import os
2
+ import pandas as pd
3
+ from fastapi import APIRouter, HTTPException
4
+ from pydantic import BaseModel
5
+ from typing import List, Optional
6
+ from google.oauth2 import service_account
7
+ from googleapiclient.discovery import build
8
+
9
+ router = APIRouter()
10
+
11
+
12
+ class ModelInfo(BaseModel):
13
+ """Model information structure"""
14
+
15
+ display_name: str
16
+ model_name: str
17
+ provider: str
18
+
19
+
20
+ class ModelsResponse(BaseModel):
21
+ """Response model for listing supported models"""
22
+
23
+ models: List[ModelInfo]
24
+ total_count: int
25
+
26
+
27
+ class AgentModelsResponse(BaseModel):
28
+ """Response model for listing supported agent models"""
29
+
30
+ models: List[str]
31
+ total_count: int
32
+
33
+
34
+ def read_google_sheet(
35
+ credentials_path: str, spreadsheet_id: str, sheet_name: str
36
+ ) -> pd.DataFrame:
37
+ """
38
+ 讀取 Google Spreadsheet 指定 sheet,回傳 pandas DataFrame。
39
+ """
40
+ try:
41
+ scopes = ["https://www.googleapis.com/auth/spreadsheets.readonly"]
42
+ credentials = service_account.Credentials.from_service_account_file(
43
+ credentials_path, scopes=scopes
44
+ )
45
+ service = build("sheets", "v4", credentials=credentials)
46
+ sheet = service.spreadsheets()
47
+ result = (
48
+ sheet.values().get(spreadsheetId=spreadsheet_id, range=sheet_name).execute()
49
+ )
50
+ values = result.get("values", [])
51
+ if not values:
52
+ return pd.DataFrame()
53
+ # 第一列為欄位名稱
54
+ df = pd.DataFrame(values[1:], columns=values[0])
55
+ return df
56
+ except Exception:
57
+ import traceback
58
+
59
+ traceback.print_exc()
60
+ return pd.DataFrame()
61
+
62
+
63
+ def get_models_from_google_sheet() -> List[ModelInfo]:
64
+ """
65
+ 從 Google Sheets 讀取模型列表
66
+ 優先順序:ENV_NAME sheet -> default sheet -> DEFAULT_SUPPORTED_MODELS
67
+ """
68
+ credentials_path = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_FOR_MODELS_SHEET")
69
+ spreadsheet_id = os.getenv("MODELS_GSPREAD_ID")
70
+ env_name = os.getenv("ENV_NAME", "")
71
+
72
+ if not credentials_path or not spreadsheet_id:
73
+ return DEFAULT_SUPPORTED_MODELS
74
+
75
+ # 首先嘗試使用 ENV_NAME 作為 sheet_name
76
+ if env_name:
77
+ df = read_google_sheet(credentials_path, spreadsheet_id, env_name)
78
+ if not df.empty and all(
79
+ col in df.columns for col in ["display_name", "model_name", "provider"]
80
+ ):
81
+ try:
82
+ return [
83
+ ModelInfo(
84
+ display_name=row["display_name"],
85
+ model_name=row["model_name"],
86
+ provider=row["provider"],
87
+ )
88
+ for _, row in df.iterrows()
89
+ ]
90
+ except Exception:
91
+ pass
92
+
93
+ # 如果 ENV_NAME sheet 找不到或有問題,嘗試 default sheet
94
+ df = read_google_sheet(credentials_path, spreadsheet_id, "default")
95
+ if not df.empty and all(
96
+ col in df.columns for col in ["display_name", "model_name", "provider"]
97
+ ):
98
+ try:
99
+ return [
100
+ ModelInfo(
101
+ display_name=row["display_name"],
102
+ model_name=row["model_name"],
103
+ provider=row["provider"],
104
+ )
105
+ for _, row in df.iterrows()
106
+ ]
107
+ except Exception:
108
+ pass
109
+
110
+ # 如果都失敗,回退到 DEFAULT_SUPPORTED_MODELS
111
+ return DEFAULT_SUPPORTED_MODELS
112
+
113
+
114
+ def get_agent_models_from_google_sheet() -> List[str]:
115
+ """
116
+ 從 Google Sheets 讀取 agent 模型列表
117
+ 優先順序:ENV_NAME-agents sheet -> default-agents sheet -> DEFAULT_AGENT_MODELS
118
+ """
119
+ credentials_path = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_FOR_MODELS_SHEET")
120
+ spreadsheet_id = os.getenv("MODELS_GSPREAD_ID")
121
+ env_name = os.getenv("ENV_NAME", "")
122
+
123
+ if not credentials_path or not spreadsheet_id:
124
+ return DEFAULT_AGENT_MODELS
125
+
126
+ # 首先嘗試使用 ENV_NAME-agents 作為 sheet_name
127
+ if env_name:
128
+ sheet_name = f"{env_name}-agents"
129
+ df = read_google_sheet(credentials_path, spreadsheet_id, sheet_name)
130
+ if not df.empty and "model_name" in df.columns:
131
+ try:
132
+ return [
133
+ row["model_name"] for _, row in df.iterrows() if row["model_name"]
134
+ ]
135
+ except Exception:
136
+ pass
137
+
138
+ # 如果 ENV_NAME-agents sheet 找不到或有問題,嘗試 default-agents sheet
139
+ df = read_google_sheet(credentials_path, spreadsheet_id, "default-agents")
140
+ if not df.empty and "model_name" in df.columns:
141
+ try:
142
+ return [row["model_name"] for _, row in df.iterrows() if row["model_name"]]
143
+ except Exception:
144
+ pass
145
+
146
+ # 如果都失敗,回退到 DEFAULT_AGENT_MODELS
147
+ return DEFAULT_AGENT_MODELS
148
+
149
+
150
+ # 定義支援的 LLM models
151
+ DEFAULT_SUPPORTED_MODELS = [
152
+ ModelInfo(
153
+ display_name="gemini-2.5-flash",
154
+ model_name="gemini-2.5-flash",
155
+ provider="gemini",
156
+ ),
157
+ ModelInfo(
158
+ display_name="claude-sonnet-4-5-20250929",
159
+ model_name="claude-sonnet-4-5-20250929",
160
+ provider="anthropic",
161
+ ),
162
+ ModelInfo(
163
+ display_name="gemini-2.5-pro",
164
+ model_name="gemini-2.5-pro",
165
+ provider="gemini",
166
+ ),
167
+ ModelInfo(
168
+ display_name="gpt-4.1-2025-04-14",
169
+ model_name="gpt-4.1-2025-04-14",
170
+ provider="openai",
171
+ ),
172
+ ModelInfo(
173
+ display_name="o4-mini-2025-04-16",
174
+ model_name="o4-mini-2025-04-16",
175
+ provider="openai",
176
+ ),
177
+ ModelInfo(
178
+ display_name="claude-3-5-haiku-latest",
179
+ model_name="claude-3-5-haiku-latest",
180
+ provider="anthropic",
181
+ ),
182
+ ModelInfo(display_name="gpt-4o-mini", model_name="gpt-4o-mini", provider="openai"),
183
+ ModelInfo(
184
+ display_name="gpt-4o-2024-08-06",
185
+ model_name="gpt-4o-2024-08-06",
186
+ provider="openai",
187
+ ),
188
+ ModelInfo(
189
+ display_name="Meta-Llama-3.1-8B-Instruct",
190
+ model_name="meta-llama/Meta-Llama-3.1-8B-Instruct",
191
+ provider="deepinfra",
192
+ ),
193
+ ModelInfo(
194
+ display_name="Meta-Llama-3.1-70B-Instruct-Turbo",
195
+ model_name="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
196
+ provider="deepinfra",
197
+ ),
198
+ ModelInfo(
199
+ display_name="Meta-Llama-3.1-405B-Instruct-Turbo",
200
+ model_name="meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo",
201
+ provider="together_ai",
202
+ ),
203
+ ModelInfo(
204
+ display_name="Llama-3.1-Nemotron-70B-Instruct",
205
+ model_name="nvidia/Llama-3.1-Nemotron-70B-Instruct",
206
+ provider="deepinfra",
207
+ ),
208
+ ModelInfo(
209
+ display_name="Llama-3.2-11B-Vision-Instruct-Turbo",
210
+ model_name="meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo",
211
+ provider="together_ai",
212
+ ),
213
+ ModelInfo(
214
+ display_name="Llama-3.2-90B-Vision-Instruct-Turbo",
215
+ model_name="meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo",
216
+ provider="together_ai",
217
+ ),
218
+ ModelInfo(
219
+ display_name="gemma-2-9b-it",
220
+ model_name="google/gemma-2-9b-it",
221
+ provider="deepinfra",
222
+ ),
223
+ ModelInfo(
224
+ display_name="gemma-2-27b-it",
225
+ model_name="google/gemma-2-27b-it",
226
+ provider="deepinfra",
227
+ ),
228
+ ModelInfo(
229
+ display_name="Mixtral-8x7B-Instruct-v0.1",
230
+ model_name="mistralai/Mixtral-8x7B-Instruct-v0.1",
231
+ provider="deepinfra",
232
+ ),
233
+ ModelInfo(
234
+ display_name="Mixtral-8x22B-Instruct-v0.1",
235
+ model_name="mistralai/Mixtral-8x22B-Instruct-v0.1",
236
+ provider="deepinfra",
237
+ ),
238
+ ModelInfo(
239
+ display_name="WizardLM-2-8x22B",
240
+ model_name="microsoft/WizardLM-2-8x22B",
241
+ provider="deepinfra",
242
+ ),
243
+ ModelInfo(
244
+ display_name="Meta-Llama-Guard-3-8B",
245
+ model_name="meta-llama/Meta-Llama-Guard-3-8B",
246
+ provider="together_ai",
247
+ ),
248
+ ModelInfo(display_name="o1-mini", model_name="o1-mini", provider="openai"),
249
+ ModelInfo(display_name="o1-preview", model_name="o1-preview", provider="openai"),
250
+ ]
251
+
252
+ # 定義支援 agent 的 LLM models
253
+ DEFAULT_AGENT_MODELS = [
254
+ "claude-sonnet-4-5-20250929",
255
+ "gemini-2.5-pro",
256
+ "gemini-2.5-flash",
257
+ ]
258
+
259
+
260
+ @router.get("/models", response_model=ModelsResponse)
261
+ async def list_models():
262
+ """
263
+ 列出所有支援的 LLM models
264
+ 優先從 Google Sheets 讀取,回退到預設列表
265
+
266
+ Args:
267
+ provider: 可選的提供商篩選 (openai, anthropic, google, perplexity, etc.)
268
+
269
+ Returns:
270
+ ModelsResponse: 包含 models 清單和總數
271
+ """
272
+ try:
273
+ # 從 Google Sheets 或預設列表獲取模型
274
+ all_models = get_models_from_google_sheet()
275
+
276
+ return ModelsResponse(models=all_models, total_count=len(all_models))
277
+ except Exception as e:
278
+ raise HTTPException(
279
+ status_code=500, detail=f"Failed to retrieve models: {str(e)}"
280
+ )
281
+
282
+
283
+ @router.get("/models/agent-models", response_model=AgentModelsResponse)
284
+ async def list_agent_models():
285
+ """
286
+ 列出所有支援的 agent models
287
+ 優先從 Google Sheets 讀取,回退到預設列表
288
+
289
+ Returns:
290
+ AgentModelsResponse: 包含 models 清單和總數
291
+ """
292
+ try:
293
+ # 從 Google Sheets 或預設列表獲取模型
294
+ all_models = get_agent_models_from_google_sheet()
295
+
296
+ return AgentModelsResponse(models=all_models, total_count=len(all_models))
297
+ except Exception as e:
298
+ raise HTTPException(
299
+ status_code=500, detail=f"Failed to retrieve agent models: {str(e)}"
300
+ )
@@ -1,32 +1,32 @@
1
- from fastapi import APIRouter, HTTPException
2
- from typing import Dict, Any
3
-
4
- from botrun_flow_lang.utils.clients.rate_limit_client import RateLimitClient
5
-
6
- router = APIRouter(prefix="/rate_limit")
7
-
8
-
9
- @router.get("/{username}")
10
- async def get_user_rate_limit(username: str) -> Dict[Any, Any]:
11
- """
12
- 獲取指定用戶的 rate limit 信息。
13
-
14
- Args:
15
- username: 用戶名
16
-
17
- Returns:
18
- 包含用戶 rate limit 信息的字典
19
-
20
- Raises:
21
- HTTPException: 當用戶不存在或後端 API 無法訪問時
22
- """
23
- try:
24
- client = RateLimitClient()
25
- result = await client.get_rate_limit(username)
26
- return result
27
- except ValueError as e:
28
- # 使用者不存在時會回傳 404
29
- if "User not found" in str(e):
30
- raise HTTPException(status_code=404, detail=f"User not found: {username}")
31
- # 其他錯誤回傳 500
32
- raise HTTPException(status_code=500, detail=str(e))
1
+ from fastapi import APIRouter, HTTPException
2
+ from typing import Dict, Any
3
+
4
+ from botrun_flow_lang.utils.clients.rate_limit_client import RateLimitClient
5
+
6
+ router = APIRouter(prefix="/rate_limit")
7
+
8
+
9
+ @router.get("/{username}")
10
+ async def get_user_rate_limit(username: str) -> Dict[Any, Any]:
11
+ """
12
+ 獲取指定用戶的 rate limit 信息。
13
+
14
+ Args:
15
+ username: 用戶名
16
+
17
+ Returns:
18
+ 包含用戶 rate limit 信息的字典
19
+
20
+ Raises:
21
+ HTTPException: 當用戶不存在或後端 API 無法訪問時
22
+ """
23
+ try:
24
+ client = RateLimitClient()
25
+ result = await client.get_rate_limit(username)
26
+ return result
27
+ except ValueError as e:
28
+ # 使用者不存在時會回傳 404
29
+ if "User not found" in str(e):
30
+ raise HTTPException(status_code=404, detail=f"User not found: {username}")
31
+ # 其他錯誤回傳 500
32
+ raise HTTPException(status_code=500, detail=str(e))