add model config and update settings

This commit is contained in:
qixinbo
2026-03-14 19:56:34 +08:00
parent 98d99ded37
commit 6089192575
9 changed files with 642 additions and 202 deletions
+67 -9
View File
@@ -1,17 +1,31 @@
import json
import os
from typing import List, Optional, Dict, Any
from fastapi import APIRouter, HTTPException, Body
from fastapi import APIRouter, HTTPException, Depends, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from jose import jwt, JWTError
from pydantic import BaseModel, Field
from app.core.security import SECRET_KEY, ALGORITHM
router = APIRouter()
security = HTTPBearer()
DATA_FILE = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "data", "llm_config.json")
class CurrentUser(BaseModel):
id: int
username: str
is_admin: bool = False
class LLMConfig(BaseModel):
id: str = Field(..., description="Unique identifier for the LLM configuration")
name: Optional[str] = Field(None, description="Display name")
provider: str = Field(..., description="Provider name (e.g., openai, azure, anthropic)")
model: str = Field(..., description="Model name (e.g., gpt-4, claude-3-opus)")
model_type: Optional[str] = Field(None, description="Model type")
base_model: Optional[str] = Field(None, description="Base model")
protocol_type: Optional[str] = Field(None, description="Protocol type")
api_key: Optional[str] = Field(None, description="API Key for the provider")
api_base: Optional[str] = Field(None, description="Base URL for the API")
extra_headers: Optional[Dict[str, str]] = Field(None, description="Extra headers for the request")
@@ -19,21 +33,52 @@ class LLMConfig(BaseModel):
class LLMConfigCreate(BaseModel):
id: str
name: Optional[str] = None
provider: str
model: str
model_type: Optional[str] = None
base_model: Optional[str] = None
protocol_type: Optional[str] = None
api_key: Optional[str] = None
api_base: Optional[str] = None
extra_headers: Optional[Dict[str, str]] = None
is_active: bool = True
class LLMConfigUpdate(BaseModel):
name: Optional[str] = None
provider: Optional[str] = None
model: Optional[str] = None
model_type: Optional[str] = None
base_model: Optional[str] = None
protocol_type: Optional[str] = None
api_key: Optional[str] = None
api_base: Optional[str] = None
extra_headers: Optional[Dict[str, str]] = None
is_active: Optional[bool] = None
def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)) -> CurrentUser:
unauthorized = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
)
try:
payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
except JWTError:
raise unauthorized
user_id = payload.get("id")
username = payload.get("sub")
is_admin = bool(payload.get("is_admin", False))
if user_id is None or username is None:
raise unauthorized
return CurrentUser(id=user_id, username=username, is_admin=is_admin)
def get_admin_user(current_user: CurrentUser = Depends(get_current_user)) -> CurrentUser:
if not current_user.is_admin:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin permission required")
return current_user
def _load_data() -> List[Dict[str, Any]]:
if not os.path.exists(DATA_FILE):
return []
@@ -48,37 +93,50 @@ def _save_data(data: List[Dict[str, Any]]):
with open(DATA_FILE, "w") as f:
json.dump(data, f, indent=2)
def _sanitize_config(item: Dict[str, Any], is_admin: bool) -> Dict[str, Any]:
config = item.copy()
if not is_admin:
config["api_key"] = None
return config
@router.get("/llm", response_model=List[LLMConfig])
def list_llm_configs():
def list_llm_configs(current_user: CurrentUser = Depends(get_current_user)):
data = _load_data()
return [LLMConfig(**item) for item in data]
return [LLMConfig(**_sanitize_config(item, current_user.is_admin)) for item in data]
@router.get("/llm/{config_id}", response_model=LLMConfig)
def get_llm_config(config_id: str):
def get_llm_config(config_id: str, current_user: CurrentUser = Depends(get_current_user)):
data = _load_data()
for item in data:
if item["id"] == config_id:
return LLMConfig(**item)
return LLMConfig(**_sanitize_config(item, current_user.is_admin))
raise HTTPException(status_code=404, detail="LLM configuration not found")
@router.post("/llm", response_model=LLMConfig)
def create_llm_config(config: LLMConfigCreate):
def create_llm_config(config: LLMConfigCreate, _: CurrentUser = Depends(get_admin_user)):
data = _load_data()
if any(item["id"] == config.id for item in data):
raise HTTPException(status_code=400, detail="LLM configuration with this ID already exists")
new_config = config.dict()
if new_config.get("is_active"):
for item in data:
item["is_active"] = False
data.append(new_config)
_save_data(data)
return LLMConfig(**new_config)
@router.put("/llm/{config_id}", response_model=LLMConfig)
def update_llm_config(config_id: str, config: LLMConfigUpdate):
def update_llm_config(config_id: str, config: LLMConfigUpdate, _: CurrentUser = Depends(get_admin_user)):
data = _load_data()
for i, item in enumerate(data):
if item["id"] == config_id:
updated_item = item.copy()
update_data = config.dict(exclude_unset=True)
if update_data.get("is_active"):
for j in range(len(data)):
data[j]["is_active"] = False
updated_item.update(update_data)
data[i] = updated_item
_save_data(data)
@@ -86,7 +144,7 @@ def update_llm_config(config_id: str, config: LLMConfigUpdate):
raise HTTPException(status_code=404, detail="LLM configuration not found")
@router.delete("/llm/{config_id}")
def delete_llm_config(config_id: str):
def delete_llm_config(config_id: str, _: CurrentUser = Depends(get_admin_user)):
data = _load_data()
initial_len = len(data)
data = [item for item in data if item["id"] != config_id]
+20
View File
@@ -0,0 +1,20 @@
[
{
"id": "m1773487590",
"provider": "zhipuai",
"model": "glm-4-7-251222",
"api_key": "secret",
"api_base": "https://ark.cn-beijing.volces.com/api/v3",
"extra_headers": null,
"is_active": true
},
{
"id": "deny1",
"provider": "openai",
"model": "gpt-4o",
"api_key": null,
"api_base": "https://api.openai.com/v1",
"extra_headers": null,
"is_active": false
}
]
Binary file not shown.