a77ec26a02
- 删除 shops/publish/categories/ozon 相关路由、模型、schema 与客户端服务(V2.1 决策放弃 API 直传,改人工上传)
- materials 新增 DELETE /assets/{id}:删除素材记录与本地文件,并同步修正 asset_counts
- 试算页支持单张素材删除,生图弹窗交互微调
- 新增 docs/v2.1/HANDOFF.md 工作交接说明,README 补充索引
203 lines
8.2 KiB
TypeScript
203 lines
8.2 KiB
TypeScript
/**
|
||
* 套图生成 / 单张 AI 生图 / 图片导出 服务层。
|
||
* 契约对齐 docs/v2.1/api.md(Phase A 前端先行;带 ★ 的接口待 Phase B 服务端实现)。
|
||
* 常量(类型/风格/模型)与 image-suite-studio 的 src/api/client.ts 保持一致。
|
||
*/
|
||
import { api } from './api';
|
||
import apiClient from './api';
|
||
|
||
/** 套图类型白名单(与服务端 prompts/common.py 对齐) */
|
||
export const SUITE_TYPE_OPTIONS = [
|
||
{ value: 'white_bg', label: '白底主图' },
|
||
{ value: 'key_features', label: '核心卖点图' },
|
||
{ value: 'selling_pt', label: '卖点图' },
|
||
{ value: 'material', label: '材质图' },
|
||
{ value: 'lifestyle', label: '场景展示图' },
|
||
{ value: 'multi_scene', label: '多场景拼图' },
|
||
{ value: 'ecommerce_detail', label: '电商详情图' },
|
||
{ value: 'size_chart', label: '尺寸标注图' },
|
||
{ value: 'sku_collection', label: 'SKU合集图' },
|
||
{ value: 'custom', label: '创意图' },
|
||
] as const;
|
||
|
||
/** 出图方案项:一类图 × 数量,可绑定 SKU 规格 */
|
||
export interface PlanItem {
|
||
kind: string;
|
||
title: string;
|
||
detail: string;
|
||
prompt_hint: string;
|
||
count: number;
|
||
variant_name?: string | null;
|
||
}
|
||
|
||
/** 默认方案:7 种基础类型各 1 张(AI 规划前) */
|
||
export const DEFAULT_PLAN: PlanItem[] = SUITE_TYPE_OPTIONS.slice(0, 7).map((t) => ({
|
||
kind: t.value,
|
||
title: t.label,
|
||
detail: '',
|
||
prompt_hint: '',
|
||
count: 1,
|
||
variant_name: null,
|
||
}));
|
||
|
||
/** 视觉风格(默认提示词可在页面上改写,随生成请求覆盖后端模板) */
|
||
export const STYLE_SET_OPTIONS = [
|
||
{ value: 1, label: '北欧极简', prompt: '北欧极简风:浅灰或米白背景,柔和漫射光,低饱和色调,画面留白充足,构图克制干净' },
|
||
{ value: 2, label: '清新明亮', prompt: '清新明亮风:明亮的白色到浅蓝渐变背景,高调光线,色彩明快通透,整体轻盈干净' },
|
||
{ value: 3, label: '高级感深色', prompt: '高级质感风:深灰或炭黑背景,戏剧性侧光打光,突出商品材质与光泽,沉稳高级' },
|
||
{ value: 4, label: '暖调生活', prompt: '温暖生活风:暖米色背景,暖色灯光氛围,温馨的家居质感,亲和力强' },
|
||
{ value: 5, label: '纯净棚拍', prompt: '标准电商棚拍:纯色浅背景,均匀的正面柔光,无杂物干扰,商品居中突出' },
|
||
] as const;
|
||
|
||
/** 试算页固定目标平台 Ozon:俄文文案 · 3:4 图片 */
|
||
export const PLATFORM_SPECS: Record<string, { lang: string; ratio: string; label: string }> = {
|
||
ozon: { lang: '俄文', ratio: '3:4', label: 'Ozon' },
|
||
};
|
||
|
||
/** 生图模型(服务端按模型名路由 provider,同 image-suite-studio) */
|
||
export const IMAGE_MODEL_OPTIONS = [
|
||
{ value: 'qwen-image-3.0-pro', label: 'qwen-image-3.0-pro', desc: '同步生成,响应快、图文理解强,适合快速批量出图' },
|
||
{ value: 'wan2.7-image-pro', label: 'wan2.7-image-pro', desc: '异步精修,质感与细节更强,适合高质量电商大片' },
|
||
{ value: 'wan2.6-image', label: 'wan2.6-image', desc: '通义 2.6 图生图,支持参考图与多图融合,速度更快、稳定性好' },
|
||
{ value: 'wan2.6-t2i', label: 'wan2.6-t2i', desc: '通义 2.6 纯文生图,不使用参考图(商品外观靠文案描述),速度最快' },
|
||
{ value: 'gpt-image-2', label: 'gpt-image-2', desc: 'GPT 图像模型,构图与图内文案渲染最强,参考图高保真,单张 1-5 分钟' },
|
||
{ value: 'gpt-image-2-vip', label: 'gpt-image-2-vip', desc: 'GPT 官逆低价通道,构图与文字渲染强、成本更低,适合大批量出图' },
|
||
{ value: 'nano-banana', label: 'nano-banana', desc: 'Google Gemini 图像模型,出图极快,图像编辑与风格迁移强,多图融合自然' },
|
||
{ value: 'nano-banana-2', label: 'nano-banana-2', desc: 'Google 新一代图像模型,画质与文字渲染大幅提升,日常生成与改图的综合首选' },
|
||
{ value: 'nano-banana-2-lite', label: 'nano-banana-2-lite', desc: 'nano-banana-2 轻量版,约 4 秒/张、成本极低,适合大批量出图与快速试错' },
|
||
{ value: 'nano-banana-pro', label: 'nano-banana-pro', desc: 'Google 最高保真旗舰,细节最强、支持 4K 输出,适合商业级精修大片' },
|
||
] as const;
|
||
|
||
export const DEFAULT_IMAGE_MODEL = 'gpt-image-2-vip';
|
||
|
||
export interface WatermarkPayload {
|
||
enabled: boolean;
|
||
type: 'image' | 'text';
|
||
text: string;
|
||
opacity: number;
|
||
}
|
||
|
||
export const DEFAULT_WATERMARK: WatermarkPayload = {
|
||
enabled: false,
|
||
type: 'text',
|
||
text: 'Panda Store',
|
||
opacity: 30,
|
||
};
|
||
|
||
/** 传给规划/生成的文本素材(kind 与采集 ScanResult.texts 一致) */
|
||
export interface SuiteTextPayload {
|
||
kind: string;
|
||
content: string;
|
||
pairs?: Array<{ key: string; value: string }> | null;
|
||
}
|
||
|
||
export interface SuitePlanPayload {
|
||
product_id?: string;
|
||
texts: SuiteTextPayload[];
|
||
sku_variants: string[];
|
||
image_stats: Record<string, number>;
|
||
platform: string;
|
||
requirements?: string | null;
|
||
}
|
||
|
||
export interface SuiteGeneratePayload {
|
||
product_id?: string;
|
||
texts: SuiteTextPayload[];
|
||
images: Array<{ url: string; group_key: string; variant_name?: string | null }>;
|
||
style_set: number;
|
||
style_prompt?: string | null;
|
||
requirements?: string | null;
|
||
plan: PlanItem[];
|
||
platform: string;
|
||
model?: string | null;
|
||
watermark?: WatermarkPayload;
|
||
}
|
||
|
||
export interface SuiteImageInfo {
|
||
type_id: string;
|
||
name: string;
|
||
url: string;
|
||
status: string;
|
||
error?: string | null;
|
||
}
|
||
|
||
export interface SuiteInfo {
|
||
id: string;
|
||
status: 'pending' | 'running' | 'done' | 'partial' | 'failed';
|
||
style_set: number;
|
||
platform: string;
|
||
lang: string;
|
||
ratio: string;
|
||
provider?: string;
|
||
total?: number;
|
||
images: SuiteImageInfo[];
|
||
error?: string | null;
|
||
}
|
||
|
||
/** ★ AI 智能规划出图方案 */
|
||
export function planSuite(payload: SuitePlanPayload) {
|
||
return api.post<{ summary: string; items: PlanItem[] }>('/suite/plan', payload);
|
||
}
|
||
|
||
/** ★ 提交一键生成任务 */
|
||
export function generateSuite(payload: SuiteGeneratePayload) {
|
||
return api.post<{ suite_id: string }>('/suite/generate', payload);
|
||
}
|
||
|
||
/** ★ 查询套图任务状态(轮询用) */
|
||
export function getSuite(suiteId: string) {
|
||
return api.get<SuiteInfo>(`/suites/${suiteId}`);
|
||
}
|
||
|
||
/** ★ 下载生成结果 ZIP(blob) */
|
||
export async function downloadSuiteZip(suiteId: string): Promise<Blob> {
|
||
const res = await apiClient.get(`/suites/${suiteId}/zip`, { responseType: 'blob' });
|
||
return res.data as Blob;
|
||
}
|
||
|
||
export interface ImageEditSinglePayload {
|
||
product_id?: string;
|
||
image_url: string;
|
||
prompt: string;
|
||
model: string;
|
||
append?: boolean;
|
||
/** 插入锚点:新素材排在该素材之后(方便与原图对比) */
|
||
after_asset_id?: string;
|
||
}
|
||
|
||
/** ★ 单张 AI 生图(采集图/生成图上的「AI生图」入口) */
|
||
export function imageEditSingle(payload: ImageEditSinglePayload) {
|
||
return api.post<{ url: string; asset_id: string | null }>('/suite/image-edit', payload);
|
||
}
|
||
|
||
/** 删除一条素材(DB 记录 + 本地文件),用于删除已生成的图片 */
|
||
export function deleteAsset(assetId: string) {
|
||
return api.delete<{ deleted: boolean }>(`/assets/${assetId}`);
|
||
}
|
||
|
||
export interface ExportImagesPayload {
|
||
title: string;
|
||
images: Array<{ url: string; groupName: string; variantName?: string | null; key: string }>;
|
||
}
|
||
|
||
/** ★ 导出采集图片 ZIP(分组建文件夹,服务端代理下载绕防盗链) */
|
||
export async function exportImages(payload: ExportImagesPayload): Promise<Blob> {
|
||
const res = await apiClient.post('/export/images', payload, { responseType: 'blob' });
|
||
return res.data as Blob;
|
||
}
|
||
|
||
/** 上传补充参考图到商品素材(已有接口:POST /api/materials/bytes) */
|
||
export async function uploadProductAsset(
|
||
productId: string,
|
||
file: File,
|
||
groupKey = 'upload',
|
||
): Promise<{ asset_id: string; status: string }> {
|
||
const form = new FormData();
|
||
form.append('product_id', productId);
|
||
form.append('group_key', groupKey);
|
||
form.append('type', 'img');
|
||
form.append('file', file);
|
||
const res = await apiClient.post('/materials/bytes', form);
|
||
return res.data as { asset_id: string; status: string };
|
||
}
|