@@ -3,7 +3,6 @@ import Form from 'react-bootstrap/Form';
3
3
import Button from 'react-bootstrap/Button' ;
4
4
import Spinner from 'react-bootstrap/Spinner' ;
5
5
import { CancelTokenSource } from 'axios' ;
6
-
7
6
import { isPair , Pairs } from '../translator' ;
8
7
import LanguageSelector from '../translator/LanguageSelector' ;
9
8
import { toAlpha3Code } from '../../util/languages' ;
@@ -40,20 +39,17 @@ const WithSrcLang = ({
40
39
} ) => {
41
40
const opts : any = { validateValue : ( l : string ) => l in pairs } ;
42
41
if ( urlSrcLang ) opts . overrideValue = urlSrcLang ;
43
-
44
42
const [ srcLang , rawSetSrcLang ] = useLocalStorage < string > ( 'dictSrcLang' , ( ) => defaultSrcLang ( pairs ) , opts ) ;
45
43
const [ recentSrcLangs , rawSetRecentSrcLangs ] = useLocalStorage < string [ ] > ( 'dictRecentSrcLangs' , ( ) => [ srcLang ] , {
46
44
validateValue : ( ls ) => Array . isArray ( ls ) && ls . every ( ( l ) => l in pairs ) ,
47
45
} ) ;
48
-
49
46
const setSrcLang = React . useCallback (
50
47
( lang : string ) => {
51
48
rawSetSrcLang ( lang ) ;
52
49
rawSetRecentSrcLangs ( ( prev ) => Array . from ( new Set ( [ lang , ...prev ] ) ) . slice ( 0 , recentLangsCount ) ) ;
53
50
} ,
54
51
[ rawSetSrcLang , rawSetRecentSrcLangs ] ,
55
52
) ;
56
-
57
53
const [ detectedLang , setDetected ] = React . useState < string | null > ( null ) ;
58
54
const setDetectedLang = React . useCallback (
59
55
( lang : string | null ) => {
@@ -62,7 +58,6 @@ const WithSrcLang = ({
62
58
} ,
63
59
[ setSrcLang ] ,
64
60
) ;
65
-
66
61
return children ( {
67
62
srcLang,
68
63
setSrcLang,
@@ -92,7 +87,6 @@ const WithTgtLang = ({
92
87
} ) => {
93
88
const opts : any = { validateValue : ( l : string ) => isPair ( pairs , srcLang , l ) } ;
94
89
if ( urlTgtLang ) opts . overrideValue = urlTgtLang ;
95
-
96
90
const [ tgtLang , rawSetTgtLang ] = useLocalStorage < string > (
97
91
'dictTgtLang' ,
98
92
( ) => {
@@ -104,23 +98,20 @@ const WithTgtLang = ({
104
98
const [ recentTgtLangs , rawSetRecentTgtLangs ] = useLocalStorage < string [ ] > ( 'dictRecentTgtLangs' , ( ) => [ tgtLang ] , {
105
99
validateValue : ( ls ) => Array . isArray ( ls ) && ls . every ( ( l ) => isPair ( pairs , srcLang , l ) ) ,
106
100
} ) ;
107
-
108
101
const setTgtLang = React . useCallback (
109
102
( lang : string ) => {
110
103
rawSetTgtLang ( lang ) ;
111
104
rawSetRecentTgtLangs ( ( prev ) => Array . from ( new Set ( [ lang , ...prev ] ) ) . slice ( 0 , recentLangsCount ) ) ;
112
105
} ,
113
106
[ rawSetTgtLang , rawSetRecentTgtLangs ] ,
114
107
) ;
115
-
116
108
React . useEffect ( ( ) => {
117
109
if ( ! isPair ( pairs , srcLang , tgtLang ) ) {
118
110
const fallback = recentTgtLangs . find ( ( l ) => isPair ( pairs , srcLang , l ) ) ;
119
111
const newTgt = fallback || ( pairs [ srcLang ] ? Array . from ( pairs [ srcLang ] ) [ 0 ] : '' ) ;
120
112
if ( newTgt && newTgt !== tgtLang ) setTgtLang ( newTgt ) ;
121
113
}
122
114
} , [ pairs , srcLang , tgtLang , recentTgtLangs , setTgtLang ] ) ;
123
-
124
115
return children ( { tgtLang, setTgtLang, recentTgtLangs } ) ;
125
116
} ;
126
117
@@ -183,13 +174,14 @@ const Dictionary: React.FC = () => {
183
174
const [ loading , setLoading ] = React . useState ( false ) ;
184
175
const [ searched , setSearched ] = React . useState ( false ) ;
185
176
const searchRef = React . useRef < CancelTokenSource | null > ( null ) ;
186
-
187
177
const [ results , setResults ] = React . useState < { head : string ; defs : string [ ] } [ ] > ( [ ] ) ;
188
178
const [ reverseResults , setReverseResults ] = React . useState < { head : string ; defs : string [ ] } [ ] > ( [ ] ) ;
179
+ const [ embeddingResults , setEmbeddingResults ] = React . useState < { head : string ; defs : string [ ] } [ ] > ( [ ] ) ;
189
180
190
181
React . useEffect ( ( ) => {
191
182
setResults ( [ ] ) ;
192
183
setReverseResults ( [ ] ) ;
184
+ setEmbeddingResults ( [ ] ) ;
193
185
setSearched ( false ) ;
194
186
} , [ srcLang , tgtLang ] ) ;
195
187
@@ -213,6 +205,7 @@ const Dictionary: React.FC = () => {
213
205
setLoading ( true ) ;
214
206
setResults ( [ ] ) ;
215
207
setReverseResults ( [ ] ) ;
208
+ setEmbeddingResults ( [ ] ) ;
216
209
217
210
const [ , reqFwd ] = apyFetch ( 'billookup' , {
218
211
q : `${ word } <*>` ,
@@ -234,33 +227,53 @@ const Dictionary: React.FC = () => {
234
227
235
228
try {
236
229
const [ respFwd , respRev ] = await Promise . all ( [ reqFwd , reqRev ] ) ;
237
- setResults ( parse ( respFwd ) ) ;
230
+ const fwdParsed = parse ( respFwd ) ;
231
+ setResults ( fwdParsed ) ;
238
232
239
233
revParsed = parse ( respRev ) . flatMap ( ( { head, defs } ) =>
240
- defs . map ( ( def ) => ( { head : def . replace ( / ^ \s * \d + \. \s * / , '' ) , defs : [ head ] } ) ) ,
234
+ defs . map ( ( d ) => ( { head : d . replace ( / ^ \s * \d + \. \s * / , '' ) , defs : [ head ] } ) ) ,
241
235
) ;
242
-
243
236
const uniqueHeads = Array . from ( new Set ( revParsed . map ( ( r ) => r . head ) ) ) ;
244
-
245
237
const headResponses = await Promise . all (
246
- uniqueHeads . map ( ( h ) => {
247
- const [ , req ] = apyFetch ( 'bilsearch' , {
248
- q : h ,
249
- langpair : `${ srcOverride } |${ tgtOverride } ` ,
250
- } ) ;
251
- return req . then ( parse ) ;
252
- } ) ,
238
+ uniqueHeads . map ( ( h ) =>
239
+ apyFetch ( 'bilsearch' , { q : h , langpair : `${ srcOverride } |${ tgtOverride } ` } ) [ 1 ] . then ( parse ) ,
240
+ ) ,
253
241
) ;
254
-
255
242
const enriched : Record < string , string [ ] > = { } ;
256
243
headResponses . forEach ( ( arr , i ) => {
257
- const h = uniqueHeads [ i ] ;
258
- enriched [ h ] = Array . from (
244
+ enriched [ uniqueHeads [ i ] ] = Array . from (
259
245
new Set ( arr . flatMap ( ( item ) => item . defs . map ( ( d ) => d . replace ( / < [ ^ > ] + > / g, '' ) . trim ( ) ) ) ) ,
260
246
) ;
261
247
} ) ;
262
-
263
248
setReverseResults ( uniqueHeads . map ( ( h ) => ( { head : h , defs : enriched [ h ] } ) ) ) ;
249
+
250
+ const exactItem = fwdParsed . find ( ( item ) => item . head . replace ( / < [ ^ > ] + > / g, '' ) === word ) ;
251
+ const translations = exactItem ?. defs . map ( ( d ) => d . replace ( / < [ ^ > ] + > / g, '' ) . trim ( ) ) || [ ] ;
252
+ const embArrays = await Promise . all (
253
+ translations . map ( ( term ) =>
254
+ apyFetch ( 'embeddings' , { q : term , langpair : `${ tgtOverride } |${ srcOverride } ` } ) [ 1 ] . then (
255
+ ( res ) =>
256
+ res . data . responseData ?. embeddingResults . flatMap ( ( obj : any ) => Object . values ( obj ) . flat ( ) ) ||
257
+ [ ] ,
258
+ ) ,
259
+ ) ,
260
+ ) ;
261
+ const sims = Array . from ( new Set ( embArrays . flat ( ) ) ) . filter ( ( sim ) => ! sim . startsWith ( '*' ) ) ;
262
+ const embResponses = await Promise . all (
263
+ sims . map ( ( sim ) => apyFetch ( 'bilsearch' , { q : sim , langpair : `${ tgtOverride } |${ srcOverride } ` } ) [ 1 ] ) ,
264
+ ) ;
265
+ let embEntries : Entry [ ] = [ ] ;
266
+ embResponses . forEach ( ( resp ) => {
267
+ const raw = resp . data . responseData ?. searchResults ?? [ ] ;
268
+ ( raw as Array < Record < string , string [ ] > > ) . forEach ( ( o ) => {
269
+ Object . entries ( o ) . forEach ( ( [ hd , defs ] ) => {
270
+ defs . forEach ( ( def ) => {
271
+ embEntries . push ( { head : def , defs : [ hd ] } ) ;
272
+ } ) ;
273
+ } ) ;
274
+ } ) ;
275
+ } ) ;
276
+ setEmbeddingResults ( embEntries ) ;
264
277
} catch {
265
278
setReverseResults ( revParsed ) ;
266
279
} finally {
@@ -275,6 +288,7 @@ const Dictionary: React.FC = () => {
275
288
const all : Entry [ ] = [
276
289
...results . map ( ( r ) => ( { head : r . head , defs : r . defs } ) ) ,
277
290
...reverseResults . map ( ( r ) => ( { head : r . head , defs : r . defs } ) ) ,
291
+ ...embeddingResults . map ( ( e ) => ( { head : e . head , defs : e . defs } ) ) ,
278
292
] ;
279
293
const map : Record < string , Entry [ ] > = { } ;
280
294
all . forEach ( ( e ) => {
@@ -286,7 +300,7 @@ const Dictionary: React.FC = () => {
286
300
} ) ;
287
301
} ) ;
288
302
return map ;
289
- } , [ results , reverseResults ] ) ;
303
+ } , [ results , reverseResults , embeddingResults ] ) ;
290
304
291
305
return (
292
306
< Form
@@ -311,7 +325,6 @@ const Dictionary: React.FC = () => {
311
325
detectedLang = { detectedLang }
312
326
setDetectedLang = { setDetectedLang }
313
327
/>
314
-
315
328
< Form . Group className = "mt-3" controlId = "searchWord" >
316
329
< Form . Control
317
330
type = "text"
@@ -320,15 +333,13 @@ const Dictionary: React.FC = () => {
320
333
onChange = { ( e ) => setSearchWord ( e . target . value ) }
321
334
/>
322
335
</ Form . Group >
323
-
324
336
< div className = "d-flex justify-content-start mt-2" >
325
337
< Button onClick = { ( ) => handleSearch ( ) } variant = "primary" size = "sm" >
326
338
{ t ( 'Search' ) }
327
339
</ Button >
328
340
</ div >
329
-
330
341
< div className = "mt-3" >
331
- { [ ... Object . entries ( grouped ) ]
342
+ { Object . entries ( grouped )
332
343
. sort ( ( [ a ] , [ b ] ) => {
333
344
if ( a === searchWord && b !== searchWord ) return - 1 ;
334
345
if ( b === searchWord && a !== searchWord ) return 1 ;
@@ -348,7 +359,6 @@ const Dictionary: React.FC = () => {
348
359
} }
349
360
/>
350
361
) ) }
351
-
352
362
{ searched && ! loading && Object . keys ( grouped ) . length === 0 && (
353
363
< div className = "text-center text-muted mt-3" > { t ( 'No_results_found' ) } </ div >
354
364
) }
0 commit comments