Fix reply bubble misidentification and add reply announcement with left-arrow navigation#75
Merged
Merged
Conversation
…ft-arrow navigation - Replace _detectReplySender with _detectReplyNames returning (replySender, quotedSender) to correctly identify reply bubbles containing two distinct cached sender names - Restrict candidate scoring to actual reply sender, preventing quoted preview text from winning on content overlap and causing wrong message to be announced - Add _findQuotedOriginal to locate the original quoted message by scanning backward from the reply's cache index - Add getLastReplyInfo() module getter so line.py can read reply context after lookup - Announce reply messages as "Sender 回覆 OriginalSender Content Time" in one utterance - Intercept Left Arrow in script_navigateAndTrack to speak the original quoted message - Add 6 new tests covering reply detection, original lookup, and edge cases Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Use line-anchored regex (^name\s*$) instead of plain str.find() in _detectReplyNames, fixing two cases: P1: a name mentioned mid-sentence (e.g. 'Thanks Bob') no longer triggers the reply filter, since it won't occupy an entire line. P2: a short name that is a substring of a longer name (e.g. '王昱' inside '王昱涵') no longer matches the line belonging to the longer name, preventing false sender identification. - Update existing reply-bubble test OCR strings to use proper format where the quoted sender name is on its own line (as real LINE OCR does). - Add two new regression tests covering the P1 and P2 cases. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Without this, pressing Left Arrow a second time on the same reply bubble would repeat the announcement indefinitely since focus never moves and lookupMessage() is never called again. Add clearLastReplyInfo() to _chatCache and call it immediately after the ui.message() announcement in the left-arrow intercept path. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Real LINE OCR for reply bubbles renders a quote-indicator glyph (commonly OCR'd as '0 ') before the quoted user name, so the quoted name does NOT occupy a standalone line. The previous regex '^name\\s*\$' was too strict and caused a regression where reply bubbles were no longer detected, falling back to the original bug of reading the long quoted preview instead of the actual reply. New regex: '^[^CJK/Latin-letters]*name(?![CJK/Latin-letters])' - Allows non-letter prefix (icons, digits, punctuation, whitespace) so '0 王昱涵' still matches. - Anchored to line start with letter-class prefix exclusion, so mid-sentence mentions like '感謝Bob' still cannot match (because '感謝' are CJK letters and won't be consumed by the prefix class). - Negative lookahead blocks substring matches, so '王昱' cannot match a line containing '王昱涵'. Add regression test using the exact OCR string from the user's log. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Sender 回覆 OriginalSender Content Timein a single utterance (previously time was split into a separate announcement).OriginalSender OriginalContent. The original is found by scanning backward in the cached chat history from the reply's position.Test plan
pytest tests/test_chat_cache.py --ignore=tests/test_message_reader_parser.py— all 126 tests passSender 回覆 OriginalSender Content HH:MMin one utteranceOriginalSender OriginalContent🤖 Generated with Claude Code
Greptile Summary
此 PR 修正了回覆氣泡被誤識的問題,並新增「回覆訊息」播報格式以及左鍵朗讀被引用原文的功能。核心邏輯透過行首錨定的正規表達式偵測 OCR 中的兩個發送者姓名,從而區分「回覆者」與「被回覆者」,並搭配向上掃描快取以找到被引用的原始訊息。
_detectReplyNames()現在使用行首錨定正規表達式,防止姓名出現在句子中間或作為長姓名的子字串時誤觸回覆篩選器。_lastReplyInfo會被清除,確保後續左鍵正常穿透。Confidence Score: 5/5
此 PR 可安全合併,邏輯設計周全,邊界條件均有對應測試覆蓋。
回覆偵測邏輯使用行首錨定正規表達式,正確排除了姓名出現在句子中間或作為長姓名子字串的情況;左鍵攔截在播報後立即清除 _lastReplyInfo,不會重複觸發;lookupMessage 在函式起始即重設 _lastReplyInfo,確保非回覆訊息不會繼承舊狀態;10 個新增單元測試涵蓋所有關鍵邊界情況。
所有檔案皆無需特別關注。
Important Files Changed
Sequence Diagram
sequenceDiagram participant User participant script_navigateAndTrack participant _copyAndReadMessage participant _chatCache User->>script_navigateAndTrack: 按下任意導覽鍵 alt "keyName == leftArrow 且有回覆資訊" script_navigateAndTrack->>_chatCache: getLastReplyInfo() _chatCache-->>script_navigateAndTrack: replyInfo (含 originalContent) script_navigateAndTrack->>User: ui.message(OriginalSender OriginalContent) script_navigateAndTrack->>_chatCache: clearLastReplyInfo() Note over script_navigateAndTrack: return(不穿透按鍵) else 其他鍵 或無回覆資訊 script_navigateAndTrack->>User: gesture.send() + 排程 UIA 焦點查詢 end User->>_copyAndReadMessage: 焦點移到訊息氣泡 _copyAndReadMessage->>_chatCache: lookupMessage(ocrText) _chatCache->>_chatCache: _detectReplyNames(ocrText) alt 偵測到兩個姓名(回覆氣泡) _chatCache->>_chatCache: 篩選候選訊息為 replySender _chatCache->>_chatCache: _findQuotedOriginal(bestIdx, quotedSender, ocrText) _chatCache->>_chatCache: 設定 _lastReplyInfo _chatCache-->>_copyAndReadMessage: (formattedText, idx) _copyAndReadMessage->>_chatCache: getLastReplyInfo() _chatCache-->>_copyAndReadMessage: replyInfo _copyAndReadMessage->>User: ui.message(發送者 回覆 被回覆者 內容 時間) else 普通訊息 _chatCache->>_chatCache: "_lastReplyInfo = None" _chatCache-->>_copyAndReadMessage: (formattedText, idx) _copyAndReadMessage->>User: ui.message(cachedText) endReviews (4): Last reviewed commit: "Fix reply detection regression: handle q..." | Re-trigger Greptile