Skip to content

Commit cc8f6ab

Browse files
committed
feat: add infographics
1 parent a4a4b8d commit cc8f6ab

2 files changed

Lines changed: 176 additions & 4 deletions

File tree

src/app/page.tsx

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import { AgentSummary } from "@/components/AgentSummary";
34
import { BrowserView } from "@/components/BrowserView";
45
import { ResultCard } from "@/components/ResultCard";
56
import { SearchForm } from "@/components/SearchForm";
@@ -57,10 +58,45 @@ export default function Home() {
5758
Ticket Hunter
5859
</h1>
5960
{!hasActivity && (
60-
<p className="mx-auto mb-10 max-w-2xl text-lg text-white/60">
61-
AI agent that autonomously browses StubHub, Ticketmaster, SeatGeek
62-
and more to find you the best available seats - live.
63-
</p>
61+
<>
62+
<p className="mx-auto mb-8 max-w-2xl text-lg leading-relaxed text-white/50">
63+
Type any event. This AI agent will search Google, open real browsers
64+
across ticket platforms, and autonomously navigate them to find you
65+
the best available seats&nbsp;&mdash;&nbsp;streaming every step live.
66+
</p>
67+
68+
{/* ── Pipeline visualization ── */}
69+
<div className="mx-auto mb-12 max-w-2xl">
70+
<div className="relative grid grid-cols-4">
71+
{/* Connecting line */}
72+
<div className="pointer-events-none absolute top-[15px] left-[12.5%] right-[12.5%] h-px bg-gradient-to-r from-[#9D97F4]/25 via-[#3D7FFC]/25 to-emerald-400/25" />
73+
74+
{[
75+
{ num: "1", label: "Search Google", tech: "Bright Data SERP", color: "#9D97F4" },
76+
{ num: "2", label: "Open Browsers", tech: "Scraping Browser", color: "#3D7FFC" },
77+
{ num: "3", label: "Navigate Pages", tech: "Yutori N1 Vision", color: "#15C1E6" },
78+
{ num: "4", label: "Best Tickets", tech: "Ranked results", color: "#34d399" },
79+
].map((step) => (
80+
<div key={step.num} className="relative flex flex-col items-center text-center">
81+
<div
82+
className="mb-3 flex h-[30px] w-[30px] items-center justify-center rounded-full text-xs font-bold"
83+
style={{
84+
background: `${step.color}15`,
85+
border: `1px solid ${step.color}30`,
86+
color: step.color,
87+
}}
88+
>
89+
{step.num}
90+
</div>
91+
<p className="text-[13px] font-medium text-white/60">{step.label}</p>
92+
<p className="mt-0.5 text-[11px]" style={{ color: `${step.color}aa` }}>
93+
{step.tech}
94+
</p>
95+
</div>
96+
))}
97+
</div>
98+
</div>
99+
</>
64100
)}
65101

66102
<div className={hasActivity ? "mb-2" : "mb-0"}>
@@ -150,6 +186,15 @@ export default function Home() {
150186
</div>
151187
)}
152188

189+
{/* ── Agent Summary (shown when done) ── */}
190+
{hasResults && !isLoading && (
191+
<AgentSummary
192+
entries={statusEntries}
193+
platformCount={Object.keys(browserSessions).length}
194+
ticketCount={validTickets.length}
195+
/>
196+
)}
197+
153198
{/* ── Results ── */}
154199
{hasResults && (
155200
<section className="mx-auto mt-8 max-w-7xl px-4">

src/components/AgentSummary.tsx

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
"use client";
2+
3+
import { useMemo } from "react";
4+
import type { SearchStatusEntry } from "@/lib/types";
5+
6+
interface AgentSummaryProps {
7+
entries: SearchStatusEntry[];
8+
platformCount: number;
9+
ticketCount: number;
10+
}
11+
12+
export function AgentSummary({
13+
entries,
14+
platformCount,
15+
ticketCount,
16+
}: AgentSummaryProps) {
17+
const stats = useMemo(() => {
18+
let serpQueries = 0;
19+
let pagesOpened = 0;
20+
let actions = 0;
21+
let extractions = 0;
22+
23+
for (const e of entries) {
24+
const m = e.message.toLowerCase();
25+
if (m.includes("serp") && (m.includes("search") || m.includes("query")))
26+
serpQueries++;
27+
if (m.includes("navigat") || m.includes("opened") || m.includes("loading page"))
28+
pagesOpened++;
29+
if (m.includes("click") || m.includes("scroll") || m.includes("type"))
30+
actions++;
31+
if (m.includes("extract")) extractions++;
32+
}
33+
34+
return {
35+
serpQueries: Math.max(serpQueries, 1),
36+
pagesOpened: Math.max(pagesOpened, platformCount),
37+
actions,
38+
extractions: Math.max(extractions, ticketCount > 0 ? 1 : 0),
39+
totalSteps: entries.length,
40+
};
41+
}, [entries, platformCount, ticketCount]);
42+
43+
const items = [
44+
{
45+
label: "SERP Queries",
46+
value: stats.serpQueries,
47+
sub: "Bright Data",
48+
icon: (
49+
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
50+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
51+
</svg>
52+
),
53+
},
54+
{
55+
label: "Pages Browsed",
56+
value: stats.pagesOpened,
57+
sub: "Scraping Browser",
58+
icon: (
59+
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
60+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9" />
61+
</svg>
62+
),
63+
},
64+
{
65+
label: "AI Actions",
66+
value: stats.actions,
67+
sub: "Yutori N1",
68+
icon: (
69+
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
70+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5M7.188 2.239l.777 2.897M5.136 7.965l-2.898-.777M13.95 4.05l-2.122 2.122m-5.657 5.656l-2.12 2.122" />
71+
</svg>
72+
),
73+
},
74+
{
75+
label: "Agent Steps",
76+
value: stats.totalSteps,
77+
sub: "Total",
78+
icon: (
79+
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
80+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" />
81+
</svg>
82+
),
83+
},
84+
];
85+
86+
return (
87+
<div className="mx-auto mt-8 max-w-7xl px-4">
88+
<div className="rounded-xl border border-white/10 bg-slate-900/60 p-5 backdrop-blur-sm">
89+
{/* Title */}
90+
<div className="mb-4 flex items-center gap-2">
91+
<div className="flex h-6 w-6 items-center justify-center rounded-md bg-[#3D7FFC]/10">
92+
<svg className="h-3.5 w-3.5 text-[#3D7FFC]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
93+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
94+
</svg>
95+
</div>
96+
<h3 className="text-sm font-semibold text-white">Agent Run Summary</h3>
97+
</div>
98+
99+
{/* Stats grid */}
100+
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
101+
{items.map((item) => (
102+
<div
103+
key={item.label}
104+
className="rounded-lg border border-white/5 bg-white/[0.02] px-4 py-3"
105+
>
106+
<div className="mb-1 flex items-center gap-1.5 text-white/40">
107+
{item.icon}
108+
<span className="text-xs">{item.label}</span>
109+
</div>
110+
<p className="text-2xl font-bold text-white">{item.value}</p>
111+
<p className="text-xs text-[#3D7FFC]/70">{item.sub}</p>
112+
</div>
113+
))}
114+
</div>
115+
116+
{/* Pipeline description */}
117+
<p className="mt-4 text-xs leading-relaxed text-white/40">
118+
Searched Google via <span className="text-white/60">Bright Data SERP API</span>,
119+
opened {stats.pagesOpened} ticket {stats.pagesOpened === 1 ? "site" : "sites"} in
120+
a <span className="text-white/60">Bright Data Scraping Browser</span>,
121+
autonomously navigated with <span className="text-white/60">Yutori N1</span> vision
122+
model, and extracted {ticketCount} structured {ticketCount === 1 ? "result" : "results"}.
123+
</p>
124+
</div>
125+
</div>
126+
);
127+
}

0 commit comments

Comments
 (0)