haixunMaster/components/settings/persona-form.tsx

118 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import {
emptyPersonaFields,
parsePersona,
serializePersona,
type PersonaFields,
} from "@/lib/ai/persona";
const PERSONA_FIELDS: Array<{
key: keyof PersonaFields;
label: string;
hint: string;
placeholder: string;
rows: number;
}> = [
{
key: "identity",
label: "我是誰",
hint: "你的身份、專業、生活脈絡,讓 AI 知道「這是誰在說話」。",
placeholder: "例35 歲科技創業者,常分享產品與職場觀察,不裝專家但敢講真話。",
rows: 2,
},
{
key: "tone",
label: "語氣特質",
hint: "形容你的說話方式:直率、溫暖、毒舌、理性…",
placeholder: "例:直率不雞湯、愛用數據與具體例子,偶爾自嘲,不說教。",
rows: 2,
},
{
key: "audience",
label: "對誰說",
hint: "你的讀者是誰?他們在煩什麼?",
placeholder: "例:想轉職或剛創業的工程師,怕踩雷、想聽實戰經驗。",
rows: 2,
},
{
key: "hooks",
label: "開場習慣",
hint: "你平常怎麼開頭?反問、反差、故事、數字衝擊…",
placeholder: "例:常用反問句開頭;或先丟一個違反直覺的結論,再解釋。",
rows: 2,
},
{
key: "examples",
label: "代表句範例",
hint: "貼 23 句你平常會講的話。這欄對文筆影響最大AI 會模仿你的語感。",
placeholder:
"例:\n很多人以為努力就夠了其實方向錯了越努力越遠。\n我花了三年才學會先問「這件事值不值得做」再問怎麼做。",
rows: 4,
},
{
key: "avoid",
label: "避免",
hint: "不要出現的詞、語氣或套路。",
placeholder: "例:不要用「陪你」「一起變好」;不要過度敬語;不要像業配。",
rows: 2,
},
];
interface PersonaFormProps {
value?: string | null;
onChange: (serialized: string) => void;
}
export function PersonaForm({ value, onChange }: PersonaFormProps) {
const fields = parsePersona(value);
function updateField(key: keyof PersonaFields, next: string) {
const merged = { ...fields, [key]: next };
onChange(serializePersona(merged));
}
return (
<div className="space-y-4">
<div className="rounded-lg border border-border bg-muted/60 px-3.5 py-3">
<p className="text-sm font-medium"></p>
<p className="mt-1 text-xs leading-relaxed text-muted-foreground">
稿AI
<strong className="font-medium text-foreground"></strong>
</p>
</div>
{PERSONA_FIELDS.map((field) => (
<div key={field.key} className="space-y-2">
<div>
<Label>{field.label}</Label>
<p className="mt-0.5 text-xs text-muted-foreground">{field.hint}</p>
</div>
<Textarea
value={fields[field.key]}
onChange={(e) => updateField(field.key, e.target.value)}
placeholder={field.placeholder}
rows={field.rows}
/>
</div>
))}
{!serializePersona(fields) && (
<p className="text-xs text-muted-foreground">
</p>
)}
</div>
);
}
export function getDefaultPersonaPreview() {
return serializePersona({
...emptyPersonaFields(),
tone: "口語、有觀點、像朋友在脆上分享",
examples: "其實很多人搞錯重點了。\n我以前也以為…後來才發現…",
});
}