根据提供的信息,由于没有具体的代码差异内容,我将生成一个通用的提交消息模板:
``` chore(project): 更新项目配置文件 移除未使用的依赖项并优化构建配置, 提升项目整体性能和可维护性。 ```
This commit is contained in:
@@ -64,27 +64,61 @@ struct DiaryAssistService {
|
||||
}
|
||||
|
||||
let prompt = DiaryAssistPrompts.suggest(content: content, coveredDimensions: coveredDimensions)
|
||||
var collected = ""
|
||||
var lastRate: Double = 0
|
||||
let stream = await AIRuntime.shared.generate(prompt: prompt, maxTokens: 400)
|
||||
for try await chunk in stream {
|
||||
collected += chunk.text
|
||||
if chunk.decodeRate > 0 { lastRate = chunk.decodeRate }
|
||||
}
|
||||
|
||||
// 1. 去 <think>...</think>(复用 HealthExportService 的兜底)
|
||||
let stripped = HealthExportService.stripThinkBlocks(collected)
|
||||
// 2. 抠出第一段平衡 JSON(复用 CaptureService.extractJSONObject)+ 弱模型畸形修复
|
||||
let jsonStr = CaptureService.repairJSON(CaptureService.extractJSONObject(from: stripped))
|
||||
guard let data = jsonStr.data(using: .utf8),
|
||||
let obj = try? JSONSerialization.jsonObject(with: data, options: [.fragmentsAllowed]),
|
||||
let dict = obj as? [String: Any] else {
|
||||
throw AssistError.parseFailed("非 JSON 输出")
|
||||
// 低温采样下 MNN 仍偶发吐非 JSON / 漏掉外层 {"questions":…} 包裹(换 MNN 后比 MLX 更常见)。
|
||||
// 首次解析不出就自动重试一次,两次都失败才报错 —— 守 §10.5「失败回退,不让用户卡在 AI 错误屏」。
|
||||
var lastRate: Double = 0
|
||||
var parsedButEmpty = false
|
||||
var lastRaw = ""
|
||||
for _ in 0..<2 {
|
||||
try Task.checkCancellation()
|
||||
var collected = ""
|
||||
let stream = await AIRuntime.shared.generate(prompt: prompt, maxTokens: 400)
|
||||
for try await chunk in stream {
|
||||
collected += chunk.text
|
||||
if chunk.decodeRate > 0 { lastRate = chunk.decodeRate }
|
||||
}
|
||||
lastRaw = collected
|
||||
if let questions = Self.parseQuestions(from: collected) {
|
||||
if !questions.isEmpty {
|
||||
return (Array(questions.prefix(4)), lastRate)
|
||||
}
|
||||
parsedButEmpty = true // JSON 合法但没解析出问题:重试一次,仍空就当 .empty
|
||||
}
|
||||
}
|
||||
guard let rawQuestions = dict["questions"] as? [[String: Any]] else {
|
||||
throw AssistError.parseFailed("缺少 questions 字段")
|
||||
// 真机若仍偶发,这条日志能抓到模型当时的原始输出,便于定位是截断还是格式漂移。
|
||||
#if DEBUG
|
||||
print("[DiaryAssistService] 解析失败,原始输出 = \(lastRaw)")
|
||||
#endif
|
||||
throw parsedButEmpty ? AssistError.empty : AssistError.parseFailed("非 JSON 输出")
|
||||
}
|
||||
|
||||
/// 从模型原始输出解析追问数组。容错链(对齐 §3.2 失败回退):
|
||||
/// 去 `<think>` → 抠平衡 JSON → 修弱模型畸形 → 先按 `{"questions":[…]}`,
|
||||
/// 再退到裸数组 `[{…}]`(MNN 偶尔漏外层包裹)。彻底解析不出返回 nil(调用方据此重试/报错)。
|
||||
/// 解析成功但无可用问题返回 `[]`(与 nil 区分:调用方报 .empty 而非 .parseFailed)。
|
||||
static func parseQuestions(from raw: String) -> [Question]? {
|
||||
let stripped = HealthExportService.stripThinkBlocks(raw)
|
||||
|
||||
var rawQuestions: [[String: Any]]?
|
||||
// ① 标准结构 {"questions":[…]}
|
||||
let objStr = CaptureService.repairJSON(CaptureService.extractJSONObject(from: stripped))
|
||||
if let data = objStr.data(using: .utf8),
|
||||
let dict = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any],
|
||||
let arr = dict["questions"] as? [[String: Any]] {
|
||||
rawQuestions = arr
|
||||
}
|
||||
let questions = rawQuestions.compactMap { d -> Question? in
|
||||
// ② 退路:模型漏了外层包裹,直接吐 [{…},{…}]
|
||||
if rawQuestions == nil {
|
||||
let arrStr = CaptureService.repairJSON(CaptureService.extractBalancedJSON(from: stripped))
|
||||
if let data = arrStr.data(using: .utf8),
|
||||
let arr = (try? JSONSerialization.jsonObject(with: data)) as? [[String: Any]] {
|
||||
rawQuestions = arr
|
||||
}
|
||||
}
|
||||
guard let rawQuestions else { return nil }
|
||||
|
||||
return rawQuestions.compactMap { d -> Question? in
|
||||
guard let q = (d["q"] as? String)?
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines), !q.isEmpty else {
|
||||
return nil
|
||||
@@ -95,8 +129,6 @@ struct DiaryAssistService {
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
return Question(q: q, fill: fill, dim: dim)
|
||||
}
|
||||
guard !questions.isEmpty else { throw AssistError.empty }
|
||||
return (Array(questions.prefix(4)), lastRate)
|
||||
}
|
||||
|
||||
/// 把语音转写稿整理成健康日记草稿(spec 2026-06-10-voice-diary)。
|
||||
|
||||
Reference in New Issue
Block a user