Files
ozon-seller-kit/studio/src/services/suite.ts
T
R524809 a77ec26a02 refactor(server): 移除已放弃的 Ozon API 直传模块,新增素材删除接口
- 删除 shops/publish/categories/ozon 相关路由、模型、schema 与客户端服务(V2.1 决策放弃 API 直传,改人工上传)
- materials 新增 DELETE /assets/{id}:删除素材记录与本地文件,并同步修正 asset_counts
- 试算页支持单张素材删除,生图弹窗交互微调
- 新增 docs/v2.1/HANDOFF.md 工作交接说明,README 补充索引
2026-08-28 17:47:57 +08:00

203 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 套图生成 / 单张 AI 生图 / 图片导出 服务层。
* 契约对齐 docs/v2.1/api.mdPhase 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}`);
}
/** ★ 下载生成结果 ZIPblob */
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 };
}