mirror of
https://github.com/JOYCEQL/magic-resume.git
synced 2026-07-03 14:07:11 +02:00
feat: add custom instructions feature to AIPolishDialog
This commit is contained in:
@@ -16,6 +16,8 @@ import {
|
||||
DialogTitle
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { useAIConfigStore } from "@/store/useAIConfigStore";
|
||||
import { AI_MODEL_CONFIGS } from "@/config/ai";
|
||||
import { cn } from "@/lib/utils";
|
||||
@@ -49,6 +51,7 @@ export default function AIPolishDialog({
|
||||
const t = useTranslations("aiPolishDialog");
|
||||
const [isPolishing, setIsPolishing] = useState(false);
|
||||
const [polishedContent, setPolishedContent] = useState("");
|
||||
const [customInstructions, setCustomInstructions] = useState("");
|
||||
const {
|
||||
selectedModel,
|
||||
doubaoApiKey,
|
||||
@@ -106,7 +109,8 @@ export default function AIPolishDialog({
|
||||
apiKey,
|
||||
apiEndpoint: selectedModel === "openai" ? openaiApiEndpoint : undefined,
|
||||
model: config.requiresModelId ? modelId : config.defaultModel,
|
||||
modelType: selectedModel
|
||||
modelType: selectedModel,
|
||||
customInstructions: customInstructions.trim() || undefined
|
||||
}),
|
||||
signal: abortControllerRef.current.signal
|
||||
});
|
||||
@@ -153,14 +157,13 @@ export default function AIPolishDialog({
|
||||
}, [polishedContent]);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
handlePolish();
|
||||
} else {
|
||||
if (!open) {
|
||||
if (abortControllerRef.current) {
|
||||
abortControllerRef.current.abort();
|
||||
abortControllerRef.current = null;
|
||||
}
|
||||
setPolishedContent("");
|
||||
setCustomInstructions("");
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
@@ -231,10 +234,39 @@ export default function AIPolishDialog({
|
||||
>
|
||||
{isPolishing
|
||||
? t("description.polishing")
|
||||
: t("description.finished")}
|
||||
: polishedContent
|
||||
? t("description.finished")
|
||||
: t("description.ready")}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label
|
||||
htmlFor="custom-instructions"
|
||||
className={cn(
|
||||
"text-sm font-medium",
|
||||
"text-neutral-600 dark:text-neutral-400"
|
||||
)}
|
||||
>
|
||||
{t("customInstructions")}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="custom-instructions"
|
||||
placeholder={t("customInstructionsPlaceholder")}
|
||||
value={customInstructions}
|
||||
onChange={(e) => setCustomInstructions(e.target.value)}
|
||||
disabled={isPolishing}
|
||||
rows={2}
|
||||
className={cn(
|
||||
"resize-none rounded-xl border",
|
||||
"bg-neutral-50 dark:bg-neutral-800/50",
|
||||
"border-neutral-200 dark:border-neutral-800",
|
||||
"text-neutral-700 dark:text-neutral-300",
|
||||
"placeholder:text-neutral-400 dark:placeholder:text-neutral-500"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2 px-3">
|
||||
@@ -323,6 +355,8 @@ export default function AIPolishDialog({
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
{t("button.generating")}
|
||||
</div>
|
||||
) : !polishedContent ? (
|
||||
t("button.start")
|
||||
) : (
|
||||
t("button.regenerate")
|
||||
)}
|
||||
|
||||
@@ -671,6 +671,7 @@
|
||||
"aiPolishDialog": {
|
||||
"title": "AI Polish",
|
||||
"description": {
|
||||
"ready": "Add optional instructions, then click \"Start polish\"",
|
||||
"polishing": "Polishing your content...",
|
||||
"finished": "Content has been optimized, please check the result"
|
||||
},
|
||||
@@ -683,7 +684,10 @@
|
||||
"original": "Original Content",
|
||||
"polished": "Polished Content"
|
||||
},
|
||||
"customInstructions": "Custom instructions",
|
||||
"customInstructionsPlaceholder": "e.g. Use more technical terms, highlight metrics, keep tone formal… (optional)",
|
||||
"button": {
|
||||
"start": "Start polish",
|
||||
"regenerate": "Regenerate",
|
||||
"generating": "Generating...",
|
||||
"apply": "Apply Content"
|
||||
|
||||
@@ -716,6 +716,7 @@
|
||||
"aiPolishDialog": {
|
||||
"title": "AI 润色",
|
||||
"description": {
|
||||
"ready": "填写可选的自定义要求后,点击「开始润色」",
|
||||
"polishing": "正在为您润色内容...",
|
||||
"finished": "已经为您优化了内容,请查看效果"
|
||||
},
|
||||
@@ -728,7 +729,10 @@
|
||||
"original": "原始内容",
|
||||
"polished": "润色后的内容"
|
||||
},
|
||||
"customInstructions": "自定义要求",
|
||||
"customInstructionsPlaceholder": "例如:请用更技术化的表述、突出量化成果、语气偏正式…(选填,留空则按默认规则润色)",
|
||||
"button": {
|
||||
"start": "开始润色",
|
||||
"regenerate": "重新生成",
|
||||
"generating": "生成中...",
|
||||
"apply": "应用内容"
|
||||
|
||||
@@ -8,12 +8,13 @@ export const Route = createFileRoute("/api/polish")({
|
||||
POST: async ({ request }) => {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { apiKey, model, content, modelType, apiEndpoint } = body as {
|
||||
const { apiKey, model, content, modelType, apiEndpoint, customInstructions } = body as {
|
||||
apiKey: string;
|
||||
model: string;
|
||||
content: string;
|
||||
modelType: AIModelType;
|
||||
apiEndpoint?: string;
|
||||
customInstructions?: string;
|
||||
};
|
||||
|
||||
const modelConfig = AI_MODEL_CONFIGS[modelType as AIModelType];
|
||||
@@ -21,7 +22,7 @@ export const Route = createFileRoute("/api/polish")({
|
||||
throw new Error("Invalid model type");
|
||||
}
|
||||
|
||||
const systemPrompt = `你是一个专业的简历优化助手。请帮助优化以下 Markdown 格式的文本,使其更加专业和有吸引力。
|
||||
let systemPrompt = `你是一个专业的简历优化助手。请帮助优化以下 Markdown 格式的文本,使其更加专业和有吸引力。
|
||||
|
||||
优化原则:
|
||||
1. 使用更专业的词汇和表达方式
|
||||
@@ -33,6 +34,10 @@ export const Route = createFileRoute("/api/polish")({
|
||||
|
||||
请直接返回优化后的 Markdown 文本,不要包含任何解释或其他内容。`;
|
||||
|
||||
if (customInstructions?.trim()) {
|
||||
systemPrompt += `\n\n用户额外要求:\n${customInstructions.trim()}`;
|
||||
}
|
||||
|
||||
if (modelType === "gemini") {
|
||||
const geminiModel = model || "gemini-flash-latest";
|
||||
const modelInstance = getGeminiModelInstance({
|
||||
|
||||
Reference in New Issue
Block a user