""" 增强版 Chat API — Phase 2.5 包含: Skill ID统一(MarketApp映射), 真实Skill执行, Agent工作流注入, 多轮上下文保持, BM25 KB检索, Function Calling循环增强 """ from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from sqlalchemy import and_, desc, asc, func from pydantic import BaseModel, Field from typing import Optional import uuid from datetime import datetime, timezone, timedelta import re import json import asyncio import math import httpx import os import logging from ..database import get_db, SessionLocal from ..models import ( User, Conversation, Message, AIModel, ModelProvider, TokenUsageLog, KnowledgeBase, KnowledgeDocument, KnowledgeDocumentChunk, EvolutionSkill, EvolutionTrajectory, MarketApp, AppPurchase, AppInstallation, gen_uuid ) from ..auth import get_current_user from ..middleware.log_service import LogService from ..capability_registry import resolve_auto_model router = APIRouter() logger = logging.getLogger(__name__) def detect_media_intent(text: str) -> str | None: """根据用户输入判断是否为 图像/视频/语音 生成请求,返回对应能力或 None。 用于 Auto 模式:用户未指定具体模型时,依据意图自动匹配平台各类能力的默认模型。 疑问句(含「吗/呢/怎么/能否」或结尾问号)不触发,避免「你能生成视频吗」被误判。 """ if not text: return None t = text.lower().strip() # 疑问句不触发媒体生成 if t.endswith(("?", "?")) or any(q in t for q in ("吗", "呢", "怎么", "如何", "能否", "是否可以", "可以吗", "会不会", "why", "how")): return None video_kw = ("视频", "短片", "影片", "vide", "动画视频", "一段视频", "做个视频", "生成视频", "视频生成", "来段视频", "拍个视频", "做段视频", "视频剪辑") image_kw = ("图片", "图像", "插画", "海报", "照片", "头像", "壁纸", "漫画", "表情包", "logo", "图标", "imag", "画一张", "画张", "画一只", "画只", "画个", "画幅", "来张", "来一张", "来幅", "发张图", "发个图", "生成图片", "生成一张", "生成一幅", "生成图", "图像生成", "做一张", "做张图", "做张", "出张图", "出一张图", "帮我画", "给我画", "请画", "绘制", "作画", "ai绘画", "ai画图", "画个图", "画张图", "画一幅图", "一张图", "一幅画", "生成一幅") audio_kw = ("语音", "配音", "朗读", "播报", "念一段", "有声", "tts", "音频", "生成语音", "读一下", "念一下", "语音合成") if any(k in t for k in video_kw): return "video" if any(k in t for k in image_kw): return "image" if any(k in t for k in audio_kw): return "audio" return None # CST timezone (UTC+8) for consistent time display CST_TZ = timezone(timedelta(hours=8)) def cst_now(): """Get current time in CST timezone""" return datetime.now(CST_TZ) def _html_escape(s: str) -> str: return (str(s).replace("&", "&").replace("<", "<").replace(">", ">") .replace('"', """).replace("'", "'")) async def _generate_media(db, ai_model, prompt: str, user_id: str = None) -> str: """图像/视频生成模型统一入口:按 capabilities 调用 AGNES 等媒体生成 API。 返回可直接在 AI 聊天中渲染的富文本(含 /