Commit ·
291a28f
1
Parent(s): 4ec8363
fix: Grammar shows word-level suggestions instead of sentence chunks - Break grammar diffs into individual word changes - Skip grammar suggestions overlapping with spelling - Add alternatives to grammar suggestions - Prevents duplication on Apply All
Browse files- src/app.py +41 -10
src/app.py
CHANGED
|
@@ -858,16 +858,47 @@ def analyze_text():
|
|
| 858 |
corrected_grammar = correct_grammar(current_text)
|
| 859 |
logger.info(f"[ANALYZE] Step 2: Grammar done in {time.time()-t0:.2f}s")
|
| 860 |
if corrected_grammar != current_text:
|
| 861 |
-
|
| 862 |
-
|
| 863 |
-
|
| 864 |
-
|
| 865 |
-
|
| 866 |
-
|
| 867 |
-
|
| 868 |
-
|
| 869 |
-
|
| 870 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 871 |
mappers.append(OffsetMapper(current_text, corrected_grammar))
|
| 872 |
current_text = corrected_grammar
|
| 873 |
except Exception as e:
|
|
|
|
| 858 |
corrected_grammar = correct_grammar(current_text)
|
| 859 |
logger.info(f"[ANALYZE] Step 2: Grammar done in {time.time()-t0:.2f}s")
|
| 860 |
if corrected_grammar != current_text:
|
| 861 |
+
# Word-level grammar diffs (individual words, not chunks)
|
| 862 |
+
g_orig_words = get_word_positions(current_text)
|
| 863 |
+
g_corr_words = get_word_positions(corrected_grammar)
|
| 864 |
+
g_matcher = difflib.SequenceMatcher(
|
| 865 |
+
None,
|
| 866 |
+
[w[0] for w in g_orig_words],
|
| 867 |
+
[w[0] for w in g_corr_words]
|
| 868 |
+
)
|
| 869 |
+
|
| 870 |
+
for tag, i1, i2, j1, j2 in g_matcher.get_opcodes():
|
| 871 |
+
if tag == 'replace':
|
| 872 |
+
# Process each original word individually
|
| 873 |
+
for k in range(i1, i2):
|
| 874 |
+
ck = j1 + (k - i1)
|
| 875 |
+
if ck < j2:
|
| 876 |
+
o_word = g_orig_words[k][0]
|
| 877 |
+
c_word = g_corr_words[ck][0]
|
| 878 |
+
if o_word != c_word:
|
| 879 |
+
g_start = g_orig_words[k][1]
|
| 880 |
+
g_end = g_orig_words[k][2]
|
| 881 |
+
orig_start, orig_end = map_range_to_original(g_start, g_end)
|
| 882 |
+
|
| 883 |
+
# Skip if overlaps with existing spelling suggestion
|
| 884 |
+
overlaps = False
|
| 885 |
+
for existing in suggestions:
|
| 886 |
+
if existing['type'] == 'spelling':
|
| 887 |
+
if not (orig_end <= existing['start'] or orig_start >= existing['end']):
|
| 888 |
+
overlaps = True
|
| 889 |
+
break
|
| 890 |
+
if overlaps:
|
| 891 |
+
continue
|
| 892 |
+
|
| 893 |
+
suggestions.append({
|
| 894 |
+
'start': orig_start,
|
| 895 |
+
'end': orig_end,
|
| 896 |
+
'original': text[orig_start:orig_end],
|
| 897 |
+
'correction': c_word,
|
| 898 |
+
'type': 'grammar',
|
| 899 |
+
'alternatives': [c_word, text[orig_start:orig_end]],
|
| 900 |
+
})
|
| 901 |
+
|
| 902 |
mappers.append(OffsetMapper(current_text, corrected_grammar))
|
| 903 |
current_text = corrected_grammar
|
| 904 |
except Exception as e:
|