优化住流程和添加复刻视频页面
This commit is contained in:
@@ -106,52 +106,78 @@ export function durationWarning(structure: VideoStructure, seconds: number): str
|
||||
return `${VIDEO_STRUCTURES[structure]}低于 ${min} 秒会压不住,建议调长`;
|
||||
}
|
||||
|
||||
// ── 2.3 按商品信息推荐默认组合 ──
|
||||
// ── 2.3 按商品分类推荐默认组合 ──
|
||||
|
||||
type Combo = { format: PresentationFormat; structure: VideoStructure };
|
||||
type Combo = { format: PresentationFormat; structure: VideoStructure; persona: string };
|
||||
|
||||
/** 品类关键词 → 推荐组合。命中第一条即用,没命中走兜底。 */
|
||||
/** 与商品库品类一一对应。改这里时同步 backend script_agent.recommend_script_setup。 */
|
||||
const CATEGORY_COMBOS: Record<string, Combo> = {
|
||||
美妆个护: { format: "oral", structure: "contrast", persona: "bestie" },
|
||||
食品饮料: { format: "oral", structure: "scene", persona: "bestie" },
|
||||
服饰鞋包: { format: "oral", structure: "scene", persona: "urban" },
|
||||
家居日用: { format: "oral", structure: "pain", persona: "mom" },
|
||||
数码家电: { format: "oral", structure: "review", persona: "reviewer" },
|
||||
母婴玩具: { format: "oral", structure: "pain", persona: "mom" },
|
||||
运动健康: { format: "oral", structure: "scene", persona: "urban" },
|
||||
珠宝配饰: { format: "oral", structure: "scene", persona: "ceo" },
|
||||
汽车用品: { format: "oral", structure: "review", persona: "reviewer" },
|
||||
宠物用品: { format: "oral", structure: "pain", persona: "mom" },
|
||||
图书文教: { format: "oral", structure: "knowledge", persona: "urban" },
|
||||
五金农资: { format: "oral", structure: "review", persona: "reviewer" },
|
||||
其他商品: { format: "oral", structure: "pain", persona: "urban" },
|
||||
};
|
||||
|
||||
/** 旧品类名 / 标题关键词兜底。命中第一条即用。 */
|
||||
const CATEGORY_RULES: ReadonlyArray<{ keywords: string[]; combo: Combo }> = [
|
||||
{ keywords: ["美妆", "护肤", "彩妆", "面膜", "精华", "洗护", "个护"], combo: { format: "oral", structure: "contrast" } },
|
||||
{ keywords: ["保健", "营养", "膳食", "益生菌", "维生素"], combo: { format: "oral", structure: "review" } },
|
||||
{ keywords: ["数码", "3c", "电子", "电器", "手机", "耳机", "相机", "工具"], combo: { format: "oral", structure: "review" } },
|
||||
{ keywords: ["食品", "零食", "饮料", "咖啡", "茶", "生鲜", "酒"], combo: { format: "vlog", structure: "scene" } },
|
||||
{ keywords: ["服饰", "女装", "男装", "服装", "鞋", "包", "配饰", "内衣"], combo: { format: "vlog", structure: "scene" } },
|
||||
{ keywords: ["家居", "家纺", "收纳", "厨具", "清洁", "日用"], combo: { format: "drama", structure: "pain" } },
|
||||
{ keywords: ["母婴", "宝宝", "儿童", "宠物"], combo: { format: "drama", structure: "pain" } },
|
||||
{ keywords: ["户外", "露营", "运动", "健身"], combo: { format: "vlog", structure: "scene" } },
|
||||
{ keywords: ["美妆", "护肤", "彩妆", "面膜", "精华", "洗护", "个护"], combo: CATEGORY_COMBOS["美妆个护"] },
|
||||
{ keywords: ["保健", "营养", "膳食", "益生菌", "维生素"], combo: { format: "oral", structure: "review", persona: "reviewer" } },
|
||||
{ keywords: ["数码", "3c", "电子", "电器", "手机", "耳机", "相机", "工具", "家电"], combo: CATEGORY_COMBOS["数码家电"] },
|
||||
{ keywords: ["食品", "零食", "饮料", "咖啡", "茶", "生鲜", "酒"], combo: CATEGORY_COMBOS["食品饮料"] },
|
||||
{ keywords: ["服饰", "女装", "男装", "服装", "鞋", "包", "配饰", "内衣"], combo: CATEGORY_COMBOS["服饰鞋包"] },
|
||||
{ keywords: ["家居", "家纺", "收纳", "厨具", "清洁", "日用"], combo: CATEGORY_COMBOS["家居日用"] },
|
||||
{ keywords: ["母婴", "宝宝", "儿童", "玩具"], combo: CATEGORY_COMBOS["母婴玩具"] },
|
||||
{ keywords: ["宠物"], combo: CATEGORY_COMBOS["宠物用品"] },
|
||||
{ keywords: ["户外", "露营", "运动", "健身"], combo: CATEGORY_COMBOS["运动健康"] },
|
||||
];
|
||||
|
||||
const FALLBACK_COMBO: Combo = { format: "oral", structure: "pain" };
|
||||
const FALLBACK_COMBO: Combo = { format: "oral", structure: "pain", persona: "urban" };
|
||||
|
||||
/** 按商品品类 + 人群推荐一组「表现形式 × 视频结构 × 时长」。纯启发式,用户随时可改。 */
|
||||
export function recommendSetup(input: { category?: string; targetAudience?: string; title?: string }): Combo & {
|
||||
/** 按商品品类推荐「表现形式 × 视频结构 × 人物 × 时长」。用户随时可改。 */
|
||||
export function recommendSetup(input: { category?: string; title?: string }): Combo & {
|
||||
duration: number;
|
||||
reason: string;
|
||||
} {
|
||||
const haystack = [input.category, input.title, input.targetAudience]
|
||||
const category = (input.category || "").trim();
|
||||
const haystack = [category, input.title]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
.toLowerCase();
|
||||
|
||||
let combo = FALLBACK_COMBO;
|
||||
let reason = "商品信息不足,先给一组最通用的";
|
||||
for (const rule of CATEGORY_RULES) {
|
||||
const hit = rule.keywords.find((word) => haystack.includes(word.toLowerCase()));
|
||||
if (hit) {
|
||||
combo = rule.combo;
|
||||
reason = `按「${hit}」品类推荐`;
|
||||
break;
|
||||
if (category && CATEGORY_COMBOS[category]) {
|
||||
combo = CATEGORY_COMBOS[category];
|
||||
reason = `按「${category}」品类推荐`;
|
||||
} else {
|
||||
for (const rule of CATEGORY_RULES) {
|
||||
const hit = rule.keywords.find((word) => haystack.includes(word.toLowerCase()));
|
||||
if (hit) {
|
||||
combo = rule.combo;
|
||||
reason = `按「${hit}」品类推荐`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 防御:规则表若被改出禁用组合,这里兜住
|
||||
const structure = isForbidden(combo.format, combo.structure)
|
||||
? allowedStructures(combo.format)[0]
|
||||
// 自动推荐只给口播;Vlog / 短剧留给用户自己选。
|
||||
const format: PresentationFormat = "oral";
|
||||
const structure = isForbidden(format, combo.structure)
|
||||
? allowedStructures(format)[0]
|
||||
: combo.structure;
|
||||
return {
|
||||
format: combo.format,
|
||||
format,
|
||||
structure,
|
||||
duration: recommendDuration(combo.format, structure),
|
||||
persona: combo.persona,
|
||||
duration: recommendDuration(format, structure),
|
||||
reason,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user