fix: AI预测无反馈 + 增加推理建议展示
- useAIPredict 增加 markdown 代码块剥离逻辑 - Prompt 模板要求返回纯 JSON - 可视化编辑器显示预测错误信息 - 展示 AI 推理建议(建议如何优化配方)
This commit is contained in:
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}` },
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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 预测失败')
|
||||
|
||||
Reference in New Issue
Block a user