Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
113 lines (105 loc) · 6.3 KB
/
Copy pathindex.html
File metadata and controls
113 lines (105 loc) · 6.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>carAgent — Used-Car Agent Toolkit</title>
<style>
:root { color-scheme: light dark; --bg:#f6f7f9; --card:#fff; --fg:#1c1e21; --muted:#6b7280; --accent:#2563eb; --border:#e5e7eb; }
@media (prefers-color-scheme: dark) { :root { --bg:#111827; --card:#1f2937; --fg:#f3f4f6; --muted:#9ca3af; --accent:#60a5fa; --border:#374151; } }
* { box-sizing: border-box; }
body { margin:0; font:15px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif; background:var(--bg); color:var(--fg); }
header { padding:40px 20px 12px; text-align:center; }
header h1 { margin:0 0 6px; font-size:2rem; }
header p { margin:0; color:var(--muted); }
main { max-width:960px; margin:0 auto; padding:16px 20px 60px; display:grid; gap:16px; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); }
section { background:var(--card); border:1px solid var(--border); border-radius:12px; padding:18px; }
section h2 { margin:0 0 10px; font-size:1.1rem; }
label { display:block; margin:8px 0 4px; font-size:.85rem; color:var(--muted); }
input, textarea { width:100%; padding:8px; border:1px solid var(--border); border-radius:8px; background:transparent; color:var(--fg); font:inherit; }
button { margin-top:12px; padding:8px 16px; border:0; border-radius:8px; background:var(--accent); color:#fff; font-weight:600; cursor:pointer; }
pre { background:var(--bg); border:1px solid var(--border); border-radius:8px; padding:10px; font-size:.8rem; overflow-x:auto; min-height:24px; white-space:pre-wrap; }
footer { text-align:center; color:var(--muted); padding:0 20px 40px; font-size:.85rem; }
</style>
</head>
<body>
<header>
<h1>🚗 carAgent</h1>
<p>VIN decode · recall check · listing inspection · quote comparison · out-the-door cost · repair estimates</p>
<p>Built in Dallas, TX · free NHTSA APIs · no keys required</p>
</header>
<main>
<section>
<h2>🔎 VIN / Recalls</h2>
<label>VIN</label>
<input id="vin" placeholder="1HGCM82633A004352">
<button onclick="run('vin')">Decode VIN</button>
<button onclick="run('recalls')">Check Recalls</button>
<pre id="out-vin">—</pre>
</section>
<section>
<h2>📋 Listing Inspection</h2>
<label>Listing text</label>
<textarea id="listing" rows="3" placeholder="2019 Toyota Camry 45,000 mi clean title $18,500"></textarea>
<button onclick="run('inspect')">Extract</button>
<pre id="out-inspect">—</pre>
</section>
<section>
<h2>💵 Quote Comparison</h2>
<label>Quotes JSON</label>
<textarea id="quotes" rows="3">[{"price":20000},{"price":22000},{"price":21000}]</textarea>
<button onclick="run('compare')">Compare</button>
<pre id="out-compare">—</pre>
</section>
<section>
<h2>🧾 Out-the-Door Cost</h2>
<label>Price</label><input id="price" type="number" value="30000">
<label>State</label><input id="state" value="TX" maxlength="2">
<button onclick="run('otd')">Calculate</button>
<pre id="out-otd">—</pre>
</section>
<section>
<h2>🔧 Repair Estimate</h2>
<label>Items JSON</label>
<textarea id="repairs" rows="3">[{"item":"brake_pads"},{"item":"oil_change"}]</textarea>
<button onclick="run('repairs')">Estimate</button>
<pre id="out-repairs">—</pre>
</section>
<section>
<h2>⚙️ Offline Demo</h2>
<p style="color:var(--muted);font-size:.85rem">Inspection, comparison, OTD and repair tools run locally in this demo. VIN and recall tools call free NHTSA APIs from the CLI (<code>node index.js</code>); browser demo shows the offline core.</p>
</section>
</main>
<footer>carAgent · MIT · <a href="https://github.com/dgiot/carAgent" style="color:var(--accent)">github.com/dgiot/carAgent</a></footer>
<script>
const TOOLS = {
inspect: (s) => ({ listing: { year: (s.match(/\b(19|20)\d{2}\b/)||[])[0]||null,
priceUsd: s.match(/\$?\s?([\d,]+)\s?(USD|dollars?)?/i) ? Number(s.match(/\$?\s?([\d,]+)\s?(USD|dollars?)?/i)[1].replace(/,/g,'')) : null,
mileage: (s.match(/([\d,]{2,7})\s?mi\b/i)||[])[1] ? Number(s.match(/([\d,]{2,7})\s?mi\b/i)[1].replace(/,/g,'')) : null,
cleanTitle: /\bclean title\b/i.test(s),
flags: (s.match(/\b(accident|salvage|rebuilt|flood)\b/i)||[]).slice(1) } }),
compare: (q) => { const p=q.map(x=>x.price); return { min:Math.min(...p), avg:Math.round(p.reduce((a,b)=>a+b,0)/p.length),
suggestedOffer:Math.round(Math.min(...p)*0.97), spreadPct:Math.round((Math.max(...p)-Math.min(...p))/Math.min(...p)*100) }; },
otd: (price, st) => { const T={TX:6.25,CA:7.25,NY:4,FL:6,WA:6.5,CO:2.9,AZ:5.6,NV:6.85,OR:0,IL:6.25,GA:4,OH:5.75};
const t=T[st.toUpperCase()]; if(t===undefined) return {error:'unknown state'};
const tax=Math.round(price*t/100); return { state:st.toUpperCase(), taxRate:t, salesTax:tax, docFee:150, titleFee:33, outTheDoor:price+tax+150+33 }; },
repairs: (items) => { const B={brake_pads:300,oil_change:80,brake_rotors:500,battery:200,alternator:600,starter:450,tires_set:800,spark_plugs:250,ac_recharge:220,wheel_alignment:120,timing_belt:900,water_pump:650};
const rows=items.map(i=>{const k=String(i.item).toLowerCase().replace(/\s+/g,'_'); const b=B[k];
return b===undefined?{item:i.item,known:false}:{item:i.item,parts:Math.round(b*0.6),labor:Math.round(b*0.4),estimate:b};});
return { total:rows.filter(r=>r.known).reduce((a,b)=>a+b.estimate,0), rows }; },
};
async function run(kind) {
let out;
try {
if (kind==='inspect') out = TOOLS.inspect(document.getElementById('listing').value);
else if (kind==='compare') out = TOOLS.compare(JSON.parse(document.getElementById('quotes').value));
else if (kind==='otd') out = TOOLS.otd(Number(document.getElementById('price').value), document.getElementById('state').value);
else if (kind==='repairs') out = TOOLS.repairs(JSON.parse(document.getElementById('repairs').value));
else { document.getElementById('out-vin').textContent = `${kind}: demo page shows offline tools — run "node index.js ${kind} <VIN>" for live NHTSA data`; return; }
} catch(e) { out = { error: e.message }; }
const key = kind==='vin'||kind==='recalls' ? 'out-vin' : kind==='inspect'?'out-inspect':kind==='compare'?'out-compare':kind==='otd'?'out-otd':'out-repairs';
document.getElementById(key).textContent = JSON.stringify(out, null, 2);
}
</script>
</body>
</html>