feat(diary): 优化日记AI协助交互体验

- 添加promptBanner作为未开始协作时的醒目邀请横幅,包含圆形图标、标题和说明文字
- 重构assistSection使用switch语句处理careState不同状态,区分隐藏、prompt和其他状态
- 增加动画过渡效果消除聚焦/失焦切换时的布局跳动
- 优化thinking状态下的UI展示,添加AIFlowBar彩色呼吸条显示推理进度
- 修改requestSuggestions逻辑,进入推理时收起键盘以完整显示协作卡片

refactor(inference): 优化性能自检界面样式

- 将性能自检入口改为描边动作按钮(TjGhostButton),与引擎选择在视觉上区分开
- 调整未就绪状态下的禁用样式和提示文案

feat(localization): 添加新的本地化字符串

- 新增"追踪"和"记一笔"的多语言翻译,包括英语、日语和韩语

fix(diary): 增强AI问答解析稳定性

- 将最大token数从400提升至512,避免中文问题JSON被截断导致解析失败
- 实现salvageQuestionObjects方法作为终极兜底机制,逐个解析平衡的{...}对象
- 当外层wrapper解析失败时,仍可救回内部已闭合的问题对象,确保用户不被AI错误卡住

test(diary): 补充AI问答解析测试用例

- 添加截断对象恢复测试,验证maxTokens截断时前序完整问题的救回能力
- 添加wrapper key错误情况的恢复测试,确保模型输出格式异常时的容错性
```
This commit is contained in:
link2026
2026-06-17 09:21:47 +08:00
parent 52db6fb85a
commit abacf5c4f5
6 changed files with 244 additions and 93 deletions

View File

@@ -43,63 +43,44 @@ struct InferenceSettingsView: View {
.onAppear { modelService.refreshStates() }
}
/// : prompt,
///
/// :/,(TjGhostButton),
/// /
@ViewBuilder
private var selfTestSection: some View {
if modelReady {
NavigationLink {
ModelSelfTestView()
} label: {
HStack(spacing: 12) {
ZStack {
Circle().fill(Tj.Palette.sand2)
Image(systemName: "gauge.with.needle")
.font(.tjScaled(18))
.foregroundStyle(Tj.Palette.ink)
}
.frame(width: 44, height: 44)
VStack(alignment: .leading, spacing: 2) {
Text("性能自检")
.font(.tjScaled(15, weight: .semibold))
.foregroundStyle(Tj.Palette.text)
Text("用上方选中的引擎跑固定 prompt,实测 prefill / 生成 tok/s")
.font(.tjScaled(12))
.foregroundStyle(Tj.Palette.text3)
.lineLimit(2)
}
Spacer()
Image(systemName: "chevron.right")
.font(.tjScaled(13, weight: .semibold))
.foregroundStyle(Tj.Palette.text3)
}
.padding(14)
.tjCard()
}
.buttonStyle(.plain)
} else {
HStack(spacing: 12) {
ZStack {
Circle().fill(Tj.Palette.sand2)
HStack(spacing: 8) {
Image(systemName: "gauge.with.needle")
.font(.tjScaled(18))
.foregroundStyle(Tj.Palette.text2)
}
.frame(width: 44, height: 44)
VStack(alignment: .leading, spacing: 2) {
Text("性能自检")
.font(.tjScaled(15, weight: .semibold))
.foregroundStyle(Tj.Palette.text)
Text("模型未就绪,前往「模型管理」下载后可用")
.font(.tjScaled(12))
.foregroundStyle(Tj.Palette.text3)
.lineLimit(2)
Text("性能自检")
Image(systemName: "arrow.right")
.font(.tjScaled(13, weight: .semibold))
}
Spacer()
.frame(maxWidth: .infinity)
}
.padding(14)
.tjCard()
.opacity(0.55)
.buttonStyle(TjGhostButton())
.padding(.top, 4)
} else {
VStack(spacing: 8) {
HStack(spacing: 8) {
Image(systemName: "gauge.with.needle")
.font(.tjScaled(15, weight: .semibold))
Text("性能自检")
}
.font(.tjScaled(15, weight: .semibold))
.foregroundStyle(Tj.Palette.text3)
.frame(maxWidth: .infinity)
.frame(height: 48)
.background(Capsule().strokeBorder(Tj.Palette.line, lineWidth: 1))
.opacity(0.6)
Text("模型未就绪,前往「模型管理」下载后可用")
.font(.tjScaled(12))
.foregroundStyle(Tj.Palette.text3)
}
.padding(.top, 4)
}
}