Skip to content

Commit b6d7e96

Browse files
committed
fix: parallel processing to improve translation speed
1 parent de9888c commit b6d7e96

File tree

1 file changed

+137
-119
lines changed

1 file changed

+137
-119
lines changed

translate/translate.go

+137-119
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @Author: Vincent Young
33
* @Date: 2024-09-16 11:59:24
44
* @LastEditors: Vincent Yang
5-
* @LastEditTime: 2025-01-20 17:09:59
5+
* @LastEditTime: 2025-02-01 03:21:41
66
* @FilePath: /DeepLX/translate/translate.go
77
* @Telegram: https://t.me/missuo
88
* @GitHub: https://github.com/missuo
@@ -19,6 +19,7 @@ import (
1919
"net/http"
2020
"net/url"
2121
"strings"
22+
"sync"
2223

2324
"github.com/abadojack/whatlanggo"
2425
"github.com/imroc/req/v3"
@@ -126,92 +127,89 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
126127
}, nil
127128
}
128129

129-
// Split text by newlines and store them for later reconstruction
130+
// Split text by newlines
130131
textParts := strings.Split(text, "\n")
131-
var translatedParts []string
132-
var allAlternatives [][]string // Store alternatives for each part
133-
134-
for _, part := range textParts {
135-
if strings.TrimSpace(part) == "" {
136-
translatedParts = append(translatedParts, "")
137-
allAlternatives = append(allAlternatives, []string{""})
138-
continue
139-
}
140132

141-
// Split text first
142-
splitResult, err := splitText(part, tagHandling == "html" || tagHandling == "xml", proxyURL, dlSession)
143-
if err != nil {
144-
return DeepLXTranslationResult{
145-
Code: http.StatusServiceUnavailable,
146-
Message: err.Error(),
147-
}, nil
148-
}
149-
150-
// Get detected language if source language is auto
151-
if sourceLang == "auto" || sourceLang == "" {
152-
sourceLang = strings.ToUpper(whatlanggo.DetectLang(part).Iso6391())
153-
}
154-
155-
// Prepare jobs from split result
156-
var jobs []Job
157-
chunks := splitResult.Get("result.texts.0.chunks").Array()
158-
for idx, chunk := range chunks {
159-
sentence := chunk.Get("sentences.0")
160-
161-
// Handle context
162-
contextBefore := []string{}
163-
contextAfter := []string{}
164-
if idx > 0 {
165-
contextBefore = []string{chunks[idx-1].Get("sentences.0.text").String()}
133+
// Create channels for results
134+
type translationResult struct {
135+
index int
136+
translation string
137+
alternatives []string
138+
err error
139+
}
140+
results := make(chan translationResult, len(textParts))
141+
142+
// Create a wait group to track all goroutines
143+
var wg sync.WaitGroup
144+
145+
// Launch goroutines for each text part
146+
for i := range textParts {
147+
wg.Add(1)
148+
go func(index int, text string) {
149+
defer wg.Done()
150+
151+
if strings.TrimSpace(text) == "" {
152+
results <- translationResult{
153+
index: index,
154+
translation: "",
155+
alternatives: []string{""},
156+
}
157+
return
166158
}
167-
if idx < len(chunks)-1 {
168-
contextAfter = []string{chunks[idx+1].Get("sentences.0.text").String()}
159+
160+
// Split text first
161+
splitResult, err := splitText(text, tagHandling == "html" || tagHandling == "xml", proxyURL, dlSession)
162+
if err != nil {
163+
results <- translationResult{index: index, err: err}
164+
return
169165
}
170166

171-
jobs = append(jobs, Job{
172-
Kind: "default",
173-
PreferredNumBeams: 4,
174-
RawEnContextBefore: contextBefore,
175-
RawEnContextAfter: contextAfter,
176-
Sentences: []Sentence{{
177-
Prefix: sentence.Get("prefix").String(),
178-
Text: sentence.Get("text").String(),
179-
ID: idx + 1,
180-
}},
181-
})
182-
}
167+
// Get detected language if source language is auto
168+
currentSourceLang := sourceLang
169+
if currentSourceLang == "auto" || currentSourceLang == "" {
170+
currentSourceLang = strings.ToUpper(whatlanggo.DetectLang(text).Iso6391())
171+
}
183172

184-
hasRegionalVariant := false
185-
targetLangCode := targetLang
186-
targetLangParts := strings.Split(targetLang, "-")
187-
if len(targetLangParts) > 1 {
188-
targetLangCode = targetLangParts[0]
189-
hasRegionalVariant = true
190-
}
173+
// Prepare jobs from split result
174+
var jobs []Job
175+
chunks := splitResult.Get("result.texts.0.chunks").Array()
176+
for idx, chunk := range chunks {
177+
sentence := chunk.Get("sentences.0")
178+
179+
// Handle context
180+
contextBefore := []string{}
181+
contextAfter := []string{}
182+
if idx > 0 {
183+
contextBefore = []string{chunks[idx-1].Get("sentences.0.text").String()}
184+
}
185+
if idx < len(chunks)-1 {
186+
contextAfter = []string{chunks[idx+1].Get("sentences.0.text").String()}
187+
}
191188

192-
// Prepare translation request
193-
id := getRandomNumber()
189+
jobs = append(jobs, Job{
190+
Kind: "default",
191+
PreferredNumBeams: 4,
192+
RawEnContextBefore: contextBefore,
193+
RawEnContextAfter: contextAfter,
194+
Sentences: []Sentence{{
195+
Prefix: sentence.Get("prefix").String(),
196+
Text: sentence.Get("text").String(),
197+
ID: idx + 1,
198+
}},
199+
})
200+
}
194201

195-
postData := &PostData{
196-
Jsonrpc: "2.0",
197-
Method: "LMT_handle_jobs",
198-
ID: id,
199-
Params: Params{
200-
CommonJobParams: CommonJobParams{
201-
Mode: "translate",
202-
},
203-
Lang: Lang{
204-
SourceLangComputed: strings.ToUpper(sourceLang),
205-
TargetLang: strings.ToUpper(targetLangCode),
206-
},
207-
Jobs: jobs,
208-
Priority: 1,
209-
Timestamp: getTimeStamp(getICount(part)),
210-
},
211-
}
202+
hasRegionalVariant := false
203+
targetLangCode := targetLang
204+
targetLangParts := strings.Split(targetLang, "-")
205+
if len(targetLangParts) > 1 {
206+
targetLangCode = targetLangParts[0]
207+
hasRegionalVariant = true
208+
}
212209

213-
if hasRegionalVariant {
214-
postData = &PostData{
210+
// Prepare translation request
211+
id := getRandomNumber()
212+
postData := &PostData{
215213
Jsonrpc: "2.0",
216214
Method: "LMT_handle_jobs",
217215
ID: id,
@@ -221,62 +219,82 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
221219
RegionalVariant: map[bool]string{true: targetLang, false: ""}[hasRegionalVariant],
222220
},
223221
Lang: Lang{
224-
SourceLangComputed: strings.ToUpper(sourceLang),
222+
SourceLangComputed: strings.ToUpper(currentSourceLang),
225223
TargetLang: strings.ToUpper(targetLangCode),
226224
},
227225
Jobs: jobs,
228226
Priority: 1,
229-
Timestamp: getTimeStamp(getICount(part)),
227+
Timestamp: getTimeStamp(getICount(text)),
230228
},
231229
}
232-
}
233230

234-
// Make translation request
235-
result, err := makeRequest(postData, "LMT_handle_jobs", proxyURL, dlSession)
236-
if err != nil {
237-
return DeepLXTranslationResult{
238-
Code: http.StatusServiceUnavailable,
239-
Message: err.Error(),
240-
}, nil
241-
}
242-
243-
// Process translation results
244-
var partTranslation string
245-
var partAlternatives []string
246-
247-
translations := result.Get("result.translations").Array()
248-
if len(translations) > 0 {
249-
// Process main translation
250-
for _, translation := range translations {
251-
partTranslation += translation.Get("beams.0.sentences.0.text").String() + " "
231+
// Make translation request
232+
result, err := makeRequest(postData, "LMT_handle_jobs", proxyURL, dlSession)
233+
if err != nil {
234+
results <- translationResult{index: index, err: err}
235+
return
252236
}
253-
partTranslation = strings.TrimSpace(partTranslation)
254237

255-
// Process alternatives
256-
numBeams := len(translations[0].Get("beams").Array())
257-
for i := 1; i < numBeams; i++ { // Start from 1 since 0 is the main translation
258-
var altText string
238+
// Process translation results
239+
var partTranslation string
240+
var partAlternatives []string
241+
242+
translations := result.Get("result.translations").Array()
243+
if len(translations) > 0 {
244+
// Process main translation
259245
for _, translation := range translations {
260-
beams := translation.Get("beams").Array()
261-
if i < len(beams) {
262-
altText += beams[i].Get("sentences.0.text").String() + " "
263-
}
246+
partTranslation += translation.Get("beams.0.sentences.0.text").String() + " "
264247
}
265-
if altText != "" {
266-
partAlternatives = append(partAlternatives, strings.TrimSpace(altText))
248+
partTranslation = strings.TrimSpace(partTranslation)
249+
250+
// Process alternatives
251+
numBeams := len(translations[0].Get("beams").Array())
252+
for i := 1; i < numBeams; i++ {
253+
var altText string
254+
for _, translation := range translations {
255+
beams := translation.Get("beams").Array()
256+
if i < len(beams) {
257+
altText += beams[i].Get("sentences.0.text").String() + " "
258+
}
259+
}
260+
if altText != "" {
261+
partAlternatives = append(partAlternatives, strings.TrimSpace(altText))
262+
}
267263
}
268264
}
269-
}
270265

271-
if partTranslation == "" {
266+
if partTranslation == "" {
267+
results <- translationResult{index: index, err: fmt.Errorf("translation failed")}
268+
return
269+
}
270+
271+
results <- translationResult{
272+
index: index,
273+
translation: partTranslation,
274+
alternatives: partAlternatives,
275+
}
276+
}(i, textParts[i])
277+
}
278+
279+
// Close results channel when all goroutines are done
280+
go func() {
281+
wg.Wait()
282+
close(results)
283+
}()
284+
285+
// Collect results maintaining original order
286+
translatedParts := make([]string, len(textParts))
287+
allAlternatives := make([][]string, len(textParts))
288+
289+
for result := range results {
290+
if result.err != nil {
272291
return DeepLXTranslationResult{
273292
Code: http.StatusServiceUnavailable,
274-
Message: "Translation failed",
293+
Message: result.err.Error(),
275294
}, nil
276295
}
277-
278-
translatedParts = append(translatedParts, partTranslation)
279-
allAlternatives = append(allAlternatives, partAlternatives)
296+
translatedParts[result.index] = result.translation
297+
allAlternatives[result.index] = result.alternatives
280298
}
281299

282300
// Join all translated parts with newlines
@@ -298,17 +316,17 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
298316
if i < len(alts) {
299317
altParts = append(altParts, alts[i])
300318
} else if len(translatedParts[j]) == 0 {
301-
altParts = append(altParts, "") // Keep empty lines
319+
altParts = append(altParts, "")
302320
} else {
303-
altParts = append(altParts, translatedParts[j]) // Use main translation if no alternative
321+
altParts = append(altParts, translatedParts[j])
304322
}
305323
}
306324
combinedAlternatives = append(combinedAlternatives, strings.Join(altParts, "\n"))
307325
}
308326

309327
return DeepLXTranslationResult{
310328
Code: http.StatusOK,
311-
ID: getRandomNumber(), // Using new ID for the complete translation
329+
ID: getRandomNumber(),
312330
Data: translatedText,
313331
Alternatives: combinedAlternatives,
314332
SourceLang: sourceLang,

0 commit comments

Comments
 (0)