<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hybrid-Image-Search on ICE-ICE-BEAR-BLOG</title><link>https://ice-ice-bear.github.io/tags/hybrid-image-search/</link><description>Recent content in Hybrid-Image-Search on ICE-ICE-BEAR-BLOG</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Fri, 10 Apr 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://ice-ice-bear.github.io/tags/hybrid-image-search/index.xml" rel="self" type="application/rss+xml"/><item><title>Hybrid Image Search Dev Log #12 — Reranking Pipeline Fixes, Dual-Batch Generation, Frontend Sprint</title><link>https://ice-ice-bear.github.io/posts/2026-04-10-hybrid-search-dev12/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0900</pubDate><guid>https://ice-ice-bear.github.io/posts/2026-04-10-hybrid-search-dev12/</guid><description>&lt;img src="https://ice-ice-bear.github.io/" alt="Featured image of post Hybrid Image Search Dev Log #12 — Reranking Pipeline Fixes, Dual-Batch Generation, Frontend Sprint" /&gt;&lt;p&gt;&lt;a class="link" href="https://ice-ice-bear.github.io/ko/posts/2026-04-08-hybrid-search-dev11/" &gt;Previous: Hybrid Image Search Dev Log #11&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dev log #12 covers three major tracks. First, I tracked down and fixed four bugs that had been quietly breaking the reranking pipeline. Second, I replaced the single-tone + angle-image generation approach with a dual-batch system (3-tone and 5-tone) driven by text-based angle directives. Third, I implemented a batch of frontend components — AnglePicker, ReactionButtons, LikesTab, ImageLightbox, and FeedbackModal. Total diff: 42 files, +2,749/-662 lines.&lt;/p&gt;
&lt;h2 id="overall-work-flow"&gt;Overall Work Flow
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 A["Reranking pipeline fixes"] --&gt; B["Restore CE weight from 0.03"]
 A --&gt; C["Switch to Korean-finetuned model"]
 A --&gt; D["expanded_query → original_query"]
 A --&gt; E["geometric mean → arithmetic mean"]

 F["Multi-tone + angle text overhaul"] --&gt; G["angle_text.py &amp;lt;br/&amp;gt; lens.py presets"]
 F --&gt; H["Dual batch &amp;lt;br/&amp;gt; 3-tone / 5-tone"]
 F --&gt; I["person-intent &amp;lt;br/&amp;gt; auto model injection"]

 J["Frontend sprint"] --&gt; K["AnglePicker"]
 J --&gt; L["ReactionButtons &amp;lt;br/&amp;gt; LikesTab"]
 J --&gt; M["ImageLightbox &amp;lt;br/&amp;gt; FeedbackModal"]

 E --&gt; F
 H --&gt; J&lt;/pre&gt;&lt;h2 id="1-reranking-pipeline--four-bugs-fixed-at-once"&gt;1. Reranking Pipeline — Four Bugs Fixed at Once
&lt;/h2&gt;&lt;p&gt;Reranking was effectively doing nothing. When I traced the root cause, I found not one bug but four.&lt;/p&gt;
&lt;h3 id="problem-analysis"&gt;Problem Analysis
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Bug&lt;/th&gt;
 &lt;th&gt;Symptom&lt;/th&gt;
 &lt;th&gt;Impact&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;CE weight 0.03&lt;/td&gt;
 &lt;td&gt;Cross-Encoder scores contributed only 3% to the final score&lt;/td&gt;
 &lt;td&gt;Reranking had almost zero effect&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Model not fine-tuned on Korean&lt;/td&gt;
 &lt;td&gt;Poor relevance judgment for Korean queries&lt;/td&gt;
 &lt;td&gt;Degraded search quality&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Passing &lt;code&gt;expanded_query&lt;/code&gt; to CE&lt;/td&gt;
 &lt;td&gt;Expanded query distorted CE scores away from the original intent&lt;/td&gt;
 &lt;td&gt;Irrelevant results ranked higher&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Geometric mean&lt;/td&gt;
 &lt;td&gt;A single low sub-score dragged down otherwise strong partial matches&lt;/td&gt;
 &lt;td&gt;Good partial matches disappeared from results&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="fix"&gt;Fix
&lt;/h3&gt;&lt;p&gt;All four were fixed together. CE weight was restored to a sensible value, &lt;code&gt;original_query&lt;/code&gt; replaced &lt;code&gt;expanded_query&lt;/code&gt; as the Cross-Encoder input, and geometric mean was replaced with arithmetic mean.&lt;/p&gt;
&lt;p&gt;I also attempted a model upgrade. &lt;code&gt;bge-reranker-v2-m3&lt;/code&gt; (568M parameters) showed noticeably better Korean performance, but took 16 seconds per component on an EC2 CPU — not viable in production. I rolled back to &lt;code&gt;mmarco-mMiniLMv2&lt;/code&gt; (136M) and kept the other three fixes.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 subgraph Before["Before"]
 Q1["expanded_query"] --&gt; CE1["CE &amp;lt;br/&amp;gt; weight=0.03"]
 CE1 --&gt; GM["geometric mean"]
 end

 subgraph After["After"]
 Q2["original_query"] --&gt; CE2["CE &amp;lt;br/&amp;gt; weight restored"]
 CE2 --&gt; AM["arithmetic mean"]
 end

 Before --&gt;|"4 bugs fixed"| After&lt;/pre&gt;&lt;h2 id="2-multi-tone--angle-text-overhaul"&gt;2. Multi-Tone + Angle Text Overhaul
&lt;/h2&gt;&lt;p&gt;The previous approach injected a single tone and a single angle reference image per generation. This sprint replaced that entirely.&lt;/p&gt;
&lt;h3 id="angle-from-images-to-text-directives"&gt;Angle: From Images to Text Directives
&lt;/h3&gt;&lt;p&gt;I removed angle reference images and switched to text-based presets. &lt;code&gt;angle_text.py&lt;/code&gt; defines presets like &amp;ldquo;45-degree downward angle,&amp;rdquo; &amp;ldquo;overhead,&amp;rdquo; and &amp;ldquo;eye level.&amp;rdquo; &lt;code&gt;lens.py&lt;/code&gt; adds per-category focal length presets (e.g., 85mm for portraits, 24mm for landscapes).&lt;/p&gt;
&lt;p&gt;The advantage is straightforward: no more cost of finding and managing angle reference images, and finer control is possible at the prompt level.&lt;/p&gt;
&lt;h3 id="tone-single--dual-batch-3-tone--5-tone"&gt;Tone: Single → Dual Batch (3-tone / 5-tone)
&lt;/h3&gt;&lt;p&gt;A single generation request now runs a 3-tone batch and a 5-tone batch in parallel. Users can compare results via a tone3/tone5 toggle in the frontend. The DB schema was updated to add multi-tone columns, and &lt;code&gt;log_generation&lt;/code&gt; was updated accordingly.&lt;/p&gt;
&lt;h3 id="person-intent-auto-model-injection"&gt;person-intent Auto Model Injection
&lt;/h3&gt;&lt;p&gt;An &lt;code&gt;intent_person&lt;/code&gt; field was added to the Gemini classification prompt. If the user&amp;rsquo;s reference images contain no people but the query implies a person, the system automatically injects a model image from the &lt;code&gt;refs/model_image_ref/&lt;/code&gt; directory. This covers the case where the intent is person-focused but the uploaded references don&amp;rsquo;t include any people.&lt;/p&gt;
&lt;h2 id="3-frontend-feature-sprint"&gt;3. Frontend Feature Sprint
&lt;/h2&gt;&lt;p&gt;Frontend components were built out to match the backend changes.&lt;/p&gt;
&lt;h3 id="new-components"&gt;New Components
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AnglePicker&lt;/strong&gt; — Search and select angle presets. Fetches the list from &lt;code&gt;/api/angle-presets&lt;/code&gt;. Integrated into the detail page so the angle can be changed after generation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ReactionButtons&lt;/strong&gt; — Quick emoji reaction buttons for generated images.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LikesTab&lt;/strong&gt; — A gallery tab collecting all images the user has liked.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ImageLightbox&lt;/strong&gt; — Expanded view on thumbnail click.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FeedbackModal&lt;/strong&gt; — A modal for submitting detailed text-based feedback.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dual-batch-ui"&gt;Dual-Batch UI
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;MAX_REFS&lt;/code&gt; was raised to 7 on the frontend, and dual-batch generation is now supported. The detail page shows multi-tone metadata and a tone3/tone5 toggle.&lt;/p&gt;
&lt;h3 id="api-endpoints"&gt;API Endpoints
&lt;/h3&gt;&lt;p&gt;Added &lt;code&gt;GET /api/angle-presets&lt;/code&gt;, reaction and feedback endpoints, and updated API interface type definitions.&lt;/p&gt;
&lt;h2 id="4-production-server-debugging--infrastructure"&gt;4. Production Server Debugging &amp;amp; Infrastructure
&lt;/h2&gt;&lt;h3 id="grafana-data-missing"&gt;Grafana Data Missing
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;DEPLOYMENT_ENV&lt;/code&gt; was not set, and a missing newline in the &lt;code&gt;.env&lt;/code&gt; file was causing the S3 path to be assembled incorrectly. Both were fixed to restore monitoring data collection.&lt;/p&gt;
&lt;h3 id="missing-db-migration"&gt;Missing DB Migration
&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;injected_model_filename&lt;/code&gt; column was absent from the production database, causing the auto model injection feature to fail. A migration script was added to resolve this.&lt;/p&gt;
&lt;h3 id="infrastructure-improvements"&gt;Infrastructure Improvements
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Switched prod SSH key to ed25519 and added a lifecycle guard&lt;/li&gt;
&lt;li&gt;Closed open ports and configured nginx reverse proxy&lt;/li&gt;
&lt;li&gt;Removed duplicate 401 errors that occurred during startup auth checks&lt;/li&gt;
&lt;li&gt;Fixed mobile responsive layout&lt;/li&gt;
&lt;li&gt;Updated Security Group descriptions to match AWS validation requirements&lt;/li&gt;
&lt;li&gt;Removed &lt;code&gt;APP_ENVIRONMENT&lt;/code&gt; from ecosystem.config.js&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wrap-up"&gt;Wrap-Up
&lt;/h2&gt;&lt;p&gt;The most meaningful work in this sprint was the reranking fix. Four bugs coexisted in a way that masked each other&amp;rsquo;s effects — fixing them one at a time actually made results worse in some cases. Only after fixing all four simultaneously did reranking start working correctly.&lt;/p&gt;
&lt;p&gt;The dual-batch generation and text-based angle directives haven&amp;rsquo;t gathered enough user feedback yet. The next step is to use reaction and feedback data to validate whether 3-tone or 5-tone is preferred, and whether text angle presets actually outperform angle reference images.&lt;/p&gt;</description></item></channel></rss>