Initial commit: Pixel AI comic/video creation platform
- FastAPI backend with SQLModel, Alembic migrations, AgentScope agents - Next.js 15 frontend with React 19, Tailwind, Zustand, React Flow - Multi-provider AI system (DashScope, Kling, MiniMax, Volcengine, OpenAI, etc.) - All HTTP clients migrated from sync requests to async httpx - Admin-managed API keys via environment variables - SSRF vulnerability fixed in ensure_url()
This commit is contained in:
198
backend/src/config/database.py
Normal file
198
backend/src/config/database.py
Normal file
@@ -0,0 +1,198 @@
|
||||
from sqlmodel import create_engine, SQLModel, Session
|
||||
from sqlalchemy.pool import StaticPool, QueuePool
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy import event
|
||||
from src.config.settings import DB_PATH, DATABASE_URL
|
||||
import logging
|
||||
import time
|
||||
import os
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Slow query threshold in seconds
|
||||
SLOW_QUERY_THRESHOLD = float(os.getenv("SLOW_QUERY_THRESHOLD", "1.0"))
|
||||
|
||||
# Connection pool configuration from environment variables
|
||||
POOL_SIZE = int(os.getenv("DB_POOL_SIZE", "20"))
|
||||
MAX_OVERFLOW = int(os.getenv("DB_MAX_OVERFLOW", "10"))
|
||||
POOL_TIMEOUT = int(os.getenv("DB_POOL_TIMEOUT", "30"))
|
||||
POOL_RECYCLE = int(os.getenv("DB_POOL_RECYCLE", "3600"))
|
||||
POOL_PRE_PING = os.getenv("DB_POOL_PRE_PING", "true").lower() == "true"
|
||||
|
||||
# Create the database engine with optimized connection pooling
|
||||
if DATABASE_URL:
|
||||
# PostgreSQL Configuration with configurable connection pool
|
||||
engine = create_engine(
|
||||
DATABASE_URL,
|
||||
echo=False,
|
||||
poolclass=QueuePool,
|
||||
pool_size=POOL_SIZE,
|
||||
max_overflow=MAX_OVERFLOW,
|
||||
pool_timeout=POOL_TIMEOUT,
|
||||
pool_recycle=POOL_RECYCLE,
|
||||
pool_pre_ping=POOL_PRE_PING,
|
||||
# Additional optimizations
|
||||
connect_args={
|
||||
"connect_timeout": 10,
|
||||
"options": "-c statement_timeout=120000" # 120 second statement timeout for AI operations
|
||||
}
|
||||
)
|
||||
logger.info(
|
||||
f"PostgreSQL engine created with pool_size={POOL_SIZE}, "
|
||||
f"max_overflow={MAX_OVERFLOW}, pool_timeout={POOL_TIMEOUT}s, "
|
||||
f"pool_recycle={POOL_RECYCLE}s, pool_pre_ping={POOL_PRE_PING}"
|
||||
)
|
||||
else:
|
||||
# SQLite Configuration (Fallback)
|
||||
engine = create_engine(
|
||||
f"sqlite:///{DB_PATH}",
|
||||
echo=False,
|
||||
connect_args={
|
||||
"check_same_thread": False,
|
||||
"timeout": 30 # 30 second busy timeout
|
||||
},
|
||||
poolclass=StaticPool, # Use StaticPool for SQLite
|
||||
)
|
||||
logger.info(f"SQLite engine created with StaticPool at {DB_PATH}")
|
||||
|
||||
|
||||
# Add slow query logging
|
||||
@event.listens_for(engine, "before_cursor_execute")
|
||||
def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
|
||||
""" 记录 query start time."""
|
||||
conn.info.setdefault("query_start_time", []).append(time.time())
|
||||
|
||||
|
||||
@event.listens_for(engine, "after_cursor_execute")
|
||||
def after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
|
||||
""" 日志 slow queries."""
|
||||
total_time = time.time() - conn.info["query_start_time"].pop()
|
||||
|
||||
if total_time > SLOW_QUERY_THRESHOLD:
|
||||
logger.warning(
|
||||
f"Slow query detected (took {total_time:.2f}s): {statement[:200]}",
|
||||
extra={
|
||||
"query_time": total_time,
|
||||
"query": statement[:500],
|
||||
"parameters": str(parameters)[:200] if parameters else None
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def init_db():
|
||||
""" Initialize the database tables."""
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
# Try to create all tables
|
||||
try:
|
||||
SQLModel.metadata.create_all(engine)
|
||||
except OperationalError as e:
|
||||
if "already exists" in str(e):
|
||||
# Table or index already exists, skip creation
|
||||
logger.warning(f"Skipping table/index creation: {e}")
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def get_session():
|
||||
""" 依赖 for getting a database session.
|
||||
Ensures proper cleanup and connection management.
|
||||
"""
|
||||
with Session(engine) as session:
|
||||
try:
|
||||
yield session
|
||||
finally:
|
||||
# 会话 is automatically closed by context manager
|
||||
# This ensures connections are returned to the pool
|
||||
pass
|
||||
|
||||
|
||||
def get_pool_status() -> dict:
|
||||
""" Get current connection pool status for monitoring.
|
||||
Returns pool statistics including size, checked out connections, etc.
|
||||
"""
|
||||
pool = engine.pool
|
||||
|
||||
status = {
|
||||
"pool_size": getattr(pool, "size", lambda: 0)(),
|
||||
"checked_out": getattr(pool, "checkedout", lambda: 0)(),
|
||||
"overflow": getattr(pool, "overflow", lambda: 0)(),
|
||||
"checked_in": getattr(pool, "checkedin", lambda: 0)(),
|
||||
}
|
||||
|
||||
# Add pool-specific attributes if available
|
||||
if hasattr(pool, "_pool"):
|
||||
status["available"] = pool._pool.qsize()
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def check_database_health() -> tuple[bool, str]:
|
||||
"""
|
||||
Check database connectivity and health.
|
||||
Returns (is_healthy, message).
|
||||
"""
|
||||
try:
|
||||
with Session(engine) as session:
|
||||
# Simple connectivity probe without model dependency.
|
||||
session.exec(text("SELECT 1"))
|
||||
return True, "Database connection healthy"
|
||||
except Exception as e:
|
||||
logger.error(f"Database health check failed: {e}")
|
||||
return False, f"Database connection failed: {str(e)}"
|
||||
|
||||
|
||||
def check_pool_health() -> dict:
|
||||
"""
|
||||
Comprehensive pool health check with recommendations.
|
||||
Returns detailed pool status and health indicators.
|
||||
"""
|
||||
status = get_pool_status()
|
||||
pool = engine.pool
|
||||
|
||||
# Calculate health metrics
|
||||
total_connections = status.get("pool_size", 0) + status.get("overflow", 0)
|
||||
checked_out = status.get("checked_out", 0)
|
||||
available = status.get("available", 0)
|
||||
|
||||
# Health checks
|
||||
health = {
|
||||
"status": "healthy",
|
||||
"checks": {},
|
||||
"recommendations": [],
|
||||
"pool_status": status
|
||||
}
|
||||
|
||||
# Check 1: Connection exhaustion
|
||||
if checked_out >= total_connections * 0.9:
|
||||
health["checks"]["exhaustion"] = "critical"
|
||||
health["status"] = "critical"
|
||||
health["recommendations"].append(
|
||||
f"Pool near exhaustion: {checked_out}/{total_connections} connections in use. "
|
||||
f"Consider increasing DB_POOL_SIZE or DB_MAX_OVERFLOW."
|
||||
)
|
||||
elif checked_out >= total_connections * 0.75:
|
||||
health["checks"]["exhaustion"] = "warning"
|
||||
health["status"] = "warning"
|
||||
health["recommendations"].append(
|
||||
f"Pool usage high: {checked_out}/{total_connections} connections in use."
|
||||
)
|
||||
else:
|
||||
health["checks"]["exhaustion"] = "healthy"
|
||||
|
||||
# Check 2: Available connections
|
||||
if available == 0 and total_connections > 0:
|
||||
health["checks"]["availability"] = "warning"
|
||||
if health["status"] == "healthy":
|
||||
health["status"] = "warning"
|
||||
else:
|
||||
health["checks"]["availability"] = "healthy"
|
||||
|
||||
# Check 3: Pool size configuration
|
||||
if total_connections < 5:
|
||||
health["recommendations"].append(
|
||||
"Pool size may be too small for production workloads. "
|
||||
"Consider DB_POOL_SIZE >= 10"
|
||||
)
|
||||
|
||||
return health
|
||||
217
backend/src/config/database_async.py
Normal file
217
backend/src/config/database_async.py
Normal file
@@ -0,0 +1,217 @@
|
||||
"""
|
||||
异步数据库配置模块
|
||||
|
||||
提供 SQLAlchemy 2.0 AsyncSession 支持,用于完全异步的数据库操作。
|
||||
支持 PostgreSQL (asyncpg) 和 SQLite (aiosqlite)。
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from typing import AsyncGenerator
|
||||
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.ext.asyncio import (
|
||||
create_async_engine,
|
||||
AsyncSession,
|
||||
async_sessionmaker,
|
||||
AsyncEngine,
|
||||
)
|
||||
from sqlalchemy.pool import NullPool
|
||||
from sqlmodel import SQLModel
|
||||
|
||||
from src.config.settings import DB_PATH, DATABASE_URL
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Slow query threshold in seconds
|
||||
SLOW_QUERY_THRESHOLD = float(os.getenv("SLOW_QUERY_THRESHOLD", "1.0"))
|
||||
|
||||
# Connection pool configuration from environment variables
|
||||
POOL_SIZE = int(os.getenv("DB_POOL_SIZE", "20"))
|
||||
MAX_OVERFLOW = int(os.getenv("DB_MAX_OVERFLOW", "10"))
|
||||
POOL_TIMEOUT = int(os.getenv("DB_POOL_TIMEOUT", "30"))
|
||||
POOL_RECYCLE = int(os.getenv("DB_POOL_RECYCLE", "3600"))
|
||||
POOL_PRE_PING = os.getenv("DB_POOL_PRE_PING", "true").lower() == "true"
|
||||
|
||||
# Global engine instance
|
||||
async_engine: AsyncEngine | None = None
|
||||
async_session_maker: async_sessionmaker[AsyncSession] | None = None
|
||||
|
||||
|
||||
def _get_async_url() -> str:
|
||||
"""Generate async database URL from settings."""
|
||||
if DATABASE_URL:
|
||||
# Convert PostgreSQL URL to async version
|
||||
if DATABASE_URL.startswith("postgresql://"):
|
||||
return DATABASE_URL.replace("postgresql://", "postgresql+asyncpg://", 1)
|
||||
elif DATABASE_URL.startswith("postgresql+psycopg2://"):
|
||||
return DATABASE_URL.replace("postgresql+psycopg2://", "postgresql+asyncpg://", 1)
|
||||
return DATABASE_URL
|
||||
else:
|
||||
# SQLite async URL
|
||||
return f"sqlite+aiosqlite:///{DB_PATH}"
|
||||
|
||||
|
||||
def init_async_engine() -> AsyncEngine:
|
||||
"""Initialize async database engine with optimized connection pooling."""
|
||||
global async_engine
|
||||
|
||||
if async_engine is not None:
|
||||
return async_engine
|
||||
|
||||
async_url = _get_async_url()
|
||||
|
||||
if "postgresql" in async_url:
|
||||
# PostgreSQL async configuration
|
||||
async_engine = create_async_engine(
|
||||
async_url,
|
||||
echo=False,
|
||||
pool_size=POOL_SIZE,
|
||||
max_overflow=MAX_OVERFLOW,
|
||||
pool_timeout=POOL_TIMEOUT,
|
||||
pool_recycle=POOL_RECYCLE,
|
||||
pool_pre_ping=POOL_PRE_PING,
|
||||
connect_args={
|
||||
"timeout": 10,
|
||||
"command_timeout": 30,
|
||||
},
|
||||
)
|
||||
logger.info(
|
||||
f"Async PostgreSQL engine created with pool_size={POOL_SIZE}, "
|
||||
f"max_overflow={MAX_OVERFLOW}, pool_timeout={POOL_TIMEOUT}s"
|
||||
)
|
||||
else:
|
||||
# SQLite async configuration
|
||||
async_engine = create_async_engine(
|
||||
async_url,
|
||||
echo=False,
|
||||
poolclass=NullPool, # SQLite doesn't support connection pooling well
|
||||
connect_args={
|
||||
"timeout": 30,
|
||||
"check_same_thread": False,
|
||||
},
|
||||
)
|
||||
logger.info(f"Async SQLite engine created at {DB_PATH}")
|
||||
|
||||
return async_engine
|
||||
|
||||
|
||||
def init_async_session_maker() -> async_sessionmaker[AsyncSession]:
|
||||
"""Initialize async session maker."""
|
||||
global async_session_maker
|
||||
|
||||
if async_session_maker is not None:
|
||||
return async_session_maker
|
||||
|
||||
engine = init_async_engine()
|
||||
|
||||
async_session_maker = async_sessionmaker(
|
||||
engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False,
|
||||
autocommit=False,
|
||||
autoflush=False,
|
||||
)
|
||||
|
||||
return async_session_maker
|
||||
|
||||
|
||||
async def init_db_async():
|
||||
"""Initialize database tables asynchronously."""
|
||||
engine = init_async_engine()
|
||||
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(SQLModel.metadata.create_all)
|
||||
|
||||
logger.info("Database tables initialized (async)")
|
||||
|
||||
|
||||
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
|
||||
"""
|
||||
Dependency for getting async database session.
|
||||
|
||||
Usage:
|
||||
@router.get("/items")
|
||||
async def get_items(session: AsyncSession = Depends(get_async_session)):
|
||||
...
|
||||
"""
|
||||
session_maker = init_async_session_maker()
|
||||
|
||||
async with session_maker() as session:
|
||||
try:
|
||||
yield session
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
|
||||
async def get_async_session_context() -> AsyncSession:
|
||||
"""
|
||||
Get async session as context manager.
|
||||
|
||||
Usage:
|
||||
async with get_async_session_context() as session:
|
||||
result = await session.execute(...)
|
||||
"""
|
||||
session_maker = init_async_session_maker()
|
||||
return session_maker()
|
||||
|
||||
|
||||
async def get_pool_status_async() -> dict:
|
||||
"""
|
||||
Get current connection pool status for monitoring.
|
||||
Returns pool statistics including size, checked out connections, etc.
|
||||
"""
|
||||
engine = init_async_engine()
|
||||
pool = engine.pool
|
||||
|
||||
status = {
|
||||
"pool_size": getattr(pool, "size", lambda: 0)(),
|
||||
"checked_out": getattr(pool, "checkedout", lambda: 0)(),
|
||||
"overflow": getattr(pool, "overflow", lambda: 0)(),
|
||||
}
|
||||
|
||||
return status
|
||||
|
||||
|
||||
async def check_database_health_async() -> tuple[bool, str]:
|
||||
"""
|
||||
Check database connectivity and health asynchronously.
|
||||
Returns (is_healthy, message).
|
||||
"""
|
||||
try:
|
||||
engine = init_async_engine()
|
||||
async with engine.connect() as conn:
|
||||
start_time = time.time()
|
||||
await conn.execute(text("SELECT 1"))
|
||||
elapsed = time.time() - start_time
|
||||
|
||||
return True, f"Database connection healthy ({elapsed:.3f}s)"
|
||||
except Exception as e:
|
||||
logger.error(f"Database health check failed: {e}")
|
||||
return False, f"Database connection failed: {str(e)}"
|
||||
|
||||
|
||||
async def close_async_engine():
|
||||
"""Close async engine and cleanup connections."""
|
||||
global async_engine, async_session_maker
|
||||
|
||||
if async_engine is not None:
|
||||
await async_engine.dispose()
|
||||
async_engine = None
|
||||
async_session_maker = None
|
||||
logger.info("Async database engine closed")
|
||||
|
||||
|
||||
# Import guards for sync operations
|
||||
async def migrate_sync_to_async():
|
||||
"""
|
||||
Migration helper to ensure both sync and async engines are initialized.
|
||||
During transition period, both can coexist.
|
||||
"""
|
||||
# Initialize async engine
|
||||
init_async_engine()
|
||||
init_async_session_maker()
|
||||
|
||||
# Sync engine is already initialized in database.py
|
||||
logger.info("Both sync and async database engines are ready")
|
||||
465
backend/src/config/generation_options.json
Normal file
465
backend/src/config/generation_options.json
Normal file
@@ -0,0 +1,465 @@
|
||||
{
|
||||
"image": {
|
||||
"aspectRatios": {
|
||||
"label": "比例",
|
||||
"options": [
|
||||
{ "value": "1:1", "label": "1:1 (正方形)" },
|
||||
{ "value": "3:4", "label": "3:4 (竖版)" },
|
||||
{ "value": "4:3", "label": "4:3 (横版)" },
|
||||
{ "value": "9:16", "label": "9:16 (手机竖版)" },
|
||||
{ "value": "16:9", "label": "16:9 (宽屏)" }
|
||||
],
|
||||
"default": "16:9"
|
||||
},
|
||||
"resolutions": {
|
||||
"label": "分辨率",
|
||||
"options": [
|
||||
{ "value": "1K", "label": "1K (标准)", "description": "1280x720 或 1024x1024" },
|
||||
{ "value": "2K", "label": "2K (高清)", "description": "2560x1440 或 2048x2048" },
|
||||
{ "value": "4K", "label": "4K (超高清)", "description": "3840x2160 或 4096x4096" }
|
||||
],
|
||||
"default": "1K"
|
||||
},
|
||||
"counts": {
|
||||
"label": "生成数量",
|
||||
"options": [
|
||||
{ "value": 1, "label": "1张" },
|
||||
{ "value": 2, "label": "2张" },
|
||||
{ "value": 3, "label": "3张" },
|
||||
{ "value": 4, "label": "4张" }
|
||||
],
|
||||
"default": 1,
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"templates": {
|
||||
"label": "模板类型",
|
||||
"options": [
|
||||
{ "value": "general", "label": "通用", "description": "通用图片生成" },
|
||||
{ "value": "character_white_bg", "label": "角色白底图", "description": "角色图片,白色背景" },
|
||||
{ "value": "character_three_view", "label": "角色三视图", "description": "角色正面、侧面、背面视图" },
|
||||
{ "value": "storyboard_integrated", "label": "分镜出图", "description": "基于分镜生成图片" }
|
||||
],
|
||||
"default": "general"
|
||||
}
|
||||
},
|
||||
"video": {
|
||||
"aspectRatios": {
|
||||
"label": "比例",
|
||||
"options": [
|
||||
{ "value": "1:1", "label": "1:1 (正方形)" },
|
||||
{ "value": "3:4", "label": "3:4 (竖版)" },
|
||||
{ "value": "4:3", "label": "4:3 (横版)" },
|
||||
{ "value": "9:16", "label": "9:16 (手机竖版)" },
|
||||
{ "value": "16:9", "label": "16:9 (宽屏)" }
|
||||
],
|
||||
"default": "16:9"
|
||||
},
|
||||
"resolutions": {
|
||||
"label": "分辨率",
|
||||
"options": [
|
||||
{ "value": "720p", "label": "720P (1280x720)", "width": 1280, "height": 720 },
|
||||
{ "value": "1080p", "label": "1080P (1920x1080)", "width": 1920, "height": 1080 }
|
||||
],
|
||||
"default": "1080p"
|
||||
},
|
||||
"durations": {
|
||||
"label": "时长",
|
||||
"options": [
|
||||
{ "value": "2s", "label": "2秒" },
|
||||
{ "value": "3s", "label": "3秒" },
|
||||
{ "value": "4s", "label": "4秒" },
|
||||
{ "value": "5s", "label": "5秒" },
|
||||
{ "value": "6s", "label": "6秒" },
|
||||
{ "value": "7s", "label": "7秒" },
|
||||
{ "value": "8s", "label": "8秒" },
|
||||
{ "value": "10s", "label": "10秒" }
|
||||
],
|
||||
"default": "5s",
|
||||
"description": "视频时长(秒)"
|
||||
},
|
||||
"counts": {
|
||||
"label": "生成数量",
|
||||
"options": [
|
||||
{ "value": 1, "label": "1个" },
|
||||
{ "value": 2, "label": "2个" },
|
||||
{ "value": 3, "label": "3个" },
|
||||
{ "value": 4, "label": "4个" }
|
||||
],
|
||||
"default": 1,
|
||||
"min": 1,
|
||||
"max": 4
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
"durations": {
|
||||
"label": "时长",
|
||||
"options": [
|
||||
{ "value": "5s", "label": "5秒" },
|
||||
{ "value": "10s", "label": "10秒" },
|
||||
{ "value": "30s", "label": "30秒" },
|
||||
{ "value": "60s", "label": "1分钟" }
|
||||
],
|
||||
"default": "10s"
|
||||
},
|
||||
"formats": {
|
||||
"label": "音频格式",
|
||||
"options": [
|
||||
{ "value": "mp3", "label": "MP3" },
|
||||
{ "value": "wav", "label": "WAV" }
|
||||
],
|
||||
"default": "mp3"
|
||||
}
|
||||
},
|
||||
"music": {
|
||||
"formats": {
|
||||
"label": "音频格式",
|
||||
"options": [
|
||||
{ "value": "mp3", "label": "MP3" },
|
||||
{ "value": "wav", "label": "WAV" },
|
||||
{ "value": "pcm", "label": "PCM" }
|
||||
],
|
||||
"default": "mp3"
|
||||
},
|
||||
"sampleRates": {
|
||||
"label": "采样率",
|
||||
"options": [
|
||||
{ "value": 16000, "label": "16kHz" },
|
||||
{ "value": 24000, "label": "24kHz" },
|
||||
{ "value": 32000, "label": "32kHz" },
|
||||
{ "value": 44100, "label": "44.1kHz" }
|
||||
],
|
||||
"default": 44100
|
||||
},
|
||||
"bitrates": {
|
||||
"label": "码率",
|
||||
"options": [
|
||||
{ "value": 32000, "label": "32kbps" },
|
||||
{ "value": 64000, "label": "64kbps" },
|
||||
{ "value": 128000, "label": "128kbps" },
|
||||
{ "value": 256000, "label": "256kbps" }
|
||||
],
|
||||
"default": 256000
|
||||
},
|
||||
"outputFormats": {
|
||||
"label": "返回格式",
|
||||
"options": [
|
||||
{ "value": "url", "label": "URL (24小时有效)" },
|
||||
{ "value": "hex", "label": "HEX" }
|
||||
],
|
||||
"default": "url"
|
||||
}
|
||||
},
|
||||
"script": {
|
||||
"movieTones": {
|
||||
"label": "整体基调",
|
||||
"options": [
|
||||
{ "value": "悬疑/惊悚", "label": "悬疑/惊悚 (Suspense/Thriller)", "en": "Suspense/Thriller" },
|
||||
{ "value": "古装/权谋", "label": "古装/权谋 (Historical/Political)", "en": "Historical/Political" },
|
||||
{ "value": "现代/都市", "label": "现代/都市 (Modern/Urban)", "en": "Modern/Urban" },
|
||||
{ "value": "科幻/未来", "label": "科幻/未来 (Sci-Fi/Future)", "en": "Sci-Fi/Future" },
|
||||
{ "value": "喜剧/荒诞", "label": "喜剧/荒诞 (Comedy/Absurd)", "en": "Comedy/Absurd" },
|
||||
{ "value": "动作/犯罪", "label": "动作/犯罪 (Action/Crime)", "en": "Action/Crime" },
|
||||
{ "value": "爱情/治愈", "label": "爱情/治愈 (Romance/Healing)", "en": "Romance/Healing" },
|
||||
{ "value": "奇幻/仙侠", "label": "奇幻/仙侠 (Fantasy/Xianxia)", "en": "Fantasy/Xianxia" },
|
||||
{ "value": "现实/人文", "label": "现实/人文 (Realistic/Humanistic)", "en": "Realistic/Humanistic" }
|
||||
],
|
||||
"default": "现代/都市"
|
||||
},
|
||||
"targetAudiences": {
|
||||
"label": "目标受众",
|
||||
"options": [
|
||||
{ "value": "全年龄段", "label": "全年龄段 (All Ages)", "en": "All Ages" },
|
||||
{ "value": "青少年", "label": "青少年 (Teenagers)", "en": "Teenagers" },
|
||||
{ "value": "年轻女性", "label": "年轻女性 (Young Women)", "en": "Young Women" },
|
||||
{ "value": "年轻男性", "label": "年轻男性 (Young Men)", "en": "Young Men" },
|
||||
{ "value": "成年观众", "label": "成年观众 (Adults)", "en": "Adults" },
|
||||
{ "value": "家庭观众", "label": "家庭观众 (Family)", "en": "Family" },
|
||||
{ "value": "资深影迷", "label": "资深影迷 (Cinephiles)", "en": "Cinephiles" }
|
||||
],
|
||||
"default": "全年龄段"
|
||||
}
|
||||
},
|
||||
"director": {
|
||||
"narrativeStyles": {
|
||||
"label": "叙事手法",
|
||||
"options": [
|
||||
{ "value": "线性叙事", "label": "线性叙事 (Linear)", "en": "Linear Narrative" },
|
||||
{ "value": "非线性/插叙", "label": "非线性/插叙 (Non-linear)", "en": "Non-linear Narrative" },
|
||||
{ "value": "多线并行", "label": "多线并行 (Multi-line)", "en": "Multi-line Narrative" },
|
||||
{ "value": "倒叙", "label": "倒叙 (Flashback)", "en": "Flashback" },
|
||||
{ "value": "意识流", "label": "意识流 (Stream of Consciousness)", "en": "Stream of Consciousness" },
|
||||
{ "value": "伪纪录片", "label": "伪纪录片 (Mockumentary)", "en": "Mockumentary" }
|
||||
],
|
||||
"default": "线性叙事"
|
||||
},
|
||||
"editingPaces": {
|
||||
"label": "剪辑节奏",
|
||||
"options": [
|
||||
{ "value": "缓慢/沉浸", "label": "缓慢/沉浸 (Slow/Immersive)", "en": "Slow/Immersive" },
|
||||
{ "value": "明快/流畅", "label": "明快/流畅 (Brisk/Fluid)", "en": "Brisk/Fluid" },
|
||||
{ "value": "快速/凌厉", "label": "快速/凌厉 (Fast/Sharp)", "en": "Fast/Sharp" },
|
||||
{ "value": "极速/碎片化", "label": "极速/碎片化 (Rapid/Fragmented)", "en": "Rapid/Fragmented" },
|
||||
{ "value": "舒缓/诗意", "label": "舒缓/诗意 (Soothing/Poetic)", "en": "Soothing/Poetic" }
|
||||
],
|
||||
"default": "明快/流畅"
|
||||
},
|
||||
"styles": {
|
||||
"label": "导演风格",
|
||||
"options": [
|
||||
{ "value": "孔笙 (Kong Sheng)", "label": "孔笙 (厚重/写实/山海情)", "en": "Kong Sheng Style" },
|
||||
{ "value": "郑晓龙 (Zheng Xiaolong)", "label": "郑晓龙 (宫廷/传奇/甄嬛传)", "en": "Zheng Xiaolong Style" },
|
||||
{ "value": "张黎 (Zhang Li)", "label": "张黎 (历史/权谋/大明王朝)", "en": "Zhang Li Style" },
|
||||
{ "value": "辛爽 (Xin Shuang)", "label": "辛爽 (悬疑/美学/漫长的季节)", "en": "Xin Shuang Style" },
|
||||
{ "value": "王家卫 (Wong Kar-wai)", "label": "王家卫 (繁花/光影/霓虹)", "en": "Wong Kar-wai Style" },
|
||||
{ "value": "李路 (Li Lu)", "label": "李路 (史诗/人世间/人民的名义)", "en": "Li Lu Style" },
|
||||
{ "value": "曹盾 (Cao Dun)", "label": "曹盾 (视觉/长镜头/长安十二时辰)", "en": "Cao Dun Style" },
|
||||
{ "value": "王伟 (Wang Wei)", "label": "王伟 (硬汉/刑侦/白夜追凶)", "en": "Wang Wei Style" },
|
||||
{ "value": "汪俊 (Wang Jun)", "label": "汪俊 (都市/细腻/小欢喜)", "en": "Wang Jun Style" },
|
||||
{ "value": "徐纪周 (Xu Jizhou)", "label": "徐纪周 (群像/狂飙/快节奏)", "en": "Xu Jizhou Style" },
|
||||
{ "value": "吕行 (Lu Xing)", "label": "吕行 (犯罪/人性/无证之罪)", "en": "Lu Xing Style" },
|
||||
{ "value": "丁黑 (Ding Hei)", "label": "丁黑 (警察荣誉/那年花开)", "en": "Ding Hei Style" }
|
||||
],
|
||||
"default": "孔笙 (Kong Sheng)"
|
||||
}
|
||||
},
|
||||
"character": {
|
||||
"genders": {
|
||||
"label": "性别",
|
||||
"options": [
|
||||
{ "value": "男", "label": "男" },
|
||||
{ "value": "女", "label": "女" },
|
||||
{ "value": "未知", "label": "未知" }
|
||||
],
|
||||
"default": "未知"
|
||||
},
|
||||
"costumeStyles": {
|
||||
"label": "服装风格",
|
||||
"options": [
|
||||
{ "value": "现代日常", "label": "现代日常 (Modern Daily)", "en": "Modern Daily" },
|
||||
{ "value": "古装汉服", "label": "古装汉服 (Ancient Hanfu)", "en": "Ancient Hanfu" },
|
||||
{ "value": "民国风情", "label": "民国风情 (Republic Era)", "en": "Republic Era" },
|
||||
{ "value": "赛博科幻", "label": "赛博科幻 (Cyberpunk Sci-Fi)", "en": "Cyberpunk Sci-Fi" },
|
||||
{ "value": "职业制服", "label": "职业制服 (Professional Uniform)", "en": "Professional Uniform" },
|
||||
{ "value": "街头潮流", "label": "街头潮流 (Streetwear)", "en": "Streetwear" },
|
||||
{ "value": "极简森系", "label": "极简森系 (Minimalist Mori)", "en": "Minimalist Mori" },
|
||||
{ "value": "奢华礼服", "label": "奢华礼服 (Luxury/Formal)", "en": "Luxury/Formal" }
|
||||
],
|
||||
"default": "现代日常"
|
||||
},
|
||||
"roles": {
|
||||
"label": "角色定位",
|
||||
"options": [
|
||||
{ "value": "主角", "label": "主角" },
|
||||
{ "value": "配角", "label": "配角" },
|
||||
{ "value": "反派", "label": "反派" },
|
||||
{ "value": "龙套", "label": "龙套" },
|
||||
{ "value": "群演", "label": "群演" }
|
||||
],
|
||||
"default": "配角"
|
||||
},
|
||||
"emotions": {
|
||||
"label": "情绪基调",
|
||||
"options": [
|
||||
{ "value": "平静", "label": "平静 (Neutral)", "en": "Neutral/Calm" },
|
||||
{ "value": "喜悦", "label": "喜悦 (Happy)", "en": "Happy/Joyful" },
|
||||
{ "value": "悲伤", "label": "悲伤 (Sad)", "en": "Sad/Sorrowful" },
|
||||
{ "value": "愤怒", "label": "愤怒 (Angry)", "en": "Angry/Furious" },
|
||||
{ "value": "恐惧", "label": "恐惧 (Fearful)", "en": "Fearful/Scared" },
|
||||
{ "value": "惊讶", "label": "惊讶 (Surprised)", "en": "Surprised/Shocked" },
|
||||
{ "value": "自信", "label": "自信 (Confident)", "en": "Confident/Bold" },
|
||||
{ "value": "思索", "label": "思索 (Thinking)", "en": "Thinking/Pensive" }
|
||||
],
|
||||
"default": "平静"
|
||||
}
|
||||
},
|
||||
"storyboard": {
|
||||
"shotTypes": {
|
||||
"label": "镜头类型",
|
||||
"options": [
|
||||
{ "value": "大远景 (ELS)", "label": "大远景 (ELS)", "en": "Extreme Long Shot (ELS)" },
|
||||
{ "value": "远景 (LS)", "label": "远景 (LS)", "en": "Long Shot (LS)" },
|
||||
{ "value": "全景 (FS)", "label": "全景 (FS)", "en": "Full Shot (FS)" },
|
||||
{ "value": "中远景 (MLS)", "label": "中远景 (MLS)", "en": "Medium Long Shot (MLS)" },
|
||||
{ "value": "中景 (MS)", "label": "中景 (MS)", "en": "Medium Shot (MS)" },
|
||||
{ "value": "中特写 (MCU)", "label": "中特写 (MCU)", "en": "Medium Close-Up (MCU)" },
|
||||
{ "value": "特写 (CU)", "label": "特写 (CU)", "en": "Close-Up (CU)" },
|
||||
{ "value": "大特写 (ECU)", "label": "大特写 (ECU)", "en": "Extreme Close-Up (ECU)" },
|
||||
{ "value": "建立镜头", "label": "建立镜头", "en": "Establishing Shot" },
|
||||
{ "value": "主观镜头 (POV)", "label": "主观镜头 (POV)", "en": "Point of View (POV)" },
|
||||
{ "value": "过肩镜头 (OTS)", "label": "过肩镜头 (OTS)", "en": "Over the Shoulder (OTS)" }
|
||||
],
|
||||
"default": "中景 (MS)"
|
||||
},
|
||||
"cameraMovements": {
|
||||
"label": "运镜方式",
|
||||
"options": [
|
||||
{ "value": "固定镜头 (Static)", "label": "固定镜头 (Static)", "en": "Static" },
|
||||
{ "value": "左摇 (Pan Left)", "label": "左摇 (Pan Left)", "en": "Pan Left" },
|
||||
{ "value": "右摇 (Pan Right)", "label": "右摇 (Pan Right)", "en": "Pan Right" },
|
||||
{ "value": "上仰 (Tilt Up)", "label": "上仰 (Tilt Up)", "en": "Tilt Up" },
|
||||
{ "value": "下俯 (Tilt Down)", "label": "下俯 (Tilt Down)", "en": "Tilt Down" },
|
||||
{ "value": "推镜头 (Zoom In)", "label": "推镜头 (Zoom In)", "en": "Zoom In" },
|
||||
{ "value": "拉镜头 (Zoom Out)", "label": "拉镜头 (Zoom Out)", "en": "Zoom Out" },
|
||||
{ "value": "前移 (Dolly In)", "label": "前移 (Dolly In)", "en": "Dolly In" },
|
||||
{ "value": "后移 (Dolly Out)", "label": "后移 (Dolly Out)", "en": "Dolly Out" },
|
||||
{ "value": "跟随 (Tracking)", "label": "跟随 (Tracking)", "en": "Tracking" },
|
||||
{ "value": "环绕 (Arc)", "label": "环绕 (Arc)", "en": "Arc" },
|
||||
{ "value": "手持 (Handheld)", "label": "手持 (Handheld)", "en": "Handheld" }
|
||||
],
|
||||
"default": "固定镜头 (Static)"
|
||||
},
|
||||
"transitions": {
|
||||
"label": "转场效果",
|
||||
"options": [
|
||||
{ "value": "切 (Cut)", "label": "切 (Cut)", "en": "Cut" },
|
||||
{ "value": "叠化 (Dissolve)", "label": "叠化 (Dissolve)", "en": "Dissolve" },
|
||||
{ "value": "淡入 (Fade In)", "label": "淡入 (Fade In)", "en": "Fade In" },
|
||||
{ "value": "淡出 (Fade Out)", "label": "淡出 (Fade Out)", "en": "Fade Out" },
|
||||
{ "value": "划像 (Wipe)", "label": "划像 (Wipe)", "en": "Wipe" },
|
||||
{ "value": "圈入 (Iris In)", "label": "圈入 (Iris In)", "en": "Iris In" },
|
||||
{ "value": "圈出 (Iris Out)", "label": "圈出 (Iris Out)", "en": "Iris Out" },
|
||||
{ "value": "匹配剪辑 (Match Cut)", "label": "匹配剪辑 (Match Cut)", "en": "Match Cut" },
|
||||
{ "value": "跳接 (Jump Cut)", "label": "跳接 (Jump Cut)", "en": "Jump Cut" }
|
||||
],
|
||||
"default": "切 (Cut)"
|
||||
},
|
||||
"compositions": {
|
||||
"label": "构图方式",
|
||||
"options": [
|
||||
{ "value": "三分法 (Rule of Thirds)", "label": "三分法 (Rule of Thirds)", "en": "Rule of Thirds" },
|
||||
{ "value": "中心构图 (Center Framed)", "label": "中心构图 (Center Framed)", "en": "Center Framed" },
|
||||
{ "value": "对称构图 (Symmetrical)", "label": "对称构图 (Symmetrical)", "en": "Symmetrical" },
|
||||
{ "value": "引导线 (Leading Lines)", "label": "引导线 (Leading Lines)", "en": "Leading Lines" },
|
||||
{ "value": "对角线 (Diagonal)", "label": "对角线 (Diagonal)", "en": "Diagonal" },
|
||||
{ "value": "框架构图 (Framing)", "label": "框架构图 (Framing)", "en": "Framing" },
|
||||
{ "value": "极简留白 (Minimalist/Negative Space)", "label": "极简留白 (Minimalist/Negative Space)", "en": "Minimalist/Negative Space" },
|
||||
{ "value": "黄金螺旋 (Golden Spiral)", "label": "黄金螺旋 (Golden Spiral)", "en": "Golden Spiral" }
|
||||
],
|
||||
"default": "三分法 (Rule of Thirds)"
|
||||
}
|
||||
},
|
||||
"scene": {
|
||||
"timesOfDay": {
|
||||
"label": "拍摄时段",
|
||||
"options": [
|
||||
{ "value": "清晨", "label": "清晨 (Dawn)", "en": "Dawn" },
|
||||
{ "value": "早晨", "label": "早晨 (Morning)", "en": "Morning" },
|
||||
{ "value": "正午", "label": "正午 (Noon)", "en": "Noon" },
|
||||
{ "value": "下午", "label": "下午 (Afternoon)", "en": "Afternoon" },
|
||||
{ "value": "黄金时刻", "label": "黄金时刻 (Golden Hour)", "en": "Golden Hour" },
|
||||
{ "value": "傍晚", "label": "傍晚 (Dusk)", "en": "Dusk" },
|
||||
{ "value": "蓝调时刻", "label": "蓝调时刻 (Blue Hour)", "en": "Blue Hour" },
|
||||
{ "value": "夜晚", "label": "夜晚 (Night)", "en": "Night" },
|
||||
{ "value": "深夜", "label": "深夜 (Late Night)", "en": "Late Night" }
|
||||
],
|
||||
"default": "早晨"
|
||||
},
|
||||
"environmentTypes": {
|
||||
"label": "空间类型",
|
||||
"options": [
|
||||
{ "value": "室内", "label": "室内 (Interior)", "en": "Interior" },
|
||||
{ "value": "室外", "label": "室外 (Exterior)", "en": "Exterior" },
|
||||
{ "value": "半室外", "label": "半室外 (Semi-Exterior)", "en": "Semi-Exterior" }
|
||||
],
|
||||
"default": "室内"
|
||||
},
|
||||
"weather": {
|
||||
"label": "天气环境",
|
||||
"options": [
|
||||
{ "value": "晴朗", "label": "晴朗 (Clear)", "en": "Clear/Sunny" },
|
||||
{ "value": "多云", "label": "多云 (Cloudy)", "en": "Partly Cloudy" },
|
||||
{ "value": "阴天", "label": "阴天 (Overcast)", "en": "Overcast" },
|
||||
{ "value": "小雨", "label": "小雨 (Rainy)", "en": "Light Rain" },
|
||||
{ "value": "大雨", "label": "大雨 (Heavy Rain)", "en": "Heavy Rain" },
|
||||
{ "value": "暴风雨", "label": "暴风雨 (Storm)", "en": "Storm" },
|
||||
{ "value": "小雪", "label": "小雪 (Snowy)", "en": "Light Snow" },
|
||||
{ "value": "大雪", "label": "大雪 (Heavy Snow)", "en": "Heavy Snow" },
|
||||
{ "value": "大雾", "label": "大雾 (Foggy)", "en": "Dense Fog" },
|
||||
{ "value": "沙尘", "label": "沙尘 (Dusty)", "en": "Dusty/Sandstorm" }
|
||||
],
|
||||
"default": "晴朗"
|
||||
}
|
||||
},
|
||||
"cinematic": {
|
||||
"visualStyles": {
|
||||
"label": "视觉画风",
|
||||
"options": [
|
||||
{ "value": "现实主义/纪录片感", "label": "现实主义/纪录片感 (Realistic/Documentary)", "en": "Realistic/Documentary" },
|
||||
{ "value": "电影质感/胶片风", "label": "电影质感/胶片风 (Cinematic/Film)", "en": "Cinematic/Film" },
|
||||
{ "value": "赛博朋克/霓虹", "label": "赛博朋克/霓虹 (Cyberpunk/Neon)", "en": "Cyberpunk/Neon" },
|
||||
{ "value": "古风/水墨", "label": "古风/水墨 (Ancient/Ink Wash)", "en": "Ancient/Ink Wash" },
|
||||
{ "value": "极简主义/冷淡", "label": "极简主义/冷淡 (Minimalist/Cold)", "en": "Minimalist/Cold" },
|
||||
{ "value": "唯美/梦幻", "label": "唯美/梦幻 (Aesthetic/Dreamy)", "en": "Aesthetic/Dreamy" },
|
||||
{ "value": "暗黑/哥特", "label": "暗黑/哥特 (Dark/Gothic)", "en": "Dark/Gothic" },
|
||||
{ "value": "动画/二次元", "label": "动画/二次元 (Anime/2D)", "en": "Anime/2D" }
|
||||
],
|
||||
"default": "电影质感/胶片风"
|
||||
},
|
||||
"cameraAngles": {
|
||||
"label": "镜头角度",
|
||||
"options": [
|
||||
{ "value": "平视", "label": "平视 (Eye Level)", "en": "Eye Level" },
|
||||
{ "value": "俯拍", "label": "俯拍 (High Angle)", "en": "High Angle" },
|
||||
{ "value": "仰拍", "label": "仰拍 (Low Angle)", "en": "Low Angle" },
|
||||
{ "value": "顶拍", "label": "顶拍 (Top Down)", "en": "Top Down/Bird's Eye" },
|
||||
{ "value": "底拍", "label": "底拍 (Worm's Eye)", "en": "Worm's Eye View" },
|
||||
{ "value": "斜角镜头", "label": "斜角镜头 (Dutch Angle)", "en": "Dutch Angle" }
|
||||
],
|
||||
"default": "平视"
|
||||
},
|
||||
"lighting": {
|
||||
"label": "灯光风格",
|
||||
"options": [
|
||||
{ "value": "电影感光效", "label": "电影感 (Cinematic)", "en": "Cinematic Lighting" },
|
||||
{ "value": "自然光", "label": "自然光 (Natural)", "en": "Natural Lighting" },
|
||||
{ "value": "柔光", "label": "柔光 (Soft)", "en": "Soft Lighting" },
|
||||
{ "value": "强反差/明暗对照", "label": "强反差 (High Contrast)", "en": "Chiaroscuro/High Contrast" },
|
||||
{ "value": "轮廓光", "label": "轮廓光 (Rim Lighting)", "en": "Rim Lighting" },
|
||||
{ "value": "三点式亮光", "label": "三点式亮光 (Three-point Lighting)", "en": "Three-point Lighting" },
|
||||
{ "value": "工作室光效", "label": "工作室 (Studio)", "en": "Studio Lighting" }
|
||||
],
|
||||
"default": "电影感光效"
|
||||
},
|
||||
"colorStyle": {
|
||||
"label": "色调氛围",
|
||||
"options": [
|
||||
{ "value": "电影感", "label": "电影感 (Cinematic)", "en": "Cinematic" },
|
||||
{ "value": "暖色调", "label": "暖色调 (Warm Tones)", "en": "Warm Tones" },
|
||||
{ "value": "冷色调", "label": "冷色调 (Cold Tones)", "en": "Cold Tones" },
|
||||
{ "value": "黑白", "label": "黑白 (Black and White)", "en": "Black and White" },
|
||||
{ "value": "复古/胶片感", "label": "复古/胶片 (Vintage)", "en": "Vintage Film" },
|
||||
{ "value": "赛博朋克", "label": "赛博朋克 (Cyberpunk)", "en": "Cyberpunk" },
|
||||
{ "value": "高饱和", "label": "高饱和 (Vibrant)", "en": "Vibrant" },
|
||||
{ "value": "低饱和/灰色调", "label": "低饱和 (Muted)", "en": "Muted/Desaturated" }
|
||||
],
|
||||
"default": "电影感"
|
||||
},
|
||||
"lenses": {
|
||||
"label": "镜头焦距",
|
||||
"options": [
|
||||
{ "value": "广角镜头", "label": "超广角 (14-24mm)", "en": "Ultra Wide Lens" },
|
||||
{ "value": "标准广角", "label": "广角 (35mm)", "en": "Wide Angle Lens" },
|
||||
{ "value": "标准镜头", "label": "标准 (50mm)", "en": "Standard/Nifty Fifty" },
|
||||
{ "value": "人像镜头", "label": "长焦 (85mm)", "en": "Portrait/Short Telephoto" },
|
||||
{ "value": "远摄镜头", "label": "超长焦 (200mm+)", "en": "Telephoto Lens" },
|
||||
{ "value": "鱼眼镜头", "label": "鱼眼 (Fisheye)", "en": "Fisheye Lens" },
|
||||
{ "value": "变焦镜头", "label": "变焦 (Anamorphic)", "en": "Anamorphic Lens" }
|
||||
],
|
||||
"default": "标准镜头"
|
||||
},
|
||||
"focus": {
|
||||
"label": "焦点控制",
|
||||
"options": [
|
||||
{ "value": "自动对焦", "label": "自动对焦 (Auto)", "en": "Auto Focus" },
|
||||
{ "value": "浅景深/虚化", "label": "浅景深 (Shallow Bokeh)", "en": "Shallow Depth of Field" },
|
||||
{ "value": "大深景", "label": "大深景 (Deep Focus)", "en": "Deep Depth of Field" },
|
||||
{ "value": "焦点转移", "label": "变焦对焦 (Rack Focus)", "en": "Rack Focus" },
|
||||
{ "value": "微距焦点", "label": "微距 (Macro)", "en": "Macro Focus" },
|
||||
{ "value": "移轴效果", "label": "移轴 (Tilt-Shift)", "en": "Tilt-Shift" }
|
||||
],
|
||||
"default": "自动对焦"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
16
backend/src/config/script_agent_config.json
Normal file
16
backend/src/config/script_agent_config.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"roles": {
|
||||
"story_architect": "moonshot-v1-8k",
|
||||
"character_consultant": "moonshot-v1-8k",
|
||||
"scriptwriter": "moonshot-v1-8k",
|
||||
"director": "moonshot-v1-8k",
|
||||
"auditor": "moonshot-v1-8k",
|
||||
"moderator": "moonshot-v1-8k",
|
||||
"psychologist": "moonshot-v1-8k",
|
||||
"visualizer": "moonshot-v1-8k",
|
||||
"continuity_manager": "moonshot-v1-8k",
|
||||
"showrunner": "moonshot-v1-8k",
|
||||
"chief_editor": "moonshot-v1-8k",
|
||||
"specialist": "moonshot-v1-8k"
|
||||
}
|
||||
}
|
||||
5
backend/src/config/services/alibaba/provider.json
Normal file
5
backend/src/config/services/alibaba/provider.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": "aliyun",
|
||||
"name": "阿里云",
|
||||
"description": "阿里云提供的包括图像超分、视频超分等服务"
|
||||
}
|
||||
8
backend/src/config/services/alibaba/upscale.json
Normal file
8
backend/src/config/services/alibaba/upscale.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"videoenhan": {
|
||||
"name": "阿里巴巴图像超分",
|
||||
"class": "backend.src.services.post_process.super_resolution.SuperResolutionService",
|
||||
"args": [],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
16
backend/src/config/services/anthropic/provider.json
Normal file
16
backend/src/config/services/anthropic/provider.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"id": "anthropic",
|
||||
"name": "Anthropic",
|
||||
"description": "Claude 系列模型",
|
||||
"dashboard_url": "https://console.anthropic.com/settings/keys",
|
||||
"helpUrl": "https://console.anthropic.com/settings/keys",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "API Key",
|
||||
"placeholder": "sk-ant-...",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
488
backend/src/config/services/dashscope/audio.json
Normal file
488
backend/src/config/services/dashscope/audio.json
Normal file
@@ -0,0 +1,488 @@
|
||||
{
|
||||
"cosyvoice-v3-plus": {
|
||||
"name": "CosyVoice-V3-Plus",
|
||||
"class": "backend.src.services.provider.dashscope.audio.DashScopeAudioService",
|
||||
"args": ["cosyvoice-v3-plus"],
|
||||
"voices": [
|
||||
{
|
||||
"id": "longanyang",
|
||||
"name": "龙安洋",
|
||||
"gender": "male",
|
||||
"desc": "阳光大男孩"
|
||||
},
|
||||
{
|
||||
"id": "longanhuan",
|
||||
"name": "龙安欢",
|
||||
"gender": "female",
|
||||
"desc": "欢脱元气女"
|
||||
},
|
||||
{
|
||||
"id": "longhuhu_v3",
|
||||
"name": "龙呼呼",
|
||||
"gender": "female",
|
||||
"desc": "天真烂漫女童"
|
||||
},
|
||||
{
|
||||
"id": "longpaopao_v3",
|
||||
"name": "龙泡泡",
|
||||
"gender": "female",
|
||||
"desc": "飞天泡泡音"
|
||||
},
|
||||
{
|
||||
"id": "longjielidou_v3",
|
||||
"name": "龙杰力豆",
|
||||
"gender": "male",
|
||||
"desc": "阳光顽皮男童"
|
||||
},
|
||||
{
|
||||
"id": "longxian_v3",
|
||||
"name": "龙仙",
|
||||
"gender": "female",
|
||||
"desc": "豪放可爱女童"
|
||||
},
|
||||
{
|
||||
"id": "longling_v3",
|
||||
"name": "龙铃",
|
||||
"gender": "female",
|
||||
"desc": "稚气呆板女童"
|
||||
},
|
||||
{
|
||||
"id": "longshanshan_v3",
|
||||
"name": "龙闪闪",
|
||||
"gender": "female",
|
||||
"desc": "戏剧化童声"
|
||||
},
|
||||
{
|
||||
"id": "longniuniu_v3",
|
||||
"name": "龙牛牛",
|
||||
"gender": "male",
|
||||
"desc": "阳光男童声"
|
||||
},
|
||||
{
|
||||
"id": "longjiaxin_v3",
|
||||
"name": "龙嘉欣",
|
||||
"gender": "female",
|
||||
"desc": "优雅粤语女"
|
||||
},
|
||||
{
|
||||
"id": "longjiayi_v3",
|
||||
"name": "龙嘉怡",
|
||||
"gender": "female",
|
||||
"desc": "知性粤语女"
|
||||
},
|
||||
{
|
||||
"id": "longanyue_v3",
|
||||
"name": "龙安粤",
|
||||
"gender": "male",
|
||||
"desc": "欢脱粤语男"
|
||||
},
|
||||
{
|
||||
"id": "longlaotie_v3",
|
||||
"name": "龙老铁",
|
||||
"gender": "male",
|
||||
"desc": "东北直率男"
|
||||
},
|
||||
{
|
||||
"id": "longshange_v3",
|
||||
"name": "龙陕哥",
|
||||
"gender": "male",
|
||||
"desc": "原味陕北男"
|
||||
},
|
||||
{
|
||||
"id": "longanmin_v3",
|
||||
"name": "龙安闽",
|
||||
"gender": "female",
|
||||
"desc": "清纯闽南女"
|
||||
},
|
||||
{
|
||||
"id": "loongkyong_v3",
|
||||
"name": "loongkyong",
|
||||
"gender": "female",
|
||||
"desc": "韩语女"
|
||||
},
|
||||
{
|
||||
"id": "loongriko_v3",
|
||||
"name": "Riko",
|
||||
"gender": "female",
|
||||
"desc": "二次元日语女"
|
||||
},
|
||||
{
|
||||
"id": "loongtomoka_v3",
|
||||
"name": "loongtomoka",
|
||||
"gender": "female",
|
||||
"desc": "日语女"
|
||||
},
|
||||
{
|
||||
"id": "longfei_v3",
|
||||
"name": "龙飞",
|
||||
"gender": "male",
|
||||
"desc": "热血磁性男"
|
||||
},
|
||||
{
|
||||
"id": "longxiaochun_v3",
|
||||
"name": "龙小淳",
|
||||
"gender": "female",
|
||||
"desc": "清丽温柔女"
|
||||
},
|
||||
{
|
||||
"id": "longxiaoxia_v3",
|
||||
"name": "龙小夏",
|
||||
"gender": "female",
|
||||
"desc": "活泼甜美女"
|
||||
},
|
||||
{
|
||||
"id": "longshu_v3",
|
||||
"name": "龙舒",
|
||||
"gender": "female",
|
||||
"desc": "知性温婉女"
|
||||
},
|
||||
{
|
||||
"id": "longyue_v3",
|
||||
"name": "龙悦",
|
||||
"gender": "male",
|
||||
"desc": "阳光青年男"
|
||||
},
|
||||
{
|
||||
"id": "longcheng_v3",
|
||||
"name": "龙城",
|
||||
"gender": "male",
|
||||
"desc": "成熟稳重男"
|
||||
},
|
||||
{
|
||||
"id": "longhua_v3",
|
||||
"name": "龙华",
|
||||
"gender": "male",
|
||||
"desc": "标准男声"
|
||||
},
|
||||
{
|
||||
"id": "longwan_v3",
|
||||
"name": "龙婉",
|
||||
"gender": "female",
|
||||
"desc": "温婉知性女"
|
||||
},
|
||||
{
|
||||
"id": "longjing_v3",
|
||||
"name": "龙静",
|
||||
"gender": "female",
|
||||
"desc": "标准女声"
|
||||
},
|
||||
{
|
||||
"id": "longmiao_v3",
|
||||
"name": "龙淼",
|
||||
"gender": "female",
|
||||
"desc": "标准女声"
|
||||
},
|
||||
{
|
||||
"id": "longshuo_v3",
|
||||
"name": "龙硕",
|
||||
"gender": "male",
|
||||
"desc": "标准男声"
|
||||
},
|
||||
{
|
||||
"id": "longxiang_v3",
|
||||
"name": "龙翔",
|
||||
"gender": "male",
|
||||
"desc": "标准男声"
|
||||
},
|
||||
{
|
||||
"id": "longyuan_v3",
|
||||
"name": "龙源",
|
||||
"gender": "male",
|
||||
"desc": "标准男声"
|
||||
}
|
||||
],
|
||||
"enabled": true
|
||||
},
|
||||
"qwen3-tts-flash": {
|
||||
"name": "Qwen3-TTS-Flash",
|
||||
"class": "backend.src.services.provider.dashscope.audio.DashScopeAudioService",
|
||||
"args": ["qwen3-tts-flash"],
|
||||
"voices": [
|
||||
{
|
||||
"id": "Cherry",
|
||||
"name": "芊悦",
|
||||
"gender": "female",
|
||||
"desc": "阳光积极、亲切自然小姐姐"
|
||||
},
|
||||
{
|
||||
"id": "Serena",
|
||||
"name": "苏瑶",
|
||||
"gender": "female",
|
||||
"desc": "温柔小姐姐"
|
||||
},
|
||||
{
|
||||
"id": "Ethan",
|
||||
"name": "晨煦",
|
||||
"gender": "male",
|
||||
"desc": "阳光、温暖、活力、朝气"
|
||||
},
|
||||
{
|
||||
"id": "Chelsie",
|
||||
"name": "千雪",
|
||||
"gender": "female",
|
||||
"desc": "二次元虚拟女友"
|
||||
},
|
||||
{
|
||||
"id": "Momo",
|
||||
"name": "茉兔",
|
||||
"gender": "female",
|
||||
"desc": "撒娇搞怪,逗你开心"
|
||||
},
|
||||
{
|
||||
"id": "Vivian",
|
||||
"name": "十三",
|
||||
"gender": "female",
|
||||
"desc": "拽拽的、可爱的小暴躁"
|
||||
},
|
||||
{ "id": "Moon", "name": "月白", "gender": "male", "desc": "率性帅气" },
|
||||
{
|
||||
"id": "Maia",
|
||||
"name": "四月",
|
||||
"gender": "female",
|
||||
"desc": "知性与温柔的碰撞"
|
||||
},
|
||||
{ "id": "Kai", "name": "凯", "gender": "male", "desc": "耳朵的一场SPA" },
|
||||
{
|
||||
"id": "Nofish",
|
||||
"name": "不吃鱼",
|
||||
"gender": "male",
|
||||
"desc": "不会翘舌音的设计师"
|
||||
},
|
||||
{
|
||||
"id": "Bella",
|
||||
"name": "萌宝",
|
||||
"gender": "female",
|
||||
"desc": "喝酒不打醉拳的小萝莉"
|
||||
},
|
||||
{
|
||||
"id": "Jennifer",
|
||||
"name": "詹妮弗",
|
||||
"gender": "female",
|
||||
"desc": "品牌级、电影质感般美语女声"
|
||||
},
|
||||
{
|
||||
"id": "Ryan",
|
||||
"name": "甜茶",
|
||||
"gender": "male",
|
||||
"desc": "节奏拉满,戏感炸裂"
|
||||
},
|
||||
{
|
||||
"id": "Katerina",
|
||||
"name": "卡捷琳娜",
|
||||
"gender": "female",
|
||||
"desc": "御姐音色,韵律回味十足"
|
||||
},
|
||||
{
|
||||
"id": "Aiden",
|
||||
"name": "艾登",
|
||||
"gender": "male",
|
||||
"desc": "精通厨艺的美语大男孩"
|
||||
},
|
||||
{
|
||||
"id": "Eldric Sage",
|
||||
"name": "沧明子",
|
||||
"gender": "male",
|
||||
"desc": "沉稳睿智的老者"
|
||||
},
|
||||
{
|
||||
"id": "Mia",
|
||||
"name": "乖小妹",
|
||||
"gender": "female",
|
||||
"desc": "温顺如春水,乖巧如初雪"
|
||||
},
|
||||
{
|
||||
"id": "Mochi",
|
||||
"name": "沙小弥",
|
||||
"gender": "male",
|
||||
"desc": "聪明伶俐的小大人"
|
||||
},
|
||||
{
|
||||
"id": "Bellona",
|
||||
"name": "燕铮莺",
|
||||
"gender": "female",
|
||||
"desc": "金戈铁马,千面人声"
|
||||
},
|
||||
{
|
||||
"id": "Vincent",
|
||||
"name": "田叔",
|
||||
"gender": "male",
|
||||
"desc": "沙哑烟嗓,江湖豪情"
|
||||
},
|
||||
{
|
||||
"id": "Bunny",
|
||||
"name": "萌小姬",
|
||||
"gender": "female",
|
||||
"desc": "萌属性爆棚的小萝莉"
|
||||
},
|
||||
{
|
||||
"id": "Neil",
|
||||
"name": "阿闻",
|
||||
"gender": "male",
|
||||
"desc": "字正腔圆的新闻主持人"
|
||||
},
|
||||
{
|
||||
"id": "Elias",
|
||||
"name": "墨讲师",
|
||||
"gender": "female",
|
||||
"desc": "严谨又通俗的知识讲解"
|
||||
},
|
||||
{
|
||||
"id": "Arthur",
|
||||
"name": "徐大爷",
|
||||
"gender": "male",
|
||||
"desc": "质朴嗓音,奇闻异事"
|
||||
},
|
||||
{
|
||||
"id": "Nini",
|
||||
"name": "邻家妹妹",
|
||||
"gender": "female",
|
||||
"desc": "又软又黏的甜蜜嗓音"
|
||||
},
|
||||
{
|
||||
"id": "Ebona",
|
||||
"name": "诡婆婆",
|
||||
"gender": "female",
|
||||
"desc": "幽暗低语,神秘诡异"
|
||||
},
|
||||
{
|
||||
"id": "Seren",
|
||||
"name": "小婉",
|
||||
"gender": "female",
|
||||
"desc": "温和舒缓,助眠音色"
|
||||
},
|
||||
{
|
||||
"id": "Pip",
|
||||
"name": "顽屁小孩",
|
||||
"gender": "male",
|
||||
"desc": "调皮捣蛋却充满童真"
|
||||
},
|
||||
{
|
||||
"id": "Stella",
|
||||
"name": "少女阿月",
|
||||
"gender": "female",
|
||||
"desc": "甜到发腻的迷糊少女音"
|
||||
},
|
||||
{
|
||||
"id": "Bodega",
|
||||
"name": "博德加",
|
||||
"gender": "male",
|
||||
"desc": "热情的西班牙大叔"
|
||||
},
|
||||
{
|
||||
"id": "Sonrisa",
|
||||
"name": "索尼莎",
|
||||
"gender": "female",
|
||||
"desc": "热情开朗的拉美大姐"
|
||||
},
|
||||
{
|
||||
"id": "Alek",
|
||||
"name": "阿列克",
|
||||
"gender": "male",
|
||||
"desc": "战斗民族的冷与暖"
|
||||
},
|
||||
{
|
||||
"id": "Dolce",
|
||||
"name": "多尔切",
|
||||
"gender": "male",
|
||||
"desc": "慵懒的意大利大叔"
|
||||
},
|
||||
{
|
||||
"id": "Sohee",
|
||||
"name": "素熙",
|
||||
"gender": "female",
|
||||
"desc": "温柔开朗的韩国欧尼"
|
||||
},
|
||||
{
|
||||
"id": "Ono Anna",
|
||||
"name": "小野杏",
|
||||
"gender": "female",
|
||||
"desc": "鬼灵精怪的青梅竹马"
|
||||
},
|
||||
{
|
||||
"id": "Lenn",
|
||||
"name": "莱恩",
|
||||
"gender": "male",
|
||||
"desc": "理性底色的德国青年"
|
||||
},
|
||||
{
|
||||
"id": "Emilien",
|
||||
"name": "埃米尔安",
|
||||
"gender": "male",
|
||||
"desc": "浪漫的法国大哥哥"
|
||||
},
|
||||
{
|
||||
"id": "Andre",
|
||||
"name": "安德雷",
|
||||
"gender": "male",
|
||||
"desc": "声音磁性,沉稳男生"
|
||||
},
|
||||
{
|
||||
"id": "Radio Gol",
|
||||
"name": "拉迪奥·戈尔",
|
||||
"gender": "male",
|
||||
"desc": "足球诗人解说员"
|
||||
},
|
||||
{
|
||||
"id": "Jada",
|
||||
"name": "上海-阿珍",
|
||||
"gender": "female",
|
||||
"desc": "风风火火的沪上阿姐"
|
||||
},
|
||||
{
|
||||
"id": "Dylan",
|
||||
"name": "北京-晓东",
|
||||
"gender": "male",
|
||||
"desc": "北京胡同里长大的少年"
|
||||
},
|
||||
{
|
||||
"id": "Li",
|
||||
"name": "南京-老李",
|
||||
"gender": "male",
|
||||
"desc": "耐心的瑜伽老师"
|
||||
},
|
||||
{
|
||||
"id": "Marcus",
|
||||
"name": "陕西-秦川",
|
||||
"gender": "male",
|
||||
"desc": "面宽话短,心实声沉"
|
||||
},
|
||||
{
|
||||
"id": "Roy",
|
||||
"name": "闽南-阿杰",
|
||||
"gender": "male",
|
||||
"desc": "诙谐直爽的台湾哥仔"
|
||||
},
|
||||
{
|
||||
"id": "Peter",
|
||||
"name": "天津-李彼得",
|
||||
"gender": "male",
|
||||
"desc": "天津相声,专业捧哏"
|
||||
},
|
||||
{
|
||||
"id": "Sunny",
|
||||
"name": "四川-晴儿",
|
||||
"gender": "female",
|
||||
"desc": "甜到你心里的川妹子"
|
||||
},
|
||||
{
|
||||
"id": "Eric",
|
||||
"name": "四川-程川",
|
||||
"gender": "male",
|
||||
"desc": "跳脱市井的成都男子"
|
||||
},
|
||||
{
|
||||
"id": "Rocky",
|
||||
"name": "粤语-阿强",
|
||||
"gender": "male",
|
||||
"desc": "幽默风趣,在线陪聊"
|
||||
},
|
||||
{
|
||||
"id": "Kiki",
|
||||
"name": "粤语-阿清",
|
||||
"gender": "female",
|
||||
"desc": "甜美的港妹闺蜜"
|
||||
}
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
143
backend/src/config/services/dashscope/image.json
Normal file
143
backend/src/config/services/dashscope/image.json
Normal file
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"z-image": {
|
||||
"name": "Z-Image",
|
||||
"class": "backend.src.services.provider.dashscope.image.ZImageService",
|
||||
"args": [
|
||||
"z-image"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2i": "z-image-turbo"
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1536*864",
|
||||
"9:16": "864*1536",
|
||||
"1:1": "1280*1280",
|
||||
"4:3": "1280*960",
|
||||
"3:4": "960*1280",
|
||||
"21:9": "1680*720",
|
||||
"9:21": "720*1680"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2048*1152",
|
||||
"9:16": "1152*2048",
|
||||
"21:9": "2016*864",
|
||||
"9:21": "864*2016"
|
||||
}
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"wan2.6-image": {
|
||||
"name": "Wan 2.6",
|
||||
"class": "backend.src.services.provider.dashscope.image.WanImageService",
|
||||
"args": [
|
||||
"wan2.6-image"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2i": "wan2.6-t2i",
|
||||
"i2i": "wan2.6-image"
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1280*1280",
|
||||
"4:3": "1280*960",
|
||||
"3:4": "960*1280"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560*1440",
|
||||
"9:16": "1440*2560",
|
||||
"1:1": "2048*2048",
|
||||
"4:3": "2560*1920",
|
||||
"3:4": "1920*2560"
|
||||
}
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"wan2.5-image": {
|
||||
"name": "Wan 2.5",
|
||||
"class": "backend.src.services.provider.dashscope.image.WanImageService",
|
||||
"args": [
|
||||
"wan2.5-image"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2i": "wan2.5-t2i-preview",
|
||||
"i2i": "wan2.5-i2i-preview"
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1280*1280",
|
||||
"4:3": "1280*960",
|
||||
"3:4": "960*1280"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560*1440",
|
||||
"9:16": "1440*2560",
|
||||
"1:1": "2048*2048",
|
||||
"4:3": "2560*1920",
|
||||
"3:4": "1920*2560"
|
||||
}
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"qwen-image": {
|
||||
"name": "Qwen Image",
|
||||
"class": "backend.src.services.provider.dashscope.image.QwenImageService",
|
||||
"args": [
|
||||
"qwen-image"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2i": "qwen-image-plus",
|
||||
"i2i": "qwen-image-edit-plus"
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1664*928",
|
||||
"9:16": "928*1664",
|
||||
"1:1": "1328*1328",
|
||||
"4:3": "1472*1140",
|
||||
"3:4": "1140*1472"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560*1440",
|
||||
"9:16": "1440*2560",
|
||||
"1:1": "2048*2048",
|
||||
"4:3": "2560*1920",
|
||||
"3:4": "1920*2560"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
39
backend/src/config/services/dashscope/llm.json
Normal file
39
backend/src/config/services/dashscope/llm.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
"qwen-plus": {
|
||||
"name": "Qwen Plus",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": ["qwen-plus"],
|
||||
"enabled": true
|
||||
},
|
||||
"qwen3-max": {
|
||||
"name": "Qwen Max",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": ["qwen3-max"],
|
||||
"enabled": true
|
||||
},
|
||||
"qwen-flash": {
|
||||
"name": "Qwen Flash",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": ["qwen-flash"],
|
||||
"enabled": true
|
||||
},
|
||||
"deepseek": {
|
||||
"name": "Deepseek",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": ["deepseek-v3.2"],
|
||||
"enabled": true
|
||||
},
|
||||
"kimi-k2.5": {
|
||||
"name": "Kimi K2.5",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": ["kimi-k2.5"],
|
||||
"enabled": true
|
||||
},
|
||||
"MiniMax-M2.1": {
|
||||
"name": "MiniMax M2.1",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": ["MiniMax-M2.1"],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
16
backend/src/config/services/dashscope/provider.json
Normal file
16
backend/src/config/services/dashscope/provider.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"id": "dashscope",
|
||||
"name": "阿里云百炼",
|
||||
"description": "阿里云提供的大模型服务",
|
||||
"dashboard_url": "https://dashscope.console.aliyun.com/",
|
||||
"helpUrl": "https://dashscope.console.aliyun.com/apiKey",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "API Key",
|
||||
"placeholder": "sk-...",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
196
backend/src/config/services/dashscope/video.json
Normal file
196
backend/src/config/services/dashscope/video.json
Normal file
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"wan2.6-video": {
|
||||
"name": "Wan 2.6",
|
||||
"class": "backend.src.services.provider.dashscope.video.WanVideoService",
|
||||
"args": [
|
||||
"wan2.6-video"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsVideoToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": false,
|
||||
"supportsMultiImage": true,
|
||||
"supportsMultiVideo": true,
|
||||
"supportsAudio": true,
|
||||
"supportsShotType": true,
|
||||
"supportsNegativePrompt": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "wan2.6-t2v",
|
||||
"i2v": "wan2.6-i2v",
|
||||
"r2v": "wan2.6-r2v"
|
||||
},
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1280*1280",
|
||||
"4:3": "1280*960",
|
||||
"3:4": "960*1280"
|
||||
},
|
||||
"1080P": {
|
||||
"16:9": "1920*1080",
|
||||
"9:16": "1080*1920",
|
||||
"1:1": "1920*1920",
|
||||
"4:3": "1920*1440",
|
||||
"3:4": "1440*1920"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"min": 2,
|
||||
"max": 10
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"wan2.6-video-flash": {
|
||||
"name": "Wan 2.6 Flash",
|
||||
"class": "backend.src.services.provider.dashscope.video.WanVideoService",
|
||||
"args": [
|
||||
"wan2.6-video-flash"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsVideoToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": false,
|
||||
"supportsMultiImage": true,
|
||||
"supportsMultiVideo": true,
|
||||
"supportsAudio": true,
|
||||
"supportsShotType": true,
|
||||
"supportsNegativePrompt": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "wan2.6-t2v",
|
||||
"i2v": "wan2.6-i2v-flash",
|
||||
"r2v": "wan2.6-r2v-flash"
|
||||
},
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1280*1280",
|
||||
"4:3": "1280*960",
|
||||
"3:4": "960*1280"
|
||||
},
|
||||
"1080P": {
|
||||
"16:9": "1920*1080",
|
||||
"9:16": "1080*1920",
|
||||
"1:1": "1920*1920",
|
||||
"4:3": "1920*1440",
|
||||
"3:4": "1440*1920"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"min": 2,
|
||||
"max": 10
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"wan2.5-video": {
|
||||
"name": "Wan 2.5",
|
||||
"class": "backend.src.services.provider.dashscope.video.WanVideoService",
|
||||
"args": [
|
||||
"wan2.5-video"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": false,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "wan2.5-t2v-preview",
|
||||
"i2v": "wan2.5-i2v-preview"
|
||||
},
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1280*1280",
|
||||
"4:3": "1280*960",
|
||||
"3:4": "960*1280"
|
||||
},
|
||||
"1080P": {
|
||||
"16:9": "1920*1080",
|
||||
"9:16": "1080*1920",
|
||||
"1:1": "1920*1920",
|
||||
"4:3": "1920*1440",
|
||||
"3:4": "1440*1920"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"values": [
|
||||
5,
|
||||
10
|
||||
]
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"wan2.2-video": {
|
||||
"name": "Wan 2.2",
|
||||
"class": "backend.src.services.provider.dashscope.video.WanVideoService",
|
||||
"args": [
|
||||
"wan2.2-video"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "wan2.2-t2v-plus",
|
||||
"i2v": "wan2.2-i2v-flash",
|
||||
"kf2v": "wan2.2-kf2v-flash"
|
||||
},
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1280*1280",
|
||||
"4:3": "1280*960",
|
||||
"3:4": "960*1280"
|
||||
},
|
||||
"1080P": {
|
||||
"16:9": "1920*1080",
|
||||
"9:16": "1080*1920",
|
||||
"1:1": "1920*1920",
|
||||
"4:3": "1920*1440",
|
||||
"3:4": "1440*1920"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"values": [
|
||||
5
|
||||
]
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
7
backend/src/config/services/default.json
Normal file
7
backend/src/config/services/default.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"llm": "qwen-plus",
|
||||
"image": "z-image",
|
||||
"video": "wan2.6-video",
|
||||
"audio": "qwen3-tts-flash",
|
||||
"upscale": "ali-videoenhan/videoenhan"
|
||||
}
|
||||
27
backend/src/config/services/google/llm.json
Normal file
27
backend/src/config/services/google/llm.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"base_url": "https://generativelanguage.googleapis.com/v1beta/openai/",
|
||||
"gemini-1.5-pro": {
|
||||
"name": "Gemini-1.5-Pro",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": [
|
||||
"gemini-1.5-pro"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
"gemini-1.5-flash": {
|
||||
"name": "Gemini-1.5-Flash",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": [
|
||||
"gemini-1.5-flash"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
"gemini-2.0-flash": {
|
||||
"name": "Gemini-2.0-Flash",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": [
|
||||
"gemini-2.0-flash"
|
||||
],
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
16
backend/src/config/services/google/provider.json
Normal file
16
backend/src/config/services/google/provider.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"id": "google",
|
||||
"name": "Google",
|
||||
"description": "Gemini 系列模型",
|
||||
"dashboard_url": "https://aistudio.google.com/app/apikey",
|
||||
"helpUrl": "https://aistudio.google.com/app/apikey",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "API Key",
|
||||
"placeholder": "...",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
27
backend/src/config/services/kling/provider.json
Normal file
27
backend/src/config/services/kling/provider.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"id": "kling",
|
||||
"name": "可灵 AI",
|
||||
"description": "快手视频生成 - 需要 Access Key 和 Secret Key",
|
||||
"dashboard_url": "https://klingai.kuaishou.com/",
|
||||
"param_mapping": {
|
||||
"api_key": "access_key",
|
||||
"api_secret": "secret_key"
|
||||
},
|
||||
"helpUrl": "https://klingai.kuaishou.com/",
|
||||
"fields": [
|
||||
{
|
||||
"name": "accessKey",
|
||||
"label": "Access Key",
|
||||
"placeholder": "Access Key",
|
||||
"required": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "secretKey",
|
||||
"label": "Secret Key",
|
||||
"placeholder": "Secret Key",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
124
backend/src/config/services/kling/video.json
Normal file
124
backend/src/config/services/kling/video.json
Normal file
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"kling-v2-5-turbo": {
|
||||
"name": "Kling V2.5 Turbo",
|
||||
"class": "src.services.provider.kling.KlingVideoService",
|
||||
"args": [
|
||||
"kling-v2-5-turbo"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsAudio": false,
|
||||
"supportsNegativePrompt": true,
|
||||
"supportsCameraControl": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "kling-v2-5-turbo",
|
||||
"i2v": "kling-v2-5-turbo",
|
||||
"kf2v": "kling-v2-5-turbo"
|
||||
},
|
||||
"modes": ["std", "pro"],
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1024*1024"
|
||||
},
|
||||
"1080P": {
|
||||
"16:9": "1920*1080",
|
||||
"9:16": "1080*1920",
|
||||
"1:1": "1024*1024"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"values": [5, 10]
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
},
|
||||
"kling-v2-6": {
|
||||
"name": "Kling V2.6",
|
||||
"class": "src.services.provider.kling.KlingVideoService",
|
||||
"args": [
|
||||
"kling-v2-6"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsAudio": true,
|
||||
"supportsNegativePrompt": true,
|
||||
"supportsCameraControl": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "kling-v2-6",
|
||||
"i2v": "kling-v2-6",
|
||||
"kf2v": "kling-v2-6"
|
||||
},
|
||||
"modes": ["pro"],
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1024*1024"
|
||||
},
|
||||
"1080P": {
|
||||
"16:9": "1920*1080",
|
||||
"9:16": "1080*1920",
|
||||
"1:1": "1024*1024"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"values": [5, 10]
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
},
|
||||
"kling-video-o1": {
|
||||
"name": "Kling Omni (O1)",
|
||||
"class": "src.services.provider.kling.KlingVideoService",
|
||||
"args": [
|
||||
"kling-video-o1"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsVideoToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": true,
|
||||
"supportsMultiVideo": true,
|
||||
"supportsAudio": true,
|
||||
"supportsNegativePrompt": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "kling-video-o1",
|
||||
"i2v": "kling-video-o1",
|
||||
"v2v": "kling-video-o1",
|
||||
"kf2v": "kling-video-o1"
|
||||
},
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"1:1": "1024*1024"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"min": 3,
|
||||
"max": 10
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
34
backend/src/config/services/midjourney/image.json
Normal file
34
backend/src/config/services/midjourney/image.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"midjourney": {
|
||||
"name": "Midjourney",
|
||||
"class": "src.services.provider.midjourney.MidjourneyImageService",
|
||||
"args": [
|
||||
"midjourney"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2i": "midjourney"
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"1:1": "1024*1024",
|
||||
"16:9": "1280*720",
|
||||
"9:16": "720*1280",
|
||||
"4:3": "1280*960",
|
||||
"3:4": "960*1280"
|
||||
},
|
||||
"2K": {
|
||||
"1:1": "1456*1456",
|
||||
"16:9": "1456*816",
|
||||
"9:16": "816*1456",
|
||||
"4:3": "1232*928",
|
||||
"3:4": "928*1232"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
23
backend/src/config/services/midjourney/provider.json
Normal file
23
backend/src/config/services/midjourney/provider.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "midjourney",
|
||||
"name": "Midjourney(悠船)",
|
||||
"description": "悠船 API - 需要 App ID 和 Secret Key",
|
||||
"dashboard_url": "https://ali.youchuan.cn/",
|
||||
"helpUrl": "https://ali.youchuan.cn/",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "App ID",
|
||||
"placeholder": "应用 ID",
|
||||
"required": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "apiSecret",
|
||||
"label": "Secret Key",
|
||||
"placeholder": "密钥",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
378
backend/src/config/services/minimax/audio.json
Normal file
378
backend/src/config/services/minimax/audio.json
Normal file
@@ -0,0 +1,378 @@
|
||||
{
|
||||
"speech-2.8-hd": {
|
||||
"name": "speech-2.8-hd",
|
||||
"class": "src.services.provider.minimax.MiniMaxAudioService",
|
||||
"args": [
|
||||
"speech-2.8-hd"
|
||||
],
|
||||
"voices": [
|
||||
{
|
||||
"id": "male-qn-qingse",
|
||||
"name": "青涩青年",
|
||||
"gender": "male",
|
||||
"desc": "青涩青年风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-jingying",
|
||||
"name": "精英青年",
|
||||
"gender": "male",
|
||||
"desc": "精英青年风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-badao",
|
||||
"name": "霸道青年",
|
||||
"gender": "male",
|
||||
"desc": "沉稳有力的中文普通话青年男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-daxuesheng",
|
||||
"name": "青年大学生",
|
||||
"gender": "male",
|
||||
"desc": "青年大学生风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "female-shaonv",
|
||||
"name": "少女",
|
||||
"gender": "female",
|
||||
"desc": "清亮少女风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-yujie",
|
||||
"name": "御姐",
|
||||
"gender": "female",
|
||||
"desc": "成熟干练风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-chengshu",
|
||||
"name": "成熟女性",
|
||||
"gender": "female",
|
||||
"desc": "成熟女性风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-tianmei",
|
||||
"name": "甜美女性",
|
||||
"gender": "female",
|
||||
"desc": "甜美风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_News_Anchor",
|
||||
"name": "新闻女声",
|
||||
"gender": "female",
|
||||
"desc": "专业播音腔的中年女性新闻主播,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Male_Announcer",
|
||||
"name": "播报男声",
|
||||
"gender": "male",
|
||||
"desc": "富有磁性的中年男性播报员声音,标准普通话,清晰而权威"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Gentleman",
|
||||
"name": "温润男声",
|
||||
"gender": "male",
|
||||
"desc": "温润磁性的青年男性声音,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Sweet_Lady",
|
||||
"name": "甜美女声",
|
||||
"gender": "female",
|
||||
"desc": "温柔甜美的青年女性声音,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Cantonese_ProfessionalHost(F)",
|
||||
"name": "粤语专业女主持",
|
||||
"gender": "female",
|
||||
"desc": "中性、专业的青年女性粤语主持人声音"
|
||||
},
|
||||
{
|
||||
"id": "Cantonese_ProfessionalHost(M)",
|
||||
"name": "粤语专业男主持",
|
||||
"gender": "male",
|
||||
"desc": "中性、专业的青年男性粤语主持人声音"
|
||||
}
|
||||
],
|
||||
"enabled": true
|
||||
},
|
||||
"speech-2.6-hd": {
|
||||
"name": "speech-2.6-hd",
|
||||
"class": "src.services.provider.minimax.MiniMaxAudioService",
|
||||
"args": [
|
||||
"speech-2.6-hd"
|
||||
],
|
||||
"voices": [
|
||||
{
|
||||
"id": "male-qn-qingse",
|
||||
"name": "青涩青年",
|
||||
"gender": "male",
|
||||
"desc": "青涩青年风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-jingying",
|
||||
"name": "精英青年",
|
||||
"gender": "male",
|
||||
"desc": "精英青年风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-badao",
|
||||
"name": "霸道青年",
|
||||
"gender": "male",
|
||||
"desc": "沉稳有力的中文普通话青年男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-daxuesheng",
|
||||
"name": "青年大学生",
|
||||
"gender": "male",
|
||||
"desc": "青年大学生风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "female-shaonv",
|
||||
"name": "少女",
|
||||
"gender": "female",
|
||||
"desc": "清亮少女风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-yujie",
|
||||
"name": "御姐",
|
||||
"gender": "female",
|
||||
"desc": "成熟干练风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-chengshu",
|
||||
"name": "成熟女性",
|
||||
"gender": "female",
|
||||
"desc": "成熟女性风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-tianmei",
|
||||
"name": "甜美女性",
|
||||
"gender": "female",
|
||||
"desc": "甜美风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_News_Anchor",
|
||||
"name": "新闻女声",
|
||||
"gender": "female",
|
||||
"desc": "专业、播音腔的中年女性新闻主播,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Male_Announcer",
|
||||
"name": "播报男声",
|
||||
"gender": "male",
|
||||
"desc": "富有磁性的中年男性播报员声音,标准普通话,清晰而权威"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Gentleman",
|
||||
"name": "温润男声",
|
||||
"gender": "male",
|
||||
"desc": "温润磁性的青年男性声音,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Sweet_Lady",
|
||||
"name": "甜美女声",
|
||||
"gender": "female",
|
||||
"desc": "温柔甜美的青年女性声音,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Cantonese_ProfessionalHost(F)",
|
||||
"name": "粤语专业女主持",
|
||||
"gender": "female",
|
||||
"desc": "中性、专业的青年女性粤语主持人声音"
|
||||
},
|
||||
{
|
||||
"id": "Cantonese_ProfessionalHost(M)",
|
||||
"name": "粤语专业男主持",
|
||||
"gender": "male",
|
||||
"desc": "中性、专业的青年男性粤语主持人声音"
|
||||
}
|
||||
],
|
||||
"enabled": true
|
||||
},
|
||||
"speech-2.8-turbo": {
|
||||
"name": "speech-2.8-turbo",
|
||||
"class": "src.services.provider.minimax.MiniMaxAudioService",
|
||||
"args": [
|
||||
"speech-2.8-turbo"
|
||||
],
|
||||
"voices": [
|
||||
{
|
||||
"id": "male-qn-qingse",
|
||||
"name": "青涩青年",
|
||||
"gender": "male",
|
||||
"desc": "青涩青年风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-jingying",
|
||||
"name": "精英青年",
|
||||
"gender": "male",
|
||||
"desc": "精英青年风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-badao",
|
||||
"name": "霸道青年",
|
||||
"gender": "male",
|
||||
"desc": "沉稳有力的中文普通话青年男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-daxuesheng",
|
||||
"name": "青年大学生",
|
||||
"gender": "male",
|
||||
"desc": "青年大学生风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "female-shaonv",
|
||||
"name": "少女",
|
||||
"gender": "female",
|
||||
"desc": "清亮少女风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-yujie",
|
||||
"name": "御姐",
|
||||
"gender": "female",
|
||||
"desc": "成熟干练风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-chengshu",
|
||||
"name": "成熟女性",
|
||||
"gender": "female",
|
||||
"desc": "成熟女性风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-tianmei",
|
||||
"name": "甜美女性",
|
||||
"gender": "female",
|
||||
"desc": "甜美风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_News_Anchor",
|
||||
"name": "新闻女声",
|
||||
"gender": "female",
|
||||
"desc": "专业、播音腔的中年女性新闻主播,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Male_Announcer",
|
||||
"name": "播报男声",
|
||||
"gender": "male",
|
||||
"desc": "富有磁性的中年男性播报员声音,标准普通话,清晰而权威"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Gentleman",
|
||||
"name": "温润男声",
|
||||
"gender": "male",
|
||||
"desc": "温润磁性的青年男性声音,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Sweet_Lady",
|
||||
"name": "甜美女声",
|
||||
"gender": "female",
|
||||
"desc": "温柔甜美的青年女性声音,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Cantonese_ProfessionalHost(F)",
|
||||
"name": "粤语专业女主持",
|
||||
"gender": "female",
|
||||
"desc": "中性、专业的青年女性粤语主持人声音"
|
||||
},
|
||||
{
|
||||
"id": "Cantonese_ProfessionalHost(M)",
|
||||
"name": "粤语专业男主持",
|
||||
"gender": "male",
|
||||
"desc": "中性、专业的青年男性粤语主持人声音"
|
||||
}
|
||||
],
|
||||
"enabled": true
|
||||
},
|
||||
"speech-2.6-turbo": {
|
||||
"name": "speech-2.6-turbo",
|
||||
"class": "src.services.provider.minimax.MiniMaxAudioService",
|
||||
"args": [
|
||||
"speech-2.6-turbo"
|
||||
],
|
||||
"voices": [
|
||||
{
|
||||
"id": "male-qn-qingse",
|
||||
"name": "青涩青年",
|
||||
"gender": "male",
|
||||
"desc": "青涩青年风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-jingying",
|
||||
"name": "精英青年",
|
||||
"gender": "male",
|
||||
"desc": "精英青年风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-badao",
|
||||
"name": "霸道青年",
|
||||
"gender": "male",
|
||||
"desc": "沉稳有力的中文普通话青年男声"
|
||||
},
|
||||
{
|
||||
"id": "male-qn-daxuesheng",
|
||||
"name": "青年大学生",
|
||||
"gender": "male",
|
||||
"desc": "青年大学生风格中文普通话男声"
|
||||
},
|
||||
{
|
||||
"id": "female-shaonv",
|
||||
"name": "少女",
|
||||
"gender": "female",
|
||||
"desc": "清亮少女风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-yujie",
|
||||
"name": "御姐",
|
||||
"gender": "female",
|
||||
"desc": "成熟干练风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-chengshu",
|
||||
"name": "成熟女性",
|
||||
"gender": "female",
|
||||
"desc": "成熟女性风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "female-tianmei",
|
||||
"name": "甜美女性",
|
||||
"gender": "female",
|
||||
"desc": "甜美风格中文普通话女声"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_News_Anchor",
|
||||
"name": "新闻女声",
|
||||
"gender": "female",
|
||||
"desc": "专业、播音腔的中年女性新闻主播,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Male_Announcer",
|
||||
"name": "播报男声",
|
||||
"gender": "male",
|
||||
"desc": "富有磁性的中年男性播报员声音,标准普通话,清晰而权威"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Gentleman",
|
||||
"name": "温润男声",
|
||||
"gender": "male",
|
||||
"desc": "温润磁性的青年男性声音,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Chinese (Mandarin)_Sweet_Lady",
|
||||
"name": "甜美女声",
|
||||
"gender": "female",
|
||||
"desc": "温柔甜美的青年女性声音,标准普通话"
|
||||
},
|
||||
{
|
||||
"id": "Cantonese_ProfessionalHost(F)",
|
||||
"name": "粤语专业女主持",
|
||||
"gender": "female",
|
||||
"desc": "中性、专业的青年女性粤语主持人声音"
|
||||
},
|
||||
{
|
||||
"id": "Cantonese_ProfessionalHost(M)",
|
||||
"name": "粤语专业男主持",
|
||||
"gender": "male",
|
||||
"desc": "中性、专业的青年男性粤语主持人声音"
|
||||
}
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
64
backend/src/config/services/minimax/image.json
Normal file
64
backend/src/config/services/minimax/image.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"image-01": {
|
||||
"name": "image-01",
|
||||
"class": "src.services.provider.minimax.MiniMaxImageService",
|
||||
"capabilities": {
|
||||
"supportsRefImage": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"1:1": "1024x1024",
|
||||
"16:9": "1280x720",
|
||||
"9:16": "720x1280",
|
||||
"4:3": "1152x864",
|
||||
"3:4": "864x1152",
|
||||
"3:2": "1248x832",
|
||||
"2:3": "832x1248",
|
||||
"21:9": "1344x576"
|
||||
},
|
||||
"2K": {
|
||||
"1:1": "2048x2048",
|
||||
"16:9": "2560x1440",
|
||||
"9:16": "1440x2560",
|
||||
"4:3": "2304x1728",
|
||||
"3:4": "1728x2304",
|
||||
"3:2": "2496x1664",
|
||||
"2:3": "1664x2496",
|
||||
"21:9": "2688x1152"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4}
|
||||
},
|
||||
"image-01-live": {
|
||||
"name": "image-01-live",
|
||||
"class": "src.services.provider.minimax.MiniMaxImageService",
|
||||
"capabilities": {
|
||||
"supportsRefImage": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"1:1": "1024x1024",
|
||||
"16:9": "1280x720",
|
||||
"9:16": "720x1280",
|
||||
"4:3": "1152x864",
|
||||
"3:4": "864x1152",
|
||||
"3:2": "1248x832",
|
||||
"2:3": "832x1248",
|
||||
"21:9": "1344x576"
|
||||
},
|
||||
"2K": {
|
||||
"1:1": "2048x2048",
|
||||
"16:9": "2560x1440",
|
||||
"9:16": "1440x2560",
|
||||
"4:3": "2304x1728",
|
||||
"3:4": "1728x2304",
|
||||
"3:2": "2496x1664",
|
||||
"2:3": "1664x2496",
|
||||
"21:9": "2688x1152"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4}
|
||||
}
|
||||
}
|
||||
11
backend/src/config/services/minimax/llm.json
Normal file
11
backend/src/config/services/minimax/llm.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"base_url": "https://api.minimaxi.com/v1",
|
||||
"MiniMax-M2.11": {
|
||||
"name": "MiniMax M2.1",
|
||||
"class": "src.services.provider.openai_service.OpenAIService",
|
||||
"args": [
|
||||
"MiniMax-M2.1"
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
22
backend/src/config/services/minimax/music.json
Normal file
22
backend/src/config/services/minimax/music.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"lyrics-2.5": {
|
||||
"name": "lyrics-2.5",
|
||||
"class": "src.services.provider.minimax.MiniMaxMusicService",
|
||||
"args": [
|
||||
"music-2.5"
|
||||
],
|
||||
"type": "lyrics",
|
||||
"enabled": true,
|
||||
"is_default": true
|
||||
},
|
||||
"music-2.5": {
|
||||
"name": "music-2.5",
|
||||
"class": "src.services.provider.minimax.MiniMaxMusicService",
|
||||
"args": [
|
||||
"music-2.5"
|
||||
],
|
||||
"type": "music",
|
||||
"enabled": true,
|
||||
"is_default": true
|
||||
}
|
||||
}
|
||||
23
backend/src/config/services/minimax/provider.json
Normal file
23
backend/src/config/services/minimax/provider.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "minimax",
|
||||
"name": "MiniMax",
|
||||
"description": "海螺AI",
|
||||
"dashboard_url": "https://platform.minimaxi.com/",
|
||||
"helpUrl": "https://platform.minimaxi.com/user-center/basic-information/interface-key",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "API Key",
|
||||
"placeholder": "sk-api-...",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
},
|
||||
{
|
||||
"name": "groupId",
|
||||
"label": "Group ID (可选)",
|
||||
"placeholder": "分组 ID",
|
||||
"required": false,
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
68
backend/src/config/services/minimax/video.json
Normal file
68
backend/src/config/services/minimax/video.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"MiniMax-Hailuo-2.3": {
|
||||
"name": "Hailuo 2.3",
|
||||
"class": "src.services.provider.minimax.MiniMaxVideoService",
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsAudio": false,
|
||||
"supportsNegativePrompt": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"durations": {
|
||||
"values": [
|
||||
6,
|
||||
10
|
||||
]
|
||||
},
|
||||
"counts": {"min": 1, "max": 4}
|
||||
},
|
||||
"MiniMax-Hailuo-02": {
|
||||
"name": "Hailuo 02",
|
||||
"class": "src.services.provider.minimax.MiniMaxVideoService",
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsAudio": false,
|
||||
"supportsNegativePrompt": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"durations": {
|
||||
"values": [
|
||||
6,
|
||||
10
|
||||
]
|
||||
},
|
||||
"counts": {"min": 1, "max": 4}
|
||||
},
|
||||
"T2V-01-Director": {
|
||||
"name": "T2V-01-Director",
|
||||
"class": "src.services.provider.minimax.MiniMaxVideoService",
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsAudio": false,
|
||||
"supportsNegativePrompt": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"durations": {
|
||||
"values": [
|
||||
6,
|
||||
10
|
||||
]
|
||||
},
|
||||
"counts": {"min": 1, "max": 4}
|
||||
}
|
||||
}
|
||||
143
backend/src/config/services/modelscope/image.json
Normal file
143
backend/src/config/services/modelscope/image.json
Normal file
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"qwen-image": {
|
||||
"name": "Qwen Image",
|
||||
"class": "backend.src.services.provider.modelscope.image.ModelScopeImageService",
|
||||
"args": [
|
||||
"Qwen/Qwen-Image"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": false,
|
||||
"supportsLora": true
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1664x928",
|
||||
"9:16": "928x1664",
|
||||
"1:1": "1328x1328"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560x1440",
|
||||
"9:16": "1440x2560",
|
||||
"1:1": "2048x2048"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
},
|
||||
"qwen-image-edit": {
|
||||
"name": "Qwen Image Edit",
|
||||
"class": "backend.src.services.provider.modelscope.image.ModelScopeImageService",
|
||||
"args": [
|
||||
"Qwen/Qwen-Image-Edit-2511"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": true,
|
||||
"supportsLora": true
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1664x928",
|
||||
"9:16": "928x1664",
|
||||
"1:1": "1328x1328",
|
||||
"4:3": "1328x1024",
|
||||
"3:4": "1024x1328"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560x1440",
|
||||
"9:16": "1440x2560",
|
||||
"1:1": "2048x2048",
|
||||
"4:3": "2560x1920",
|
||||
"3:4": "1920x2560"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
},
|
||||
"flux-dev": {
|
||||
"name": "FLUX.2 Dev",
|
||||
"class": "backend.src.services.provider.modelscope.image.ModelScopeImageService",
|
||||
"args": [
|
||||
"black-forest-labs/FLUX.2-dev"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": false,
|
||||
"supportsLora": true
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1280x720",
|
||||
"9:16": "720x1280",
|
||||
"1:1": "1024x1024",
|
||||
"4:3": "1024x768",
|
||||
"3:4": "768x1024"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560x1440",
|
||||
"9:16": "1440x2560",
|
||||
"1:1": "2048x2048",
|
||||
"4:3": "2048x1536",
|
||||
"3:4": "1536x2048"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
},
|
||||
"z-image-turbo": {
|
||||
"name": "Z Image Turbo",
|
||||
"class": "backend.src.services.provider.modelscope.image.ModelScopeImageService",
|
||||
"args": [
|
||||
"Tongyi-MAI/Z-Image-Turbo"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": false,
|
||||
"supportsLora": true
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1280x720",
|
||||
"9:16": "720x1280",
|
||||
"1:1": "1024x1024",
|
||||
"4:3": "1024x768",
|
||||
"3:4": "768x1024"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560x1440",
|
||||
"9:16": "1440x2560",
|
||||
"1:1": "2048x2048",
|
||||
"4:3": "2048x1536",
|
||||
"3:4": "1536x2048"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
},
|
||||
"awportrait-z": {
|
||||
"name": "AWPortrait Z",
|
||||
"class": "backend.src.services.provider.modelscope.image.ModelScopeImageService",
|
||||
"args": [
|
||||
"LiblibAI/AWPortrait-Z"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": false,
|
||||
"supportsLora": true
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1280x720",
|
||||
"9:16": "720x1280",
|
||||
"1:1": "1024x1024",
|
||||
"4:3": "1024x768",
|
||||
"3:4": "768x1024"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560x1440",
|
||||
"9:16": "1440x2560",
|
||||
"1:1": "2048x2048",
|
||||
"4:3": "2048x1536",
|
||||
"3:4": "1536x2048"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
16
backend/src/config/services/modelscope/provider.json
Normal file
16
backend/src/config/services/modelscope/provider.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"id": "modelscope",
|
||||
"name": "ModelScope",
|
||||
"description": "开源模型平台",
|
||||
"dashboard_url": "https://modelscope.cn/",
|
||||
"helpUrl": "https://www.modelscope.cn/my/myaccesstoken",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "API Token",
|
||||
"placeholder": "ms-...",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
11
backend/src/config/services/moonshot/llm.json
Normal file
11
backend/src/config/services/moonshot/llm.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"base_url": "https://api.moonshot.cn/v1",
|
||||
"kimi-k2.5": {
|
||||
"name": "Kimi 2.5",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": [
|
||||
"kimi-k2.5"
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
16
backend/src/config/services/moonshot/provider.json
Normal file
16
backend/src/config/services/moonshot/provider.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"id": "moonshot",
|
||||
"name": "月之暗面",
|
||||
"description": "Kimi 大模型",
|
||||
"dashboard_url": "https://platform.moonshot.cn/",
|
||||
"helpUrl": "https://platform.moonshot.cn/",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "API Key",
|
||||
"placeholder": "sk-...",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
42
backend/src/config/services/openai/audio.json
Normal file
42
backend/src/config/services/openai/audio.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"tts-1": {
|
||||
"name": "TTS-1",
|
||||
"class": "src.services.provider.openai.OpenAIAudioService",
|
||||
"args": [
|
||||
"tts-1"
|
||||
],
|
||||
"voices": [
|
||||
{
|
||||
"id": "alloy",
|
||||
"name": "Alloy",
|
||||
"gender": "female"
|
||||
},
|
||||
{
|
||||
"id": "nova",
|
||||
"name": "Nova",
|
||||
"gender": "female"
|
||||
},
|
||||
{
|
||||
"id": "shimmer",
|
||||
"name": "Shimmer",
|
||||
"gender": "female"
|
||||
},
|
||||
{
|
||||
"id": "fable",
|
||||
"name": "Fable",
|
||||
"gender": "female"
|
||||
},
|
||||
{
|
||||
"id": "echo",
|
||||
"name": "Echo",
|
||||
"gender": "male"
|
||||
},
|
||||
{
|
||||
"id": "onyx",
|
||||
"name": "Onyx",
|
||||
"gender": "male"
|
||||
}
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
25
backend/src/config/services/openai/image.json
Normal file
25
backend/src/config/services/openai/image.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"dall-e-3": {
|
||||
"name": "DALL-E 3",
|
||||
"class": "src.services.provider.openai.OpenAIImageService",
|
||||
"args": [
|
||||
"dall-e-3"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2i": "dall-e-3"
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"1:1": "1024*1024",
|
||||
"16:9": "1792*1024",
|
||||
"9:16": "1024*1792"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 1},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
16
backend/src/config/services/openai/provider.json
Normal file
16
backend/src/config/services/openai/provider.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"id": "openai",
|
||||
"name": "OpenAI",
|
||||
"description": "GPT-4、DALL-E、Sora",
|
||||
"dashboard_url": "https://platform.openai.com/",
|
||||
"helpUrl": "https://platform.openai.com/api-keys",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "API Key",
|
||||
"placeholder": "sk-...",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
7
backend/src/config/services/provider.json.example
Normal file
7
backend/src/config/services/provider.json.example
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"id": "provider-id",
|
||||
"name": "Provider Display Name",
|
||||
"description": "Optional description",
|
||||
"api_key": "YOUR_API_KEY_OR_SET_VIA_ENV",
|
||||
"dashboard_url": "https://example.com/dashboard"
|
||||
}
|
||||
42
backend/src/config/services/volcengine/image.json
Normal file
42
backend/src/config/services/volcengine/image.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"doubao-seedream-4.5": {
|
||||
"name": "SeeDream 4.5",
|
||||
"class": "src.services.provider.volcengine.image.VolcengineImageService",
|
||||
"args": [
|
||||
"doubao-seedream-4.5"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsRefImage": true,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2i": "doubao-seedream-4-5-251128",
|
||||
"i2i": "doubao-seedream-4-5-251128"
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1280x720",
|
||||
"9:16": "720x1280",
|
||||
"1:1": "1024x1024",
|
||||
"4:3": "1152x864",
|
||||
"3:4": "864x1152"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560x1440",
|
||||
"9:16": "1440x2560",
|
||||
"1:1": "2048x2048",
|
||||
"4:3": "2304x1728",
|
||||
"3:4": "1728x2304"
|
||||
},
|
||||
"4K": {
|
||||
"16:9": "3840x2160",
|
||||
"9:16": "2160x3840",
|
||||
"1:1": "4096x4096",
|
||||
"4:3": "3456x2592",
|
||||
"3:4": "2592x3456"
|
||||
}
|
||||
},
|
||||
"counts": {"min": 1, "max": 4},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
11
backend/src/config/services/volcengine/llm.json
Normal file
11
backend/src/config/services/volcengine/llm.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"base_url": "https://ark.cn-beijing.volces.com/api/v3",
|
||||
"doubao-1.5-pro": {
|
||||
"name": "Doubao 1.5 Pro",
|
||||
"class": "backend.src.services.provider.openai_service.OpenAIService",
|
||||
"args": [
|
||||
"doubao-1-5-pro-32k-250115"
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
16
backend/src/config/services/volcengine/provider.json
Normal file
16
backend/src/config/services/volcengine/provider.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"id": "volcengine",
|
||||
"name": "火山引擎",
|
||||
"description": "豆包大模型",
|
||||
"dashboard_url": "https://console.volcengine.com/ark/",
|
||||
"helpUrl": "https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"label": "API Key",
|
||||
"placeholder": "...",
|
||||
"required": true,
|
||||
"type": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
138
backend/src/config/services/volcengine/video.json
Normal file
138
backend/src/config/services/volcengine/video.json
Normal file
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"doubao-seedance-1.5-pro": {
|
||||
"name": "SeeDance 1.5 Pro",
|
||||
"class": "src.services.provider.volcengine.video.VolcengineVideoService",
|
||||
"args": [
|
||||
"doubao-seedance-1.5-pro"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "doubao-seedance-1-5-pro-251215",
|
||||
"i2v": "doubao-seedance-1-5-pro-251215",
|
||||
"kf2v": "doubao-seedance-1-5-pro-251215"
|
||||
},
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1280x720",
|
||||
"9:16": "720x1280",
|
||||
"1:1": "1280x1280",
|
||||
"4:3": "1280x960",
|
||||
"3:4": "960x1280"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"values": [
|
||||
4,
|
||||
12
|
||||
]
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"doubao-seedance-1.0-pro": {
|
||||
"name": "SeeDance 1.0 Pro",
|
||||
"class": "src.services.provider.volcengine.video.VolcengineVideoService",
|
||||
"args": [
|
||||
"doubao-seedance-1-0-pro-250528"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": true,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "doubao-seedance-1-0-pro-250528",
|
||||
"i2v": "doubao-seedance-1-0-pro-250528",
|
||||
"kf2v": "doubao-seedance-1-0-pro-250528"
|
||||
},
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1248×704",
|
||||
"9:16": "704x1248",
|
||||
"1:1": "960×960",
|
||||
"4:3": "1120×832",
|
||||
"3:4": "832x1120"
|
||||
},
|
||||
"1080P": {
|
||||
"16:9": "1920x1088",
|
||||
"9:16": "1088x1920",
|
||||
"1:1": "1440×1440",
|
||||
"4:3": "1664×1248",
|
||||
"3:4": "1248x1664"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"values": [
|
||||
2,
|
||||
12
|
||||
]
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"doubao-seedance-1.0-pro-fast": {
|
||||
"name": "SeeDance 1.0 Pro Fast",
|
||||
"class": "src.services.provider.volcengine.video.VolcengineVideoService",
|
||||
"args": [
|
||||
"doubao-seedance-1-0-pro-fast-251015"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsTextToVideo": true,
|
||||
"supportsImageToVideo": true,
|
||||
"supportsFirstFrame": true,
|
||||
"supportsLastFrame": false,
|
||||
"supportsMultiImage": false,
|
||||
"supportsMultiVideo": false,
|
||||
"supportsLora": false
|
||||
},
|
||||
"variants": {
|
||||
"t2v": "doubao-seedance-1-0-pro-fast-251015",
|
||||
"i2v": "doubao-seedance-1-0-pro-fast-251015"
|
||||
},
|
||||
"resolutions": {
|
||||
"720P": {
|
||||
"16:9": "1248×704",
|
||||
"9:16": "704x1248",
|
||||
"1:1": "960×960",
|
||||
"4:3": "1120×832",
|
||||
"3:4": "832x1120"
|
||||
},
|
||||
"1080P": {
|
||||
"16:9": "1920x1088",
|
||||
"9:16": "1088x1920",
|
||||
"1:1": "1440×1440",
|
||||
"4:3": "1664×1248",
|
||||
"3:4": "1248x1664"
|
||||
}
|
||||
},
|
||||
"durations": {
|
||||
"values": [
|
||||
2,
|
||||
12
|
||||
]
|
||||
},
|
||||
"counts": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
98
backend/src/config/settings.py
Normal file
98
backend/src/config/settings.py
Normal file
@@ -0,0 +1,98 @@
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
from dotenv import load_dotenv
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
|
||||
# Load Storage Configuration
|
||||
SETTINGS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
STORAGE_CONFIG_PATH = os.path.join(SETTINGS_DIR, 'storage.json')
|
||||
|
||||
storage_config = {}
|
||||
if os.path.exists(STORAGE_CONFIG_PATH):
|
||||
try:
|
||||
with open(STORAGE_CONFIG_PATH, 'r') as f:
|
||||
storage_config = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load storage config: {e}")
|
||||
|
||||
# 服务器 Configuration
|
||||
PY_PORT = int(os.getenv('PY_PORT', '8000'))
|
||||
NODE_ENV = os.getenv('NODE_ENV', 'development')
|
||||
|
||||
# CORS Configuration
|
||||
ALLOWED_ORIGINS = [o for o in os.getenv('CORS_ALLOWED_ORIGINS', '').split(',') if o]
|
||||
DEV_ALLOWED_ORIGINS = [
|
||||
o for o in os.getenv(
|
||||
'CORS_DEV_ALLOWED_ORIGINS',
|
||||
'http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001'
|
||||
).split(',') if o
|
||||
]
|
||||
ALLOW_DEV_ORIGINS = (os.getenv('ALLOW_DEV_ORIGINS', '1') != '0' and NODE_ENV != 'production')
|
||||
|
||||
# 数据库 Configuration
|
||||
DATA_DIR = os.getenv('DATA_DIR') or os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'data'))
|
||||
DB_PATH = os.getenv('DB_PATH') or os.path.join(DATA_DIR, 'pixel.db')
|
||||
DATABASE_URL = os.getenv('DATABASE_URL')
|
||||
|
||||
# Alibaba Cloud OSS Configuration (env vars take precedence over storage.json)
|
||||
OSS_REGION = os.getenv('OSS_REGION') or storage_config.get('OSS_REGION', 'oss-cn-shanghai')
|
||||
OSS_ENDPOINT = os.getenv('OSS_ENDPOINT') or storage_config.get('OSS_ENDPOINT', 'oss-cn-shanghai.aliyuncs.com')
|
||||
|
||||
OSS_BUCKET = os.getenv('OSS_BUCKET') or storage_config.get('OSS_BUCKET')
|
||||
ALIBABA_CLOUD_ACCESS_KEY_ID = os.getenv('ALIBABA_CLOUD_ACCESS_KEY_ID') or storage_config.get('ALIBABA_CLOUD_ACCESS_KEY_ID')
|
||||
ALIBABA_CLOUD_ACCESS_KEY_SECRET = os.getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET') or storage_config.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET')
|
||||
|
||||
# DashScope Configuration (Qwen, Wanx)
|
||||
DASHSCOPE_API_KEY = os.getenv('DASHSCOPE_API_KEY')
|
||||
|
||||
# 模型Scope Configuration
|
||||
MODELSCOPE_API_TOKEN = os.getenv('MODELSCOPE_API_TOKEN')
|
||||
|
||||
# Volcengine Configuration
|
||||
VOLCENGINE_API_KEY = os.getenv('VOLCENGINE_API_KEY') # 火山方舟 (LLM)
|
||||
|
||||
# Google Configuration
|
||||
GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
|
||||
|
||||
# OpenAI Configuration
|
||||
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
|
||||
OPENAI_BASE_URL = os.getenv('OPENAI_BASE_URL') # 可选: for proxies
|
||||
|
||||
# MiniMax Configuration
|
||||
MINIMAX_API_KEY = os.getenv('MINIMAX_API_KEY')
|
||||
MINIMAX_GROUP_ID = os.getenv('MINIMAX_GROUP_ID') # Sometimes needed
|
||||
|
||||
# Kling AI Configuration
|
||||
KLING_ACCESS_KEY = os.getenv('KLING_ACCESS_KEY')
|
||||
KLING_SECRET_KEY = os.getenv('KLING_SECRET_KEY')
|
||||
KLING_API_BASE = os.getenv('KLING_API_BASE', 'https://api-beijing.klingai.com/v1')
|
||||
|
||||
# Midjourney Configuration (Youchuan / Proxy)
|
||||
MIDJOURNEY_API_KEY = os.getenv('MIDJOURNEY_API_KEY')
|
||||
MIDJOURNEY_PROXY_URL = os.getenv('MIDJOURNEY_PROXY_URL')
|
||||
YOUCHUAN_APP_ID = os.getenv('YOUCHUAN_APP_ID')
|
||||
YOUCHUAN_SECRET_KEY = os.getenv('YOUCHUAN_SECRET_KEY')
|
||||
|
||||
# Application Settings
|
||||
UPLOAD_DIR = os.path.join(DATA_DIR, 'uploads')
|
||||
|
||||
# 存储 Configuration
|
||||
STORAGE_TYPE = os.getenv('STORAGE_TYPE') or storage_config.get('STORAGE_TYPE', 'local') # 'local' or 'oss'
|
||||
PROJECTS_DIR = os.path.join(DATA_DIR, "projects")
|
||||
CANVAS_DIR = os.path.join(DATA_DIR, "canvas")
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_URL = os.getenv('REDIS_URL', 'redis://localhost:6379')
|
||||
REDIS_ENABLED = os.getenv('REDIS_ENABLED', '1') != '0'
|
||||
|
||||
# 追踪 Configuration
|
||||
TRACING_ENABLED = os.getenv('TRACING_ENABLED', '0') != '0'
|
||||
OTLP_ENDPOINT = os.getenv('OTLP_ENDPOINT', 'http://localhost:4317')
|
||||
|
||||
# Task Management Configuration
|
||||
# Unified task manager is now always used
|
||||
6
backend/src/config/storage.example.json
Normal file
6
backend/src/config/storage.example.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"OSS_REGION": "oss-cn-shanghai",
|
||||
"OSS_ENDPOINT": "oss-cn-shanghai.aliyuncs.com",
|
||||
"OSS_BUCKET": "your-bucket-name",
|
||||
"STORAGE_TYPE": "oss"
|
||||
}
|
||||
152
backend/src/config/styles.json
Normal file
152
backend/src/config/styles.json
Normal file
@@ -0,0 +1,152 @@
|
||||
{
|
||||
"styles": [
|
||||
{
|
||||
"id": "cyberpunk",
|
||||
"name": "赛博朋克",
|
||||
"type": "prompt",
|
||||
"desc": "高对比度霓虹灯光,未来主义建筑,机械改造",
|
||||
"prompt": "cyberpunk style, neon lights, high contrast, futuristic buildings, mechanical modifications",
|
||||
"color": "from-pink-500/20 to-blue-500/20"
|
||||
},
|
||||
{
|
||||
"id": "ink",
|
||||
"name": "水墨风",
|
||||
"type": "prompt",
|
||||
"desc": "传统中国水墨渲染,黑白灰为主,意境深远",
|
||||
"prompt": "traditional chinese ink painting style, black and white, artistic conception, ink wash",
|
||||
"color": "from-gray-200/10 to-gray-900/10"
|
||||
},
|
||||
{
|
||||
"id": "pixar",
|
||||
"name": "皮克斯风格",
|
||||
"type": "prompt",
|
||||
"desc": "3D卡通渲染,色彩鲜艳,光影柔和,表情夸张",
|
||||
"prompt": "pixar style, 3d cartoon rendering, vibrant colors, soft lighting, expressive",
|
||||
"color": "from-orange-400/20 to-yellow-400/20"
|
||||
},
|
||||
{
|
||||
"id": "anime",
|
||||
"name": "日漫",
|
||||
"type": "prompt",
|
||||
"desc": "典型日本动画风格,线条清晰,赛璐璐上色",
|
||||
"prompt": "japanese anime style, clear lines, cel shading, 2d animation",
|
||||
"color": "from-purple-500/20 to-pink-500/20"
|
||||
},
|
||||
{
|
||||
"id": "chinese-anime",
|
||||
"name": "国漫风",
|
||||
"type": "prompt",
|
||||
"desc": "中国现代动画风格,融合传统与现代元素,色彩华丽",
|
||||
"prompt": "chinese donghua style, chinese anime, elegant, detailed background, vibrant colors, mix of traditional and modern aesthetics",
|
||||
"color": "from-red-500/20 to-yellow-500/20"
|
||||
},
|
||||
{
|
||||
"id": "cel-shading",
|
||||
"name": "赛璐璐风",
|
||||
"type": "prompt",
|
||||
"desc": "经典的赛璐璐上色风格,阴影边缘硬朗,色彩鲜明",
|
||||
"prompt": "cel shading, hard shadows, flat colors, anime coloring style, clean lines",
|
||||
"color": "from-blue-400/20 to-indigo-400/20"
|
||||
},
|
||||
{
|
||||
"id": "korean-webtoon",
|
||||
"name": "韩漫风",
|
||||
"type": "prompt",
|
||||
"desc": "韩国条漫风格,人物美型,色彩明亮,光影细腻",
|
||||
"prompt": "manhwa style, korean webtoon, beautiful characters, detailed eyes, soft lighting, vibrant digital art",
|
||||
"color": "from-pink-400/20 to-rose-400/20"
|
||||
},
|
||||
{
|
||||
"id": "american-comic",
|
||||
"name": "美漫风",
|
||||
"type": "prompt",
|
||||
"desc": "美国漫画风格,线条粗犷,阴影浓重,动态感强",
|
||||
"prompt": "american comic book style, bold lines, heavy shadows, dynamic poses, halftone patterns, marvel/dc style",
|
||||
"color": "from-red-600/20 to-blue-600/20"
|
||||
},
|
||||
{
|
||||
"id": "ghibli",
|
||||
"name": "吉卜力风格",
|
||||
"type": "prompt",
|
||||
"desc": "宫崎骏动画风格,色彩清新自然,细节丰富,治愈系",
|
||||
"prompt": "studio ghibli style, miyazaki hayao style, anime scenery, vibrant colors, lush greenery, detailed clouds, soothing atmosphere",
|
||||
"color": "from-green-400/20 to-blue-400/20"
|
||||
},
|
||||
{
|
||||
"id": "realistic",
|
||||
"name": "写实",
|
||||
"type": "prompt",
|
||||
"desc": "电影级写实渲染,细节丰富,光照真实",
|
||||
"prompt": "cinematic realistic, highly detailed, photorealistic, 8k, movie quality",
|
||||
"color": "from-blue-900/20 to-slate-900/20"
|
||||
},
|
||||
{
|
||||
"id": "hand-drawn",
|
||||
"name": "手绘",
|
||||
"type": "prompt",
|
||||
"desc": "传统手绘质感,笔触明显,艺术感强",
|
||||
"prompt": "hand-drawn style, visible brush strokes, artistic, sketch",
|
||||
"color": "from-emerald-500/20 to-teal-500/20"
|
||||
},
|
||||
{
|
||||
"id": "watercolor",
|
||||
"name": "水彩画",
|
||||
"type": "prompt",
|
||||
"desc": "水彩晕染效果,色彩通透,艺术感强",
|
||||
"prompt": "watercolor painting, wet on wet, soft blending, artistic, translucent colors, paper texture",
|
||||
"color": "from-cyan-400/20 to-blue-300/20"
|
||||
},
|
||||
{
|
||||
"id": "oil-painting",
|
||||
"name": "油画",
|
||||
"type": "prompt",
|
||||
"desc": "厚涂油画质感,笔触丰富,光影层次感强",
|
||||
"prompt": "oil painting, impasto, textured canvas, classical art, rich colors, visible brushwork",
|
||||
"color": "from-amber-700/20 to-yellow-600/20"
|
||||
},
|
||||
{
|
||||
"id": "pixel-art",
|
||||
"name": "像素风",
|
||||
"type": "prompt",
|
||||
"desc": "复古8-bit/16-bit像素艺术,怀旧游戏风格",
|
||||
"prompt": "pixel art, 16-bit, retro game style, dot art, low resolution aesthetics",
|
||||
"color": "from-purple-600/20 to-indigo-600/20"
|
||||
},
|
||||
{
|
||||
"id": "ukiyo-e",
|
||||
"name": "浮世绘",
|
||||
"type": "prompt",
|
||||
"desc": "日本传统木刻版画风格,线条流畅,色彩古朴",
|
||||
"prompt": "ukiyo-e style, japanese woodblock print, traditional japanese art, flat colors, bold outlines",
|
||||
"color": "from-red-400/20 to-orange-300/20"
|
||||
},
|
||||
{
|
||||
"id": "vaporwave",
|
||||
"name": "蒸汽波",
|
||||
"type": "prompt",
|
||||
"desc": "80年代复古未来主义,霓虹色彩,故障艺术",
|
||||
"prompt": "vaporwave style, 80s retro aesthetics, neon pink and blue, glitch art, surrealism, statue, palm trees",
|
||||
"color": "from-pink-600/20 to-purple-600/20"
|
||||
},
|
||||
{
|
||||
"id": "low-poly",
|
||||
"name": "低多边形",
|
||||
"type": "prompt",
|
||||
"desc": "3D几何多边形风格,简约抽象,棱角分明",
|
||||
"prompt": "low poly style, 3d geometric, minimalist, angular, flat shading, isometric",
|
||||
"color": "from-blue-500/20 to-cyan-500/20"
|
||||
},
|
||||
{
|
||||
"id": "clay-style-lora",
|
||||
"name": "黏土风 (LoRA)",
|
||||
"type": "lora",
|
||||
"desc": "特殊的黏土材质风格",
|
||||
"lora": {
|
||||
"id": "lora-clay-v1",
|
||||
"base_model": "modelscope/qwen-image",
|
||||
"trigger_word": "clay style"
|
||||
},
|
||||
"color": "from-amber-600/20 to-orange-600/20"
|
||||
}
|
||||
]
|
||||
}
|
||||
8
backend/src/config/user_config.json
Normal file
8
backend/src/config/user_config.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"defaultImageModel": "dashscope/z-image",
|
||||
"defaultVideoModel": "dashscope/wan2.6-video",
|
||||
"defaultAudioModel": "minimax/speech-2.8-turbo",
|
||||
"defaultLLMModel": "dashscope/qwen-plus",
|
||||
"defaultStyle": "anime",
|
||||
"defaultAspectRatio": "16:9"
|
||||
}
|
||||
Reference in New Issue
Block a user