From 4c0474fcfe50499b9f20dee3851a276f89a19aed Mon Sep 17 00:00:00 2001 From: silk Date: Thu, 14 May 2026 22:05:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E4=BA=9B=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E4=BD=BF=E7=94=A8=E4=B8=AD=E5=9E=92=E7=81=AB=E7=84=B1?= =?UTF-8?q?=E5=A4=A7=E6=A8=A1=E5=9E=8B=E7=BD=91=E5=85=B3=E7=9A=84=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + admin-frontend/vite.config.js | 2 + backend/.env.example | 74 ++-- backend/Dockerfile | 16 + backend/services/vector_service.py | 4 +- backend/services/vision_service.py | 130 ++++--- backend/tools/tools.py | 534 +++++++++++++---------------- 7 files changed, 366 insertions(+), 397 deletions(-) create mode 100644 backend/Dockerfile diff --git a/.gitignore b/.gitignore index 6ae655b..ea77a85 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,8 @@ backend/logs/ .env.* !.env.example !**/.env.example +!.env.docker +!**/.env.docker # IDE .vscode/ @@ -99,3 +101,4 @@ Thumbs.db # 本地导出的 IDE / 对话历史等(按需) history.txt .cursor/ +backend/.env.docker \ No newline at end of file diff --git a/admin-frontend/vite.config.js b/admin-frontend/vite.config.js index 99edb09..03b6760 100644 --- a/admin-frontend/vite.config.js +++ b/admin-frontend/vite.config.js @@ -2,6 +2,8 @@ import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; export default defineConfig({ + // Docker 部署在 /admin/ 子路径下时需构建前设置 VITE_BASE_PATH=/admin/ + base: process.env.VITE_BASE_PATH || "/", plugins: [vue()], server: { port: 5174, diff --git a/backend/.env.example b/backend/.env.example index a10923e..97ad9cb 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -10,8 +10,24 @@ APP.NAME=星云 API Server DB_HOST=106.15.186.110 DB_PORT=5432 DB_NAME=qiyeban_huoyanai -DB_USER=zuoleiroot -DB_PASSWORD=C1C0DDleRy4wgSkD +DB_USER=changeme_in_production +DB_PASSWORD=changeme_in_production + + +# ==================== Neo4j 图数据库配置 ==================== +NEO4J_URI=bolt://ip:7687 +NEO4J_USER=neo4j +NEO4J_PASSWORD=graph123 + +# 数据库连接池配置 +DB_POOL_MIN_SIZE=5 +DB_POOL_MAX_SIZE=20 +DB_COMMAND_TIMEOUT=60 +CHECKPOINTER_POOL_MAX_SIZE=20 + +# ==================== ChromaDB(与原项目同网络)==================== +CHROMA_HOST=106.15.186.110 +CHROMA_PORT=9527 # ==================== JWT 认证配置 ==================== @@ -32,23 +48,18 @@ logging.enable_console=True # HTTP 请求超时时间(秒) HTTPX_DEFAULT_TIMEOUT=120 -# ==================== 代理配置 ==================== -# 如果需要通过代理访问 GitHub(可选) -# HTTP_PROXY=http://127.0.0.1:7890 -# HTTPS_PROXY=http://127.0.0.1:7890 - +# ==================== 业务 / 第三方 MCP ==================== MCP_JUHE_TOKEN=SLIC4Zv3KnCkxyOYsZj4FabImp0RDdz8Td17Io0Tn2YHio -OSS_ACCESS_KEY_ID = 'LTAI5tFGRDXbWyCzJL2e8Apd' -OSS_ACCESS_KEY_SECRET = 'QMEBsDhuAX6YwSmAbbILvsA7WFU58w' + +# ==================== 阿里云 OSS(按需)==================== +OSS_ACCESS_KEY_ID = changeme_in_production +OSS_ACCESS_KEY_SECRET = changeme_in_production OSS_ENDPOINT = 'https://oss-cn-hangzhou.aliyuncs.com' # 根据你的区域修改 - -OSS_BUCKET_NAME = 'zhongleiai' -CHROMA_HOST=106.15.186.110 -CHROMA_PORT=9527 +OSS_BUCKET_NAME = changeme_in_production -# RAG 配置 +# ==================== RAG / Embedding ==================== RAG_CHUNK_SIZE=512 # 文本分块大小 RAG_CHUNK_OVERLAP=50 # 分块重叠大小 RAG_TOP_K=5 # 检索返回的文档数量 @@ -59,27 +70,28 @@ EMBEDDING_MODEL=text-embedding-v4 # 通义千问 Embedding 模型 EMBEDDING_DIMENSION=1536 # Embedding 维度 -# OCR_ACCESS_KEY_ID=LTAI5tE5oGfC37bh3Vg1KLNK -# OCR_ACCESS_KEY_SECRET=WBAa3Fh8Tw9Kvgx4zzagWDOcPlSp4L -# OCR_ENDPOINT=ocr-api.cn-hangzhou.aliyuncs.com -# OCR_USE_LOCAL=false - -OCR_ACCESS_KEY_ID=LTAI5tHAbs3umUtnMS1yR8Ti -OCR_ACCESS_KEY_SECRET=eByWHxrWrrDtKgOmKIu9jood6RTtwS +# ==================== 阿里云 OCR ==================== +OCR_ACCESS_KEY_ID=changeme_in_production +OCR_ACCESS_KEY_SECRET=changeme_in_production OCR_ENDPOINT=ocr-api.cn-hangzhou.aliyuncs.com OCR_USE_LOCAL=false MODERATION_ENABLED=false -# ==================== Neo4j 图数据库配置 ==================== -NEO4J_URI=bolt://47.110.73.142:7687 -NEO4J_USER=neo4j -NEO4J_PASSWORD=graph123 +# DEEPSEEK_API_KEY=sk-changeme_in_production +# DASHSCOPE_API_KEY=sk-changeme_in_production +# DEEPSEEK_API_BASE=https://api.zlapi.com.cn/api/v1 +# DASHSCOPE_API_BASE=https://api.zlapi.com.cn/api/v1 -DEEPSEEK_API_KEY=sk-CvmggZnFVo0JlaBOa1EL9FRjn4bEprK -DASHSCOPE_API_KEY=sk-CvmggZnFVo0JlaBOa1EL9FRjn4bEprK -DEEPSEEK_API_BASE=https://api.zlapi.com.cn/api/v1 -DASHSCOPE_API_BASE=https://api.zlapi.com.cn/api/v1 -# 通义:ChatOpenAI / 视觉等走此兼容 base(如 .../compatible-mode/v1)。USE_ORIGIN_MODEL=true 时 ChatTongyi / 文生图等原生 SDK 会自动用同主机 .../api/v1(勿把兼容 URL 直接当原生 base)。 -USE_ORIGIN_MODEL=false \ No newline at end of file +DEEPSEEK_API_KEY=changeme_in_production +DASHSCOPE_API_KEY=changeme_in_production +#DEEPSEEK_API_BASE=https://api.deepseek.com/v1 +DASHSCOPE_API_BASE=https://dashscope.aliyuncs.com/compatible-mode/v1 + +# 当此处为 true 时,表示聊天模型,使用的是原生的厂商模型以及原生厂商地址,否则,使用的是中垒的d大模型网关 +USE_ORIGIN_MODEL=True + +# 此处为必填,表示一定要使用中垒的dashscope网关,设计到的服务有text_to_image, text_to_video, text_to_poster以及向量化服务的embedding模型 +ZL_DASHSCOPE_API_BASE=https://api.zlapi.com.cn/api/v1 +ZL_DASHSCOPE_API_KEY=changeme_in_production \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..4c0c977 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,16 @@ +# Python 3.11 + uv(与 pyproject 中 requires-python 一致) +FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim + +WORKDIR /app + +COPY pyproject.toml uv.lock ./ +RUN uv sync --frozen --no-dev + +COPY . . + +ENV PYTHONUNBUFFERED=1 + +EXPOSE 7861 7862 + +# 端口以环境变量 API.PORT / API_PORT 为准(见 core.config) +CMD ["uv", "run", "python", "-m", "main"] diff --git a/backend/services/vector_service.py b/backend/services/vector_service.py index 5b37321..33f5760 100644 --- a/backend/services/vector_service.py +++ b/backend/services/vector_service.py @@ -131,8 +131,8 @@ class VectorService: print(settings.dashscope_api_key, settings.dashscope_api_base) self.embedding = OpenAIEmbeddings( model="text-embedding-v4", - api_key=settings.dashscope_api_key, - base_url=settings.dashscope_api_base, + api_key=os.getenv("ZL_DASHSCOPE_API_KEY"), # 如果您没有配置环境变量,请在此处用您的API Key进行替换 + base_url=os.getenv("ZL_DASHSCOPE_API_BASE"), check_embedding_ctx_length=False, ) diff --git a/backend/services/vision_service.py b/backend/services/vision_service.py index 4745fec..d3658e3 100644 --- a/backend/services/vision_service.py +++ b/backend/services/vision_service.py @@ -1,11 +1,12 @@ """ 视觉模型服务 -基于阿里云通义千问视觉模型 (qwen-vl-max-latest) 提供图片理解能力。 -参考 server/aaa/jenius_attachment_knowledge_base/jenius_rag_util.py 的实现。 +基于 OpenAI 兼容 ``chat.completions`` 接口(参见阿里云百炼视觉文档),使用支持图像输入的多模态模型。 +默认模型 ``qwen3-vl-plus``;网关与密钥优先读 ``ZL_OPENAI_*``,未配置时回退 ``DASHSCOPE_*`` / ``settings``。 """ import asyncio import base64 +import os from typing import Optional from openai import OpenAI, AsyncOpenAI @@ -15,6 +16,27 @@ from logger.logging import get_logger logger = get_logger(__name__) +# 与 OpenAI 兼容视觉示例一致;可通过环境变量覆盖 +VISION_CHAT_MODEL = (os.getenv("ZL_OPENAI_VISION_MODEL") or "qwen3-vl-plus").strip() + + +def _vision_openai_api_key() -> str: + zl = (os.getenv("ZL_OPENAI_API_KEY") or "").strip() + if zl: + return zl + return (settings.dashscope_api_key or "").strip() + + +def _vision_openai_base_url() -> str: + zl = (os.getenv("ZL_OPENAI_BASE_URL") or "").strip().rstrip("/") + if zl: + return zl + return tongyi_openai_compatible_base_url().strip().rstrip("/") + + +def _vision_client_signature() -> tuple[str, str]: + return (_vision_openai_api_key(), _vision_openai_base_url()) + def _is_vision_image_url(url: str) -> bool: if not url: @@ -45,39 +67,33 @@ def image_bytes_to_data_url(image_bytes: bytes, mime_hint: Optional[str] = None) class VisionService: - """视觉模型服务类 - - 使用阿里云通义千问视觉模型进行图片理解和描述。 - """ + """视觉模型服务:OpenAI SDK ``chat.completions`` + ``image_url``(URL 或 base64 data URL)。""" _client_cache: Optional[AsyncOpenAI] = None _sync_client_cache: Optional[OpenAI] = None + _async_client_sig: Optional[tuple[str, str]] = None + _sync_client_sig: Optional[tuple[str, str]] = None _lock = asyncio.Lock() @classmethod async def _get_async_client(cls) -> AsyncOpenAI: - """获取或创建异步客户端(单例模式)""" - if cls._client_cache is not None: - return cls._client_cache - + """获取或创建异步客户端(凭证变更时重建)。""" + sig = _vision_client_signature() async with cls._lock: - if cls._client_cache is None: - cls._client_cache = AsyncOpenAI( - api_key=settings.dashscope_api_key, - base_url=tongyi_openai_compatible_base_url(), - ) + if cls._client_cache is not None and cls._async_client_sig == sig: + return cls._client_cache + cls._async_client_sig = sig + cls._client_cache = AsyncOpenAI(api_key=sig[0], base_url=sig[1]) return cls._client_cache @classmethod def _get_sync_client(cls) -> OpenAI: - """获取或创建同步客户端(单例模式)""" - if cls._sync_client_cache is not None: + """获取或创建同步客户端(凭证变更时重建)。""" + sig = _vision_client_signature() + if cls._sync_client_cache is not None and cls._sync_client_sig == sig: return cls._sync_client_cache - - cls._sync_client_cache = OpenAI( - api_key=settings.dashscope_api_key, - base_url=tongyi_openai_compatible_base_url(), - ) + cls._sync_client_sig = sig + cls._sync_client_cache = OpenAI(api_key=sig[0], base_url=sig[1]) return cls._sync_client_cache @classmethod @@ -104,27 +120,21 @@ class VisionService: client = await cls._get_async_client() completion = await client.chat.completions.create( - model="qwen-vl-max-latest", + model=VISION_CHAT_MODEL, messages=[ - { - "role": "system", - "content": [{"type": "text", "text": "You are a helpful assistant."}] - }, { "role": "user", "content": [ - { - "type": "image_url", - "image_url": {"url": image_url} - }, - {"type": "text", "text": prompt} - ] + {"type": "image_url", "image_url": {"url": image_url}}, + {"type": "text", "text": prompt}, + ], } - ] + ], ) - description = completion.choices[0].message.content - logger.info(f"成功获取图片描述: {description[:50]}...") + description = completion.choices[0].message.content or "" + if description: + logger.info(f"成功获取图片描述: {description[:50]}...") return description except Exception as e: @@ -142,8 +152,8 @@ class VisionService: 从内存中的图片字节获取描述(异步),使用 data URL 调用通义 VL。 用于知识图谱上传等无公网 URL 的场景。 """ - if not settings.dashscope_api_key: - logger.warning("未配置 DASHSCOPE_API_KEY,无法进行视觉理解") + if not _vision_openai_api_key(): + logger.warning("未配置 ZL_OPENAI_API_KEY 或 DASHSCOPE_API_KEY,无法进行视觉理解") return "" if not image_bytes: return "" @@ -174,27 +184,21 @@ class VisionService: client = cls._get_sync_client() completion = client.chat.completions.create( - model="qwen-vl-max-latest", + model=VISION_CHAT_MODEL, messages=[ - { - "role": "system", - "content": [{"type": "text", "text": "You are a helpful assistant."}] - }, { "role": "user", "content": [ - { - "type": "image_url", - "image_url": {"url": image_url} - }, - {"type": "text", "text": prompt} - ] + {"type": "image_url", "image_url": {"url": image_url}}, + {"type": "text", "text": prompt}, + ], } - ] + ], ) - description = completion.choices[0].message.content - logger.info(f"成功获取图片描述: {description[:50]}...") + description = completion.choices[0].message.content or "" + if description: + logger.info(f"成功获取图片描述: {description[:50]}...") return description except Exception as e: @@ -225,27 +229,21 @@ class VisionService: client = await cls._get_async_client() completion = await client.chat.completions.create( - model="qwen-vl-max-latest", + model=VISION_CHAT_MODEL, messages=[ - { - "role": "system", - "content": [{"type": "text", "text": "You are a helpful assistant that can analyze images and answer questions about them."}] - }, { "role": "user", "content": [ - { - "type": "image_url", - "image_url": {"url": image_url} - }, - {"type": "text", "text": question} - ] + {"type": "image_url", "image_url": {"url": image_url}}, + {"type": "text", "text": question}, + ], } - ] + ], ) - answer = completion.choices[0].message.content - logger.info(f"成功分析图片并回答问题") + answer = completion.choices[0].message.content or "" + if answer: + logger.info("成功分析图片并回答问题") return answer except Exception as e: diff --git a/backend/tools/tools.py b/backend/tools/tools.py index c5620f1..e60039c 100644 --- a/backend/tools/tools.py +++ b/backend/tools/tools.py @@ -3,20 +3,18 @@ 定义各种 AI 工具函数,包括网络搜索、文生图、文生视频、RAG 检索等。 """ +import os import time import uuid import requests from typing import Literal, Optional -from http import HTTPStatus +from openai import OpenAI from langchain.tools import tool -from dashscope import ImageSynthesis, VideoSynthesis -import dashscope from concurrent.futures import ThreadPoolExecutor, as_completed import json from tavily import TavilyClient from core.config import settings -from core import llm_env from utils.datetime_utils import format_beijing_time_for_agent from logger.logging import get_logger from services.vector_service import get_vector_service @@ -26,11 +24,6 @@ from services.oss_service import get_oss_service logger = get_logger(__name__) -def _dashscope_http_api_base() -> str: - """``dashscope`` 原生 SDK 使用的 HTTP 根路径(与 OpenAI 兼容 ``DASHSCOPE_API_BASE`` 可能不同)。""" - return llm_env.dashscope_native_http_api_base().strip().rstrip("/") - - # 初始化 Tavily 客户端 tavily_client = TavilyClient(api_key=settings.tavily_api_key) @@ -125,92 +118,91 @@ def _download_and_upload_image_to_oss(image_url: str, image_index: int) -> tuple return image_url, None, 0.0, 0.0 +def _normalize_openai_image_size(size: str) -> str: + """将「宽*高」转为 OpenAI 兼容接口要求的「宽x高」。""" + return (size or "").strip().replace("*", "x") + + @tool def text_to_image( prompt: str, negative_prompt: str = "", - size: str = "1280*720", + size: str = "1024x1024", n: int = 1, -)->str: + prompt_extend: bool = True, + watermark: bool = False, + seed: Optional[int] = None, +) -> str: """ 文生图工具:根据文本描述生成高质量图片。 - - 当用户需要生成图片、创建图像、制作插图、设计视觉内容时,使用此工具。 - 该工具使用阿里云百炼平台的 AI 图像生成模型,可以根据文字描述生成相应的图片。 - 生成的图片会自动上传到 OSS 存储,返回永久可访问的 URL。 - + + 通过 OpenAI 兼容接口 ``/v1/images/generations`` 调用通义千问文生图模型(如同步返回的 Qwen-Image 系列)。 + 生成的图片会自动上传到 OSS,返回永久可访问的 URL。 + 使用场景: - - 用户说"生成一张...的图片"、"画一个..."、"创建...的图像" - - 需要为文章、演示文稿、社交媒体创建配图 - - 用户想要可视化某个概念、场景、物体或人物 - - 需要生成多个不同风格的图片供选择 - + - 用户说「生成一张…的图片」「画一个…」「创建…的图像」 + - 需要配图、插图或可视化某个概念/场景 + 参数说明: - prompt (必需): 详细描述想要生成的图片内容。应该包含: - - 主体对象(人物、动物、物品等) - - 场景和环境(背景、地点、氛围) - - 风格和艺术效果(写实、卡通、油画、水彩等) - - 颜色和光线(明亮、昏暗、暖色调等) - - 构图和视角(正面、侧面、俯视、特写等) - 示例:"一只可爱的橘色小猫坐在窗台上,阳光透过窗户洒在它身上,背景是温馨的客厅,写实风格" - - negative_prompt (可选): 描述不希望在图片中出现的内容,用于排除不想要的元素。 - 示例:"模糊,低质量,文字,水印,变形,多余的手指" - - size (可选): 图片尺寸,格式为 "宽*高"。支持的官方尺寸: - - "1280*1280" - 1:1 正方形(适合头像、图标、社交媒体头像) - - "800*1200" - 2:3 竖向(适合手机壁纸、竖版海报) - - "1200*800" - 3:2 横向(适合横向展示、横幅) - - "960*1280" - 3:4 竖向(适合手机屏幕、竖版内容) - - "1280*960" - 4:3 横向(适合传统显示器比例、横版内容) - - "720*1280" - 9:16 竖向(适合手机竖屏、短视频封面) - - "1280*720" - 16:9 横向(默认,适合宽屏显示器、视频封面、网页横幅) - - "1344*576" - 21:9 超宽屏(适合电影比例、超宽屏展示) - 默认值:"1280*720" - - n (可选): 生成图片的数量,范围 1-4。生成多张图片时会并行处理以提高效率。 - 默认值:1 - + prompt: 正向提示词(建议详细描述主体、场景、风格、光线与构图)。 + negative_prompt: 反向提示词;不需要可留空。 + size: 分辨率,OpenAI 标准 ``宽x高``(也可用 ``宽*高``,会自动转为 ``x``)。 + qwen-image-2.0 系列常用:``2048x2048``(默认 1:1)、``2688x1536``(16:9)、 + ``1536x2688``(9:16)、``2368x1728``(4:3)、``1728x2368``(3:4)。 + plus / qwen-image 系列可参考:``1664x928``、``1472x1104``、``1328x1328`` 等。 + n: 生成张数;qwen-image-2.0 系列多为 1–6,其它系列常为 1。 + prompt_extend: 是否开启提示词智能改写(True 时模型会润色提示词)。 + watermark: 是否在图像上加 Qwen-Image 水印。 + seed: 随机种子 [0, 2147483647];不传则由服务端随机。 + 返回值: - 返回包含图片的 Markdown 格式字符串,图片会自动显示在对话中。 - 如果生成多张图片,会按顺序展示所有图片。 - - 注意事项: - - 生成图片需要一定时间,请耐心等待 - - 提示词越详细,生成的图片质量越好 - - 生成多张图片时,总耗时会更长,但会并行处理以提高效率 - - 如果用户没有明确指定尺寸,使用默认尺寸即可 + Markdown 文本,包含可供渲染的图片链接(OSS 永久 URL,失败时回退临时 URL)。 + + 注意: + 平台返回的原始图像 URL 通常约 24 小时有效;本工具会尽快转存 OSS。 """ try: - api_key = settings.dashscope_api_key + api_key = (os.getenv("ZL_DASHSCOPE_API_KEY") or "").strip() + base_url = (os.getenv("ZL_DASHSCOPE_API_BASE") or "").strip().rstrip("/") if not api_key: return "错误:未配置 DASHSCOPE_API_KEY 环境变量" - - dashscope.base_http_api_url = _dashscope_http_api_base() + if not base_url: + return "错误:未配置 DASHSCOPE_API_BASE 环境变量" + + client = OpenAI(api_key=api_key, base_url=base_url) + model_image = "qwen-image-2.0" + + size_norm = _normalize_openai_image_size(size) + n_req = max(1, min(int(n), 6)) + + extra_body: dict = { + "prompt_extend": prompt_extend, + "watermark": watermark, + } + np = (negative_prompt or "").strip() + if np: + extra_body["negative_prompt"] = np + if seed is not None: + extra_body["seed"] = seed + + logger.info( + f"开始生成图片(OpenAI 兼容 images/generations),model={model_image}, n={n_req}, size={size_norm}" + ) + + response = client.images.generate( + model=model_image, + prompt=prompt, + size=size_norm, + n=n_req, + extra_body=extra_body, + ) + + image_urls: list[str] = [] + for item in response.data or []: + url = getattr(item, "url", None) + if url: + image_urls.append(url) - logger.info(f"开始生成图片,prompt: {prompt}, n={n}") - - # 创建异步任务 - rsp = ImageSynthesis.call(api_key=api_key, - model="wan2.2-t2i-flash", - prompt=prompt, - n=n, - size=size, - negative_prompt=negative_prompt, - prompt_extend=True, - watermark=True) - print(f'response: {rsp}') - if rsp.status_code != HTTPStatus.OK: - print(f'同步调用失败, status_code: {rsp.status_code}, code: {rsp.code}, message: {rsp.message}') - return "图片生成失败" - - # 提取图片 URL - image_urls = [] - if rsp.output and rsp.output.results: - for result in rsp.output.results: - if hasattr(result, 'url') and result.url: - image_urls.append(result.url) - if not image_urls: return "图片生成完成,但未获取到图片URL" @@ -266,12 +258,9 @@ def text_to_image( from typing import Optional from langchain_core.tools import tool -import os import logging import uuid import requests -from dashscope import VideoSynthesis -from http import HTTPStatus from services.oss_service import get_oss_service @@ -279,141 +268,127 @@ from services.oss_service import get_oss_service def text_to_video( prompt: str, negative_prompt: str = "", - size: str = "832*480", + size: str = "1280x720", duration: int = 5, ) -> str: """ 文生视频工具:根据文本描述生成动态视频。 - - 当用户需要生成视频、创建动画、制作短视频、需要动态视觉内容时,使用此工具。 - 该工具使用阿里云百炼平台的 AI 视频生成模型,可以根据文字描述生成相应的视频。 - 生成的视频会自动上传到 OSS 存储,返回永久可访问的 URL。 - + + 通过 OpenAI 兼容接口(``POST /v1/videos`` / ``GET /v1/videos/{id}``)调用万相文生视频模型 + ``wan2.6-t2v``。任务为异步队列:queued → in_progress → completed / failed; + SDK 使用 ``create_and_poll`` 自动轮询直至结束。 + 生成的视频会自动下载并上传到 OSS,返回永久可访问的播放地址。 + 使用场景: - - 用户说"生成一个...的视频"、"创建一个...的动画"、"制作...的短视频" - - 需要为产品演示、营销推广创建动态视频内容 - - 社交媒体短视频内容生成(抖音、快手、小红书等) - - 需要展示动态场景、运动过程、变化效果 - - 用户想要可视化动态概念或过程 - + - 用户说「生成一个…的视频」「做一个短视频」「需要动态画面」 + - 产品演示、营销素材、社交媒体短视频脚本可视化 + 参数说明: - prompt (必需): 详细描述想要生成的视频内容。应该包含: - - 主体对象和动作(什么在做什么) - - 场景和环境(背景、地点、氛围) - - 运动方式和动态效果(移动、旋转、变化等) - - 风格和视觉效果(写实、动画、电影感等) - - 颜色和光线(明亮、昏暗、暖色调等) - 示例:"一只橘色小猫在窗台上玩耍,阳光透过窗户洒在它身上,它好奇地看向窗外,背景是温馨的客厅,写实风格,画面流畅自然" - - negative_prompt (可选): 描述不希望在视频中出现的内容,用于排除不想要的元素。 - 示例:"模糊,低质量,文字,水印,画面抖动,不自然的运动,变形" - - size (可选): 视频尺寸,格式为 "宽*高"。支持的尺寸: - - "832*480" - 标准横向(默认,适合通用视频) - - "1280*720" - 高清横向(适合高质量视频) - - "720*1280" - 竖向(适合手机竖屏视频、短视频平台) - 默认值:"832*480" - - duration (可选): 视频时长,单位为秒。支持的时长: - - 5 秒(默认,适合短视频) - - 10 秒(适合中等长度视频) - - 15 秒(适合较长视频) - 默认值:5 - + prompt: 视频内容描述(中英文均可,建议写清主体、动作、镜头与风格)。 + negative_prompt: 不希望出现的内容;若填写则附加到提示中约束生成方向。 + size: 分辨率,OpenAI 标准 ``宽x高``(也可用 ``宽*高``,会自动转为 ``x``)。 + 例如 ``1280x720``、``1920x1080``、``720x1280``(竖屏)等。 + duration: 时长(秒),平台支持 **2–15** 秒,超出范围会自动裁剪到该区间。 + 返回值: - 返回包含视频的 HTML 格式字符串,视频会自动显示在对话中,用户可以直接播放。 - 视频已上传到 OSS,返回的是永久可访问的 URL。 - + 包含 ``