2025-12-04 14:48:38 +08:00
|
|
|
|
"""LLM configuration management API endpoints."""
|
|
|
|
|
|
|
|
|
|
|
|
from typing import List, Optional
|
|
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
|
|
|
|
|
from sqlalchemy.orm import Session
|
2025-12-17 19:26:36 +08:00
|
|
|
|
from sqlalchemy import or_
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
from ...db.database import get_db
|
2025-12-04 14:48:38 +08:00
|
|
|
|
from ...models.user import User
|
|
|
|
|
|
from ...models.llm_config import LLMConfig
|
|
|
|
|
|
from ...core.simple_permissions import require_super_admin, require_authenticated_user
|
2025-12-17 19:26:36 +08:00
|
|
|
|
from ...services.auth import AuthService
|
|
|
|
|
|
from ...utils.logger import get_logger
|
2025-12-04 14:48:38 +08:00
|
|
|
|
from ...schemas.llm_config import (
|
|
|
|
|
|
LLMConfigCreate, LLMConfigUpdate, LLMConfigResponse,
|
|
|
|
|
|
LLMConfigTest
|
|
|
|
|
|
)
|
|
|
|
|
|
from th_agenter.services.document_processor import get_document_processor
|
2025-12-17 19:26:36 +08:00
|
|
|
|
logger = get_logger(__name__)
|
2025-12-16 13:55:16 +08:00
|
|
|
|
router = APIRouter(prefix="/llm-configs", tags=["llm-configs"])
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
|
|
|
|
|
|
@router.get("/", response_model=List[LLMConfigResponse])
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_llm_configs(
|
|
|
|
|
|
skip: int = Query(0, ge=0),
|
|
|
|
|
|
limit: int = Query(100, ge=1, le=1000),
|
|
|
|
|
|
search: Optional[str] = Query(None),
|
|
|
|
|
|
provider: Optional[str] = Query(None),
|
|
|
|
|
|
is_active: Optional[bool] = Query(None),
|
|
|
|
|
|
is_embedding: Optional[bool] = Query(None),
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_authenticated_user)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""获取大模型配置列表."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
query = db.query(LLMConfig)
|
|
|
|
|
|
|
|
|
|
|
|
# 搜索
|
|
|
|
|
|
if search:
|
|
|
|
|
|
query = query.filter(
|
|
|
|
|
|
or_(
|
|
|
|
|
|
LLMConfig.name.ilike(f"%{search}%"),
|
|
|
|
|
|
LLMConfig.model_name.ilike(f"%{search}%"),
|
|
|
|
|
|
LLMConfig.description.ilike(f"%{search}%")
|
|
|
|
|
|
)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
2025-12-17 19:26:36 +08:00
|
|
|
|
|
|
|
|
|
|
# 服务商筛选
|
|
|
|
|
|
if provider:
|
|
|
|
|
|
query = query.filter(LLMConfig.provider == provider)
|
|
|
|
|
|
|
|
|
|
|
|
# 状态筛选
|
|
|
|
|
|
if is_active is not None:
|
|
|
|
|
|
query = query.filter(LLMConfig.is_active == is_active)
|
|
|
|
|
|
|
|
|
|
|
|
# 模型类型筛选
|
|
|
|
|
|
if is_embedding is not None:
|
|
|
|
|
|
query = query.filter(LLMConfig.is_embedding == is_embedding)
|
|
|
|
|
|
|
|
|
|
|
|
# 排序
|
|
|
|
|
|
query = query.order_by(LLMConfig.name)
|
|
|
|
|
|
|
|
|
|
|
|
# 分页
|
|
|
|
|
|
configs = query.offset(skip).limit(limit).all()
|
|
|
|
|
|
|
|
|
|
|
|
return [config.to_dict(include_sensitive=True) for config in configs]
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Error getting LLM configs: {str(e)}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="获取大模型配置列表失败"
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
@router.get("/providers")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_llm_providers(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_authenticated_user)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""获取支持的大模型服务商列表."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
providers = db.query(LLMConfig.provider).distinct().all()
|
|
|
|
|
|
return [provider[0] for provider in providers if provider[0]]
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Error getting LLM providers: {str(e)}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="获取服务商列表失败"
|
|
|
|
|
|
)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-16 13:55:16 +08:00
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
@router.get("/active", response_model=List[LLMConfigResponse])
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_active_llm_configs(
|
|
|
|
|
|
is_embedding: Optional[bool] = Query(None),
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_authenticated_user)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""获取所有激活的大模型配置."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
query = db.query(LLMConfig).filter(LLMConfig.is_active == True)
|
|
|
|
|
|
|
|
|
|
|
|
if is_embedding is not None:
|
|
|
|
|
|
query = query.filter(LLMConfig.is_embedding == is_embedding)
|
|
|
|
|
|
|
|
|
|
|
|
configs = query.order_by(LLMConfig.created_at).all()
|
|
|
|
|
|
|
|
|
|
|
|
return [config.to_dict(include_sensitive=True) for config in configs]
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Error getting active LLM configs: {str(e)}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="获取激活配置列表失败"
|
|
|
|
|
|
)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
|
|
|
|
|
|
@router.get("/default", response_model=LLMConfigResponse)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_default_llm_config(
|
|
|
|
|
|
is_embedding: bool = Query(False, description="是否获取嵌入模型默认配置"),
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_authenticated_user)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""获取默认大模型配置."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
config = db.query(LLMConfig).filter(
|
|
|
|
|
|
LLMConfig.is_default == True,
|
|
|
|
|
|
LLMConfig.is_embedding == is_embedding,
|
|
|
|
|
|
LLMConfig.is_active == True
|
|
|
|
|
|
).first()
|
|
|
|
|
|
|
|
|
|
|
|
if not config:
|
|
|
|
|
|
model_type = "嵌入模型" if is_embedding else "对话模型"
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail=f"未找到默认{model_type}配置"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return config.to_dict(include_sensitive=True)
|
|
|
|
|
|
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Error getting default LLM config: {str(e)}")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="获取默认配置失败"
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
|
|
|
|
|
|
@router.get("/{config_id}", response_model=LLMConfigResponse)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def get_llm_config(
|
|
|
|
|
|
config_id: int,
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_authenticated_user)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""获取大模型配置详情."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
|
|
|
|
|
|
if not config:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="大模型配置不存在"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return config.to_dict(include_sensitive=True)
|
|
|
|
|
|
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Error getting LLM config {config_id}: {str(e)}")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="获取大模型配置详情失败"
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
@router.post("/", response_model=LLMConfigResponse, status_code=status.HTTP_201_CREATED)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def create_llm_config(
|
|
|
|
|
|
config_data: LLMConfigCreate,
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_super_admin)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""创建大模型配置."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
# 检查配置名称是否已存在
|
|
|
|
|
|
existing_config = db.query(LLMConfig).filter(
|
|
|
|
|
|
LLMConfig.name == config_data.name
|
|
|
|
|
|
).first()
|
|
|
|
|
|
if existing_config:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
|
detail="配置名称已存在"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 创建临时配置对象进行验证
|
|
|
|
|
|
temp_config = LLMConfig(
|
|
|
|
|
|
name=config_data.name,
|
|
|
|
|
|
provider=config_data.provider,
|
|
|
|
|
|
model_name=config_data.model_name,
|
|
|
|
|
|
api_key=config_data.api_key,
|
|
|
|
|
|
base_url=config_data.base_url,
|
|
|
|
|
|
max_tokens=config_data.max_tokens,
|
|
|
|
|
|
temperature=config_data.temperature,
|
|
|
|
|
|
top_p=config_data.top_p,
|
|
|
|
|
|
frequency_penalty=config_data.frequency_penalty,
|
|
|
|
|
|
presence_penalty=config_data.presence_penalty,
|
|
|
|
|
|
description=config_data.description,
|
|
|
|
|
|
is_active=config_data.is_active,
|
|
|
|
|
|
is_default=config_data.is_default,
|
|
|
|
|
|
is_embedding=config_data.is_embedding,
|
|
|
|
|
|
extra_config=config_data.extra_config or {}
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
2025-12-17 19:26:36 +08:00
|
|
|
|
|
|
|
|
|
|
# 验证配置
|
|
|
|
|
|
validation_result = temp_config.validate_config()
|
|
|
|
|
|
if not validation_result['valid']:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
|
detail=validation_result['error']
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 如果设为默认,取消同类型的其他默认配置
|
|
|
|
|
|
if config_data.is_default:
|
|
|
|
|
|
db.query(LLMConfig).filter(
|
|
|
|
|
|
LLMConfig.is_embedding == config_data.is_embedding
|
|
|
|
|
|
).update({"is_default": False})
|
|
|
|
|
|
|
|
|
|
|
|
# 创建配置
|
|
|
|
|
|
config = LLMConfig(
|
|
|
|
|
|
name=config_data.name,
|
|
|
|
|
|
provider=config_data.provider,
|
|
|
|
|
|
model_name=config_data.model_name,
|
|
|
|
|
|
api_key=config_data.api_key,
|
|
|
|
|
|
base_url=config_data.base_url,
|
|
|
|
|
|
max_tokens=config_data.max_tokens,
|
|
|
|
|
|
temperature=config_data.temperature,
|
|
|
|
|
|
top_p=config_data.top_p,
|
|
|
|
|
|
frequency_penalty=config_data.frequency_penalty,
|
|
|
|
|
|
presence_penalty=config_data.presence_penalty,
|
|
|
|
|
|
description=config_data.description,
|
|
|
|
|
|
is_active=config_data.is_active,
|
|
|
|
|
|
is_default=config_data.is_default,
|
|
|
|
|
|
is_embedding=config_data.is_embedding,
|
|
|
|
|
|
extra_config=config_data.extra_config or {}
|
|
|
|
|
|
)
|
|
|
|
|
|
config.set_audit_fields(current_user.id)
|
|
|
|
|
|
|
|
|
|
|
|
db.add(config)
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
db.refresh(config)
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"LLM config created: {config.name} by user {current_user.username}")
|
|
|
|
|
|
return config.to_dict()
|
|
|
|
|
|
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
db.rollback()
|
|
|
|
|
|
logger.error(f"Error creating LLM config: {str(e)}")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="创建大模型配置失败"
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
|
|
|
|
|
|
@router.put("/{config_id}", response_model=LLMConfigResponse)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def update_llm_config(
|
|
|
|
|
|
config_id: int,
|
|
|
|
|
|
config_data: LLMConfigUpdate,
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_super_admin)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""更新大模型配置."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
|
|
|
|
|
|
if not config:
|
2025-12-16 13:55:16 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="大模型配置不存在"
|
2025-12-16 13:55:16 +08:00
|
|
|
|
)
|
2025-12-17 19:26:36 +08:00
|
|
|
|
|
|
|
|
|
|
# 检查配置名称是否已存在(排除自己)
|
|
|
|
|
|
if config_data.name and config_data.name != config.name:
|
|
|
|
|
|
existing_config = db.query(LLMConfig).filter(
|
|
|
|
|
|
LLMConfig.name == config_data.name,
|
|
|
|
|
|
LLMConfig.id != config_id
|
|
|
|
|
|
).first()
|
|
|
|
|
|
if existing_config:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
|
detail="配置名称已存在"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 如果设为默认,取消同类型的其他默认配置
|
|
|
|
|
|
if config_data.is_default is True:
|
|
|
|
|
|
# 获取当前配置的embedding类型,如果更新中包含is_embedding则使用新值
|
|
|
|
|
|
is_embedding = config_data.is_embedding if config_data.is_embedding is not None else config.is_embedding
|
|
|
|
|
|
db.query(LLMConfig).filter(
|
|
|
|
|
|
LLMConfig.is_embedding == is_embedding,
|
|
|
|
|
|
LLMConfig.id != config_id
|
|
|
|
|
|
).update({"is_default": False})
|
|
|
|
|
|
|
|
|
|
|
|
# 更新字段
|
|
|
|
|
|
update_data = config_data.dict(exclude_unset=True)
|
|
|
|
|
|
for field, value in update_data.items():
|
|
|
|
|
|
setattr(config, field, value)
|
|
|
|
|
|
|
|
|
|
|
|
config.set_audit_fields(current_user.id, is_update=True)
|
|
|
|
|
|
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
db.refresh(config)
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"LLM config updated: {config.name} by user {current_user.username}")
|
|
|
|
|
|
return config.to_dict()
|
|
|
|
|
|
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
db.rollback()
|
|
|
|
|
|
logger.error(f"Error updating LLM config {config_id}: {str(e)}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="更新大模型配置失败"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-12-04 14:48:38 +08:00
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
@router.delete("/{config_id}", status_code=status.HTTP_204_NO_CONTENT)
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def delete_llm_config(
|
|
|
|
|
|
config_id: int,
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_super_admin)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""删除大模型配置."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
|
|
|
|
|
|
if not config:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="大模型配置不存在"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: 检查是否有对话或其他功能正在使用该配置
|
|
|
|
|
|
# 这里可以添加相关的检查逻辑
|
|
|
|
|
|
|
|
|
|
|
|
db.delete(config)
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"LLM config deleted: {config.name} by user {current_user.username}")
|
|
|
|
|
|
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
db.rollback()
|
|
|
|
|
|
logger.error(f"Error deleting LLM config {config_id}: {str(e)}")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="删除大模型配置失败"
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
|
|
|
|
|
|
@router.post("/{config_id}/test")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def test_llm_config(
|
|
|
|
|
|
config_id: int,
|
|
|
|
|
|
test_data: LLMConfigTest,
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_super_admin)
|
|
|
|
|
|
):
|
2025-12-17 19:26:36 +08:00
|
|
|
|
"""测试大模型配置."""
|
|
|
|
|
|
try:
|
|
|
|
|
|
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
|
|
|
|
|
|
if not config:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="大模型配置不存在"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 验证配置
|
|
|
|
|
|
validation_result = config.validate_config()
|
|
|
|
|
|
if not validation_result["valid"]:
|
|
|
|
|
|
return {
|
|
|
|
|
|
"success": False,
|
|
|
|
|
|
"message": f"配置验证失败: {validation_result['error']}",
|
|
|
|
|
|
"details": validation_result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 尝试创建客户端并发送测试请求
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 这里应该根据不同的服务商创建相应的客户端
|
|
|
|
|
|
# 由于具体的客户端实现可能因服务商而异,这里提供一个通用的框架
|
|
|
|
|
|
|
|
|
|
|
|
test_message = test_data.message or "Hello, this is a test message."
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: 实现具体的测试逻辑
|
|
|
|
|
|
# 例如:
|
|
|
|
|
|
# client = config.get_client()
|
|
|
|
|
|
# response = client.chat.completions.create(
|
|
|
|
|
|
# model=config.model_name,
|
|
|
|
|
|
# messages=[{"role": "user", "content": test_message}],
|
|
|
|
|
|
# max_tokens=100
|
|
|
|
|
|
# )
|
|
|
|
|
|
|
|
|
|
|
|
# 模拟测试成功
|
|
|
|
|
|
logger.info(f"LLM config test: {config.name} by user {current_user.username}")
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
"success": True,
|
|
|
|
|
|
"message": "配置测试成功",
|
|
|
|
|
|
"test_message": test_message,
|
|
|
|
|
|
"response": "这是一个模拟的测试响应。实际实现中,这里会是大模型的真实响应。",
|
|
|
|
|
|
"latency_ms": 150, # 模拟延迟
|
|
|
|
|
|
"config_info": config.get_client_config()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as test_error:
|
|
|
|
|
|
logger.error(f"LLM config test failed: {config.name}, error: {str(test_error)}")
|
|
|
|
|
|
return {
|
|
|
|
|
|
"success": False,
|
|
|
|
|
|
"message": f"配置测试失败: {str(test_error)}",
|
|
|
|
|
|
"test_message": test_message,
|
|
|
|
|
|
"config_info": config.get_client_config()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Error testing LLM config {config_id}: {str(e)}")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="测试大模型配置失败"
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
@router.post("/{config_id}/toggle-status")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def toggle_llm_config_status(
|
|
|
|
|
|
config_id: int,
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_super_admin)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""切换大模型配置状态."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
|
|
|
|
|
|
if not config:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="大模型配置不存在"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 切换状态
|
|
|
|
|
|
config.is_active = not config.is_active
|
|
|
|
|
|
config.set_audit_fields(current_user.id, is_update=True)
|
|
|
|
|
|
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
db.refresh(config)
|
|
|
|
|
|
|
|
|
|
|
|
status_text = "激活" if config.is_active else "禁用"
|
|
|
|
|
|
logger.info(f"LLM config status toggled: {config.name} {status_text} by user {current_user.username}")
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
"message": f"配置已{status_text}",
|
|
|
|
|
|
"is_active": config.is_active
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
db.rollback()
|
|
|
|
|
|
logger.error(f"Error toggling LLM config status {config_id}: {str(e)}")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="切换配置状态失败"
|
2025-12-04 14:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-17 19:26:36 +08:00
|
|
|
|
@router.post("/{config_id}/set-default")
|
2025-12-04 14:48:38 +08:00
|
|
|
|
async def set_default_llm_config(
|
|
|
|
|
|
config_id: int,
|
2025-12-17 19:26:36 +08:00
|
|
|
|
db: Session = Depends(get_db),
|
2025-12-04 14:48:38 +08:00
|
|
|
|
current_user: User = Depends(require_super_admin)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""设置默认大模型配置."""
|
2025-12-17 19:26:36 +08:00
|
|
|
|
try:
|
|
|
|
|
|
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
|
|
|
|
|
|
if not config:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="大模型配置不存在"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 检查配置是否激活
|
|
|
|
|
|
if not config.is_active:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
|
detail="只能将激活的配置设为默认"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 取消同类型的其他默认配置
|
|
|
|
|
|
db.query(LLMConfig).filter(
|
|
|
|
|
|
LLMConfig.is_embedding == config.is_embedding,
|
|
|
|
|
|
LLMConfig.id != config_id
|
|
|
|
|
|
).update({"is_default": False})
|
|
|
|
|
|
|
|
|
|
|
|
# 设置当前配置为默认
|
|
|
|
|
|
config.is_default = True
|
|
|
|
|
|
config.set_audit_fields(current_user.id, is_update=True)
|
|
|
|
|
|
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
db.refresh(config)
|
|
|
|
|
|
|
|
|
|
|
|
model_type = "嵌入模型" if config.is_embedding else "对话模型"
|
|
|
|
|
|
logger.info(f"Default LLM config set: {config.name} ({model_type}) by user {current_user.username}")
|
|
|
|
|
|
# 更新文档处理器默认embedding
|
|
|
|
|
|
get_document_processor()._init_embeddings()
|
|
|
|
|
|
return {
|
|
|
|
|
|
"message": f"已将 {config.name} 设为默认{model_type}配置",
|
|
|
|
|
|
"is_default": config.is_default
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
db.rollback()
|
|
|
|
|
|
logger.error(f"Error setting default LLM config {config_id}: {str(e)}")
|
2025-12-16 13:55:16 +08:00
|
|
|
|
raise HTTPException(
|
2025-12-17 19:26:36 +08:00
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="设置默认配置失败"
|
|
|
|
|
|
)
|