更新大志备注

This commit is contained in:
zhanggangyong
2026-01-16 10:38:17 +00:00
parent 9ceb72abf1
commit 6d164c838b
16 changed files with 1343 additions and 251 deletions
+235 -93
View File
@@ -551,7 +551,7 @@ async def get_admin_dashboard_stats(
"totalTenants": total_tenants,
"totalAgents": total_agents,
"totalCalls": total_calls,
"totalRevenue": total_revenue,
"totalRevenue": round(total_revenue, 2),
# 总资源分配(平台端 + 自定义)
"totalAllocatedCpu": round(total_cpu, 2),
"totalAllocatedMemory": round(total_memory, 2),
@@ -1543,42 +1543,60 @@ async def allocate_channel_resources(
# LiteLLM 更新成功后,更新本地数据库
# 删除现有模型资源分配
# 分配模型资源(追加模式:只添加新模型,保留已有模型)
# 存储每个模型名称,而不是供应商 ID
# 这样渠道给租户分配模型时才能正确验证权限
from sqlalchemy import delete
await db.execute(
delete(ResourceAllocation).where(
and_(
ResourceAllocation.target_id == channel_id,
ResourceAllocation.target_type == "channel",
ResourceAllocation.resource_type == "model"
for model_name in all_model_names:
# 检查是否已存在该模型的分配
existing_model_result = await db.execute(
select(ResourceAllocation).where(
and_(
ResourceAllocation.target_id == channel_id,
ResourceAllocation.target_type == "channel",
ResourceAllocation.resource_type == "model",
ResourceAllocation.resource_id == model_name
)
)
)
)
# 分配模型资源(存储每个模型名称,而不是供应商 ID)
# 这样渠道给租户分配模型时才能正确验证权限
for model_name in all_model_names:
allocation = ResourceAllocation(
target_id=channel_id,
target_type="channel",
resource_type="model",
resource_id=model_name, # 存储模型名称(如 gpt-4o),而不是供应商 ID
)
db.add(allocation)
existing_model = existing_model_result.scalar_one_or_none()
if not existing_model:
# 只有不存在时才添加新分配
allocation = ResourceAllocation(
target_id=channel_id,
target_type="channel",
resource_type="model",
resource_id=model_name, # 存储模型名称(如 gpt-4o),而不是供应商 ID
)
db.add(allocation)
logger.info(f"追加模型分配给渠道 {channel.name}: model={model_name}")
else:
logger.info(f"模型 {model_name} 已分配给渠道 {channel.name},跳过重复分配")
# Bug 修复:同时创建 ChannelProviderAccess 记录,确保渠道能看到分配的供应商
# 删除旧的供应商访问记录
await db.execute(
delete(ChannelProviderAccess).where(
ChannelProviderAccess.channel_id == channel_id
)
)
# 为每个供应商创建访问权限记录
# 追加模式:只添加新的供应商访问权限,保留已有的
user_id = principal.get("claims", {}).get("user_id") or principal.get("sub")
for provider_id in provider_ids:
try:
provider_uuid = uuid.UUID(provider_id)
# 检查是否已存在该供应商的访问权限
existing_access_result = await db.execute(
select(ChannelProviderAccess).where(
and_(
ChannelProviderAccess.channel_id == channel_id,
ChannelProviderAccess.provider_id == provider_uuid
)
)
)
existing_access = existing_access_result.scalar_one_or_none()
if existing_access:
# 已存在,跳过重复分配
logger.info(f"供应商 {provider_id} 的访问权限已存在于渠道 {channel.name},跳过重复分配")
continue
# 查询供应商信息
provider_result = await db.execute(
select(ModelProvider).where(ModelProvider.id == provider_uuid)
@@ -1597,70 +1615,86 @@ async def allocate_channel_resources(
approved_at=datetime.utcnow(),
)
db.add(access)
logger.info(f"创建渠道 {channel.name} 的供应商访问权限: {provider.name}")
logger.info(f"追加渠道 {channel.name} 的供应商访问权限: {provider.name}")
except (ValueError, TypeError) as e:
logger.warning(f"无法为供应商 {provider_id} 创建访问权限: {e}")
# 删除现有 Agent 资源分配
await db.execute(
delete(ResourceAllocation).where(
and_(
ResourceAllocation.target_id == channel_id,
ResourceAllocation.target_type == "channel",
ResourceAllocation.resource_type == "agent"
)
)
)
# 分配Agent资源
# 删除现有平台 Agent 配额
await db.execute(
delete(PlatformAgentQuota).where(
and_(
PlatformAgentQuota.target_id == channel_id,
PlatformAgentQuota.target_type == "channel"
)
)
)
# 分配Agent资源(追加模式:在现有配额基础上增加)
# 不再删除现有配额,改为追加
user_id_for_allocation = principal.get("claims", {}).get("user_id") or principal.get("sub")
for agent_alloc in req.agents:
# 1. 创建 ResourceAllocation 记录(兼容旧逻辑)
allocation = ResourceAllocation(
target_id=channel_id,
target_type="channel",
resource_type="agent",
resource_id=agent_alloc.agentId,
quantity=agent_alloc.quantity,
# 1. 查找现有的平台 Agent 配额
existing_quota_result = await db.execute(
select(PlatformAgentQuota).where(
and_(
PlatformAgentQuota.target_id == channel_id,
PlatformAgentQuota.target_type == "channel",
PlatformAgentQuota.template_name == agent_alloc.agentId
)
)
)
db.add(allocation)
existing_quota = existing_quota_result.scalar_one_or_none()
# 2. Bug 修复:同时创建 PlatformAgentQuota 记录,确保渠道能看到配额
quota = PlatformAgentQuota(
target_id=channel_id,
target_type="channel",
template_name=agent_alloc.agentId, # agentId 是模板名称
pod_quota=agent_alloc.quantity,
pod_used=0,
allocated_by=uuid.UUID(user_id_for_allocation) if user_id_for_allocation else None,
allocated_at=datetime.utcnow(),
)
db.add(quota)
if existing_quota:
# 追加模式:在现有配额基础上增加
existing_quota.pod_quota = (existing_quota.pod_quota or 0) + agent_alloc.quantity
existing_quota.allocated_at = datetime.utcnow()
if user_id_for_allocation:
existing_quota.allocated_by = uuid.UUID(user_id_for_allocation)
logger.info(
f"追加平台 Agent 配额给渠道 {channel.name}: "
f"template={agent_alloc.agentId}, 追加量={agent_alloc.quantity}, 新配额={existing_quota.pod_quota}"
)
else:
# 创建新配额记录
quota = PlatformAgentQuota(
target_id=channel_id,
target_type="channel",
template_name=agent_alloc.agentId, # agentId 是模板名称
pod_quota=agent_alloc.quantity,
pod_used=0,
allocated_by=uuid.UUID(user_id_for_allocation) if user_id_for_allocation else None,
allocated_at=datetime.utcnow(),
)
db.add(quota)
logger.info(
f"创建平台 Agent 配额给渠道 {channel.name}: "
f"template={agent_alloc.agentId}, quota={agent_alloc.quantity}"
)
logger.info(
f"分配平台 Agent 配额给渠道 {channel.name}: "
f"template={agent_alloc.agentId}, quota={agent_alloc.quantity}"
# 2. 更新或创建 ResourceAllocation 记录(兼容旧逻辑)
# 先查找是否已存在
existing_alloc_result = await db.execute(
select(ResourceAllocation).where(
and_(
ResourceAllocation.target_id == channel_id,
ResourceAllocation.target_type == "channel",
ResourceAllocation.resource_type == "agent",
ResourceAllocation.resource_id == agent_alloc.agentId
)
)
)
existing_alloc = existing_alloc_result.scalar_one_or_none()
if existing_alloc:
# 追加模式
existing_alloc.quantity = (existing_alloc.quantity or 0) + agent_alloc.quantity
else:
# 创建新记录
allocation = ResourceAllocation(
target_id=channel_id,
target_type="channel",
resource_type="agent",
resource_id=agent_alloc.agentId,
quantity=agent_alloc.quantity,
)
db.add(allocation)
# 更新自定义Agent资源(旧格式,保留兼容)
# Bug 修复:customAgentResources 也需要创建 ChannelCustomAgentQuota 记录
# 追加模式:在现有配额基础上增加
if req.customAgentResources:
channel.custom_agent_cpu = req.customAgentResources.cpu
channel.custom_agent_memory = req.customAgentResources.memory
# 同时更新新格式字段
channel.custom_agent_cpu_quota = req.customAgentResources.cpu
channel.custom_agent_memory_quota = req.customAgentResources.memory
# 查找或创建渠道配额记录
channel_quota_result = await db.execute(
select(ChannelCustomAgentQuota).where(
@@ -1670,9 +1704,16 @@ async def allocate_channel_resources(
channel_quota = channel_quota_result.scalar_one_or_none()
if channel_quota:
# 更新现有配额
channel_quota.cpu_quota = req.customAgentResources.cpu
channel_quota.memory_quota = req.customAgentResources.memory
# 追加模式:在现有配额基础上增加
new_cpu_quota = float(channel_quota.cpu_quota or 0) + req.customAgentResources.cpu
new_memory_quota = float(channel_quota.memory_quota or 0) + req.customAgentResources.memory
channel_quota.cpu_quota = new_cpu_quota
channel_quota.memory_quota = new_memory_quota
# 同步更新渠道表字段
channel.custom_agent_cpu = new_cpu_quota
channel.custom_agent_memory = new_memory_quota
channel.custom_agent_cpu_quota = new_cpu_quota
channel.custom_agent_memory_quota = new_memory_quota
else:
# 创建新配额记录
channel_quota = ChannelCustomAgentQuota(
@@ -1683,13 +1724,15 @@ async def allocate_channel_resources(
memory_allocated=0,
)
db.add(channel_quota)
# 同步更新渠道表字段
channel.custom_agent_cpu = req.customAgentResources.cpu
channel.custom_agent_memory = req.customAgentResources.memory
channel.custom_agent_cpu_quota = req.customAgentResources.cpu
channel.custom_agent_memory_quota = req.customAgentResources.memory
# 更新自定义 Agent 配额(新格式)
# 追加模式:在现有配额基础上增加
if req.customAgentQuota:
# 更新渠道表中的配额字段
channel.custom_agent_cpu_quota = req.customAgentQuota.cpuQuota
channel.custom_agent_memory_quota = req.customAgentQuota.memoryQuota
# 查找或创建渠道配额记录
channel_quota_result = await db.execute(
select(ChannelCustomAgentQuota).where(
@@ -1699,9 +1742,14 @@ async def allocate_channel_resources(
channel_quota = channel_quota_result.scalar_one_or_none()
if channel_quota:
# 更新现有配额
channel_quota.cpu_quota = req.customAgentQuota.cpuQuota
channel_quota.memory_quota = req.customAgentQuota.memoryQuota
# 追加模式:在现有配额基础上增加
new_cpu_quota = float(channel_quota.cpu_quota or 0) + req.customAgentQuota.cpuQuota
new_memory_quota = float(channel_quota.memory_quota or 0) + req.customAgentQuota.memoryQuota
channel_quota.cpu_quota = new_cpu_quota
channel_quota.memory_quota = new_memory_quota
# 更新渠道表中的配额字段
channel.custom_agent_cpu_quota = new_cpu_quota
channel.custom_agent_memory_quota = new_memory_quota
else:
# 创建新配额记录
channel_quota = ChannelCustomAgentQuota(
@@ -1712,6 +1760,9 @@ async def allocate_channel_resources(
memory_allocated=0,
)
db.add(channel_quota)
# 更新渠道表中的配额字段
channel.custom_agent_cpu_quota = req.customAgentQuota.cpuQuota
channel.custom_agent_memory_quota = req.customAgentQuota.memoryQuota
channel.channel_credit = req.channelCredit
@@ -3063,8 +3114,20 @@ async def review_provider_application(
application.review_reason = req.reason
application.reviewed_at = datetime.utcnow()
# 如果批准,创建渠道供应商授权记录
# 如果批准,创建渠道供应商授权记录并更新 LiteLLM team
if req.approved:
# 获取渠道信息
channel_result = await db.execute(
select(Channel).where(Channel.id == application.channel_id)
)
channel = channel_result.scalar_one_or_none()
if not channel:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="渠道不存在"
)
# 检查是否已存在授权
existing_result = await db.execute(
select(ChannelProviderAccess).where(
@@ -3095,6 +3158,77 @@ async def review_provider_application(
approved_at=datetime.utcnow(),
)
db.add(access)
# 更新 LiteLLM team 的 models 列表(添加该供应商的所有模型)
if channel.litellm_team_id and provider.supported_models:
try:
from app.litellm_client import get_litellm_client, LiteLLMClientError
litellm_client = get_litellm_client()
# 获取渠道当前已分配的模型列表
current_models_result = await db.execute(
select(ResourceAllocation).where(
and_(
ResourceAllocation.target_id == application.channel_id,
ResourceAllocation.target_type == "channel",
ResourceAllocation.resource_type == "model"
)
)
)
current_models = {alloc.resource_id for alloc in current_models_result.scalars().all()}
# 添加供应商的模型(去重)
new_models = set(provider.supported_models)
all_models = list(current_models | new_models)
# 更新 LiteLLM team
await litellm_client.update_team(
team_id=channel.litellm_team_id,
models=all_models,
metadata={
"channel_id": str(channel.id),
"channel_name": channel.name,
"channel_email": channel.email,
"models_count": len(all_models),
"provider_ids": [str(application.provider_id)],
}
)
logger.info(f"渠道 {channel.name} 的 LiteLLM Team 模型列表已更新(批准供应商申请): {all_models}")
# 同时更新 ResourceAllocation 记录(追加模式)
for model_name in new_models:
if model_name not in current_models:
allocation = ResourceAllocation(
target_id=application.channel_id,
target_type="channel",
resource_type="model",
resource_id=model_name,
)
db.add(allocation)
logger.info(f"追加模型分配给渠道 {channel.name}: model={model_name}(来自供应商申请)")
except LiteLLMClientError as e:
logger.error(f"更新渠道 {channel.name} 的 LiteLLM Team 失败(批准供应商申请): {e}")
await db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"LiteLLM Team 更新失败,供应商申请审批已取消: {str(e)}"
)
except Exception as e:
logger.error(f"更新渠道 {channel.name} 的 LiteLLM 连接失败(批准供应商申请): {e}")
await db.rollback()
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=f"无法连接 LiteLLM Gateway,供应商申请审批已取消: {str(e)}"
)
elif not channel.litellm_team_id:
# 渠道没有关联的 LiteLLM Team,无法批准申请
await db.rollback()
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="渠道没有关联的 LiteLLM Team,无法批准供应商申请。请先重新创建渠道或联系管理员"
)
await db.commit()
@@ -3860,12 +3994,16 @@ async def allocate_platform_agent_to_channel(
quota = quota_result.scalar_one_or_none()
if quota:
# 更新现有配额
old_quota = quota.pod_quota
quota.pod_quota = pod_quota
# 追加模式:在现有配额基础上增加
old_quota = quota.pod_quota or 0
quota.pod_quota = old_quota + pod_quota
quota.allocated_by = user_id
quota.allocated_at = datetime.utcnow()
message = f"平台 Agent 配额已更新({old_quota} -> {pod_quota})"
message = f"平台 Agent 配额已追加({old_quota} + {pod_quota} = {quota.pod_quota})"
logger.info(
f"追加平台 Agent 配额给渠道 {channel.name}: "
f"template={template_name}, 追加量={pod_quota}, 新配额={quota.pod_quota}"
)
else:
# 创建新配额记录
quota = PlatformAgentQuota(
@@ -3879,6 +4017,10 @@ async def allocate_platform_agent_to_channel(
)
db.add(quota)
message = "平台 Agent 配额分配成功"
logger.info(
f"创建平台 Agent 配额给渠道 {channel.name}: "
f"template={template_name}, quota={pod_quota}"
)
await db.commit()