| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- const path = require('path');
- const { readJson, writeJson, defaultMemoryPath } = require('../../core/memory-store');
- const DEFAULT_MEMORY_FILE = 'douyin-trend-memory.json';
- function cleanList(values) {
- return [...new Set((values || [])
- .flatMap(value => Array.isArray(value) ? value : String(value || '').split(/[,,、\n\r]+|以及|与|和/))
- .map(value => String(value || '').trim())
- .filter(Boolean))];
- }
- function appendNote(notes, note) {
- const text = String(note || '').trim();
- if (!text) return (notes || []).slice(-20);
- const next = [...(notes || []).filter(Boolean), text];
- return [...new Set(next)].slice(-20);
- }
- function defaultTrendMemory() {
- return {
- version: '0.3.12',
- preferredDirections: [],
- blockedDirections: [],
- focusModes: [],
- notes: [],
- updatedAt: ''
- };
- }
- function trendMemoryPath(input = {}) {
- return path.resolve(input.memory || input.memoryPath || defaultMemoryPath(DEFAULT_MEMORY_FILE));
- }
- function readTrendMemory(memoryPath) {
- return {
- ...defaultTrendMemory(),
- ...readJson(memoryPath, {})
- };
- }
- function extractAfter(text, pattern) {
- const match = String(text || '').match(pattern);
- return match ? match[1] : '';
- }
- function inferPreferenceFromMessage(message) {
- const text = String(message || '').trim();
- const preferred = cleanList([
- extractAfter(text, /(?:保留|多给|继续给|更喜欢|适合)(.+?)(?:。|;|;|,但|但是|不要|少给|降权|$)/)
- ]);
- const blocked = cleanList([
- extractAfter(text, /(?:不要|少给|降权|过滤|不适合|避开)(.+?)(?:。|;|;|,|$)/)
- ]);
- const focus = cleanList([
- extractAfter(text, /(?:更偏|侧重|多看|下一版更偏)(.+?)(?:。|;|;|,|$)/)
- ]);
- return { preferred, blocked, focus };
- }
- function updateTrendMemory(input = {}) {
- const memoryPath = trendMemoryPath(input);
- const memory = readTrendMemory(memoryPath);
- const inferred = inferPreferenceFromMessage(input.message || input.feedback || '');
- const preferredDirections = cleanList([
- ...memory.preferredDirections,
- ...inferred.preferred,
- ...(input.preferredDirections || [])
- ]);
- const blockedDirections = cleanList([
- ...memory.blockedDirections,
- ...inferred.blocked,
- ...(input.blockedDirections || [])
- ]);
- const focusModes = cleanList([
- ...memory.focusModes,
- ...inferred.focus,
- ...(input.focusModes || [])
- ]);
- const note = String(input.message || input.feedback || '').trim();
- const notes = appendNote(memory.notes, note);
- const next = {
- ...memory,
- version: defaultTrendMemory().version,
- preferredDirections,
- blockedDirections,
- focusModes,
- notes,
- updatedAt: new Date().toISOString()
- };
- writeJson(memoryPath, next);
- return { memoryPath, memory: next };
- }
- function topicMatches(topic, terms) {
- const text = `${topic.title || ''} ${topic.angle || ''} ${topic.evidence || ''}`;
- const domainTerms = ['抖音', '视频', '评论', '口播', '开头', '脚本', '账号', '表达', '钩子', '转化', '选题', '流量'];
- const candidates = cleanList(terms).flatMap(term => {
- const trimmed = String(term || '').replace(/(方向|选题|内容|话术|场景|趋势)$/u, '');
- return cleanList([
- term,
- trimmed,
- ...domainTerms.filter(domainTerm => String(term || '').includes(domainTerm))
- ]);
- });
- return candidates.some(term => text.includes(term));
- }
- function rankTopicsWithMemory(topics, memory) {
- const preferred = cleanList(memory.preferredDirections);
- const blocked = cleanList(memory.blockedDirections);
- return [...topics]
- .map((topic, originalIndex) => {
- let score = topics.length - originalIndex;
- if (topicMatches(topic, preferred)) score += 20;
- if (topicMatches(topic, blocked)) score -= 50;
- return { topic, score };
- })
- .sort((a, b) => b.score - a.score)
- .map(item => item.topic);
- }
- module.exports = {
- DEFAULT_MEMORY_FILE,
- trendMemoryPath,
- readTrendMemory,
- updateTrendMemory,
- rankTopicsWithMemory,
- cleanList
- };
|