Improve translation fallback and scale UI
build-push / docker (push) Successful in 4m12s

This commit is contained in:
AI Assistant
2026-03-13 12:11:38 +09:00
parent 6852e07607
commit 4a51998cbd
2 changed files with 70 additions and 30 deletions
+50 -10
View File
@@ -8,6 +8,7 @@ import (
"io"
"mime"
"net/http"
neturl "net/url"
"strings"
"time"
)
@@ -201,16 +202,18 @@ 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 strings.TrimSpace(query)
}
func (g *GeminiService) generateText(body map[string]any) (string, error) {
rawBody, _ := json.Marshal(body)
@@ -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
}
+20 -20
View File
@@ -8,12 +8,12 @@
<link rel="stylesheet" href="/style.css" />
</head>
<body class="min-h-full bg-zinc-950 text-zinc-100 selection:bg-white selection:text-black">
<main class="mx-auto flex min-h-screen max-w-7xl flex-col gap-6 px-4 py-6 lg:px-8">
<header class="rounded-3xl border border-white/10 bg-white/5 p-6 backdrop-blur">
<main class="mx-auto flex min-h-screen max-w-[1560px] flex-col gap-8 px-5 py-8 lg:px-10">
<header class="rounded-3xl border border-white/10 bg-white/5 p-8 backdrop-blur">
<div class="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div>
<p class="text-xs uppercase tracking-[0.4em] text-zinc-500">AI Media Asset Ingest Hub</p>
<h1 class="mt-3 text-3xl font-semibold tracking-tight text-white">SAVE THE NURSE AI Search</h1>
<h1 class="mt-3 text-4xl font-semibold tracking-tight text-white">SAVE THE NURSE AI Search</h1>
</div>
<div class="w-full max-w-md">
<div class="mb-2 flex items-center justify-between text-xs uppercase tracking-[0.3em] text-zinc-500">
@@ -27,41 +27,41 @@
</div>
</header>
<section class="grid gap-6 lg:grid-cols-[1.2fr_0.9fr]">
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-5">
<section class="grid gap-8 lg:grid-cols-[1.3fr_0.95fr]">
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-7">
<div class="mb-4 flex items-center justify-between">
<div>
<p class="text-xs uppercase tracking-[0.3em] text-zinc-500">Zone A</p>
<h2 class="text-xl font-semibold text-white">AI Smart Discovery</h2>
<h2 class="text-2xl font-semibold text-white">AI Smart Discovery</h2>
</div>
</div>
<form id="searchForm" class="flex flex-col gap-3 md:flex-row">
<input id="searchQuery" type="text" placeholder="한글 검색어를 입력하세요" class="flex-1 rounded-2xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white outline-none ring-0 placeholder:text-zinc-500" />
<button class="rounded-2xl border border-white bg-white px-5 py-3 text-sm font-medium text-black transition hover:bg-zinc-200">AI Search</button>
<input id="searchQuery" type="text" placeholder="한글 검색어를 입력하세요" class="flex-1 rounded-2xl border border-white/10 bg-black/40 px-5 py-4 text-base text-white outline-none ring-0 placeholder:text-zinc-500" />
<button class="rounded-2xl border border-white bg-white px-7 py-4 text-base font-medium text-black transition hover:bg-zinc-200">AI Search</button>
</form>
<div id="searchWarning" class="mt-3 hidden rounded-2xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-200"></div>
<div id="queryVariants" class="mt-3 hidden flex-wrap gap-2"></div>
<div id="searchResults" class="mt-5 grid gap-4 sm:grid-cols-2 xl:grid-cols-3"></div>
<div id="searchResults" class="mt-6 grid gap-5 sm:grid-cols-2 xl:grid-cols-3"></div>
</article>
<div class="grid gap-6">
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-5">
<div class="grid gap-8">
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-7">
<p class="text-xs uppercase tracking-[0.3em] text-zinc-500">Zone B</p>
<h2 class="text-xl font-semibold text-white">Smart Ingest Dropzone</h2>
<h2 class="text-2xl font-semibold text-white">Smart Ingest Dropzone</h2>
<label id="dropzone" class="mt-4 flex min-h-64 cursor-pointer flex-col items-center justify-center rounded-3xl border border-dashed border-white/20 bg-black/30 p-6 text-center transition hover:border-white/50 hover:bg-white/[0.05]">
<input id="fileInput" type="file" class="hidden" />
<span class="text-lg font-medium text-white">Drop file here</span>
<span class="mt-2 text-sm text-zinc-400">or click to upload into /app/downloads</span>
<span class="text-2xl font-medium text-white">Drop file here</span>
<span class="mt-2 text-base text-zinc-400">or click to upload into /app/downloads</span>
</label>
<p id="uploadResult" class="mt-3 text-sm text-zinc-400"></p>
</article>
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-5">
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-7">
<p class="text-xs uppercase tracking-[0.3em] text-zinc-500">Zone C</p>
<h2 class="text-xl font-semibold text-white">Direct Downloader & Crop</h2>
<h2 class="text-2xl font-semibold text-white">Direct Downloader & Crop</h2>
<form id="downloadForm" class="mt-4 space-y-3">
<input id="downloadUrl" type="url" placeholder="https://..." class="w-full rounded-2xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white placeholder:text-zinc-500" />
<button class="w-full rounded-2xl border border-white px-5 py-3 text-sm font-medium text-white transition hover:bg-white hover:text-black">Preview & Queue</button>
<input id="downloadUrl" type="url" placeholder="https://..." class="w-full rounded-2xl border border-white/10 bg-black/40 px-5 py-4 text-base text-white placeholder:text-zinc-500" />
<button class="w-full rounded-2xl border border-white px-6 py-4 text-base font-medium text-white transition hover:bg-white hover:text-black">Preview & Queue</button>
</form>
<p id="downloadResult" class="mt-3 text-sm text-zinc-400"></p>
</article>
@@ -131,8 +131,8 @@
<div class="absolute left-3 top-3 rounded-full border border-white/20 bg-black/60 px-3 py-1 text-[11px] uppercase tracking-[0.25em] text-white">AI Recommended</div>
<div class="source-badge absolute bottom-3 left-3 rounded-full bg-white px-3 py-1 text-[11px] font-medium uppercase tracking-[0.2em] text-black"></div>
</div>
<div class="space-y-2 p-4">
<h3 class="line-clamp-2 text-sm font-medium text-white"></h3>
<div class="space-y-2 p-5">
<h3 class="line-clamp-2 text-base font-medium text-white"></h3>
<p class="line-clamp-3 text-sm text-zinc-400"></p>
</div>
</a>