90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
export const STYLE_8D_KEYS = [
|
||
"d1Tone",
|
||
"d2Structure",
|
||
"d3Interaction",
|
||
"d4Topics",
|
||
"d5Rhythm",
|
||
"d6Visual",
|
||
"d7Conversion",
|
||
"d8Risk",
|
||
] as const;
|
||
|
||
export type Style8DKey = (typeof STYLE_8D_KEYS)[number];
|
||
|
||
export const STYLE_8D_LABELS: Record<Style8DKey, string> = {
|
||
d1Tone: "D1 語氣人格",
|
||
d2Structure: "D2 結構模板",
|
||
d3Interaction: "D3 互動方式",
|
||
d4Topics: "D4 主題分布",
|
||
d5Rhythm: "D5 發文節奏",
|
||
d6Visual: "D6 視覺語法",
|
||
d7Conversion: "D7 轉換方式",
|
||
d8Risk: "D8 風險紅線",
|
||
};
|
||
|
||
export interface StoredStyle8DProfile {
|
||
username: string;
|
||
analyzedAt: string;
|
||
postCount: number;
|
||
engagement: {
|
||
measuredPosts: number;
|
||
medianInteractions: number;
|
||
averageInteractions: number;
|
||
postsAboveThreshold: number;
|
||
threshold: number;
|
||
verdict: "strong" | "usable" | "unknown";
|
||
};
|
||
analysis: Record<Style8DKey, { summary: string; evidence: string[] }>;
|
||
personaDraft: string;
|
||
}
|
||
|
||
export function createEmptyStyle8DProfile(username = ""): StoredStyle8DProfile {
|
||
const emptyDimension = () => ({ summary: "", evidence: [] as string[] });
|
||
return {
|
||
username,
|
||
analyzedAt: "",
|
||
postCount: 0,
|
||
engagement: {
|
||
measuredPosts: 0,
|
||
medianInteractions: 0,
|
||
averageInteractions: 0,
|
||
postsAboveThreshold: 0,
|
||
threshold: 10,
|
||
verdict: "unknown",
|
||
},
|
||
analysis: {
|
||
d1Tone: emptyDimension(),
|
||
d2Structure: emptyDimension(),
|
||
d3Interaction: emptyDimension(),
|
||
d4Topics: emptyDimension(),
|
||
d5Rhythm: emptyDimension(),
|
||
d6Visual: emptyDimension(),
|
||
d7Conversion: emptyDimension(),
|
||
d8Risk: emptyDimension(),
|
||
},
|
||
personaDraft: "",
|
||
};
|
||
}
|
||
|
||
export function parseStyle8DProfile(raw?: string | null): StoredStyle8DProfile | null {
|
||
if (!raw?.trim()) return null;
|
||
try {
|
||
const value = JSON.parse(raw) as StoredStyle8DProfile;
|
||
if (!value?.analysis) return null;
|
||
return value;
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
export function buildStyle8DPromptBlock(raw?: string | null): string | null {
|
||
const profile = parseStyle8DProfile(raw);
|
||
if (!profile) return null;
|
||
const dimensions = STYLE_8D_KEYS.map((key) => {
|
||
const summary = profile.analysis[key]?.summary?.trim();
|
||
return summary ? `${STYLE_8D_LABELS[key]}:${summary}` : null;
|
||
}).filter(Boolean);
|
||
if (dimensions.length === 0) return null;
|
||
return `【8D 風格策略】\n產文與回覆都必須遵守:\n${dimensions.join("\n")}`;
|
||
}
|