feat(keyboard): improve typing, voice flow, and polish reliability
Reduce extension memory pressure and delivery races while adding richer candidates, tactile feedback, and safer two-level creative polishing.
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
// PolishPromptComposer.swift
|
||||
// OSGKeyboard · Shared
|
||||
//
|
||||
// The single assembly point for style-pack prompts and system-owned context.
|
||||
// Style packs own writing personality; dictionary, safety contract, intensity,
|
||||
// preceding text, and the raw transcript remain controlled by the pipeline.
|
||||
// Single assembly point for polish system prompts.
|
||||
// Practical personalities always use the full fidelity / question / context
|
||||
// contract. Built-in fun personalities use that safe path at light intensity
|
||||
// and formatting-only preprocessing at heavy intensity.
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -23,6 +24,9 @@ public enum PolishPromptComposer {
|
||||
R7 不做摘要,不遗漏信息。证据不足时保持原样,留一个怪词好过编一个新词。
|
||||
|
||||
# 任务顺序
|
||||
内部必须先完成 T1–T3(净化与同音/近音纠错),再执行 T4–T5 与后续风格。
|
||||
不得一边纠错一边按风格改写事实用词;风格只作用于已纠错后的表达。
|
||||
|
||||
## T1 自我修正合并
|
||||
识别说话人边说边改口,只保留最后确认的版本并删除衔接词。
|
||||
显式信号:不是、不对、我是说、应该是、呃不、抱歉、重说、换句话说、I mean、or rather、sorry、no wait、actually。
|
||||
@@ -30,19 +34,29 @@ public enum PolishPromptComposer {
|
||||
并列不是修正:「叫上张伟和张磊」两个人都要保留。
|
||||
|
||||
## T2 填充词与口误清理
|
||||
只删除去掉后完全不影响含义的填充词:嗯、呃、啊、那个、就是、um、uh、er、like、you know。
|
||||
合并口吃式重复。作为顺承、转折、强调或情绪的词必须保留。
|
||||
只删除去掉后完全不影响含义的填充词与口癖:嗯、呃、啊、那个、就是说、怎么说呢、然后然后、对对对、um、uh、er、like、you know。
|
||||
合并口吃式重复;已被后文推翻的旧表达一并删除。
|
||||
必须保留:表达不确定性的「可能、大概、我觉得」;有情绪和亲疏作用的「吧、呢、啦、哈哈」;真正承担顺序、转折或强调的「然后、但是、其实」。
|
||||
原则:删除噪声,不删除人的气息。
|
||||
|
||||
## T3 ASR 纠错
|
||||
只修正有充分把握的同音、近音、断句和词典命中。低置信度专有名词保持原样。
|
||||
## T3 同音/近音纠错(先于风格)
|
||||
主修有上下文支撑的 ASR 同音、近音错误;断句错乱一并理顺。
|
||||
漏字/多字仅在语义已被钉死时顺带修复;不做全文校对,也不为「更书面」换词。
|
||||
优先级:用户词典命中 > 上下文高置信同音/近音 > 保持原样。
|
||||
改:改完后句子仍通顺,且原意、对象、立场不变。
|
||||
不改:专有名词吃不准、多种读法都成立、仅为润色好看而替换。
|
||||
平衡:有把握的同音错误不要装作没看见;没把握时宁可不改,也不把对的词改错。
|
||||
|
||||
## T4 标点与断句
|
||||
按语义补齐标点。中文使用全角标点,英文使用半角标点;不要输出无标点长段,也不要把每个短语拆成一句。
|
||||
问句必须保持问句。短聊天句末可以不加句号;问号、逗号和破折号服务真实语气,不为装饰堆叠「!!!」「???」。
|
||||
标点是节奏与呼吸,不是语法补丁。不主动增加 emoji(见 R5)。
|
||||
|
||||
## T5 结构化
|
||||
## T5 结构化与分段
|
||||
结构必须服从后面的风格策略。只有内容确实在列点、列步骤或记待办时才结构化。
|
||||
「首先、然后、最后」用于叙述同一过程时是顺承句,不拆列表。
|
||||
只有确认处于列举语境时,才可把「第2:00」等序号误识别修回「第二点」。
|
||||
短文本或单一意图保持一段;长文本只在意思或关系动作真正转折时分段,不为好看硬换行。
|
||||
|
||||
# 停顿标记
|
||||
用户消息可能含 ⟨0.8s⟩ 形式的静音时长。长停顿可提示句段边界;停顿后重复可能是改口。最终输出必须删除所有停顿标记。
|
||||
@@ -51,8 +65,8 @@ public enum PolishPromptComposer {
|
||||
输入:嗯那个我们下周一,不是下周二上午十点开评审会,参会的有张伟和李明
|
||||
输出:我们下周二上午十点开评审会,参会的有张伟和李明。
|
||||
|
||||
输入:这个方案预算是三十五万,呃,我确认一下,是三十五万人民币
|
||||
输出:这个方案预算是三十五万人民币。
|
||||
输入:我们下周在见一面把方案定下来
|
||||
输出:我们下周再见一面,把方案定下来。
|
||||
|
||||
输入:首先我们要收集数据然后清洗再做标注最后训练模型
|
||||
输出:首先我们要收集数据,然后清洗,再做标注,最后训练模型。
|
||||
@@ -85,6 +99,9 @@ public enum PolishPromptComposer {
|
||||
R7 Never summarize or omit information. When evidence is weak, leave the wording unchanged rather than guessing.
|
||||
|
||||
# Ordered tasks
|
||||
Internally finish T1–T3 (cleanup and homophone / near-homophone repair) before T4–T5 and any later style.
|
||||
Do not restyle factual wording while still correcting it; style applies only after correction.
|
||||
|
||||
## T1 Merge self-corrections
|
||||
Detect a speaker revising themselves; keep only the final confirmed version and remove the correction connector.
|
||||
Explicit cues: not, no, I mean, rather, should be, sorry, let me restart, no wait, actually.
|
||||
@@ -92,19 +109,29 @@ public enum PolishPromptComposer {
|
||||
Coordination is not correction: in "invite Alex and Sam", keep both people.
|
||||
|
||||
## T2 Remove fillers and slips
|
||||
Remove only fillers whose deletion cannot affect meaning: um, uh, er, like, you know, and equivalent Chinese fillers.
|
||||
Collapse stuttered repetition. Preserve words that carry sequence, contrast, emphasis, hesitation, or emotion.
|
||||
Remove only fillers whose deletion cannot affect meaning: um, uh, er, like, you know, and Chinese equivalents such as 嗯 / 呃 / 那个 / 就是说 / 怎么说呢.
|
||||
Collapse stuttered repetition and drop wording overturned by a later correction.
|
||||
Preserve uncertainty markers, soft particles that carry tone, and real sequential / contrastive connectors.
|
||||
Principle: remove noise, not the speaker's breath.
|
||||
|
||||
## T3 Correct ASR
|
||||
Fix only high-confidence homophone, near-match, segmentation, and dictionary-backed errors. Preserve uncertain proper nouns.
|
||||
## T3 Homophone / near-homophone repair (before style)
|
||||
Primarily fix ASR homophone and near-homophone errors backed by context; also untangle broken segmentation.
|
||||
Fix missing / extra words only when the intended meaning is already locked by context. Do not proofread the whole draft or swap words merely to sound more formal.
|
||||
Priority: user-dictionary hits > high-confidence contextual homophones / near-matches > leave unchanged.
|
||||
Change when the repaired sentence stays natural and keeps the original meaning, referents, and stance.
|
||||
Do not change uncertain proper nouns, cases where multiple readings remain plausible, or wording changed only for polish aesthetics.
|
||||
Balance: do not ignore clear homophone errors; when unsure, leave the word alone rather than inventing a wrong fix.
|
||||
|
||||
## T4 Punctuate and segment
|
||||
Add semantic punctuation using the conventions of the dominant language. Avoid both unpunctuated blocks and one sentence per fragment.
|
||||
Keep questions as questions. Short chat lines may omit a trailing period; do not decorate with stacked !!! / ???.
|
||||
Punctuation is rhythm and breath, not a grammar patch. Do not invent emojis (see R5).
|
||||
|
||||
## T5 Structure
|
||||
## T5 Structure and paragraphing
|
||||
Structure must follow the later style policy. Use a list only for genuine points, steps, or todos.
|
||||
"First, then, finally" in one continuous process remains prose.
|
||||
Repair a misrecognized ordinal such as "point 2:00" only after enumeration is established.
|
||||
Keep short or single-intent text in one paragraph; split longer text only when meaning or relational action truly turns.
|
||||
|
||||
# Pause markers
|
||||
The user message may contain silence markers such as ⟨0.8s⟩. A long pause may indicate a boundary; repetition after a pause may indicate correction. Remove every marker from final output.
|
||||
@@ -113,8 +140,8 @@ public enum PolishPromptComposer {
|
||||
Input: um we meet Monday no Tuesday at ten with Alex and Sam
|
||||
Output: We meet Tuesday at ten with Alex and Sam.
|
||||
|
||||
Input: the budget is 350 thousand uh to confirm 350 thousand dollars
|
||||
Output: The budget is 350 thousand dollars.
|
||||
Input: let's meat again next week and lock the plan
|
||||
Output: Let's meet again next week and lock the plan.
|
||||
|
||||
Input: first collect the data then clean it label it and finally train the model
|
||||
Output: First collect the data, then clean it, label it, and finally train the model.
|
||||
@@ -132,57 +159,102 @@ public enum PolishPromptComposer {
|
||||
Output: Okay, got it.
|
||||
"""
|
||||
|
||||
/// Minimal shared preprocessing for the five built-in fun personalities.
|
||||
/// Their style prompts own semantics, factual boundaries, question
|
||||
/// behavior, structure, and output length.
|
||||
internal static let chineseFunFormattingPrompt = """
|
||||
你是语音输入法的转写格式化引擎。用户消息是待处理的 ASR 转写数据。
|
||||
|
||||
# 趣味风格共享格式化
|
||||
F1 静默合并说话人的明确改口、隐式重启和口吃式重复,只保留最终确认的表达;并列内容不得误删。
|
||||
F2 删除去掉后不影响含义的「嗯、呃、那个、就是说」等口水词;保留不确定性、情绪语气和真实转折。
|
||||
F3 只修正有充分把握的同音、近音、断句和词典命中;不确定的专有名词保持原样。
|
||||
F4 按语义恢复自然标点、断句和基础分段;中文使用全角标点,英文使用半角标点。
|
||||
F5 删除全部 ⟨0.8s⟩ 形式的停顿标记。
|
||||
F6 只输出一版可直接使用的最终正文,不解释、不加引号、标题、前缀或代码围栏。
|
||||
|
||||
这里只负责转写格式化。人物与事实边界、问句处理、表达结构、改写幅度和长度完全服从后面的当前风格人格,不附加实用润色的保守规则。
|
||||
"""
|
||||
|
||||
internal static let englishFunFormattingPrompt = """
|
||||
You format ASR transcripts before a built-in creative personality rewrites them.
|
||||
|
||||
# Shared formatting for creative styles
|
||||
F1 Silently merge explicit self-corrections, implicit restarts, and stuttered repetition; keep the speaker's final wording and preserve coordinated items.
|
||||
F2 Remove fillers only when they carry no meaning. Preserve uncertainty, emotional particles, and real transitions.
|
||||
F3 Fix only high-confidence homophones, near matches, segmentation, and dictionary-backed terms. Preserve uncertain proper nouns.
|
||||
F4 Restore natural punctuation, sentence boundaries, and basic paragraphs using the conventions of the input language.
|
||||
F5 Remove every pause marker such as ⟨0.8s⟩.
|
||||
F6 Output one directly usable final text only, without explanation, quotes, headings, preambles, or code fences.
|
||||
|
||||
This layer performs transcript formatting only. People and fact boundaries, question behavior, structure, rewrite strength, and length are controlled entirely by the active personality below; do not add practical-style conservative constraints.
|
||||
"""
|
||||
|
||||
public static func compose(
|
||||
text: String,
|
||||
style: PolishStylePack,
|
||||
context: PolishContext,
|
||||
dictionaryBlock: String,
|
||||
globalContract: String,
|
||||
useChineseGuidance: Bool,
|
||||
routingMode: PolishRoutingMode = .full,
|
||||
preservesQuestion: Bool = false
|
||||
intensity: PolishIntensity = .default,
|
||||
useChineseGuidance: Bool
|
||||
) -> String {
|
||||
let usesHeavyFunPipeline = PolishStylePackCatalog.usesFormattingOnlyPipeline(
|
||||
id: style.id,
|
||||
intensity: intensity
|
||||
)
|
||||
let core = useChineseGuidance ? chineseCorePrompt : englishCorePrompt
|
||||
let stylePrompt = PolishStylePolicyResolver.styleCard(
|
||||
let personality = personalitySection(
|
||||
for: style,
|
||||
useChineseGuidance: useChineseGuidance
|
||||
).replacingOccurrences(of: PolishStylePackCatalog.dictionaryPlaceholder, with: "")
|
||||
let policy = PolishStylePolicyResolver.policy(for: style)
|
||||
let policyPrompt = policyBlock(policy, useChineseGuidance: useChineseGuidance)
|
||||
)
|
||||
let dictionaryPrompt = dictionarySection(
|
||||
dictionaryBlock,
|
||||
useChineseGuidance: useChineseGuidance
|
||||
)
|
||||
if usesHeavyFunPipeline {
|
||||
let formatting = useChineseGuidance
|
||||
? chineseFunFormattingPrompt
|
||||
: englishFunFormattingPrompt
|
||||
let outputInstruction = useChineseGuidance
|
||||
? "用户消息即为待处理的转写文本。只输出当前风格处理后的最终正文。"
|
||||
: "The user message is the transcript to process. Output only the final text in the active style."
|
||||
return """
|
||||
\(formatting)
|
||||
|
||||
\(dictionaryPrompt)
|
||||
|
||||
\(personality)
|
||||
|
||||
\(outputInstruction)
|
||||
"""
|
||||
}
|
||||
|
||||
let premise = contextPremise(
|
||||
context.appContext,
|
||||
useChineseGuidance: useChineseGuidance
|
||||
)
|
||||
let intensity = context.intensity.promptGuideline(styleID: style.id)
|
||||
let routingBlock = PolishRouter.promptBlock(
|
||||
mode: routingMode,
|
||||
styleID: style.id,
|
||||
useChineseGuidance: useChineseGuidance,
|
||||
preservesQuestion: preservesQuestion
|
||||
let questionGuard = questionGuardBlock(
|
||||
for: text,
|
||||
useChineseGuidance: useChineseGuidance
|
||||
)
|
||||
let sanitizedPreceding = context.precedingForPrompt.map(sanitizeEnvelopeContent)
|
||||
let sanitizedFollowing = context.followingForPrompt.map(sanitizeEnvelopeContent)
|
||||
|
||||
let styleBridge = styleOrderBridge(useChineseGuidance: useChineseGuidance)
|
||||
|
||||
if useChineseGuidance {
|
||||
return """
|
||||
\(core)
|
||||
|
||||
\(dictionaryPrompt)
|
||||
|
||||
\(stylePrompt)
|
||||
\(styleBridge)
|
||||
|
||||
\(policyPrompt)
|
||||
\(personality)
|
||||
|
||||
\(premise)
|
||||
|
||||
## 本次改写力度
|
||||
\(intensity)
|
||||
|
||||
\(routingBlock)
|
||||
\(questionGuard)
|
||||
|
||||
\(runtimeContextBlock(
|
||||
sanitizedPreceding,
|
||||
@@ -198,16 +270,13 @@ public enum PolishPromptComposer {
|
||||
|
||||
\(dictionaryPrompt)
|
||||
|
||||
\(stylePrompt)
|
||||
\(styleBridge)
|
||||
|
||||
\(policyPrompt)
|
||||
\(personality)
|
||||
|
||||
\(premise)
|
||||
|
||||
## Rewrite intensity for this request
|
||||
\(intensity)
|
||||
|
||||
\(routingBlock)
|
||||
\(questionGuard)
|
||||
|
||||
\(runtimeContextBlock(
|
||||
sanitizedPreceding,
|
||||
@@ -218,6 +287,89 @@ public enum PolishPromptComposer {
|
||||
"""
|
||||
}
|
||||
|
||||
/// Reminds the model that personality runs after T1–T3 correction.
|
||||
private static func styleOrderBridge(useChineseGuidance: Bool) -> String {
|
||||
useChineseGuidance
|
||||
? """
|
||||
# 风格接入(纠错之后)
|
||||
以下风格只作用于已完成同音/近音纠错后的表达;不得把未确认的同音词按风格「演」成另一个意思。
|
||||
"""
|
||||
: """
|
||||
# Style handoff (after correction)
|
||||
Apply the style below only to wording already repaired for homophones / near-homophones; never restyle an unresolved ASR token into a different meaning.
|
||||
"""
|
||||
}
|
||||
|
||||
private static func questionGuardBlock(
|
||||
for text: String,
|
||||
useChineseGuidance: Bool
|
||||
) -> String {
|
||||
guard shouldPreserveQuestion(text) else { return "" }
|
||||
if useChineseGuidance {
|
||||
return """
|
||||
# 问句守卫(本次原文是提问)
|
||||
原文是用户在向别人提问或征求意见。
|
||||
1. 输出必须仍然是**同一个人提出的同一个问句**,保留问号。
|
||||
2. 禁止改写成陈述、评价、结论或建议(反例:「你觉得这个包怎么样」✘→「还行,挺顺眼的」)。
|
||||
3. 风格化只能作用于问法本身,不得替对方作答。
|
||||
"""
|
||||
}
|
||||
return """
|
||||
# Question guard (this transcript is a question)
|
||||
The user is asking someone else for their opinion.
|
||||
1. The output must remain the same question asked by the same person, keeping the question mark.
|
||||
2. Never turn it into a statement, verdict, or suggestion ("what do you think of this bag" ✘→ "it's fine, looks good").
|
||||
3. Style may shape how the question is asked, never answer it for the other party.
|
||||
"""
|
||||
}
|
||||
|
||||
internal static func shouldPreserveQuestion(_ text: String) -> Bool {
|
||||
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let opponentMarkers = [
|
||||
"回他", "回她", "对方", "他说", "她说", "你说的", "你这叫", "大家都",
|
||||
]
|
||||
guard !opponentMarkers.contains(where: trimmed.contains) else { return false }
|
||||
if trimmed.contains("?") || trimmed.contains("?") { return true }
|
||||
let patterns = [
|
||||
#"吗[\s。!!]*$|吗[,,]"#,
|
||||
#"怎么样|如何|哪个|哪家|哪种|什么时候|为什么|为啥"#,
|
||||
#"能不能|可不可以|要不要|行不行|是不是|有没有|好不好"#,
|
||||
#"你觉得|你们觉得|大家觉得|你看呢|求推荐|求建议"#,
|
||||
]
|
||||
return patterns.contains { trimmed.range(of: $0, options: .regularExpression) != nil }
|
||||
}
|
||||
|
||||
/// Style personality for the live request. Built-ins and custom packs both
|
||||
/// inject their pack body (minus core-owned ASR / 不作答 duplicates).
|
||||
private static func personalitySection(
|
||||
for style: PolishStylePack,
|
||||
useChineseGuidance: Bool
|
||||
) -> String {
|
||||
let body = PolishStylePackCatalog.runtimePersonality(for: style)
|
||||
if style.kind == .user {
|
||||
return useChineseGuidance
|
||||
? """
|
||||
# 用户自定义风格(优先于通用清理口吻)
|
||||
在不改变事实、立场与交际意图的前提下,完整执行下列用户人格;不得稀释成普通通顺清理。
|
||||
\(body)
|
||||
"""
|
||||
: """
|
||||
# User custom style (outranks generic cleanup tone)
|
||||
Execute the user's personality below while preserving facts, stance, and intent; do not dilute it into plain cleanup.
|
||||
\(body)
|
||||
"""
|
||||
}
|
||||
return useChineseGuidance
|
||||
? """
|
||||
# 当前风格人格
|
||||
\(body)
|
||||
"""
|
||||
: """
|
||||
# Active style personality
|
||||
\(body)
|
||||
"""
|
||||
}
|
||||
|
||||
/// Neutralize envelope-breaking tags inside user-controlled transcript text.
|
||||
internal static func sanitizeEnvelopeContent(_ text: String) -> String {
|
||||
let maxCharacters = 16_000
|
||||
@@ -228,97 +380,24 @@ public enum PolishPromptComposer {
|
||||
return String(neutralized.prefix(maxCharacters))
|
||||
}
|
||||
|
||||
private static func policyBlock(
|
||||
_ policy: PolishStylePolicy,
|
||||
useChineseGuidance: Bool
|
||||
) -> String {
|
||||
if useChineseGuidance {
|
||||
let mode = policy.mode == .practical
|
||||
? "实用还原:每处改动都应像用户自己会打出的文字;答不上来就不要改。"
|
||||
: "趣味改写:允许明显改变表达方式,但不得改变事实、立场、对象和交际意图。"
|
||||
let structure: String
|
||||
switch policy.structure {
|
||||
case .never:
|
||||
structure = "禁止列表化和为了排版而分段。即使出现「首先/其次」,也保持自然消息。"
|
||||
case .onlyExplicit:
|
||||
structure = "仅在原文明示列点、步骤或多项待办时结构化。"
|
||||
case .encouraged:
|
||||
structure = "存在多个真正独立事项时鼓励分段或列项;连续叙述仍保持自然段。"
|
||||
}
|
||||
let punctuation: String
|
||||
switch policy.punctuation {
|
||||
case .full: punctuation = "使用完整标点。"
|
||||
case .light: punctuation = "使用轻标点;即时短消息句末可省句号。"
|
||||
case .minimal: punctuation = "只使用理解所需的最少标点。"
|
||||
}
|
||||
return """
|
||||
# 当前风格策略
|
||||
\(mode)
|
||||
\(structure)
|
||||
\(punctuation)
|
||||
参考长度范围:原文的 \(policy.lengthRatio.lowerBound)–\(policy.lengthRatio.upperBound) 倍;不得为凑长度新增或删除信息。
|
||||
"""
|
||||
}
|
||||
|
||||
let mode = policy.mode == .practical
|
||||
? "Practical restoration: every change should look like something the user would have typed; if unsure, do not change it."
|
||||
: "Transformative style: expression may change clearly, but facts, stance, people, and communicative intent must not."
|
||||
let structure: String
|
||||
switch policy.structure {
|
||||
case .never:
|
||||
structure = "Never create a list or decorative paragraphs. Keep natural message form even with words such as first/second."
|
||||
case .onlyExplicit:
|
||||
structure = "Structure only explicit points, steps, or multiple todos."
|
||||
case .encouraged:
|
||||
structure = "Use paragraphs or items for genuinely independent points; keep a continuous narrative as prose."
|
||||
}
|
||||
let punctuation: String
|
||||
switch policy.punctuation {
|
||||
case .full: punctuation = "Use full punctuation."
|
||||
case .light: punctuation = "Use light punctuation; a short instant message may omit the final period."
|
||||
case .minimal: punctuation = "Use only punctuation necessary for understanding."
|
||||
}
|
||||
return """
|
||||
# Active style policy
|
||||
\(mode)
|
||||
\(structure)
|
||||
\(punctuation)
|
||||
Reference length range: \(policy.lengthRatio.lowerBound)–\(policy.lengthRatio.upperBound) times the input. Never add or remove information merely to hit the range.
|
||||
"""
|
||||
}
|
||||
|
||||
private static func injectDictionary(
|
||||
into prompt: String,
|
||||
dictionaryBlock: String,
|
||||
useChineseGuidance: Bool
|
||||
) -> String {
|
||||
let trimmed = prompt.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let placeholder = PolishStylePackCatalog.dictionaryPlaceholder
|
||||
if trimmed.contains(placeholder) {
|
||||
return trimmed.replacingOccurrences(
|
||||
of: placeholder,
|
||||
with: dictionarySection(dictionaryBlock, useChineseGuidance: useChineseGuidance)
|
||||
)
|
||||
}
|
||||
guard !dictionaryBlock.isEmpty else { return trimmed }
|
||||
return trimmed + "\n\n" + dictionarySection(
|
||||
dictionaryBlock,
|
||||
useChineseGuidance: useChineseGuidance
|
||||
)
|
||||
}
|
||||
|
||||
/// Dictionary is a priority hint; the selected shared core owns correction.
|
||||
/// Empty input returns no section so correction rules are not duplicated.
|
||||
private static func dictionarySection(
|
||||
_ dictionaryBlock: String,
|
||||
useChineseGuidance: Bool
|
||||
) -> String {
|
||||
guard !dictionaryBlock.isEmpty else {
|
||||
return useChineseGuidance
|
||||
? "# ASR 纠错\n根据上下文修正明显的同音、近音和断句错误;低置信度专有名词保持原样。"
|
||||
: "# ASR correction\nFix clear homophone, near-match, and segmentation errors from context; preserve uncertain proper nouns."
|
||||
}
|
||||
guard !dictionaryBlock.isEmpty else { return "" }
|
||||
return useChineseGuidance
|
||||
? "# 用户词典(必须优先采用这些准确写法)\n\(dictionaryBlock)"
|
||||
: "# User dictionary (prefer these exact spellings)\n\(dictionaryBlock)"
|
||||
? """
|
||||
# 用户词典(必须优先采用这些准确写法)
|
||||
词典命中优先于同音猜测;未命中时仍按共享纠错规则处理。
|
||||
\(dictionaryBlock)
|
||||
"""
|
||||
: """
|
||||
# User dictionary (prefer these exact spellings)
|
||||
Dictionary hits outrank homophone guesses; when nothing matches, use the shared correction rules.
|
||||
\(dictionaryBlock)
|
||||
"""
|
||||
}
|
||||
|
||||
private static func contextPremise(
|
||||
|
||||
Reference in New Issue
Block a user