产品设计

Wispr Flow:说完之后,仍能决定文字怎么留下

Wispr Flow 把口述输入到邮件、文档和聊天中,并整理标点、列表与明确的改口。它帮助人们把连续表达变成文字,同时保留回看和取回原始转录的路径。

先尝试拆解问题、设计和实现,再展开思路,检查状态、边界与取舍,并设计验证用例。思路提供分析路径,不给出完整实现。

01
代码思考进阶

选择性接受修改时,怎样保住原始坐标?

练习场景

为自己的听写工具设计“选择性接受修改”模块。上游已经给出原始转录和若干编辑建议;用户可以勾选部分建议,预览一份新文本。你只处理确定的修改范围,不做语音识别、意图识别或自动生成建议。

输入约定

  1. 原始转录为只读 token 数组,最多1,000,000项。token 是上游分好的非空字符串片段,可含中文、表情或空格;本题不再分词,也不按字符、字节或JS字符串长度计算位置。空数组合法。
  2. 最多100,000条建议,每条是含唯一非空字符串 id、整数 start/end 和 replacement 数组的非null对象。0 ≤ start ≤ end ≤ 原数组长度,replacement各项也为非空字符串;所有建议replacement项数合计最多1,000,000。其他字段忽略。
  3. [start,end) 始终引用原数组的半开范围。start=end 是插入;replacement为空是删除,也允许空插入作为无效果建议。建议可以乱序到达,不因接受较早建议而改变其他建议的坐标。
  4. 所有非空范围之间不得重叠,但可以首尾相接。插入位置不得严格落在某个非空范围内部;可以在边界处插入。同一位置最多一条插入建议,即使内容相同也算冲突。边界上的插入放在“此前范围替换结果之后、从该位置开始的范围替换结果之前”。
  5. 已接受项是一组建议ID;未知ID或重复ID属于输入错误。必须先校验全部建议,包括未勾选的建议。任一结构、类型、范围、限额或冲突错误,都不生成半份结果,原始输入保持不变。结构与字段错误报告输入路径(如原转录项下标、建议下标/字段或已接受项下标);只有建议间冲突才另外报告相关两条建议的下标及ID。非法字段本身没有可用ID时,不要求编造ID。空接受集合返回原内容的等值预览。

从这个例子开始

原token为 ["周一","下午","三点","开会"]。建议A把 [0,1) 换成 ["周二"];B在 [2,2) 插入 ["大约"];C把 [2,3) 换成 ["四点"]。只接受A/C与接受A/B/C应得到什么?取消A后能否从同一原数组重新生成?再加入D替换 [1,3),为什么应拒绝整组建议,而非只忽略D?

交付物

给出校验顺序、范围索引与拼接设计,手推三个有效接受集合和D的冲突。提出至少四条不变量及边界测试,覆盖空原文、末尾插入、相接替换、重复插入和表情token。解释n个原token、p条建议、r个最终输出token时的时间/空间复杂度。仅写思路与验证方法,不给完整实现或逐行伪代码。

查看思路
  1. 把坐标固定在原文上。 接受集合只决定哪些建议参与输出,不改变建议的基准。每次预览都由同一原数组和当前接受集合产生,避免先改文本再套旧下标。保留输入而非就地splice,也便于整次失败不影响旧预览。
  2. 先验证全集,再处理选择。 检查对象、字符串数组、整数边界、ID唯一与限额;用ID索引验证接受集合。按起点排序检查非空区间重叠,单独处理零长度插入:同位置重复、严格位于区间内部都冲突;边界插入合法。一般错误按题面报告输入字段路径;只有建议间冲突才补充原建议下标和两个相关ID。
  3. 按原顺序拼接未改片段与替换。 不变部分只复制一次;同坐标的插入先于从这里开始的替换,而此前结束的替换已经输出。相接替换不能被误判为重叠,replacement为空也不能跳过原范围的消耗。
  4. 手推接受集合。 A/C得到 ["周二","下午","四点","开会"];A/B/C得到 ["周二","下午","大约","四点","开会"];取消A、保留B/C得到 ["周一","下午","大约","四点","开会"]。D与C的非空范围重叠,B也严格位于D内部;即使D未勾选,全集校验仍失败。
  5. 检查不变量和成本。 原输入不变;未被选择覆盖的原token顺序不变;插入不消费原token;替换只消费原半开范围;相同输入与接受集合结果一致。设 L 为所有建议的 replacement 数组中 token 的总数,包含未选择的建议,因为它们也需要校验。用区间排序与扫描避免两两比较,时间为 O(n+L+p log p+r),输出和索引所需的额外空间为 O(p+r)。这只验证编辑结构,不判断语义是否正确。