HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1import type { CompiledFilter, CompiledQuery2 } from '@/lib/types';23/*4 Search compiler v2 helpers (server-safe, pure). Two ways to "drop a chip":5 - re-query: remove the chip's `source_span` from the text and search again (works for every filter);6 - structured: map the remaining compiled filters to `/models?…` parameters when the compiled type is `model`.7 Filters the listing API cannot express are reported, never silently dropped.8*/910export function withoutSpan(text: string, span: string | null | undefined): string {11 if (!span) return text;12 const i = text.toLowerCase().indexOf(span.toLowerCase());13 if (i < 0) return text;14 return `${text.slice(0, i)} ${text.slice(i + span.length)}`.replace(/\s{2,}/g, ' ').trim();15}1617export type Mapped = { params: URLSearchParams; unmapped: { filter: CompiledFilter; why: string }[]; links: { label: string; href: string }[] };1819const SORT_MAP: Record<string, { sort: string; order?: string }> = { newest: { sort: 'release' }, largest: { sort: 'params' }, smallest: { sort: 'params', order: 'asc' }, cheapest: { sort: 'cheapest' }, best: { sort: 'quality' } };2021/** Map compiled filters to `/models` query parameters (docs/API.md `/models`). */22export function toModelsParams(compiled: CompiledFilter[], residual?: string | null): Mapped {23 const p = new URLSearchParams();24 const unmapped: Mapped['unmapped'] = [];25 const links: Mapped['links'] = [];26 const slugOf = (v: unknown) => (v && typeof v === 'object' && 'slug' in (v as Record<string, unknown>) ? String((v as { slug: unknown }).slug) : typeof v === 'string' ? v : null);27 for (const f of compiled) {28 const v = f.value;29 switch (f.filter) {30 case 'entity_type':31 break;32 case 'params_min':33 p.set('min_params', String(v));34 break;35 case 'params_max':36 p.set('max_params', String(v));37 break;38 case 'params_range':39 if (Array.isArray(v) && v.length === 2) {40 p.set('min_params', String(v[0]));41 p.set('max_params', String(v[1]));42 }43 break;44 case 'context_min':45 p.set('min_context', String(v));46 break;47 case 'year':48 p.set('year_from', String(v));49 p.set('year_to', String(v));50 break;51 case 'year_from':52 p.set('year_from', String(v));53 break;54 case 'year_to':55 p.set('year_to', String(v));56 break;57 case 'license':58 p.set('license', String(v));59 break;60 case 'modality':61 p.set('modality', String(v));62 break;63 case 'openness':64 p.set('openness', String(v));65 break;66 case 'organization': {67 const s = slugOf(v);68 if (s) p.set('org', s);69 else unmapped.push({ filter: f, why: 'organization not resolved to a slug' });70 break;71 }72 case 'family': {73 const s = slugOf(v);74 if (s) p.set('family', s);75 break;76 }77 case 'reasoning':78 p.set('reasoning', v ? '1' : '0');79 break;80 case 'status':81 p.set('status', String(v));82 break;83 case 'sort': {84 const m = SORT_MAP[String(v)];85 if (m) {86 p.set('sort', m.sort);87 if (m.order) p.set('order', m.order);88 } else unmapped.push({ filter: f, why: `sort “${String(v)}” has no /models equivalent` });89 break;90 }91 case 'benchmark': {92 const s = slugOf(v);93 if (s) links.push({ label: `${f.label} → leaderboard`, href: `/benchmarks/${encodeURIComponent(s)}` });94 break;95 }96 case 'provider': {97 const s = slugOf(v);98 if (s) links.push({ label: `${f.label} → provider page`, href: `/providers/${encodeURIComponent(s)}` });99 break;100 }101 case 'max_input_price':102 case 'max_output_price':103 unmapped.push({ filter: f, why: '/models has no price filter — use Prices sorted cheapest' });104 links.push({ label: 'Prices, cheapest first', href: `/prices?sort=${f.filter === 'max_input_price' ? 'input' : 'output'}` });105 break;106 case 'memory_gb':107 unmapped.push({ filter: f, why: 'an ESTIMATED parameter bound — use Run locally for a real fit' });108 links.push({ label: `Run locally with ${String(v)} GB`, href: `/run-locally?memory_gb=${encodeURIComponent(String(v))}` });109 break;110 case 'days_back':111 unmapped.push({ filter: f, why: '/models filters by release year, not by a rolling window' });112 break;113 case 'commercial_use':114 unmapped.push({ filter: f, why: 'licence permissions are not a /models filter — see Licenses' });115 links.push({ label: 'Licenses (commercial use)', href: '/licenses' });116 break;117 default:118 unmapped.push({ filter: f, why: 'no /models equivalent' });119 }120 }121 if (residual && residual.trim()) p.set('q', residual.trim());122 return { params: p, unmapped, links };123}124125/** Which model columns the query implies (always Model · Org; the rest depends on the compiled filters). */126export function impliedColumns(compiled: CompiledFilter[], sort?: string | null): Set<string> {127 const cols = new Set<string>(['params', 'context', 'openness', 'released']);128 for (const f of compiled) {129 if (/params|memory_gb/.test(f.filter)) cols.add('params');130 if (/context/.test(f.filter)) cols.add('context');131 if (/price/.test(f.filter)) cols.add('price');132 if (/openness|license|commercial/.test(f.filter)) cols.add('openness');133 if (/year|days_back/.test(f.filter)) cols.add('released');134 if (f.filter === 'reasoning') cols.add('reasoning');135 if (f.filter === 'modality') cols.add('modalities');136 }137 if (sort === 'cheapest') cols.add('price');138 return cols;139}140141export function compiledType(q: CompiledQuery2 | undefined): string | null {142 const t = (q?.entity_type ?? q?.type) as string | null | undefined;143 return t ?? null;144}145