D122: xhs widget system - natural language intent mapper + 8 content types
This commit is contained in:
parent
7b682fd4ad
commit
dd73c2174c
174
image-generator/xiaohongshu-widgets/intent-mapper.js
Normal file
174
image-generator/xiaohongshu-widgets/intent-mapper.js
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
// 小红书封面意图映射引擎 v1.0
|
||||||
|
// 自然语言 → widget组合 + 随机化策略
|
||||||
|
// 国作登字-2026-A-00037559
|
||||||
|
|
||||||
|
import { WIDGETS, randomVariant } from './widgets.js'
|
||||||
|
|
||||||
|
// 内容类型 → 预设widget组合
|
||||||
|
const CONTENT_PRESETS = {
|
||||||
|
tutorial: {
|
||||||
|
name: '教程攻略',
|
||||||
|
widgets: ['badge','title','gradient-stripe','bullet-list','info-tag-row','highlight-box'],
|
||||||
|
decorChance: 0.6,
|
||||||
|
layout: 'card',
|
||||||
|
},
|
||||||
|
review: {
|
||||||
|
name: '测评推荐',
|
||||||
|
widgets: ['sticker-badge','title','photo-frame','bullet-list','mood-indicator'],
|
||||||
|
decorChance: 0.5,
|
||||||
|
layout: 'card',
|
||||||
|
},
|
||||||
|
quote: {
|
||||||
|
name: '金句语录',
|
||||||
|
widgets: ['title','scribble-underline','sticky-note','highlight-box'],
|
||||||
|
decorChance: 0.3,
|
||||||
|
layout: 'card',
|
||||||
|
},
|
||||||
|
recipe: {
|
||||||
|
name: '美食食谱',
|
||||||
|
widgets: ['sticker-badge','title','photo-frame','info-tag-row','bullet-list'],
|
||||||
|
decorChance: 0.7,
|
||||||
|
layout: 'card',
|
||||||
|
},
|
||||||
|
travel: {
|
||||||
|
name: '旅游攻略',
|
||||||
|
widgets: ['title','photo-frame','info-tag-row','bullet-list','mood-indicator'],
|
||||||
|
decorChance: 0.8,
|
||||||
|
layout: 'card',
|
||||||
|
},
|
||||||
|
lifestyle: {
|
||||||
|
name: '生活分享',
|
||||||
|
widgets: ['sticker-badge','title','photo-frame','mood-indicator','sticky-note'],
|
||||||
|
decorChance: 0.8,
|
||||||
|
layout: 'card',
|
||||||
|
},
|
||||||
|
study: {
|
||||||
|
name: '学习笔记',
|
||||||
|
widgets: ['title','gradient-stripe','bullet-list','highlight-box','info-tag-row'],
|
||||||
|
decorChance: 0.4,
|
||||||
|
layout: 'card',
|
||||||
|
},
|
||||||
|
general: {
|
||||||
|
name: '通用模板',
|
||||||
|
widgets: ['title','bullet-list','highlight-box'],
|
||||||
|
decorChance: 0.5,
|
||||||
|
layout: 'card',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 情绪 → 配色和装饰偏好
|
||||||
|
const MOOD_MAP = {
|
||||||
|
warm: { presetScheme: 'warm', decorPrefs: ['dot-grid:warm','gradient-stripe:warm-sunset','sticker-badge:hot'] },
|
||||||
|
elegant: { presetScheme: 'green', decorPrefs: ['dot-grid:mixed','gradient-stripe:forest','sticker-badge:free'] },
|
||||||
|
cool: { presetScheme: 'tech', decorPrefs: ['dot-grid:cool','gradient-stripe:cool-ocean','sticker-badge:top'] },
|
||||||
|
sweet: { presetScheme: 'rose', decorPrefs: ['dot-grid:mixed','gradient-stripe:rose-gold','sticker-badge:new'] },
|
||||||
|
neutral: { presetScheme: 'minimal', decorPrefs: ['dot-grid:large','gradient-stripe:warm-sunset','sticker-badge:hand'] },
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自然语言关键词 → 内容类型
|
||||||
|
const KEYWORD_MAP = {
|
||||||
|
tutorial: ['教程','攻略','指南','步骤','方法','如何','怎么','手把手','入门'],
|
||||||
|
review: ['测评','评测','推荐','值得买','避坑','踩雷','拔草','种草','开箱'],
|
||||||
|
quote: ['金句','语录','名言','说','一句话','文案','摘抄'],
|
||||||
|
recipe: ['食谱','美食','做饭','料理','烘焙','家常菜','甜品','饮料'],
|
||||||
|
travel: ['旅游','旅行','攻略','打卡','拍照','景点','路线','酒店'],
|
||||||
|
lifestyle: ['日常','生活','穿搭','护肤','化妆','好物','分享','记录'],
|
||||||
|
study: ['学习','笔记','读书','复习','考试','备考','打卡','计划'],
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关键词 → widget覆盖
|
||||||
|
const WIDGET_OVERRIDES = {
|
||||||
|
'打卡': { add: ['mood-indicator'], remove: [] },
|
||||||
|
'对比': { add: ['split-layout'], remove: ['bullet-list'] },
|
||||||
|
'好物': { add: ['photo-frame','sticker-badge','info-tag-row'], remove: [] },
|
||||||
|
'合集': { add: ['card-grid','photo-frame'], remove: ['bullet-list'] },
|
||||||
|
'读书': { add: ['highlight-box','sticky-note'], remove: ['photo-frame'] },
|
||||||
|
'快乐': { add: ['mood-indicator:happy','sticker-badge:hand'], remove: [] },
|
||||||
|
'干货': { add: ['bullet-list:star','highlight-box:green-marker'], remove: ['photo-frame'] },
|
||||||
|
'心情': { add: ['mood-indicator','sticky-note'], remove: ['info-tag-row'] },
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析自然语言 → 结构化意图
|
||||||
|
export function parseIntent(text) {
|
||||||
|
if (!text) return CONTENT_PRESETS.general
|
||||||
|
|
||||||
|
// 检测内容类型
|
||||||
|
let contentType = 'general'
|
||||||
|
let maxScore = 0
|
||||||
|
for (const [type, keywords] of Object.entries(KEYWORD_MAP)) {
|
||||||
|
let score = 0
|
||||||
|
for (const kw of keywords) {
|
||||||
|
if (text.includes(kw)) score++
|
||||||
|
}
|
||||||
|
if (score > maxScore) {
|
||||||
|
maxScore = score
|
||||||
|
contentType = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测情绪
|
||||||
|
let mood = 'neutral'
|
||||||
|
if (/温馨|温暖|治愈|温柔|舒服/i.test(text)) mood = 'warm'
|
||||||
|
else if (/高级|文艺|优雅|质感|简约/i.test(text)) mood = 'elegant'
|
||||||
|
else if (/酷|科技|未来|赛博|暗黑/i.test(text)) mood = 'cool'
|
||||||
|
else if (/可爱|甜|少女|粉|软/i.test(text)) mood = 'sweet'
|
||||||
|
|
||||||
|
return { contentType, mood }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据意图生成widget组合
|
||||||
|
export function buildComposition(intent, options = {}) {
|
||||||
|
const { contentType, mood } = intent
|
||||||
|
const preset = { ...CONTENT_PRESETS[contentType] || CONTENT_PRESETS.general }
|
||||||
|
|
||||||
|
// 复制widget列表
|
||||||
|
let widgets = [...preset.widgets]
|
||||||
|
|
||||||
|
// 应用情绪装饰偏好
|
||||||
|
const moodPrefs = MOOD_MAP[mood] || MOOD_MAP.neutral
|
||||||
|
|
||||||
|
// 应用关键词覆盖
|
||||||
|
const text = options.text || ''
|
||||||
|
for (const [kw, override] of Object.entries(WIDGET_OVERRIDES)) {
|
||||||
|
if (text.includes(kw)) {
|
||||||
|
widgets = widgets.filter(w => !override.remove.includes(w))
|
||||||
|
for (const add of override.add) {
|
||||||
|
if (!widgets.includes(add)) widgets.push(add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 随机化:根据decorChance概率添加装饰widget
|
||||||
|
const decorWidgets = ['dot-grid','gradient-stripe','sticker-badge','hand-drawn-circle','corner-fold']
|
||||||
|
if (Math.random() < preset.decorChance) {
|
||||||
|
const decor = decorWidgets[Math.floor(Math.random() * decorWidgets.length)]
|
||||||
|
if (!widgets.includes(decor)) {
|
||||||
|
// 装饰widget放在前面或最后
|
||||||
|
widgets.unshift(decor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 随机决定是否加照片框
|
||||||
|
if (options.hasImage && !widgets.includes('photo-frame')) {
|
||||||
|
widgets.splice(2, 0, 'photo-frame')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建组件栈
|
||||||
|
const stack = widgets.map(widgetId => {
|
||||||
|
const variant = options.specificVariants?.[widgetId] || randomVariant(widgetId)
|
||||||
|
return {
|
||||||
|
component: widgetId,
|
||||||
|
variant: variant?.id || 'default',
|
||||||
|
params: variant?.css ? { ...variant } : {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
contentType,
|
||||||
|
mood,
|
||||||
|
presetName: preset.name,
|
||||||
|
scheme: moodPrefs.presetScheme,
|
||||||
|
layout: preset.layout,
|
||||||
|
stack,
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user