- Augment log search with app type filtering to enable keyword searching within workflow_executions. - Introduce execution sequence markers to ensure logs are displayed in the correct chronological order. - Ameliorate error handling to capture successful node outputs alongside failure details. - Rectify the processing of empty JSON bodies in HTTP request nodes.
111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
"""应用日志(消息记录)接口"""
|
||
import uuid
|
||
from typing import Optional
|
||
|
||
from fastapi import APIRouter, Depends, Query
|
||
from sqlalchemy.orm import Session
|
||
|
||
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_current_user, cur_workspace_access_guard
|
||
from app.schemas.app_log_schema import AppLogConversation, AppLogConversationDetail, AppLogMessage
|
||
from app.schemas.response_schema import PageData, PageMeta
|
||
from app.services.app_service import AppService
|
||
from app.services.app_log_service import AppLogService
|
||
|
||
router = APIRouter(prefix="/apps", tags=["App Logs"])
|
||
logger = get_business_logger()
|
||
|
||
|
||
@router.get("/{app_id}/logs", summary="应用日志 - 会话列表")
|
||
@cur_workspace_access_guard()
|
||
def list_app_logs(
|
||
app_id: uuid.UUID,
|
||
page: int = Query(1, ge=1),
|
||
pagesize: int = Query(20, ge=1, le=100),
|
||
is_draft: Optional[bool] = Query(None, description="是否草稿会话(不传则返回全部)"),
|
||
keyword: Optional[str] = Query(None, description="搜索关键词(匹配消息内容)"),
|
||
db: Session = Depends(get_db),
|
||
current_user=Depends(get_current_user),
|
||
):
|
||
"""查看应用下所有会话记录(分页)
|
||
|
||
- is_draft 不传则返回所有会话(草稿 + 正式)
|
||
- is_draft=True 只返回草稿会话
|
||
- is_draft=False 只返回发布会话
|
||
- 支持按 keyword 搜索(匹配消息内容)
|
||
- 按最新更新时间倒序排列
|
||
"""
|
||
workspace_id = current_user.current_workspace_id
|
||
|
||
# 验证应用访问权限
|
||
app_service = AppService(db)
|
||
app = app_service.get_app(app_id, workspace_id)
|
||
|
||
# 使用 Service 层查询
|
||
log_service = AppLogService(db)
|
||
conversations, total = log_service.list_conversations(
|
||
app_id=app_id,
|
||
workspace_id=workspace_id,
|
||
page=page,
|
||
pagesize=pagesize,
|
||
is_draft=is_draft,
|
||
keyword=keyword,
|
||
app_type=app.type,
|
||
)
|
||
|
||
items = [AppLogConversation.model_validate(c) for c in conversations]
|
||
meta = PageMeta(page=page, pagesize=pagesize, total=total, hasnext=(page * pagesize) < total)
|
||
|
||
return success(data=PageData(page=meta, items=items))
|
||
|
||
|
||
@router.get("/{app_id}/logs/{conversation_id}", summary="应用日志 - 会话消息详情")
|
||
@cur_workspace_access_guard()
|
||
def get_app_log_detail(
|
||
app_id: uuid.UUID,
|
||
conversation_id: uuid.UUID,
|
||
db: Session = Depends(get_db),
|
||
current_user=Depends(get_current_user),
|
||
):
|
||
"""查看某会话的完整消息记录
|
||
|
||
- 返回会话基本信息 + 所有消息(按时间正序)
|
||
- 消息 meta_data 包含模型名、token 用量等信息
|
||
- 所有人(包括共享者和被共享者)都只能查看自己的会话详情
|
||
"""
|
||
workspace_id = current_user.current_workspace_id
|
||
|
||
# 验证应用访问权限
|
||
app_service = AppService(db)
|
||
app = app_service.get_app(app_id, workspace_id)
|
||
|
||
# 使用 Service 层查询
|
||
log_service = AppLogService(db)
|
||
conversation, messages, node_executions_map = log_service.get_conversation_detail(
|
||
app_id=app_id,
|
||
conversation_id=conversation_id,
|
||
workspace_id=workspace_id,
|
||
app_type=app.type
|
||
)
|
||
|
||
# 构建基础会话信息(不经过 ORM relationship)
|
||
base = AppLogConversation.model_validate(conversation)
|
||
|
||
# 单独处理 messages,避免触发 SQLAlchemy relationship 校验
|
||
if messages and isinstance(messages[0], AppLogMessage):
|
||
# 工作流:已经是 AppLogMessage 实例
|
||
msg_list = messages
|
||
else:
|
||
# Agent:ORM Message 对象逐个转换
|
||
msg_list = [AppLogMessage.model_validate(m) for m in messages]
|
||
|
||
detail = AppLogConversationDetail(
|
||
**base.model_dump(),
|
||
messages=msg_list,
|
||
node_executions_map=node_executions_map,
|
||
)
|
||
|
||
return success(data=detail)
|