Spaces:
Running
Running
RobertoBarrosoLuque
commited on
Commit
·
6903420
1
Parent(s):
75361de
Cleanup
Browse files- src/app.py +35 -20
- src/config.py +66 -30
- src/constants/code_snippets.py +0 -120
src/app.py
CHANGED
|
@@ -14,13 +14,6 @@ from src.search.vector_search import (
|
|
| 14 |
search_vector_with_reranking,
|
| 15 |
)
|
| 16 |
from src.data_prep.data_prep import load_clean_amazon_product_data
|
| 17 |
-
from src.constants.code_snippets import (
|
| 18 |
-
CODE_STAGE_1,
|
| 19 |
-
CODE_STAGE_2,
|
| 20 |
-
CODE_STAGE_3,
|
| 21 |
-
CODE_STAGE_4,
|
| 22 |
-
)
|
| 23 |
-
|
| 24 |
|
| 25 |
_FILE_PATH = Path(__file__).parents[1]
|
| 26 |
|
|
@@ -268,11 +261,37 @@ def generate_comparison_table(all_metrics: List[Dict]) -> str:
|
|
| 268 |
|
| 269 |
html += "\n---\n\n"
|
| 270 |
html += "## Key Insights\n\n"
|
| 271 |
-
html += f"- **Top-1
|
| 272 |
-
html += f"- **
|
| 273 |
-
html +=
|
| 274 |
-
html += "- Each stage
|
| 275 |
-
html += "-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
|
| 277 |
return html
|
| 278 |
|
|
@@ -376,6 +395,10 @@ with gr.Blocks(
|
|
| 376 |
"""
|
| 377 |
<h1 class="header-title" style="font-size: 2.5em; text-align: left;">Search Alchemy</h1>
|
| 378 |
<p style="color: #64748B; font-size: 1.1em; margin-top: 0; text-align: left;">Building Production Search Pipelines with Fireworks AI</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
"""
|
| 380 |
)
|
| 381 |
with gr.Row(elem_classes="compact-header"):
|
|
@@ -430,23 +453,15 @@ with gr.Blocks(
|
|
| 430 |
|
| 431 |
with gr.Tab("Stage 1: BM25 Baseline"):
|
| 432 |
stage1_output = gr.Markdown(label="Results")
|
| 433 |
-
with gr.Accordion("Show Code", open=False):
|
| 434 |
-
gr.Markdown(CODE_STAGE_1)
|
| 435 |
|
| 436 |
with gr.Tab("Stage 2: + Vector Embeddings"):
|
| 437 |
stage2_output = gr.Markdown(label="Results")
|
| 438 |
-
with gr.Accordion("Show Code", open=False):
|
| 439 |
-
gr.Markdown(CODE_STAGE_2)
|
| 440 |
|
| 441 |
with gr.Tab("Stage 3: + Query Expansion"):
|
| 442 |
stage3_output = gr.Markdown(label="Results")
|
| 443 |
-
with gr.Accordion("Show Code", open=False):
|
| 444 |
-
gr.Markdown(CODE_STAGE_3)
|
| 445 |
|
| 446 |
with gr.Tab("Stage 4: + LLM Reranking"):
|
| 447 |
stage4_output = gr.Markdown(label="Results")
|
| 448 |
-
with gr.Accordion("Show Code", open=False):
|
| 449 |
-
gr.Markdown(CODE_STAGE_4)
|
| 450 |
|
| 451 |
with gr.Tab("Compare All Stages"):
|
| 452 |
comparison_output = gr.Markdown(label="Comparison")
|
|
|
|
| 14 |
search_vector_with_reranking,
|
| 15 |
)
|
| 16 |
from src.data_prep.data_prep import load_clean_amazon_product_data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
_FILE_PATH = Path(__file__).parents[1]
|
| 19 |
|
|
|
|
| 261 |
|
| 262 |
html += "\n---\n\n"
|
| 263 |
html += "## Key Insights\n\n"
|
| 264 |
+
html += f"- **Relevance Improvement**: Top-1 score increases by **{top1_improvement:.0f}%**, Top-5 average by **{top5_improvement:.0f}%**\n"
|
| 265 |
+
html += f"- **Production-Ready Performance**: All stages complete in under **{max(m['latency_ms'] for m in all_metrics)}ms**\n"
|
| 266 |
+
html += "- **Semantic Understanding**: Vector embeddings provide the largest single improvement in search quality\n"
|
| 267 |
+
html += "- **Progressive Enhancement**: Each stage builds upon the previous, creating a robust pipeline\n"
|
| 268 |
+
html += "- **Real-World Applicability**: This architecture scales to millions of documents with proper infrastructure\n"
|
| 269 |
+
|
| 270 |
+
html += "\n\n---\n\n"
|
| 271 |
+
html += """
|
| 272 |
+
<div style="background: #FFF7ED; border-left: 4px solid #F97316; padding: 20px; border-radius: 8px; margin-top: 24px;">
|
| 273 |
+
<h3 style="color: #C2410C; margin-top: 0; font-size: 1.2em;">
|
| 274 |
+
💡 Understanding Reranker Scores
|
| 275 |
+
</h3>
|
| 276 |
+
<p style="color: #7C2D12; font-size: 1.0em; line-height: 1.6; margin-bottom: 12px;">
|
| 277 |
+
<strong>Note:</strong> You may notice that reranking shows the <em>same cosine similarity scores</em> from Stage 2
|
| 278 |
+
despite improved result ordering. This is intentional and highlights an important concept:
|
| 279 |
+
</p>
|
| 280 |
+
<ul style="color: #7C2D12; font-size: 0.95em; line-height: 1.7; margin-left: 20px;">
|
| 281 |
+
<li><strong>Different ranking mechanisms:</strong> Cosine similarity measures vector distance in embedding space,
|
| 282 |
+
while rerankers use cross-encoder models that analyze query-document pairs directly for deeper semantic understanding.</li>
|
| 283 |
+
<li><strong>Why reranking works better:</strong> Cross-encoders examine token-level interactions between the query
|
| 284 |
+
and each document, capturing nuances that simple vector distance misses.</li>
|
| 285 |
+
<li><strong>The scores displayed:</strong> We preserve cosine scores to show that reranking <em>reorders</em> results
|
| 286 |
+
based on relevance, not similarity. A document with slightly lower cosine similarity might be more contextually relevant.</li>
|
| 287 |
+
<li><strong>Production best practice:</strong> Use fast vector search to retrieve candidates (~100-1000 results),
|
| 288 |
+
then apply computationally expensive reranking to the top results for maximum accuracy.</li>
|
| 289 |
+
</ul>
|
| 290 |
+
<p style="color: #7C2D12; font-size: 0.9em; margin-top: 12px; font-style: italic;">
|
| 291 |
+
This two-stage approach (retrieve + rerank) is the industry standard for building high-quality search systems at scale.
|
| 292 |
+
</p>
|
| 293 |
+
</div>
|
| 294 |
+
"""
|
| 295 |
|
| 296 |
return html
|
| 297 |
|
|
|
|
| 395 |
"""
|
| 396 |
<h1 class="header-title" style="font-size: 2.5em; text-align: left;">Search Alchemy</h1>
|
| 397 |
<p style="color: #64748B; font-size: 1.1em; margin-top: 0; text-align: left;">Building Production Search Pipelines with Fireworks AI</p>
|
| 398 |
+
<p style="color: #475569; font-size: 1.0em; line-height: 1.6; margin: 0;">
|
| 399 |
+
Four progressive stages demonstrating production-grade semantic search:
|
| 400 |
+
<strong>BM25</strong> → <strong>Vector Embeddings</strong> → <strong>Query Expansion</strong> → <strong>Reranking</strong>
|
| 401 |
+
</p>
|
| 402 |
"""
|
| 403 |
)
|
| 404 |
with gr.Row(elem_classes="compact-header"):
|
|
|
|
| 453 |
|
| 454 |
with gr.Tab("Stage 1: BM25 Baseline"):
|
| 455 |
stage1_output = gr.Markdown(label="Results")
|
|
|
|
|
|
|
| 456 |
|
| 457 |
with gr.Tab("Stage 2: + Vector Embeddings"):
|
| 458 |
stage2_output = gr.Markdown(label="Results")
|
|
|
|
|
|
|
| 459 |
|
| 460 |
with gr.Tab("Stage 3: + Query Expansion"):
|
| 461 |
stage3_output = gr.Markdown(label="Results")
|
|
|
|
|
|
|
| 462 |
|
| 463 |
with gr.Tab("Stage 4: + LLM Reranking"):
|
| 464 |
stage4_output = gr.Markdown(label="Results")
|
|
|
|
|
|
|
| 465 |
|
| 466 |
with gr.Tab("Compare All Stages"):
|
| 467 |
comparison_output = gr.Markdown(label="Comparison")
|
src/config.py
CHANGED
|
@@ -69,33 +69,35 @@ CUSTOM_CSS = """
|
|
| 69 |
.result-card {
|
| 70 |
background: white;
|
| 71 |
border-radius: 12px;
|
| 72 |
-
padding:
|
| 73 |
-
margin:
|
| 74 |
-
box-shadow: 0 2px
|
| 75 |
border: 1px solid #E6EAF4;
|
| 76 |
-
transition: all 0.
|
| 77 |
}
|
| 78 |
|
| 79 |
.result-card:hover {
|
| 80 |
-
|
|
|
|
| 81 |
border-color: #C4B5FD;
|
| 82 |
}
|
| 83 |
|
| 84 |
.metric-box {
|
| 85 |
-
background: linear-gradient(
|
| 86 |
-
border-left:
|
| 87 |
-
padding:
|
| 88 |
margin: 8px 0;
|
| 89 |
-
border-radius:
|
| 90 |
font-size: 0.9em;
|
|
|
|
| 91 |
}
|
| 92 |
|
| 93 |
.code-section {
|
| 94 |
-
background: linear-gradient(
|
| 95 |
-
border-left:
|
| 96 |
-
padding:
|
| 97 |
margin: 12px 0;
|
| 98 |
-
border-radius:
|
| 99 |
font-family: 'JetBrains Mono', monospace;
|
| 100 |
font-size: 0.9em;
|
| 101 |
}
|
|
@@ -104,62 +106,76 @@ CUSTOM_CSS = """
|
|
| 104 |
width: 100%;
|
| 105 |
border-collapse: collapse;
|
| 106 |
margin: 20px 0;
|
|
|
|
|
|
|
|
|
|
| 107 |
}
|
| 108 |
|
| 109 |
.comparison-table th {
|
| 110 |
-
background: #6720FF;
|
| 111 |
color: white;
|
| 112 |
-
padding:
|
| 113 |
text-align: left;
|
| 114 |
font-weight: 600;
|
|
|
|
|
|
|
|
|
|
| 115 |
}
|
| 116 |
|
| 117 |
.comparison-table td {
|
| 118 |
-
padding:
|
| 119 |
border-bottom: 1px solid #E6EAF4;
|
|
|
|
| 120 |
}
|
| 121 |
|
| 122 |
-
.comparison-table tr:hover {
|
| 123 |
-
background: #
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
}
|
| 125 |
|
| 126 |
::-webkit-scrollbar {
|
| 127 |
-
width:
|
| 128 |
-
height:
|
| 129 |
}
|
| 130 |
|
| 131 |
::-webkit-scrollbar-track {
|
| 132 |
background: #F3F0FF;
|
| 133 |
-
border-radius:
|
| 134 |
}
|
| 135 |
|
| 136 |
::-webkit-scrollbar-thumb {
|
| 137 |
-
background: #C4B5FD;
|
| 138 |
-
border-radius:
|
| 139 |
}
|
| 140 |
|
| 141 |
::-webkit-scrollbar-thumb:hover {
|
| 142 |
-
background: #A78BFA;
|
| 143 |
}
|
| 144 |
|
| 145 |
details {
|
| 146 |
border: 1px solid #E6EAF4;
|
| 147 |
-
border-radius:
|
| 148 |
-
padding:
|
| 149 |
-
margin:
|
| 150 |
background: white;
|
|
|
|
| 151 |
}
|
| 152 |
|
| 153 |
details[open] {
|
| 154 |
-
border-color: #
|
| 155 |
-
box-shadow: 0 4px
|
| 156 |
}
|
| 157 |
|
| 158 |
summary {
|
| 159 |
font-weight: 600;
|
| 160 |
color: #6720FF;
|
| 161 |
cursor: pointer;
|
| 162 |
-
padding:
|
|
|
|
|
|
|
| 163 |
}
|
| 164 |
|
| 165 |
summary:hover {
|
|
@@ -181,6 +197,26 @@ summary:hover {
|
|
| 181 |
font-size: 0.85em;
|
| 182 |
padding: 8px 12px;
|
| 183 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
"""
|
| 185 |
|
| 186 |
|
|
|
|
| 69 |
.result-card {
|
| 70 |
background: white;
|
| 71 |
border-radius: 12px;
|
| 72 |
+
padding: 18px;
|
| 73 |
+
margin: 10px 0;
|
| 74 |
+
box-shadow: 0 2px 6px rgba(103, 32, 255, 0.08);
|
| 75 |
border: 1px solid #E6EAF4;
|
| 76 |
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
| 77 |
}
|
| 78 |
|
| 79 |
.result-card:hover {
|
| 80 |
+
transform: translateY(-2px);
|
| 81 |
+
box-shadow: 0 6px 16px rgba(103, 32, 255, 0.15);
|
| 82 |
border-color: #C4B5FD;
|
| 83 |
}
|
| 84 |
|
| 85 |
.metric-box {
|
| 86 |
+
background: linear-gradient(135deg, #F3F0FF 0%, #FFFFFF 100%);
|
| 87 |
+
border-left: 4px solid #6720FF;
|
| 88 |
+
padding: 16px;
|
| 89 |
margin: 8px 0;
|
| 90 |
+
border-radius: 10px;
|
| 91 |
font-size: 0.9em;
|
| 92 |
+
box-shadow: 0 2px 4px rgba(103, 32, 255, 0.05);
|
| 93 |
}
|
| 94 |
|
| 95 |
.code-section {
|
| 96 |
+
background: linear-gradient(135deg, #F3F0FF 0%, #FFFFFF 100%);
|
| 97 |
+
border-left: 4px solid #6720FF;
|
| 98 |
+
padding: 18px;
|
| 99 |
margin: 12px 0;
|
| 100 |
+
border-radius: 10px;
|
| 101 |
font-family: 'JetBrains Mono', monospace;
|
| 102 |
font-size: 0.9em;
|
| 103 |
}
|
|
|
|
| 106 |
width: 100%;
|
| 107 |
border-collapse: collapse;
|
| 108 |
margin: 20px 0;
|
| 109 |
+
box-shadow: 0 2px 8px rgba(103, 32, 255, 0.08);
|
| 110 |
+
border-radius: 10px;
|
| 111 |
+
overflow: hidden;
|
| 112 |
}
|
| 113 |
|
| 114 |
.comparison-table th {
|
| 115 |
+
background: linear-gradient(135deg, #6720FF 0%, #7B2FFF 100%);
|
| 116 |
color: white;
|
| 117 |
+
padding: 14px;
|
| 118 |
text-align: left;
|
| 119 |
font-weight: 600;
|
| 120 |
+
text-transform: uppercase;
|
| 121 |
+
font-size: 0.85em;
|
| 122 |
+
letter-spacing: 0.5px;
|
| 123 |
}
|
| 124 |
|
| 125 |
.comparison-table td {
|
| 126 |
+
padding: 14px;
|
| 127 |
border-bottom: 1px solid #E6EAF4;
|
| 128 |
+
background: white;
|
| 129 |
}
|
| 130 |
|
| 131 |
+
.comparison-table tr:hover td {
|
| 132 |
+
background: #F8F7FF;
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
.comparison-table tr:last-child td {
|
| 136 |
+
border-bottom: none;
|
| 137 |
}
|
| 138 |
|
| 139 |
::-webkit-scrollbar {
|
| 140 |
+
width: 10px;
|
| 141 |
+
height: 10px;
|
| 142 |
}
|
| 143 |
|
| 144 |
::-webkit-scrollbar-track {
|
| 145 |
background: #F3F0FF;
|
| 146 |
+
border-radius: 5px;
|
| 147 |
}
|
| 148 |
|
| 149 |
::-webkit-scrollbar-thumb {
|
| 150 |
+
background: linear-gradient(135deg, #C4B5FD 0%, #A78BFA 100%);
|
| 151 |
+
border-radius: 5px;
|
| 152 |
}
|
| 153 |
|
| 154 |
::-webkit-scrollbar-thumb:hover {
|
| 155 |
+
background: linear-gradient(135deg, #A78BFA 0%, #8B5CF6 100%);
|
| 156 |
}
|
| 157 |
|
| 158 |
details {
|
| 159 |
border: 1px solid #E6EAF4;
|
| 160 |
+
border-radius: 12px;
|
| 161 |
+
padding: 14px;
|
| 162 |
+
margin: 12px 0;
|
| 163 |
background: white;
|
| 164 |
+
transition: all 0.3s ease;
|
| 165 |
}
|
| 166 |
|
| 167 |
details[open] {
|
| 168 |
+
border-color: #C4B5FD;
|
| 169 |
+
box-shadow: 0 4px 16px rgba(103, 32, 255, 0.12);
|
| 170 |
}
|
| 171 |
|
| 172 |
summary {
|
| 173 |
font-weight: 600;
|
| 174 |
color: #6720FF;
|
| 175 |
cursor: pointer;
|
| 176 |
+
padding: 6px;
|
| 177 |
+
user-select: none;
|
| 178 |
+
transition: color 0.2s ease;
|
| 179 |
}
|
| 180 |
|
| 181 |
summary:hover {
|
|
|
|
| 197 |
font-size: 0.85em;
|
| 198 |
padding: 8px 12px;
|
| 199 |
}
|
| 200 |
+
|
| 201 |
+
/* Tab styling */
|
| 202 |
+
.tabs button {
|
| 203 |
+
transition: all 0.2s ease;
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
.tabs button[aria-selected="true"] {
|
| 207 |
+
border-bottom: 3px solid #6720FF !important;
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
/* Button enhancements */
|
| 211 |
+
button.primary {
|
| 212 |
+
background: linear-gradient(135deg, #6720FF 0%, #7B2FFF 100%) !important;
|
| 213 |
+
transition: all 0.3s ease !important;
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
button.primary:hover {
|
| 217 |
+
transform: translateY(-1px);
|
| 218 |
+
box-shadow: 0 4px 12px rgba(103, 32, 255, 0.25) !important;
|
| 219 |
+
}
|
| 220 |
"""
|
| 221 |
|
| 222 |
|
src/constants/code_snippets.py
DELETED
|
@@ -1,120 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
Code snippets for displaying implementation examples in the Gradio UI.
|
| 3 |
-
Each snippet shows the actual implementation approach for each search stage.
|
| 4 |
-
"""
|
| 5 |
-
|
| 6 |
-
CODE_STAGE_1 = """
|
| 7 |
-
```python
|
| 8 |
-
import bm25s
|
| 9 |
-
import pandas as pd
|
| 10 |
-
|
| 11 |
-
# Step 1: Create BM25 index (one-time setup)
|
| 12 |
-
df = pd.read_parquet("data/amazon_products.parquet")
|
| 13 |
-
corpus = df["FullText"].tolist()
|
| 14 |
-
corpus_tokens = bm25s.tokenize(corpus, stopwords="en")
|
| 15 |
-
|
| 16 |
-
retriever = bm25s.BM25()
|
| 17 |
-
retriever.index(corpus_tokens)
|
| 18 |
-
retriever.save("data/bm25_index")
|
| 19 |
-
|
| 20 |
-
# Step 2: Load index and search
|
| 21 |
-
bm25_index = bm25s.BM25.load("data/bm25_index", load_corpus=False)
|
| 22 |
-
query_tokens = bm25s.tokenize(query, stopwords="en")
|
| 23 |
-
results, scores = bm25_index.retrieve(query_tokens, k=5)
|
| 24 |
-
|
| 25 |
-
# Extract top results
|
| 26 |
-
top_products = [df.iloc[idx] for idx in results[0]]
|
| 27 |
-
```
|
| 28 |
-
"""
|
| 29 |
-
|
| 30 |
-
CODE_STAGE_2 = """
|
| 31 |
-
```python
|
| 32 |
-
from openai import OpenAI
|
| 33 |
-
import faiss
|
| 34 |
-
import numpy as np
|
| 35 |
-
|
| 36 |
-
# Initialize Fireworks AI client
|
| 37 |
-
client = OpenAI(
|
| 38 |
-
api_key="your_fireworks_api_key",
|
| 39 |
-
base_url="https://api.fireworks.ai/inference/v1"
|
| 40 |
-
)
|
| 41 |
-
|
| 42 |
-
# Generate query embedding
|
| 43 |
-
response = client.embeddings.create(
|
| 44 |
-
model="accounts/fireworks/models/qwen3-embedding-8b",
|
| 45 |
-
input=query
|
| 46 |
-
)
|
| 47 |
-
query_embedding = np.array(response.data[0].embedding, dtype=np.float32)
|
| 48 |
-
query_vector = query_embedding.reshape(1, -1)
|
| 49 |
-
|
| 50 |
-
# Normalize for cosine similarity using L2 distance
|
| 51 |
-
faiss.normalize_L2(query_vector)
|
| 52 |
-
|
| 53 |
-
# Load pre-built FAISS index
|
| 54 |
-
index = faiss.read_index("data/faiss_index.bin")
|
| 55 |
-
|
| 56 |
-
# Search for top-k similar documents
|
| 57 |
-
distances, indices = index.search(query_vector, k=10)
|
| 58 |
-
|
| 59 |
-
# Convert L2 distances to cosine similarity scores
|
| 60 |
-
# After normalization: L2_distance = 2 * (1 - cosine_similarity)
|
| 61 |
-
# So: cosine_similarity = 1 - (L2_distance / 2)
|
| 62 |
-
similarity_scores = 1 - (distances[0] / 2)
|
| 63 |
-
|
| 64 |
-
# Get top results
|
| 65 |
-
top_results = [
|
| 66 |
-
{
|
| 67 |
-
"product": df.iloc[idx],
|
| 68 |
-
"score": float(score)
|
| 69 |
-
}
|
| 70 |
-
for idx, score in zip(indices[0], similarity_scores)
|
| 71 |
-
]
|
| 72 |
-
```
|
| 73 |
-
"""
|
| 74 |
-
|
| 75 |
-
CODE_STAGE_3 = """
|
| 76 |
-
```python
|
| 77 |
-
# Query expansion with LLM
|
| 78 |
-
response = client.chat.completions.create(
|
| 79 |
-
model="accounts/fireworks/models/llama-v3p1-8b-instruct",
|
| 80 |
-
messages=[{
|
| 81 |
-
"role": "user",
|
| 82 |
-
"content": f"Extract 2-3 key search concepts from: {query}"
|
| 83 |
-
}]
|
| 84 |
-
)
|
| 85 |
-
|
| 86 |
-
expanded_query = response.choices[0].message.content
|
| 87 |
-
|
| 88 |
-
# Search with expanded query
|
| 89 |
-
response = client.embeddings.create(
|
| 90 |
-
model="accounts/fireworks/models/qwen3-embedding-8b",
|
| 91 |
-
input=[expanded_query] + documents
|
| 92 |
-
)
|
| 93 |
-
|
| 94 |
-
# Continue with embedding search...
|
| 95 |
-
```
|
| 96 |
-
"""
|
| 97 |
-
|
| 98 |
-
CODE_STAGE_4 = """
|
| 99 |
-
```python
|
| 100 |
-
# First get top 20 candidates from Stage 3
|
| 101 |
-
top_20_results = get_stage_3_results(query, k=20)
|
| 102 |
-
|
| 103 |
-
# Rerank with Fireworks reranker
|
| 104 |
-
rerank_response = client.post(
|
| 105 |
-
"https://api.fireworks.ai/inference/v1/rerank",
|
| 106 |
-
json={
|
| 107 |
-
"model": "fireworks/qwen3-reranker-8b",
|
| 108 |
-
"query": query,
|
| 109 |
-
"documents": [r["text"] for r in top_20_results],
|
| 110 |
-
"top_n": 5
|
| 111 |
-
}
|
| 112 |
-
)
|
| 113 |
-
|
| 114 |
-
# Get final ranked results
|
| 115 |
-
final_results = [
|
| 116 |
-
top_20_results[r["index"]]
|
| 117 |
-
for r in rerank_response.json()["results"]
|
| 118 |
-
]
|
| 119 |
-
```
|
| 120 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|