fix: AI预测无反馈 + 增加推理建议展示

- useAIPredict 增加 markdown 代码块剥离逻辑
- Prompt 模板要求返回纯 JSON
- 可视化编辑器显示预测错误信息
- 展示 AI 推理建议(建议如何优化配方)
This commit is contained in:
qichi.liang
2026-05-20 18:17:31 +08:00
parent 3afc38df6a
commit 2d06d34e5b
4 changed files with 22 additions and 3 deletions

View File

@@ -0,0 +1,10 @@
{
"sessionID": "ses_1bcf4061fffeZ83r0Ra7NUB40Y",
"updatedAt": "2026-05-20T01:45:53.650Z",
"sources": {
"background-task": {
"state": "idle",
"updatedAt": "2026-05-20T01:45:53.650Z"
}
}
}

View File

@@ -3,7 +3,7 @@ import type { ChatMessage } from '../providers/types.js'
export function predictMetricsPrompt(ingredients: Array<{ name: string; percentage: number; category: string }>): ChatMessage[] {
const ingList = ingredients.map(i => `- ${i.name} (${i.category}): ${i.percentage}%`).join('\n')
return [
{ role: 'system', content: '你是一名资深化妆品配方工程师。根据成分列表预测配方的肤感指数、稳定性评分和成本估算。返回 JSON 格式{"sensoryIndex":{"spreadability":0-100,"absorption":0-100,"stickiness":0-100,"overall":0-100},"stabilityScore":0-100,"costEstimate":元/kg,"confidence":0-1,"reasoning":"简短理由"}' },
{ role: 'system', content: '你是一名资深化妆品配方工程师。根据成分列表预测配方的肤感指数、稳定性评分和成本估算。直接返回 JSON,不要用 ``` 包裹{"sensoryIndex":{"spreadability":0-100,"absorption":0-100,"stickiness":0-100,"overall":0-100},"stabilityScore":0-100,"costEstimate":元/kg,"confidence":0-1,"reasoning":"简短理由"}' },
{ role: 'user', content: `请分析以下配方的指标:\n${ingList}` },
]
}

View File

@@ -121,7 +121,7 @@ export default function FormulaVisualEditor({ phases: initialPhases, onSave }: P
} finally { setSaving(false) }
}
const { prediction, loading: predicting, predict } = useAIPredict()
const { prediction, loading: predicting, error: predictError, predict } = useAIPredict()
const handlePredict = () => {
predict(allIngredients.map(i => ({
@@ -169,6 +169,7 @@ export default function FormulaVisualEditor({ phases: initialPhases, onSave }: P
{predicting ? <Loader2 size={14} className="animate-spin" /> : <Sparkles size={14} />}
{predicting ? '预测中...' : 'AI 预测指标'}
</button>
{predictError && <span className="text-xs text-red-500">{predictError}</span>}
</div>
{hasPrediction && (
@@ -188,6 +189,13 @@ export default function FormulaVisualEditor({ phases: initialPhases, onSave }: P
</div>
)}
{hasPrediction && prediction!.reasoning && (
<div className="mb-4 rounded-lg border border-blue-200 bg-blue-50 p-3">
<p className="text-xs font-medium text-blue-600 mb-1">💡 AI </p>
<p className="text-sm text-blue-800">{prediction!.reasoning}</p>
</div>
)}
{hasPrediction && (
<div className="mb-4 grid grid-cols-1 gap-4 lg:grid-cols-2">
<div className="rounded-lg border p-3">

View File

@@ -56,7 +56,8 @@ export function useAIPredict() {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6)) as { type: string; content: string }
if (data.type === 'result') {
const parsed = JSON.parse(data.content) as PredictionResult
const clean = data.content.replace(/```(?:json)?\s*/g, '').replace(/```/g, '').trim()
const parsed = JSON.parse(clean) as PredictionResult
setPrediction(parsed)
} else if (data.type === 'error') {
setError('AI 预测失败')