Files
yingqing/core/backend/apps/ai/model_library.py
T
seaislee1209andClaude Opus 4.8 6464001f84 feat(core): AI 生成 Agent 化 — 多模型流式脚本 agent + 可插拔 Provider + gpt-image-2 参考图 + 模特库
- 后端·可插拔 Provider 层:通用 OpenAICompatibleProvider(tokenssr 等中转站,base_url+api_key,零改代码换站)+ ModelProvider.api_key
- 后端·脚本 agent:结构化 ScriptDraft 契约 + 加载电商 skill + 出稿/改稿一体对话 agent(3模式/多模型)+ 流式 SSE 端点(DRF SSE renderer)
- 后端·图像:gpt-image-2 参考图出图 + 故事板 @图1@图2@图3 多锚点合成(锁脸锁商品);Seedance 打开 generate_audio
- 后端·模特库:gpt-image-2 生成器(9:16氛围图→16:9白底三视图)+ seed_demo_models 管理命令
- DB·迁移:tokenssr 中转站 + 多模型 seed(豆包/GPT-5.5/Gemini + gpt-image-2);ScriptSegment 结构化字段
- 前端·脚本趴:接真 SSE(工具卡 + 思考流)+ 模型下拉 + 3模式 + 改稿;agentScriptStream
- skills/ecommerce-video-script 电商脚本技能(运行时依赖)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 03:12:03 +08:00

93 lines
4.0 KiB
Python

"""模特库生成:用 gpt-image-2 预生成电商真人模特。
流程(与用户定的 SOP 一致):
1) 先出 9:16 竖屏氛围正面图(image_generation);
2) 以正面图为参考,出 16:9 白底三视图(image_edit,提示词锁角色一致性)。
两张都落 TOS,存为 person 类 Asset(metadata.kind="model"),进模特库/资产库。
可被管理命令(seed_demo_models)或后端业务复用。模型走默认 image 模型(当前 = tokenssr:gpt-image-2)。
"""
from __future__ import annotations
import uuid
from io import BytesIO
from apps.ai.models import ModelConfig
from apps.ai.services import _asset_preview_url, build_provider, get_default_model
from apps.assets.models import Asset, AssetFile
from apps.assets.storage import TosStorage
THREE_VIEW_PROMPT = (
"参考图1角色,生成角色三视图,从左往右依次为:胸像特写,全身正面,全身侧面,全身背面,白色背景"
)
def _store_model_asset(*, team, user, media: str, name: str, brief: str, view: str) -> Asset:
"""把生成的图片(url/base64)落 TOS,存为 person 类模特资产(非项目维度)。"""
from apps.ai.providers import VolcanoArkProvider # media_to_bytes 复用
fileobj, content_type = VolcanoArkProvider.media_to_bytes(media)
suffix = ".png"
if "jpeg" in (content_type or ""):
suffix = ".jpg"
elif "webp" in (content_type or ""):
suffix = ".webp"
asset_id = uuid.uuid4()
object_key = f"teams/{team.id}/models/{asset_id}{suffix}"
raw = fileobj.getvalue()
stored = TosStorage().upload_fileobj(fileobj=BytesIO(raw), object_key=object_key, content_type=content_type or "image/png")
asset = Asset.objects.create(
id=asset_id,
team=team,
created_by=user,
name=name,
asset_type=Asset.Type.IMAGE,
source=Asset.Source.AI_GENERATED,
category=Asset.Category.PERSON,
metadata={"kind": "model", "brief": brief, "view": view},
)
AssetFile.objects.create(
asset=asset,
object_key=stored.object_key,
bucket=stored.bucket,
content_type=stored.content_type,
size_bytes=stored.size_bytes,
is_primary=True,
)
return asset
def generate_model(*, team, user, brief: str, name: str | None = None) -> dict:
"""生成一个电商模特(9:16 氛围正面图 + 16:9 白底三视图)。返回 {"frontal":Asset,"three_view":Asset}。"""
model_config = get_default_model(ModelConfig.Capability.IMAGE)
if model_config is None:
raise ValueError("没有可用的图像模型(image capability)")
provider = build_provider(model_config)
if not hasattr(provider, "image_edit"):
raise ValueError(f"当前图像模型 {model_config.provider.name}:{model_config.name} 不支持参考图三视图(image_edit)")
label = name or brief[:16]
# 1) 9:16 氛围正面图
frontal_prompt = f"{brief},电商真人模特,9:16竖屏氛围正面半身,自然妆容,柔和影棚光,真实质感,单人,简洁背景"
resp = provider.image_generation(model=model_config.name, prompt=frontal_prompt, size="1024x1536")
frontal = _store_model_asset(
team=team, user=user, media=provider.extract_first_media_url(resp),
name=f"{label}·正面氛围", brief=brief, view="frontal",
)
# 2) 16:9 白底三视图(以正面图为参考,锁角色一致性)
frontal_url = _asset_preview_url(frontal)
resp2 = provider.image_edit(model=model_config.name, prompt=THREE_VIEW_PROMPT, images=[frontal_url], size="1536x1024")
three_view = _store_model_asset(
team=team, user=user, media=provider.extract_first_media_url(resp2),
name=f"{label}·三视图", brief=brief, view="three_view",
)
return {"frontal": frontal, "three_view": three_view}
# 演示用默认模特画像(电商常用人设)
DEFAULT_MODEL_BRIEFS = [
"26岁都市白领女性,知性温柔,黑色及肩直发,米色针织衫",
"30岁阳光运动男性,短发,健康肤色,浅灰色休闲卫衣",
"22岁元气学生女生,马尾,清透妆,浅蓝色衬衫",
]