diff --git a/backend/services/gemini.go b/backend/services/gemini.go index 41b5e9f..e0c2f39 100644 --- a/backend/services/gemini.go +++ b/backend/services/gemini.go @@ -8,6 +8,7 @@ import ( "io" "mime" "net/http" + neturl "net/url" "strings" "time" ) @@ -201,15 +202,17 @@ func (g *GeminiService) TranslateQuery(query string) string { } rawText, err := g.generateText(body) - if err != nil { - return strings.TrimSpace(query) + if err == nil { + translated := sanitizePlainEnglishLine(rawText) + if translated != "" && !strings.EqualFold(translated, strings.TrimSpace(query)) { + return translated + } } - translated := sanitizePlainEnglishLine(rawText) - if translated == "" { - return strings.TrimSpace(query) + if translated, err := g.translateViaGoogle(query); err == nil && translated != "" { + return translated } - return translated + return strings.TrimSpace(query) } func (g *GeminiService) generateText(body map[string]any) (string, error) { @@ -464,10 +467,6 @@ func fallbackQueryExpansion(originalQuery, englishQuery string) []string { base + " 4k footage", base + " cinematic b-roll", } - if strings.TrimSpace(originalQuery) != "" && !strings.EqualFold(strings.TrimSpace(originalQuery), strings.TrimSpace(englishQuery)) { - candidates = append(candidates, strings.TrimSpace(originalQuery)) - } - seen := map[string]bool{} queries := make([]string, 0, len(candidates)) for _, item := range candidates { @@ -519,3 +518,44 @@ func looksMostlyASCII(text string) bool { } return ascii >= len(runes)*8/10 } + +func (g *GeminiService) translateViaGoogle(query string) (string, error) { + endpoint := "https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=en&dt=t&q=" + neturl.QueryEscape(query) + resp, err := g.Client.Get(endpoint) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode >= 300 { + return "", fmt.Errorf("google translate fallback returned status %d", resp.StatusCode) + } + + var payload []any + if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil { + return "", err + } + if len(payload) == 0 { + return "", fmt.Errorf("google translate fallback returned no payload") + } + top, ok := payload[0].([]any) + if !ok { + return "", fmt.Errorf("google translate fallback returned unexpected payload") + } + + var builder strings.Builder + for _, part := range top { + segment, ok := part.([]any) + if !ok || len(segment) == 0 { + continue + } + if text, ok := segment[0].(string); ok { + builder.WriteString(text) + } + } + translated := strings.TrimSpace(builder.String()) + if translated == "" { + return "", fmt.Errorf("google translate fallback returned empty translation") + } + return translated, nil +} diff --git a/frontend/index.html b/frontend/index.html index ac58ca7..0d88078 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -8,12 +8,12 @@ -
-
+
+

AI Media Asset Ingest Hub

-

SAVE THE NURSE AI Search

+

SAVE THE NURSE AI Search

@@ -27,41 +27,41 @@
-
-
+
+

Zone A

-

AI Smart Discovery

+

AI Smart Discovery

- - + +
-
+
-
-
+
+

Zone B

-

Smart Ingest Dropzone

+

Smart Ingest Dropzone

-
+

Zone C

-

Direct Downloader & Crop

+

Direct Downloader & Crop

- - + +

@@ -131,8 +131,8 @@
AI Recommended
-
-

+
+