admin commited on
Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
"""
|
| 2 |
Hunter Omega — Live NIAH Demo
|
| 3 |
One-click needle in a haystack test from 8K to 12M tokens.
|
| 4 |
-
|
| 5 |
"""
|
| 6 |
import gradio as gr
|
| 7 |
import requests
|
|
@@ -13,7 +13,6 @@ import os
|
|
| 13 |
API_URL = os.environ.get("HUNTER_API")
|
| 14 |
MODEL = "hunter-omega-12m-fast"
|
| 15 |
|
| 16 |
-
# Diverse filler paragraphs (no repetition)
|
| 17 |
FILLERS = [
|
| 18 |
"The evolution of distributed systems has fundamentally changed how we architect software. Microservices emerged as a response to monolithic limitations, enabling teams to deploy independently and scale specific components. Service meshes handle the complexity of inter-service communication, providing observability and traffic management.",
|
| 19 |
"Machine learning pipelines require careful orchestration from data ingestion through model deployment. Feature stores centralize feature computation and serving, ensuring consistency between training and inference. MLOps practices bring version control and automated testing to model development workflows.",
|
|
@@ -32,9 +31,14 @@ FILLERS = [
|
|
| 32 |
"Robotics integrates sensing planning and actuation for autonomous interaction. Simultaneous localization and mapping builds environment models while tracking position. Motion planning finds collision-free paths through configuration spaces.",
|
| 33 |
]
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
def generate_needle():
|
| 37 |
-
"""Generate a random unique passphrase that can't be guessed."""
|
| 38 |
code = ''.join(random.choices(string.ascii_uppercase, k=4))
|
| 39 |
nums = ''.join(random.choices(string.digits, k=4))
|
| 40 |
word = random.choice(["ALPHA", "BRAVO", "DELTA", "ECHO", "FOXTROT", "GOLF", "HOTEL",
|
|
@@ -44,7 +48,6 @@ def generate_needle():
|
|
| 44 |
|
| 45 |
|
| 46 |
def generate_haystack(target_tokens):
|
| 47 |
-
"""Generate diverse filler text of target token count."""
|
| 48 |
words = []
|
| 49 |
target_words = target_tokens * 3 // 4
|
| 50 |
i = 0
|
|
@@ -54,178 +57,138 @@ def generate_haystack(target_tokens):
|
|
| 54 |
return words[:target_words]
|
| 55 |
|
| 56 |
|
| 57 |
-
def
|
| 58 |
-
"""
|
|
|
|
| 59 |
needle_code = generate_needle()
|
| 60 |
needle = f"The classified authorization code for Operation Starfall is {needle_code}."
|
| 61 |
query = "What is the classified authorization code for Operation Starfall? State ONLY the code."
|
|
|
|
| 62 |
|
| 63 |
# Generate haystack
|
| 64 |
-
words = generate_haystack(
|
| 65 |
-
depth = random.randint(10, 90)
|
| 66 |
insert_pos = int(len(words) * depth / 100)
|
| 67 |
words.insert(insert_pos, needle)
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
actual_words = len(haystack.split())
|
| 71 |
-
actual_tokens_est = actual_words * 4 // 3
|
| 72 |
-
|
| 73 |
-
# Query the model
|
| 74 |
-
t0 = time.time()
|
| 75 |
-
try:
|
| 76 |
-
r = requests.post(API_URL, json={
|
| 77 |
-
"model": MODEL,
|
| 78 |
-
"messages": [{"role": "user", "content": haystack + "\n\n" + query}],
|
| 79 |
-
"max_tokens": 50,
|
| 80 |
-
"temperature": 0,
|
| 81 |
-
}, timeout=300)
|
| 82 |
-
elapsed = time.time() - t0
|
| 83 |
-
|
| 84 |
-
if r.status_code != 200:
|
| 85 |
-
return f"Server returned {r.status_code}. Server may be busy, please retry.", "", "", ""
|
| 86 |
-
|
| 87 |
-
d = r.json()
|
| 88 |
-
answer = d["choices"][0]["message"]["content"]
|
| 89 |
-
found = needle_code.lower() in answer.lower()
|
| 90 |
|
| 91 |
-
|
| 92 |
-
|
| 93 |
|
| 94 |
-
**Context:** {
|
| 95 |
-
**
|
| 96 |
-
**
|
| 97 |
-
**
|
|
|
|
| 98 |
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
**Passphrase:** {needle_code}"""
|
| 102 |
-
|
| 103 |
-
return result_text, needle_info, status, f"{elapsed:.1f}s"
|
| 104 |
-
|
| 105 |
-
except requests.exceptions.Timeout:
|
| 106 |
-
return "Request timed out. Server may be processing other requests. Please retry.", "", "TIMEOUT", ""
|
| 107 |
-
except Exception as e:
|
| 108 |
-
return f"Connection error. Server may be busy. Please retry in a moment.", "", "ERROR", ""
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
def run_niah_extended(context_tokens):
|
| 112 |
-
"""Run NIAH test beyond 1M using the overflow pipeline."""
|
| 113 |
-
needle_code = generate_needle()
|
| 114 |
-
needle = f"The classified authorization code for Operation Starfall is {needle_code}."
|
| 115 |
-
query = "What is the classified authorization code for Operation Starfall? State ONLY the code."
|
| 116 |
-
|
| 117 |
-
# Generate document
|
| 118 |
-
words = generate_haystack(context_tokens)
|
| 119 |
-
depth = random.randint(55, 95) # Always in overflow portion
|
| 120 |
-
insert_pos = int(len(words) * depth / 100)
|
| 121 |
-
words.insert(insert_pos, needle)
|
| 122 |
-
doc = " ".join(words)
|
| 123 |
-
|
| 124 |
-
actual_words = len(doc.split())
|
| 125 |
-
actual_tokens_est = actual_words * 4 // 3
|
| 126 |
-
|
| 127 |
-
user_id = f"demo_{random.randint(100000, 999999)}"
|
| 128 |
-
api_base = API_URL.replace("/v1/chat/completions", "")
|
| 129 |
-
|
| 130 |
-
# Upload document
|
| 131 |
-
t0 = time.time()
|
| 132 |
-
try:
|
| 133 |
-
r = requests.post(f"{api_base}/v1/documents", json={
|
| 134 |
-
"user_id": user_id,
|
| 135 |
-
"text": doc,
|
| 136 |
-
}, timeout=1800)
|
| 137 |
-
upload_time = time.time() - t0
|
| 138 |
-
|
| 139 |
-
if r.status_code != 200:
|
| 140 |
-
return f"Upload failed ({r.status_code}). Server may be busy.", "", "", ""
|
| 141 |
-
|
| 142 |
-
info = r.json()
|
| 143 |
-
chunks = info.get("overflow_chunks", 0)
|
| 144 |
-
|
| 145 |
-
# Query
|
| 146 |
-
t1 = time.time()
|
| 147 |
-
r = requests.post(API_URL, json={
|
| 148 |
-
"model": MODEL,
|
| 149 |
-
"messages": [{"role": "user", "content": query}],
|
| 150 |
-
"max_tokens": 50,
|
| 151 |
-
"temperature": 0,
|
| 152 |
-
"user": user_id,
|
| 153 |
-
}, timeout=600)
|
| 154 |
-
query_time = time.time() - t1
|
| 155 |
-
total_time = time.time() - t0
|
| 156 |
-
|
| 157 |
-
# Cleanup
|
| 158 |
-
requests.delete(f"{api_base}/v1/documents/{user_id}", timeout=10)
|
| 159 |
-
|
| 160 |
-
if r.status_code != 200:
|
| 161 |
-
return f"Query failed ({r.status_code}). Server may be busy.", "", "", ""
|
| 162 |
-
|
| 163 |
-
d = r.json()
|
| 164 |
-
answer = d["choices"][0]["message"]["content"]
|
| 165 |
-
found = needle_code.lower() in answer.lower()
|
| 166 |
-
|
| 167 |
-
result_text = f"""## Result: {"✅ NEEDLE FOUND" if found else "❌ NEEDLE NOT FOUND"}
|
| 168 |
-
|
| 169 |
-
**Context:** {actual_tokens_est:,} tokens (~{actual_words:,} words)
|
| 170 |
-
**Overflow chunks:** {chunks}
|
| 171 |
-
**Needle depth:** {depth}%
|
| 172 |
-
**Index time:** {upload_time:.1f}s
|
| 173 |
-
**Query time:** {query_time:.1f}s
|
| 174 |
-
**Total time:** {total_time:.1f}s
|
| 175 |
-
**Model answer:** {answer[:200]}"""
|
| 176 |
-
|
| 177 |
-
needle_info = f"""**Hidden needle:** "{needle}"
|
| 178 |
-
**Inserted at:** {depth}% depth (position {insert_pos:,} of {actual_words:,} words)
|
| 179 |
-
**Passphrase:** {needle_code}"""
|
| 180 |
-
|
| 181 |
-
return result_text, needle_info, "FOUND" if found else "NOT FOUND", f"{total_time:.1f}s"
|
| 182 |
-
|
| 183 |
-
except requests.exceptions.Timeout:
|
| 184 |
-
requests.delete(f"{api_base}/v1/documents/{user_id}", timeout=10)
|
| 185 |
-
return "Request timed out. Large documents take time to index. Please retry.", "", "TIMEOUT", ""
|
| 186 |
-
except Exception as e:
|
| 187 |
-
return f"Connection error. Server may be busy.", "", "ERROR", ""
|
| 188 |
|
|
|
|
| 189 |
|
| 190 |
-
|
| 191 |
-
"""Main test function called by Gradio."""
|
| 192 |
-
size_map = {
|
| 193 |
-
"8K": 8000,
|
| 194 |
-
"32K": 32000,
|
| 195 |
-
"64K": 64000,
|
| 196 |
-
"128K": 128000,
|
| 197 |
-
"256K": 256000,
|
| 198 |
-
"512K": 512000,
|
| 199 |
-
"1M": 1000000,
|
| 200 |
-
"1.5M": 1500000,
|
| 201 |
-
"3M": 3000000,
|
| 202 |
-
"6M": 6000000,
|
| 203 |
-
"12M": 12000000,
|
| 204 |
-
}
|
| 205 |
-
|
| 206 |
-
tokens = size_map.get(context_size, 128000)
|
| 207 |
|
| 208 |
if tokens <= 1000000:
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
else:
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
gr.Markdown("""
|
| 217 |
-
# Hunter Omega — Live Needle in a Haystack
|
| 218 |
|
| 219 |
-
**
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
-
|
| 223 |
|
| 224 |
-
**8K to 1M:** Native full attention
|
| 225 |
-
**1.5M to 12M:** Extended context via overflow pipeline. Larger sizes take longer to index.
|
| 226 |
|
| 227 |
-
*Running on a single GPU cluster. If
|
| 228 |
-
limitation, not an accuracy issue.*
|
| 229 |
""")
|
| 230 |
|
| 231 |
with gr.Row():
|
|
@@ -236,33 +199,28 @@ limitation, not an accuracy issue.*
|
|
| 236 |
)
|
| 237 |
run_btn = gr.Button("Find the Needle", variant="primary", size="lg")
|
| 238 |
|
| 239 |
-
|
| 240 |
-
with gr.Column():
|
| 241 |
-
result_output = gr.Markdown(label="Result")
|
| 242 |
-
with gr.Column():
|
| 243 |
-
needle_output = gr.Markdown(label="Hidden Needle (revealed after test)")
|
| 244 |
|
| 245 |
with gr.Row():
|
| 246 |
-
|
| 247 |
-
|
|
|
|
|
|
|
| 248 |
|
| 249 |
gr.Markdown("""
|
| 250 |
---
|
| 251 |
-
**Estimated
|
| 252 |
-
|
| 253 |
-
| Size | Index Time | Query Time | Total |
|
| 254 |
-
|:----:|:----------:|:----------:|:-----:|
|
| 255 |
-
| 8K - 1M | None (native) | 1-90s | 1-90s |
|
| 256 |
-
| 1.5M | ~1 min | ~16s | ~1.5 min |
|
| 257 |
-
| 3M | ~3 min | ~16s | ~3.5 min |
|
| 258 |
-
| 6M | ~5 min | ~16s | ~6 min |
|
| 259 |
-
| 12M | ~13 min | ~90s | ~14 min |
|
| 260 |
|
| 261 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
|
| 263 |
-
|
| 264 |
-
filler text. The model is asked to retrieve the exact passphrase. No keyword hints in the query.
|
| 265 |
-
The passphrase and its location are revealed after the test so you can verify.
|
| 266 |
|
| 267 |
[Full benchmarks and methodology](https://github.com/SovNodeAI/hunter-omega-benchmarks)
|
| 268 |
""")
|
|
@@ -270,7 +228,7 @@ The passphrase and its location are revealed after the test so you can verify.
|
|
| 270 |
run_btn.click(
|
| 271 |
fn=run_test,
|
| 272 |
inputs=[context_dropdown],
|
| 273 |
-
outputs=[
|
| 274 |
)
|
| 275 |
|
| 276 |
|
|
|
|
| 1 |
"""
|
| 2 |
Hunter Omega — Live NIAH Demo
|
| 3 |
One-click needle in a haystack test from 8K to 12M tokens.
|
| 4 |
+
Shows the needle BEFORE querying so users can verify it's not rigged.
|
| 5 |
"""
|
| 6 |
import gradio as gr
|
| 7 |
import requests
|
|
|
|
| 13 |
API_URL = os.environ.get("HUNTER_API")
|
| 14 |
MODEL = "hunter-omega-12m-fast"
|
| 15 |
|
|
|
|
| 16 |
FILLERS = [
|
| 17 |
"The evolution of distributed systems has fundamentally changed how we architect software. Microservices emerged as a response to monolithic limitations, enabling teams to deploy independently and scale specific components. Service meshes handle the complexity of inter-service communication, providing observability and traffic management.",
|
| 18 |
"Machine learning pipelines require careful orchestration from data ingestion through model deployment. Feature stores centralize feature computation and serving, ensuring consistency between training and inference. MLOps practices bring version control and automated testing to model development workflows.",
|
|
|
|
| 31 |
"Robotics integrates sensing planning and actuation for autonomous interaction. Simultaneous localization and mapping builds environment models while tracking position. Motion planning finds collision-free paths through configuration spaces.",
|
| 32 |
]
|
| 33 |
|
| 34 |
+
SIZE_MAP = {
|
| 35 |
+
"8K": 8000, "32K": 32000, "64K": 64000, "128K": 128000,
|
| 36 |
+
"256K": 256000, "512K": 512000, "1M": 1000000,
|
| 37 |
+
"1.5M": 1500000, "3M": 3000000, "6M": 6000000, "12M": 12000000,
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
|
| 41 |
def generate_needle():
|
|
|
|
| 42 |
code = ''.join(random.choices(string.ascii_uppercase, k=4))
|
| 43 |
nums = ''.join(random.choices(string.digits, k=4))
|
| 44 |
word = random.choice(["ALPHA", "BRAVO", "DELTA", "ECHO", "FOXTROT", "GOLF", "HOTEL",
|
|
|
|
| 48 |
|
| 49 |
|
| 50 |
def generate_haystack(target_tokens):
|
|
|
|
| 51 |
words = []
|
| 52 |
target_words = target_tokens * 3 // 4
|
| 53 |
i = 0
|
|
|
|
| 57 |
return words[:target_words]
|
| 58 |
|
| 59 |
|
| 60 |
+
def run_test(context_size):
|
| 61 |
+
"""Streaming test: shows needle first, then queries, then shows result."""
|
| 62 |
+
tokens = SIZE_MAP.get(context_size, 128000)
|
| 63 |
needle_code = generate_needle()
|
| 64 |
needle = f"The classified authorization code for Operation Starfall is {needle_code}."
|
| 65 |
query = "What is the classified authorization code for Operation Starfall? State ONLY the code."
|
| 66 |
+
depth = random.randint(10, 90) if tokens <= 1000000 else random.randint(55, 95)
|
| 67 |
|
| 68 |
# Generate haystack
|
| 69 |
+
words = generate_haystack(tokens)
|
|
|
|
| 70 |
insert_pos = int(len(words) * depth / 100)
|
| 71 |
words.insert(insert_pos, needle)
|
| 72 |
+
actual_words = len(words)
|
| 73 |
+
actual_tokens = actual_words * 4 // 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
+
# STEP 1: Show what we're about to test
|
| 76 |
+
setup_text = f"""## Step 1: Test Setup
|
| 77 |
|
| 78 |
+
**Context size:** {actual_tokens:,} tokens (~{actual_words:,} words)
|
| 79 |
+
**Generated needle:** `{needle_code}`
|
| 80 |
+
**Full needle sentence:** "{needle}"
|
| 81 |
+
**Hidden at:** {depth}% depth (word position {insert_pos:,} of {actual_words:,})
|
| 82 |
+
**Query:** "{query}"
|
| 83 |
|
| 84 |
+
The needle is now embedded in {actual_tokens:,} tokens of diverse technical text.
|
| 85 |
+
The model has never seen this passphrase before. It was just generated randomly.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
+
---
|
| 88 |
|
| 89 |
+
## Step 2: Querying model..."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
|
| 91 |
if tokens <= 1000000:
|
| 92 |
+
# Native window: direct prompt
|
| 93 |
+
haystack = " ".join(words)
|
| 94 |
+
yield setup_text, "", "QUERYING...", ""
|
| 95 |
+
|
| 96 |
+
t0 = time.time()
|
| 97 |
+
try:
|
| 98 |
+
r = requests.post(API_URL, json={
|
| 99 |
+
"model": MODEL,
|
| 100 |
+
"messages": [{"role": "user", "content": haystack + "\n\n" + query}],
|
| 101 |
+
"max_tokens": 50,
|
| 102 |
+
"temperature": 0,
|
| 103 |
+
}, timeout=300)
|
| 104 |
+
elapsed = time.time() - t0
|
| 105 |
+
|
| 106 |
+
if r.status_code != 200:
|
| 107 |
+
yield setup_text, "", "ERROR", f"Server returned {r.status_code}"
|
| 108 |
+
return
|
| 109 |
+
|
| 110 |
+
answer = r.json()["choices"][0]["message"]["content"]
|
| 111 |
+
found = needle_code.lower() in answer.lower()
|
| 112 |
+
|
| 113 |
+
except requests.exceptions.Timeout:
|
| 114 |
+
yield setup_text, "", "TIMEOUT", "Server busy, please retry"
|
| 115 |
+
return
|
| 116 |
+
except Exception:
|
| 117 |
+
yield setup_text, "", "ERROR", "Connection error, please retry"
|
| 118 |
+
return
|
| 119 |
else:
|
| 120 |
+
# Overflow pipeline
|
| 121 |
+
doc = " ".join(words)
|
| 122 |
+
user_id = f"demo_{random.randint(100000, 999999)}"
|
| 123 |
+
api_base = API_URL.replace("/v1/chat/completions", "")
|
| 124 |
+
|
| 125 |
+
yield setup_text + "\n\n*Indexing large document...*", "", "INDEXING...", ""
|
| 126 |
+
|
| 127 |
+
t0 = time.time()
|
| 128 |
+
try:
|
| 129 |
+
r = requests.post(f"{api_base}/v1/documents", json={
|
| 130 |
+
"user_id": user_id, "text": doc,
|
| 131 |
+
}, timeout=1800)
|
| 132 |
+
index_time = time.time() - t0
|
| 133 |
+
info = r.json()
|
| 134 |
+
chunks = info.get("overflow_chunks", 0)
|
| 135 |
+
|
| 136 |
+
yield setup_text + f"\n\n*Indexed {chunks} chunks in {index_time:.0f}s. Querying...*", "", "QUERYING...", ""
|
| 137 |
+
|
| 138 |
+
t1 = time.time()
|
| 139 |
+
r = requests.post(API_URL, json={
|
| 140 |
+
"model": MODEL,
|
| 141 |
+
"messages": [{"role": "user", "content": query}],
|
| 142 |
+
"max_tokens": 50,
|
| 143 |
+
"temperature": 0,
|
| 144 |
+
"user": user_id,
|
| 145 |
+
}, timeout=600)
|
| 146 |
+
elapsed = time.time() - t0
|
| 147 |
+
answer = r.json()["choices"][0]["message"]["content"]
|
| 148 |
+
found = needle_code.lower() in answer.lower()
|
| 149 |
+
|
| 150 |
+
requests.delete(f"{api_base}/v1/documents/{user_id}", timeout=10)
|
| 151 |
+
|
| 152 |
+
except requests.exceptions.Timeout:
|
| 153 |
+
requests.delete(f"{api_base}/v1/documents/{user_id}", timeout=10)
|
| 154 |
+
yield setup_text, "", "TIMEOUT", "Large doc timed out, please retry"
|
| 155 |
+
return
|
| 156 |
+
except Exception:
|
| 157 |
+
yield setup_text, "", "ERROR", "Connection error"
|
| 158 |
+
return
|
| 159 |
+
|
| 160 |
+
# STEP 3: Show result
|
| 161 |
+
result_text = f"""## Step 3: Result {"✅ NEEDLE FOUND" if found else "❌ NOT FOUND"}
|
| 162 |
+
|
| 163 |
+
**Expected:** `{needle_code}`
|
| 164 |
+
**Model returned:** `{answer.strip()}`
|
| 165 |
+
**Match:** {"YES" if found else "NO"}
|
| 166 |
+
**Time:** {elapsed:.1f}s
|
| 167 |
+
|
| 168 |
+
{"The model correctly retrieved the randomly generated passphrase from " + f"{actual_tokens:,} tokens of text." if found else "The model did not find the needle."}"""
|
| 169 |
+
|
| 170 |
+
full_output = setup_text + "\n\n---\n\n" + result_text
|
| 171 |
+
|
| 172 |
+
yield full_output, "", "FOUND" if found else "MISSED", f"{elapsed:.1f}s"
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
# Build interface
|
| 176 |
+
with gr.Blocks(title="Hunter Omega — Live NIAH Demo") as demo:
|
| 177 |
gr.Markdown("""
|
| 178 |
+
# Hunter Omega — Live Needle in a Haystack
|
| 179 |
|
| 180 |
+
**How this works:**
|
| 181 |
+
1. You pick a context length
|
| 182 |
+
2. The app generates a random passphrase and hides it at a random depth
|
| 183 |
+
3. You see the passphrase and its position BEFORE the model runs
|
| 184 |
+
4. The model searches the document and returns what it found
|
| 185 |
+
5. You verify it matches
|
| 186 |
|
| 187 |
+
Nothing is pre-arranged. The passphrase is generated fresh every time. Run it as many times as you want.
|
| 188 |
|
| 189 |
+
**8K to 1M:** Native full attention. **1.5M to 12M:** Extended context engine.
|
|
|
|
| 190 |
|
| 191 |
+
*Running on a single GPU cluster. If busy, responses may queue. This is capacity, not accuracy.*
|
|
|
|
| 192 |
""")
|
| 193 |
|
| 194 |
with gr.Row():
|
|
|
|
| 199 |
)
|
| 200 |
run_btn = gr.Button("Find the Needle", variant="primary", size="lg")
|
| 201 |
|
| 202 |
+
output = gr.Markdown(label="Test Progress")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
|
| 204 |
with gr.Row():
|
| 205 |
+
status_box = gr.Textbox(label="Status", interactive=False)
|
| 206 |
+
time_box = gr.Textbox(label="Time", interactive=False)
|
| 207 |
+
|
| 208 |
+
hidden = gr.Textbox(visible=False)
|
| 209 |
|
| 210 |
gr.Markdown("""
|
| 211 |
---
|
| 212 |
+
**Estimated times:**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
|
| 214 |
+
| Size | Time |
|
| 215 |
+
|:----:|:----:|
|
| 216 |
+
| 8K - 128K | 2-8s |
|
| 217 |
+
| 256K - 512K | 10-30s |
|
| 218 |
+
| 1M | 60-90s |
|
| 219 |
+
| 1.5M - 3M | 1-4 min |
|
| 220 |
+
| 6M | 5-6 min |
|
| 221 |
+
| 12M | 13-15 min |
|
| 222 |
|
| 223 |
+
If multiple users are testing, requests queue behind each other.
|
|
|
|
|
|
|
| 224 |
|
| 225 |
[Full benchmarks and methodology](https://github.com/SovNodeAI/hunter-omega-benchmarks)
|
| 226 |
""")
|
|
|
|
| 228 |
run_btn.click(
|
| 229 |
fn=run_test,
|
| 230 |
inputs=[context_dropdown],
|
| 231 |
+
outputs=[output, hidden, status_box, time_box],
|
| 232 |
)
|
| 233 |
|
| 234 |
|