[modify] app_api
This commit is contained in:
@@ -1,30 +1,28 @@
|
|||||||
"""App 服务接口 - 基于 API Key 认证"""
|
"""App 服务接口 - 基于 API Key 认证"""
|
||||||
import uuid
|
from typing import Annotated
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, Request, Body
|
from fastapi import APIRouter, Depends, Request, Body
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from typing import Optional, Annotated
|
|
||||||
|
|
||||||
from starlette.responses import StreamingResponse
|
from starlette.responses import StreamingResponse
|
||||||
|
|
||||||
from app.core.api_key_auth import require_api_key
|
from app.core.api_key_auth import require_api_key
|
||||||
from app.db import get_db
|
from app.core.error_codes import BizCode
|
||||||
from app.core.response_utils import success
|
from app.core.exceptions import BusinessException
|
||||||
from app.core.logging_config import get_business_logger
|
from app.core.logging_config import get_business_logger
|
||||||
|
from app.core.response_utils import success
|
||||||
|
from app.db import get_db
|
||||||
from app.dependencies import get_app_or_workspace
|
from app.dependencies import get_app_or_workspace
|
||||||
from app.models import AppRelease
|
|
||||||
from app.repositories import knowledge_repository
|
|
||||||
from app.schemas import AppChatRequest, conversation_schema
|
|
||||||
from app.models.app_model import App
|
from app.models.app_model import App
|
||||||
from app.models.app_model import AppType
|
from app.models.app_model import AppType
|
||||||
|
from app.repositories import knowledge_repository
|
||||||
from app.repositories.end_user_repository import EndUserRepository
|
from app.repositories.end_user_repository import EndUserRepository
|
||||||
from app.core.exceptions import BusinessException
|
from app.schemas import AppChatRequest, conversation_schema
|
||||||
from app.core.error_codes import BizCode
|
from app.schemas.api_key_schema import ApiKeyAuth
|
||||||
from app.services import workspace_service
|
from app.services import workspace_service
|
||||||
from app.services.app_chat_service import AppChatService, get_app_chat_service
|
from app.services.app_chat_service import AppChatService, get_app_chat_service
|
||||||
from app.services.app_service import AppService
|
|
||||||
from app.services.conversation_service import ConversationService, get_conversation_service
|
from app.services.conversation_service import ConversationService, get_conversation_service
|
||||||
from app.services.workflow_service import WorkflowService, get_workflow_service
|
from app.utils.app_config_utils import dict_to_multi_agent_config, dict_to_workflow_config, agent_config_4_app_release
|
||||||
from app.utils.app_config_utils import dict_to_multi_agent_config,dict_to_workflow_config,agent_config_4_app_release
|
from app.services.app_service import get_app_service, AppService
|
||||||
|
|
||||||
router = APIRouter(prefix="/app", tags=["V1 - App API"])
|
router = APIRouter(prefix="/app", tags=["V1 - App API"])
|
||||||
logger = get_business_logger()
|
logger = get_business_logger()
|
||||||
@@ -37,8 +35,9 @@ async def list_apps():
|
|||||||
|
|
||||||
# /v1/apps/{resource_id}/chat
|
# /v1/apps/{resource_id}/chat
|
||||||
|
|
||||||
|
# @router.post("/chat")
|
||||||
# async def chat(
|
# @require_api_key(scopes=["app"])
|
||||||
|
# async def chat2(
|
||||||
# request: Request,
|
# request: Request,
|
||||||
# api_key_auth: ApiKeyAuth = None,
|
# api_key_auth: ApiKeyAuth = None,
|
||||||
# db: Session = Depends(get_db),
|
# db: Session = Depends(get_db),
|
||||||
@@ -57,7 +56,6 @@ async def list_apps():
|
|||||||
# db: db_session
|
# db: db_session
|
||||||
# """
|
# """
|
||||||
# logger.info(f"API Key Auth: {api_key_auth}")
|
# logger.info(f"API Key Auth: {api_key_auth}")
|
||||||
# logger.info(f"Resource ID: {resource_id}")
|
|
||||||
# logger.info(f"Message: {message}")
|
# logger.info(f"Message: {message}")
|
||||||
# return success(data={"received": True}, msg="消息已接收")
|
# return success(data={"received": True}, msg="消息已接收")
|
||||||
|
|
||||||
@@ -76,15 +74,21 @@ def _checkAppConfig(app: App):
|
|||||||
raise BusinessException("不支持的应用类型", BizCode.AGENT_CONFIG_MISSING)
|
raise BusinessException("不支持的应用类型", BizCode.AGENT_CONFIG_MISSING)
|
||||||
|
|
||||||
@router.post("/chat")
|
@router.post("/chat")
|
||||||
# @require_api_key(scopes=["app"])
|
@require_api_key(scopes=["app"])
|
||||||
async def chat(
|
async def chat(
|
||||||
payload: AppChatRequest,
|
request:Request,
|
||||||
app: App = Depends(get_app_or_workspace),
|
api_key_auth: ApiKeyAuth = None,
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
conversation_service: Annotated[ConversationService, Depends(get_conversation_service)] = None,
|
conversation_service: Annotated[ConversationService, Depends(get_conversation_service)] = None,
|
||||||
app_chat_service: Annotated[AppChatService, Depends(get_app_chat_service)] = None,
|
app_chat_service: Annotated[AppChatService, Depends(get_app_chat_service)] = None,
|
||||||
|
app_service: Annotated[AppService, Depends(get_app_service)] = None,
|
||||||
|
message: str = Body(..., description="聊天消息内容"),
|
||||||
):
|
):
|
||||||
|
body = await request.json()
|
||||||
|
payload = AppChatRequest(**body)
|
||||||
|
|
||||||
|
other_id = payload.user_id
|
||||||
|
app = app_service.get_app(api_key_auth.resource_id, api_key_auth.workspace_id)
|
||||||
other_id = payload.user_id
|
other_id = payload.user_id
|
||||||
workspace_id = app.workspace_id
|
workspace_id = app.workspace_id
|
||||||
end_user_repo = EndUserRepository(db)
|
end_user_repo = EndUserRepository(db)
|
||||||
@@ -176,7 +180,7 @@ async def chat(
|
|||||||
storage_type=storage_type,
|
storage_type=storage_type,
|
||||||
user_rag_memory_id=user_rag_memory_id
|
user_rag_memory_id=user_rag_memory_id
|
||||||
)
|
)
|
||||||
return success(data=conversation_schema.ChatResponse(**result))
|
return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json"))
|
||||||
elif app_type == AppType.MULTI_AGENT:
|
elif app_type == AppType.MULTI_AGENT:
|
||||||
# 多 Agent 流式返回
|
# 多 Agent 流式返回
|
||||||
config = dict_to_multi_agent_config(app.current_release.config,app.id)
|
config = dict_to_multi_agent_config(app.current_release.config,app.id)
|
||||||
@@ -220,7 +224,7 @@ async def chat(
|
|||||||
user_rag_memory_id=user_rag_memory_id
|
user_rag_memory_id=user_rag_memory_id
|
||||||
)
|
)
|
||||||
|
|
||||||
return success(data=conversation_schema.ChatResponse(**result))
|
return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json"))
|
||||||
elif app_type == AppType.WORKFLOW:
|
elif app_type == AppType.WORKFLOW:
|
||||||
# 多 Agent 流式返回
|
# 多 Agent 流式返回
|
||||||
config = dict_to_workflow_config(app.current_release.config,app.id)
|
config = dict_to_workflow_config(app.current_release.config,app.id)
|
||||||
@@ -264,7 +268,7 @@ async def chat(
|
|||||||
user_rag_memory_id=user_rag_memory_id
|
user_rag_memory_id=user_rag_memory_id
|
||||||
)
|
)
|
||||||
|
|
||||||
return success(data=conversation_schema.ChatResponse(**result))
|
return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json"))
|
||||||
else:
|
else:
|
||||||
from app.core.exceptions import BusinessException
|
from app.core.exceptions import BusinessException
|
||||||
from app.core.error_codes import BizCode
|
from app.core.error_codes import BizCode
|
||||||
|
|||||||
@@ -1,26 +1,42 @@
|
|||||||
"""多 Agent 相关数据模型"""
|
"""多 Agent 相关数据模型"""
|
||||||
import datetime
|
import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
from sqlalchemy import Column, String, Boolean, DateTime, Integer, Float, Text, ForeignKey
|
from sqlalchemy import Column, String, Boolean, DateTime, Integer, Float, Text, ForeignKey
|
||||||
from sqlalchemy.dialects.postgresql import UUID, JSON
|
from sqlalchemy.dialects.postgresql import UUID, JSON
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from app.db import Base
|
from app.db import Base
|
||||||
|
|
||||||
|
class OrchestrationMode(StrEnum):
|
||||||
|
"""图标类型枚举"""
|
||||||
|
SEQUENTIAL = "sequential"
|
||||||
|
PARALLEL = "parallel"
|
||||||
|
CONDITIONAL = "conditional"
|
||||||
|
|
||||||
|
class AggregationStrategy(StrEnum):
|
||||||
|
"""图标类型枚举"""
|
||||||
|
MERGE = "merge"
|
||||||
|
VOTE = "vote"
|
||||||
|
PRIORITY = "priority"
|
||||||
|
|
||||||
class MultiAgentConfig(Base):
|
class MultiAgentConfig(Base):
|
||||||
"""多 Agent 配置表"""
|
"""多 Agent 配置表"""
|
||||||
__tablename__ = "multi_agent_configs"
|
__tablename__ = "multi_agent_configs"
|
||||||
|
|
||||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
|
||||||
|
|
||||||
# 关联应用
|
# 关联应用
|
||||||
app_id = Column(UUID(as_uuid=True), ForeignKey("apps.id"), nullable=False, unique=True, index=True, comment="关联应用")
|
app_id = Column(UUID(as_uuid=True), ForeignKey("apps.id"), nullable=False, unique=True, index=True, comment="关联应用")
|
||||||
|
|
||||||
# 主 Agent (存储发布版本 ID)
|
# 主 Agent (存储发布版本 ID)
|
||||||
master_agent_id = Column(UUID(as_uuid=True), ForeignKey("app_releases.id"), nullable=False, comment="主 Agent 发布版本 ID")
|
master_agent_id = Column(UUID(as_uuid=True), ForeignKey("app_releases.id"), nullable=True, comment="主 Agent 发布版本 ID")
|
||||||
master_agent_name = Column(String(100), comment="主 Agent 名称")
|
master_agent_name = Column(String(100), comment="主 Agent 名称")
|
||||||
|
|
||||||
|
default_model_config_id = Column(UUID(as_uuid=True), ForeignKey("model_configs.id"), nullable=False,server_default=str(uuid.UUID(int=0)), index=True, comment="默认模型配置ID")
|
||||||
|
# 结构化配置(直接存储 JSON)
|
||||||
|
model_parameters = Column(JSON, nullable=True, comment="模型参数配置(temperature、max_tokens等)")
|
||||||
# 协作模式
|
# 协作模式
|
||||||
orchestration_mode = Column(
|
orchestration_mode = Column(
|
||||||
String(20),
|
String(20),
|
||||||
@@ -28,7 +44,7 @@ class MultiAgentConfig(Base):
|
|||||||
default="conditional",
|
default="conditional",
|
||||||
comment="协作模式: sequential|parallel|conditional|loop"
|
comment="协作模式: sequential|parallel|conditional|loop"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 子 Agent 列表
|
# 子 Agent 列表
|
||||||
sub_agents = Column(
|
sub_agents = Column(
|
||||||
JSON,
|
JSON,
|
||||||
@@ -36,13 +52,13 @@ class MultiAgentConfig(Base):
|
|||||||
default=list,
|
default=list,
|
||||||
comment="子 Agent 列表: [{'agent_id': 'uuid', 'name': '...', 'role': '...', 'priority': 1}]"
|
comment="子 Agent 列表: [{'agent_id': 'uuid', 'name': '...', 'role': '...', 'priority': 1}]"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 路由规则
|
# 路由规则
|
||||||
routing_rules = Column(
|
routing_rules = Column(
|
||||||
JSON,
|
JSON,
|
||||||
comment="路由规则: [{'condition': '...', 'target_agent_id': 'uuid', 'priority': 1}]"
|
comment="路由规则: [{'condition': '...', 'target_agent_id': 'uuid', 'priority': 1}]"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 执行配置
|
# 执行配置
|
||||||
execution_config = Column(
|
execution_config = Column(
|
||||||
JSON,
|
JSON,
|
||||||
@@ -50,7 +66,7 @@ class MultiAgentConfig(Base):
|
|||||||
default=dict,
|
default=dict,
|
||||||
comment="执行配置: {'max_iterations': 5, 'timeout': 60, 'parallel_limit': 3}"
|
comment="执行配置: {'max_iterations': 5, 'timeout': 60, 'parallel_limit': 3}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 结果整合策略
|
# 结果整合策略
|
||||||
aggregation_strategy = Column(
|
aggregation_strategy = Column(
|
||||||
String(20),
|
String(20),
|
||||||
@@ -58,12 +74,12 @@ class MultiAgentConfig(Base):
|
|||||||
default="merge",
|
default="merge",
|
||||||
comment="结果整合策略: merge|vote|priority|custom"
|
comment="结果整合策略: merge|vote|priority|custom"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 状态
|
# 状态
|
||||||
is_active = Column(Boolean, default=True, nullable=False)
|
is_active = Column(Boolean, default=True, nullable=False)
|
||||||
created_at = Column(DateTime, default=datetime.datetime.now)
|
created_at = Column(DateTime, default=datetime.datetime.now)
|
||||||
updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
||||||
|
|
||||||
# 关系
|
# 关系
|
||||||
app = relationship("App")
|
app = relationship("App")
|
||||||
master_agent_release = relationship("AppRelease", foreign_keys=[master_agent_id])
|
master_agent_release = relationship("AppRelease", foreign_keys=[master_agent_id])
|
||||||
@@ -77,7 +93,7 @@ class AgentInvocation(Base):
|
|||||||
__tablename__ = "agent_invocations"
|
__tablename__ = "agent_invocations"
|
||||||
|
|
||||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
|
||||||
|
|
||||||
# 调用关系
|
# 调用关系
|
||||||
caller_agent_id = Column(
|
caller_agent_id = Column(
|
||||||
UUID(as_uuid=True),
|
UUID(as_uuid=True),
|
||||||
@@ -93,7 +109,7 @@ class AgentInvocation(Base):
|
|||||||
index=True,
|
index=True,
|
||||||
comment="被调用者 Agent ID"
|
comment="被调用者 Agent ID"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 关联信息
|
# 关联信息
|
||||||
conversation_id = Column(
|
conversation_id = Column(
|
||||||
UUID(as_uuid=True),
|
UUID(as_uuid=True),
|
||||||
@@ -106,12 +122,12 @@ class AgentInvocation(Base):
|
|||||||
index=True,
|
index=True,
|
||||||
comment="父调用 ID(用于追踪调用链)"
|
comment="父调用 ID(用于追踪调用链)"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 输入输出
|
# 输入输出
|
||||||
input_message = Column(Text, nullable=False, comment="输入消息")
|
input_message = Column(Text, nullable=False, comment="输入消息")
|
||||||
output_message = Column(Text, comment="输出消息")
|
output_message = Column(Text, comment="输出消息")
|
||||||
context = Column(JSON, comment="上下文信息")
|
context = Column(JSON, comment="上下文信息")
|
||||||
|
|
||||||
# 状态
|
# 状态
|
||||||
status = Column(
|
status = Column(
|
||||||
String(20),
|
String(20),
|
||||||
@@ -121,18 +137,18 @@ class AgentInvocation(Base):
|
|||||||
comment="状态: pending|running|completed|failed"
|
comment="状态: pending|running|completed|failed"
|
||||||
)
|
)
|
||||||
error_message = Column(Text, comment="错误信息")
|
error_message = Column(Text, comment="错误信息")
|
||||||
|
|
||||||
# 性能指标
|
# 性能指标
|
||||||
started_at = Column(DateTime, nullable=False, default=datetime.datetime.now, index=True)
|
started_at = Column(DateTime, nullable=False, default=datetime.datetime.now, index=True)
|
||||||
completed_at = Column(DateTime)
|
completed_at = Column(DateTime)
|
||||||
elapsed_time = Column(Float, comment="耗时(秒)")
|
elapsed_time = Column(Float, comment="耗时(秒)")
|
||||||
token_usage = Column(JSON, comment="Token 使用情况")
|
token_usage = Column(JSON, comment="Token 使用情况")
|
||||||
|
|
||||||
# 元数据
|
# 元数据
|
||||||
meta_data = Column(JSON, comment="额外元数据")
|
meta_data = Column(JSON, comment="额外元数据")
|
||||||
|
|
||||||
created_at = Column(DateTime, default=datetime.datetime.now)
|
created_at = Column(DateTime, default=datetime.datetime.now)
|
||||||
|
|
||||||
# 关系
|
# 关系
|
||||||
caller = relationship("AgentConfig", foreign_keys=[caller_agent_id])
|
caller = relationship("AgentConfig", foreign_keys=[caller_agent_id])
|
||||||
callee = relationship("AgentConfig", foreign_keys=[callee_agent_id])
|
callee = relationship("AgentConfig", foreign_keys=[callee_agent_id])
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
"""
|
"""
|
||||||
import datetime
|
import datetime
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Optional, List, Dict, Any, Tuple
|
from typing import Optional, List, Dict, Any, Tuple, Annotated
|
||||||
|
|
||||||
|
from fastapi import Depends
|
||||||
from sqlalchemy import select, func, or_, and_
|
from sqlalchemy import select, func, or_, and_
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ from app.core.exceptions import (
|
|||||||
BusinessException,
|
BusinessException,
|
||||||
)
|
)
|
||||||
from app.core.logging_config import get_business_logger
|
from app.core.logging_config import get_business_logger
|
||||||
|
from app.db import get_db
|
||||||
from app.models import App, AgentConfig, AppRelease, MultiAgentConfig, WorkflowConfig
|
from app.models import App, AgentConfig, AppRelease, MultiAgentConfig, WorkflowConfig
|
||||||
from app.models.app_model import AppStatus, AppType
|
from app.models.app_model import AppStatus, AppType
|
||||||
from app.repositories.app_repository import get_apps_by_id
|
from app.repositories.app_repository import get_apps_by_id
|
||||||
@@ -1407,7 +1409,7 @@ class AppService:
|
|||||||
ResourceNotFoundException: 当应用不存在时
|
ResourceNotFoundException: 当应用不存在时
|
||||||
BusinessException: 当应用不在指定工作空间或目标工作空间无效时
|
BusinessException: 当应用不在指定工作空间或目标工作空间无效时
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"分享应用",
|
"分享应用",
|
||||||
@@ -2095,3 +2097,14 @@ async def draft_run_stream(
|
|||||||
workspace_id=workspace_id
|
workspace_id=workspace_id
|
||||||
):
|
):
|
||||||
yield event
|
yield event
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 依赖注入函数 ====================
|
||||||
|
|
||||||
|
def get_app_service(
|
||||||
|
db: Annotated[Session, Depends(get_db)]
|
||||||
|
) -> AppService:
|
||||||
|
"""获取工作流服务(依赖注入)"""
|
||||||
|
return AppService(db)
|
||||||
|
|||||||
Reference in New Issue
Block a user