66 "regexp"
77 "unicode/utf8"
88
9- f1mspellchecker "github.com/f1monkey/spellchecker"
109 "github.com/f1monkey/spellchecker-web/internal/spellchecker"
10+ f1mspellchecker "github.com/f1monkey/spellchecker/v2"
1111 "github.com/swaggest/usecase"
1212 "github.com/swaggest/usecase/status"
1313)
@@ -19,8 +19,10 @@ type dictionaryGetter interface {
1919type DictionaryFixRequest struct {
2020 Code string `path:"code" minLength:"1"`
2121
22- Text string `json:"text" description:"Phrase to be checked"`
23- Limit int `json:"limit" default:"5" desciption:"Max suggestions per word"`
22+ Text string `json:"text" description:"Phrase to be checked"`
23+ Limit int `json:"limit" default:"5" desciption:"Max suggestions per word"`
24+ MaxErrors int `json:"maxErrors" default:"2" desciption:"Max spellchecker errors allowed"`
25+ SimilarityThreshold float64 `json:"similarityThreshold" minimum:"0" maximum:"1" desciption:"Word similarity percent required"`
2426}
2527
2628type DictionaryFixResponse struct {
@@ -51,71 +53,78 @@ func dictionaryFix(registry dictionaryGetter, splitter *regexp.Regexp) usecase.I
5153 errorInvalidWord = "invalid_word"
5254 )
5355
54- u := usecase .NewInteractor (func (ctx context.Context , input DictionaryFixRequest , output * DictionaryFixResponse ) error {
55- sc , err := registry .Get (input .Code )
56- if errors .Is (spellchecker .ErrNotFound , err ) {
57- return status .Wrap (err , status .NotFound )
58- } else if err != nil {
59- return status .Wrap (err , status .Internal )
60- }
61-
62- if input .Text == "" {
63- output .Fixes = make ([]Fix , 0 )
64- return nil
65- }
66-
67- matches := splitter .FindAllStringIndex (input .Text , - 1 )
68- fixes := make ([]Fix , 0 , len (matches ))
69- correct := make ([]Correct , 0 , len (matches ))
70-
71- for _ , match := range matches {
72- startByte , endByte := match [0 ], match [1 ]
73- startRune := utf8 .RuneCountInString (input .Text [:startByte ])
74- endRune := startRune + utf8 .RuneCountInString (input .Text [startByte :endByte ])
56+ u := usecase .NewInteractor (
57+ func (ctx context.Context , input DictionaryFixRequest , output * DictionaryFixResponse ) error {
58+ sc , err := registry .Get (input .Code )
59+ if errors .Is (spellchecker .ErrNotFound , err ) {
60+ return status .Wrap (err , status .NotFound )
61+ } else if err != nil {
62+ return status .Wrap (err , status .Internal )
63+ }
7564
76- fix := Fix {
77- Start : startRune ,
78- End : endRune ,
65+ if input . Text == "" {
66+ output . Fixes = make ([] Fix , 0 )
67+ return nil
7968 }
8069
81- word := input .Text [startByte :endByte ]
70+ matches := splitter .FindAllStringIndex (input .Text , - 1 )
71+ fixes := make ([]Fix , 0 , len (matches ))
72+ correct := make ([]Correct , 0 , len (matches ))
8273
83- suggestions := sc .SuggestScore (word , input .Limit )
74+ for _ , match := range matches {
75+ startByte , endByte := match [0 ], match [1 ]
76+ startRune := utf8 .RuneCountInString (input .Text [:startByte ])
77+ endRune := startRune + utf8 .RuneCountInString (input .Text [startByte :endByte ])
8478
85- if suggestions .ExactMatch {
86- correct = append (correct , Correct {
79+ fix := Fix {
8780 Start : startRune ,
8881 End : endRune ,
89- })
82+ }
9083
91- continue
92- }
84+ word := input .Text [startByte :endByte ]
9385
94- if len (suggestions .Suggestions ) == 0 {
95- fix .Error = errorUnknownWord
96- } else {
97- fix .Error = errorInvalidWord
98- fix .Suggestions = make ([]SpellcheckerSuggestion , 0 , len (suggestions .Suggestions ))
86+ suggestions := sc .Suggest (& f1mspellchecker.SearchOptions {
87+ MaxErrors : input .MaxErrors ,
88+ FilterFunc : spellchecker .ScoringFunc (input .MaxErrors , input .SimilarityThreshold ),
89+ }, word , input .Limit )
9990
100- for _ , s := range suggestions .Suggestions {
101- fix . Suggestions = append (fix . Suggestions , SpellcheckerSuggestion {
102- Text : s . Value ,
103- Score : s . Score ,
91+ if suggestions .ExactMatch {
92+ correct = append (correct , Correct {
93+ Start : startRune ,
94+ End : endRune ,
10495 })
96+
97+ continue
10598 }
106- }
10799
108- fixes = append (fixes , fix )
109- }
100+ if len (suggestions .Suggestions ) == 0 {
101+ fix .Error = errorUnknownWord
102+ } else {
103+ fix .Error = errorInvalidWord
104+ fix .Suggestions = make ([]SpellcheckerSuggestion , 0 , len (suggestions .Suggestions ))
105+
106+ for _ , s := range suggestions .Suggestions {
107+ fix .Suggestions = append (fix .Suggestions , SpellcheckerSuggestion {
108+ Text : s .Value ,
109+ Score : s .Score ,
110+ })
111+ }
112+ }
110113
111- output . Fixes = fixes
112- output . Correct = correct
114+ fixes = append ( fixes , fix )
115+ }
113116
114- return nil
115- })
117+ output .Fixes = fixes
118+ output .Correct = correct
119+
120+ return nil
121+ },
122+ )
116123
117124 u .SetTitle ("Fix text" )
118- u .SetDescription ("Performs spellchecking on the given input text. Returns misspelled words along with suggested corrections, up to the specified limit per word." )
125+ u .SetDescription (
126+ "Performs spellchecking on the given input text. Returns misspelled words along with suggested corrections, up to the specified limit per word." ,
127+ )
119128 u .SetExpectedErrors (status .Internal , status .NotFound )
120129
121130 return u
0 commit comments