Refine search status updates and preview sizing
build-push / docker (push) Has been cancelled

This commit is contained in:
AI Assistant
2026-03-13 10:46:50 +09:00
parent d0fca7374d
commit fb865d0acb
3 changed files with 27 additions and 5 deletions
+8
View File
@@ -259,13 +259,16 @@ func (a *App) searchMedia(c *gin.Context) {
return
}
a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "expanding query with Gemini", "progress": 10})
queryVariants, expandErr := a.GeminiService.ExpandQuery(req.Query)
if len(queryVariants) == 0 {
queryVariants = []string{req.Query}
}
a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "searching Google Video, Envato, and Artgrid", "progress": 35})
results, err := a.SearchService.SearchMedia(queryVariants)
if err != nil {
a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "search failed", "progress": 100, "message": err.Error()})
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
@@ -274,12 +277,15 @@ func (a *App) searchMedia(c *gin.Context) {
if expandErr != nil {
warning += " Query expansion failed: " + expandErr.Error()
}
a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "no renderable search results", "progress": 100, "message": warning})
c.JSON(http.StatusOK, gin.H{"results": []services.AIRecommendation{}, "warning": warning})
return
}
a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "ranking thumbnail candidates", "progress": 55})
scored := rankSearchResults(req.Query, results)
shortlist := scored[:min(len(scored), 10)]
a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "analyzing shortlisted thumbnails with Gemini Vision", "progress": 75})
recommended, err := a.GeminiService.Recommend(req.Query, shortlist)
if err != nil {
fallback := make([]services.AIRecommendation, 0, min(20, len(scored)))
@@ -297,6 +303,7 @@ func (a *App) searchMedia(c *gin.Context) {
if expandErr != nil {
warning = warning + " Query expansion failed: " + expandErr.Error()
}
a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "Gemini Vision fallback to ranked results", "progress": 90, "message": warning})
c.JSON(http.StatusOK, gin.H{"results": fallback, "warning": warning, "queries": queryVariants})
return
}
@@ -305,6 +312,7 @@ func (a *App) searchMedia(c *gin.Context) {
if expandErr != nil {
response["warning"] = "Gemini query expansion failed: " + expandErr.Error() + ". Using the original query only."
}
a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "search complete", "progress": 100})
c.JSON(http.StatusOK, response)
}
+16 -2
View File
@@ -13,6 +13,7 @@ const downloadUrl = document.getElementById("downloadUrl");
const downloadResult = document.getElementById("downloadResult");
const cardTemplate = document.getElementById("searchCardTemplate");
const previewModal = document.getElementById("previewModal");
const previewMediaFrame = document.getElementById("previewMediaFrame");
const previewTitle = document.getElementById("previewTitle");
const previewVideo = document.getElementById("previewVideo");
const previewThumbnail = document.getElementById("previewThumbnail");
@@ -80,7 +81,8 @@ function connectWS() {
return;
}
const data = payload.data;
setStatus(`${data.type || "task"}: ${data.status}`, Number(data.progress ?? 0));
const label = data.status || `${data.type || "task"} in progress`;
setStatus(label, Number(data.progress ?? 0));
if (data.type === "upload" && data.status === "completed") {
uploadResult.textContent = `${data.filename} saved successfully`;
}
@@ -128,7 +130,7 @@ function renderResults(results) {
searchForm.addEventListener("submit", async (event) => {
event.preventDefault();
setStatus("searching", 20);
setStatus("preparing search", 5);
searchWarning.classList.add("hidden");
try {
const data = await api("/api/search", {
@@ -169,6 +171,7 @@ function openPreviewModal(preview) {
previewVideo.pause();
previewVideo.removeAttribute("src");
previewVideo.load();
previewMediaFrame.style.aspectRatio = "";
if (preview.previewStreamUrl) {
previewVideo.src = preview.previewStreamUrl;
previewVideo.classList.remove("hidden");
@@ -199,6 +202,7 @@ function closeModal() {
previewVideo.pause();
previewVideo.removeAttribute("src");
previewVideo.load();
previewMediaFrame.style.aspectRatio = "";
previewModal.classList.add("hidden");
previewModal.classList.remove("flex");
startRange.value = "0";
@@ -298,6 +302,16 @@ setEndFromPreview.addEventListener("click", () => {
endRange.value = String(Math.floor(previewVideo.currentTime || 0));
syncRanges();
});
previewVideo.addEventListener("loadedmetadata", () => {
if (previewVideo.videoWidth > 0 && previewVideo.videoHeight > 0) {
previewMediaFrame.style.aspectRatio = `${previewVideo.videoWidth} / ${previewVideo.videoHeight}`;
}
});
previewThumbnail.addEventListener("load", () => {
if (!previewVideo.src && previewThumbnail.naturalWidth > 0 && previewThumbnail.naturalHeight > 0) {
previewMediaFrame.style.aspectRatio = `${previewThumbnail.naturalWidth} / ${previewThumbnail.naturalHeight}`;
}
});
connectWS();
setStatus("idle", 0);
+3 -3
View File
@@ -79,9 +79,9 @@
<button id="closePreviewModal" class="rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-300">Close</button>
</div>
<div class="mt-5 grid gap-5 md:grid-cols-[1.2fr_0.8fr]">
<div class="overflow-hidden rounded-3xl border border-white/10 bg-black/30">
<video id="previewVideo" class="hidden aspect-video h-full w-full bg-black object-cover" controls playsinline></video>
<img id="previewThumbnail" class="aspect-video h-full w-full object-cover" alt="" />
<div id="previewMediaFrame" class="flex min-h-[320px] items-center justify-center overflow-hidden rounded-3xl border border-white/10 bg-black/30 p-2">
<video id="previewVideo" class="hidden max-h-[60vh] w-full bg-black object-contain" controls playsinline></video>
<img id="previewThumbnail" class="max-h-[60vh] w-full object-contain" alt="" />
</div>
<div class="space-y-4">
<div class="rounded-2xl border border-white/10 bg-white/[0.03] p-4">