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")}`;
|
|||
|
|
}
|