LaelaZ's picture
Deploy SupportCopilot to HF Spaces (Docker)
8981bf6 verified
Raw
History Blame Contribute Delete
8.4 kB
{% extends "base.html" %}
{% block title %}SupportCopilot — friendly AI e-commerce support that proves its ROI{% endblock %}
{% block content %}
<!-- Hero -->
<section class="text-center max-w-3xl mx-auto">
<span class="inline-flex items-center gap-1.5 rounded-full bg-brand-50 px-3.5 py-1.5 text-xs font-bold text-brand-700 ring-1 ring-inset ring-brand-200 dark:bg-brand-500/10 dark:text-brand-300 dark:ring-brand-500/25">
<span class="relative flex h-2 w-2">
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-brand-400 opacity-60"></span>
<span class="relative inline-flex h-2 w-2 rounded-full bg-brand-500"></span>
</span>
Runs fully offline · no API keys required
</span>
<h1 class="mt-4 text-4xl font-extrabold tracking-tight sm:text-5xl">
Friendly AI support that <span class="sc-gradient-text">resolves tier-1 tickets</span><br class="hidden sm:block" /> and proves the ROI
</h1>
<p class="mt-4 text-lg leading-relaxed text-sand-600 dark:text-sand-300">
SupportCopilot answers "where's my order?", returns, and policy questions with
<strong class="text-sand-800 dark:text-sand-100">cited, policy-correct</strong> replies —
auto-resolving what it can and warmly handing the rest to a human.
</p>
<div class="mt-7 flex flex-wrap items-center justify-center gap-3">
<a href="#chat" class="sc-btn-primary">
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>
Try a live demo
</a>
<a href="/dashboard" class="sc-btn-secondary">
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><rect x="7" y="10" width="3" height="7"/><rect x="13" y="6" width="3" height="11"/></svg>
See the ROI dashboard
</a>
</div>
<!-- Proof strip (numbers come from replaying the seeded tickets) -->
<dl class="mt-9 grid grid-cols-2 gap-3 sm:grid-cols-4">
<div class="sc-card sc-kpi p-4">
<dt class="text-xs font-semibold uppercase tracking-wide text-sand-500 dark:text-sand-400">Deflection</dt>
<dd class="mt-1 text-2xl font-extrabold sc-gradient-text">{{ '%.0f' % (roi.deflection_rate * 100) }}%</dd>
</div>
<div class="sc-card sc-kpi p-4">
<dt class="text-xs font-semibold uppercase tracking-wide text-sand-500 dark:text-sand-400">Tickets handled</dt>
<dd class="mt-1 text-2xl font-extrabold text-sand-800 dark:text-sand-100">{{ roi.total_tickets }}</dd>
</div>
<div class="sc-card sc-kpi p-4">
<dt class="text-xs font-semibold uppercase tracking-wide text-sand-500 dark:text-sand-400">Escalation</dt>
<dd class="mt-1 text-2xl font-extrabold text-sand-800 dark:text-sand-100">{{ '%.0f' % (roi.escalation_rate * 100) }}%</dd>
</div>
<div class="sc-card sc-kpi p-4">
<dt class="text-xs font-semibold uppercase tracking-wide text-sand-500 dark:text-sand-400">Monthly savings</dt>
<dd class="mt-1 text-2xl font-extrabold text-brand-600 dark:text-brand-400">${{ '{:,.0f}'.format(roi.monthly_cost_saved_projection) }}</dd>
</div>
</dl>
</section>
<!-- Chat -->
<section id="chat" class="mt-12 max-w-3xl mx-auto scroll-mt-20">
<div class="mb-4 flex items-center justify-between">
<div>
<h2 class="text-xl font-extrabold tracking-tight">Customer support chat</h2>
<p class="text-sm text-sand-500 dark:text-sand-400">
Grounded in Northwind Outdoors' catalog &amp; policies — every answer cites its source.
</p>
</div>
</div>
<div class="sc-card overflow-hidden">
<!-- Thread -->
<div id="thread" class="sc-scroll flex flex-col gap-4 p-4 sm:p-5" style="min-height: 22rem; max-height: 52vh; overflow-y:auto;" aria-live="polite">
<!-- Greeting (agent) -->
<div class="flex items-start gap-2.5">
<span class="sc-grad mt-0.5 grid h-8 w-8 shrink-0 place-items-center rounded-full text-white">
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>
</span>
<div class="sc-bubble sc-bubble--agent text-sand-700 dark:text-sand-200">
Hi there! 👋 I'm the Northwind Outdoors support copilot. Ask about products, shipping,
returns, or an order — or tap an example below to see me work.
</div>
</div>
</div>
<!-- Composer -->
<form
id="chat-form"
class="border-t border-sand-200/70 p-3 dark:border-sand-700/60"
hx-post="/chat"
hx-target="#thread"
hx-swap="beforeend"
hx-on::after-request="if(event.detail.successful){this.querySelector('#message').value='';scrollThread();}"
>
<div class="mb-2 grid grid-cols-1 gap-2 sm:grid-cols-2">
<div class="relative">
<label for="order_id" class="sr-only">Order number</label>
<input id="order_id" name="order_id" type="text" autocomplete="off"
placeholder="Order # (optional, e.g. NW-1001)"
class="sc-focus w-full rounded-xl border border-sand-200 bg-sand-50/60 px-3 py-2 text-sm text-sand-800 placeholder:text-sand-400 dark:border-sand-700 dark:bg-sand-800/40 dark:text-sand-100" />
</div>
<div class="relative">
<label for="email" class="sr-only">Email</label>
<input id="email" name="email" type="email" autocomplete="off"
placeholder="Email (optional)"
class="sc-focus w-full rounded-xl border border-sand-200 bg-sand-50/60 px-3 py-2 text-sm text-sand-800 placeholder:text-sand-400 dark:border-sand-700 dark:bg-sand-800/40 dark:text-sand-100" />
</div>
</div>
<div class="flex items-center gap-2">
<label for="message" class="sr-only">Your message</label>
<input id="message" name="message" type="text" required autofocus autocomplete="off"
placeholder="Type your question…"
class="sc-focus min-w-0 flex-1 rounded-full border border-sand-200 bg-sand-50/60 px-4 py-2.5 text-[15px] text-sand-800 placeholder:text-sand-400 dark:border-sand-700 dark:bg-sand-800/40 dark:text-sand-100" />
<button type="submit"
class="sc-btn-primary sc-focus shrink-0 !px-4 !py-2.5">
<span class="htmx-indicator h-4 w-4 animate-spin rounded-full border-2 border-white/40 border-t-white"></span>
<span class="htmx-indicator-hide">Send</span>
<svg class="htmx-indicator-hide h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
</button>
</div>
</form>
</div>
<!-- Example chips -->
<div class="mt-4">
<p class="mb-2 text-xs font-semibold uppercase tracking-wide text-sand-400 dark:text-sand-500">Try an example</p>
<div class="flex flex-wrap gap-2">
{% set examples = [
("How long does standard shipping take and is it free?", "", ""),
("I'd like to return my tent, it's unused with tags.", "NW-1001", "alex@example.com"),
("What's the status of my order?", "NW-1002", "jordan@example.com"),
("Do you have an ultralight 2-person tent? How much does it weigh?", "", ""),
("My tent pole snapped on its first trip, I think it's defective.", "NW-1001", "alex@example.com")
] %}
{% for text, oid, mail in examples %}
<button type="button"
onclick='useExample({{ text | tojson }}, {{ oid | tojson }}, {{ mail | tojson }})'
class="rounded-full border border-sand-200 bg-sand-50/70 px-3.5 py-1.5 text-xs font-medium text-sand-600 transition hover:-translate-y-0.5 hover:border-brand-300 hover:bg-brand-50 hover:text-brand-700 dark:border-sand-700 dark:bg-sand-800/40 dark:text-sand-300 dark:hover:border-brand-500/40 dark:hover:text-brand-300">
{{ text }}
</button>
{% endfor %}
</div>
</div>
</section>
{% endblock %}
</content>