auto-coder-web 0.1.37__py3-none-any.whl → 0.1.39__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.
@@ -1,10 +1,22 @@
1
- from fastapi import APIRouter, HTTPException
1
+ from fastapi import APIRouter, HTTPException, Request
2
2
  from typing import List, Dict, Optional
3
+ import json
4
+ import os
3
5
  from pydantic import BaseModel
4
6
  from autocoder import models as model_utils
5
7
 
6
8
  router = APIRouter()
7
9
 
10
+ async def get_project_path(request: Request):
11
+ """获取项目路径作为依赖"""
12
+ return request.app.state.project_path
13
+
14
+ # Path for providers JSON file
15
+ PROVIDERS_FILE = os.path.expanduser("~/.auto-coder/keys/models_providers.json")
16
+
17
+ # Ensure directory exists
18
+ os.makedirs(os.path.dirname(PROVIDERS_FILE), exist_ok=True)
19
+
8
20
  class Model(BaseModel):
9
21
  name: str
10
22
  description: str = ""
@@ -17,7 +29,7 @@ class Model(BaseModel):
17
29
  output_price: float = 0.0
18
30
  average_speed: float = 0.0
19
31
 
20
- @router.get("/models", response_model=List[Model])
32
+ @router.get("/api/models", response_model=List[Model])
21
33
  async def get_models():
22
34
  """
23
35
  Get all available models
@@ -28,7 +40,7 @@ async def get_models():
28
40
  except Exception as e:
29
41
  raise HTTPException(status_code=500, detail=str(e))
30
42
 
31
- @router.get("/models/{model_name}", response_model=Model)
43
+ @router.get("/api/models/{model_name}", response_model=Model)
32
44
  async def get_model(model_name: str):
33
45
  """
34
46
  Get a specific model by name
@@ -39,13 +51,13 @@ async def get_model(model_name: str):
39
51
  except Exception as e:
40
52
  raise HTTPException(status_code=404, detail=str(e))
41
53
 
42
- @router.post("/models", response_model=Model)
54
+ @router.post("/api/models", response_model=Model)
43
55
  async def add_model(model: Model):
44
56
  """
45
57
  Add a new model
46
58
  """
47
59
  try:
48
- existing_models = models.load_models()
60
+ existing_models = model_utils.load_models()
49
61
  if any(m["name"] == model.name for m in existing_models):
50
62
  raise HTTPException(status_code=400, detail="Model with this name already exists")
51
63
 
@@ -55,7 +67,7 @@ async def add_model(model: Model):
55
67
  except Exception as e:
56
68
  raise HTTPException(status_code=500, detail=str(e))
57
69
 
58
- @router.put("/models/{model_name}", response_model=Model)
70
+ @router.put("/api/models/{model_name}", response_model=Model)
59
71
  async def update_model(model_name: str, model: Model):
60
72
  """
61
73
  Update an existing model
@@ -78,7 +90,7 @@ async def update_model(model_name: str, model: Model):
78
90
  except Exception as e:
79
91
  raise HTTPException(status_code=500, detail=str(e))
80
92
 
81
- @router.delete("/models/{model_name}")
93
+ @router.delete("/api/models/{model_name}")
82
94
  async def delete_model(model_name: str):
83
95
  """
84
96
  Delete a model by name
@@ -95,7 +107,7 @@ async def delete_model(model_name: str):
95
107
  except Exception as e:
96
108
  raise HTTPException(status_code=500, detail=str(e))
97
109
 
98
- @router.put("/models/{model_name}/api_key")
110
+ @router.put("/api/models/{model_name}/api_key")
99
111
  async def update_model_api_key(model_name: str, api_key: str):
100
112
  """
101
113
  Update the API key for a specific model
@@ -109,7 +121,7 @@ async def update_model_api_key(model_name: str, api_key: str):
109
121
  except Exception as e:
110
122
  raise HTTPException(status_code=500, detail=str(e))
111
123
 
112
- @router.put("/models/{model_name}/input_price")
124
+ @router.put("/api/models/{model_name}/input_price")
113
125
  async def update_model_input_price(model_name: str, price: float):
114
126
  """
115
127
  Update the input price for a specific model
@@ -125,7 +137,7 @@ async def update_model_input_price(model_name: str, price: float):
125
137
  except Exception as e:
126
138
  raise HTTPException(status_code=500, detail=str(e))
127
139
 
128
- @router.put("/models/{model_name}/output_price")
140
+ @router.put("/api/models/{model_name}/output_price")
129
141
  async def update_model_output_price(model_name: str, price: float):
130
142
  """
131
143
  Update the output price for a specific model
@@ -141,7 +153,7 @@ async def update_model_output_price(model_name: str, price: float):
141
153
  except Exception as e:
142
154
  raise HTTPException(status_code=500, detail=str(e))
143
155
 
144
- @router.put("/models/{model_name}/speed")
156
+ @router.put("/api/models/{model_name}/speed")
145
157
  async def update_model_speed(model_name: str, speed: float):
146
158
  """
147
159
  Update the average speed for a specific model
@@ -154,3 +166,147 @@ async def update_model_speed(model_name: str, speed: float):
154
166
  raise HTTPException(status_code=404, detail="Model not found")
155
167
  except Exception as e:
156
168
  raise HTTPException(status_code=500, detail=str(e))
169
+
170
+ # Provider management endpoints
171
+ class ModelInfo(BaseModel):
172
+ id: str
173
+ name: str
174
+ input_price: float
175
+ output_price: float
176
+ is_reasoning: bool
177
+
178
+ class ProviderConfig(BaseModel):
179
+ name: str
180
+ base_url: str
181
+ models: List[ModelInfo]
182
+
183
+ def load_providers() -> List[Dict]:
184
+ """Load providers from JSON file"""
185
+ # Default providers if file doesn't exist
186
+ default_providers = [
187
+ {
188
+ "name": "volcanoEngine",
189
+ "base_url": "https://ark.cn-beijing.volces.com/api/v3",
190
+ "models": [
191
+ {
192
+ "id": "deepseek-v3-241226",
193
+ "name": "Deepseek V3",
194
+ "input_price": 1.0,
195
+ "output_price": 4.0,
196
+ "is_reasoning": False
197
+ },
198
+ {
199
+ "id": "deepseek-r1-250120",
200
+ "name": "Deepseek R1",
201
+ "input_price": 2.0,
202
+ "output_price": 8.0,
203
+ "is_reasoning": True
204
+ }
205
+ ]
206
+ },
207
+ {
208
+ "name": "openrouter",
209
+ "base_url": "https://openrouter.ai/api/v1",
210
+ "models": [
211
+ {
212
+ "id": "anthropic/claude-3.7-sonnet:thinking",
213
+ "name": "Claude 3.7 Sonnet Thinking",
214
+ "input_price": 22.0,
215
+ "output_price": 111.0,
216
+ "is_reasoning": True
217
+ },
218
+ {
219
+ "id": "anthropic/claude-3.7-sonnet",
220
+ "name": "Claude 3.7 Sonnet",
221
+ "input_price": 22.0,
222
+ "output_price": 111.0,
223
+ "is_reasoning": False
224
+ }
225
+ ]
226
+ }
227
+ ]
228
+
229
+ if not os.path.exists(PROVIDERS_FILE):
230
+ return default_providers
231
+ try:
232
+ with open(PROVIDERS_FILE, 'r',encoding='utf-8') as f:
233
+ # 根据名字去重,优先保留文件中的提供商配置
234
+ loaded_providers = json.load(f)
235
+ providers_map = {provider["name"]: provider for provider in loaded_providers}
236
+
237
+ # 只添加名字不重复的默认提供商
238
+ for default_provider in default_providers:
239
+ if default_provider["name"] not in providers_map:
240
+ providers_map[default_provider["name"]] = default_provider
241
+
242
+ return list(providers_map.values())
243
+ except Exception as e:
244
+ print(f"Error loading providers: {e}")
245
+ return default_providers
246
+
247
+ def save_providers(providers: List[Dict]) -> None:
248
+ """Save providers to JSON file"""
249
+ with open(PROVIDERS_FILE, 'w',encoding='utf-8') as f:
250
+ # 根据名字去重,然后再统一保存
251
+ json.dump(providers, f, indent=2,ensure_ascii=False)
252
+
253
+ @router.get("/api/providers", response_model=List[ProviderConfig])
254
+ async def get_providers():
255
+ """Get all available providers"""
256
+ try:
257
+ providers = load_providers()
258
+ return providers
259
+ except Exception as e:
260
+ raise HTTPException(status_code=500, detail=str(e))
261
+
262
+ @router.post("/api/providers", response_model=ProviderConfig)
263
+ async def add_provider(provider: ProviderConfig):
264
+ """Add a new provider"""
265
+ try:
266
+ providers = load_providers()
267
+
268
+ # Check if provider with same name already exists
269
+ if any(p["name"] == provider.name for p in providers):
270
+ raise HTTPException(status_code=400, detail="Provider with this name already exists")
271
+
272
+ providers.append(provider.model_dump())
273
+ save_providers(providers)
274
+ return provider
275
+ except Exception as e:
276
+ raise HTTPException(status_code=500, detail=str(e))
277
+
278
+ @router.put("/api/providers/{provider_name}", response_model=ProviderConfig)
279
+ async def update_provider(provider_name: str, provider: ProviderConfig):
280
+ """Update an existing provider"""
281
+ try:
282
+ providers = load_providers()
283
+ updated = False
284
+
285
+ for p in providers:
286
+ if p["name"] == provider_name:
287
+ p.update(provider.model_dump())
288
+ updated = True
289
+ break
290
+
291
+ if not updated:
292
+ raise HTTPException(status_code=404, detail="Provider not found")
293
+
294
+ save_providers(providers)
295
+ return provider
296
+ except Exception as e:
297
+ raise HTTPException(status_code=500, detail=str(e))
298
+
299
+ @router.delete("/api/providers/{provider_name}")
300
+ async def delete_provider(provider_name: str):
301
+ """Delete a provider by name"""
302
+ try:
303
+ providers = load_providers()
304
+ providers_list = [p for p in providers if p["name"] != provider_name]
305
+
306
+ if len(providers) == len(providers_list):
307
+ raise HTTPException(status_code=404, detail="Provider not found")
308
+
309
+ save_providers(providers_list)
310
+ return {"message": f"Provider {provider_name} deleted successfully"}
311
+ except Exception as e:
312
+ raise HTTPException(status_code=500, detail=str(e))
auto_coder_web/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.37"
1
+ __version__ = "0.1.39"
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "files": {
3
- "main.css": "/static/css/main.e70fd4a5.css",
4
- "main.js": "/static/js/main.066e08e9.js",
3
+ "main.css": "/static/css/main.0ef9afe0.css",
4
+ "main.js": "/static/js/main.c3e68e66.js",
5
5
  "static/js/453.d855a71b.chunk.js": "/static/js/453.d855a71b.chunk.js",
6
6
  "index.html": "/index.html",
7
- "main.e70fd4a5.css.map": "/static/css/main.e70fd4a5.css.map",
8
- "main.066e08e9.js.map": "/static/js/main.066e08e9.js.map",
7
+ "main.0ef9afe0.css.map": "/static/css/main.0ef9afe0.css.map",
8
+ "main.c3e68e66.js.map": "/static/js/main.c3e68e66.js.map",
9
9
  "453.d855a71b.chunk.js.map": "/static/js/453.d855a71b.chunk.js.map"
10
10
  },
11
11
  "entrypoints": [
12
- "static/css/main.e70fd4a5.css",
13
- "static/js/main.066e08e9.js"
12
+ "static/css/main.0ef9afe0.css",
13
+ "static/js/main.c3e68e66.js"
14
14
  ]
15
15
  }
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.066e08e9.js"></script><link href="/static/css/main.e70fd4a5.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.c3e68e66.js"></script><link href="/static/css/main.0ef9afe0.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>