Spaces:
Sleeping
Sleeping
| {# HTML fragment returned by POST /chat and appended to the chat thread by htmx. #} | |
| {# ----- User message (right) ----- #} | |
| <div class="sc-fade flex items-start justify-end gap-2.5"> | |
| <div class="sc-bubble sc-bubble--user">{{ message }}</div> | |
| <span class="mt-0.5 grid h-8 w-8 shrink-0 place-items-center rounded-full bg-sand-200 text-sand-500 dark:bg-sand-700 dark:text-sand-300"> | |
| <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="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg> | |
| </span> | |
| </div> | |
| {# ----- Agent reply (left) ----- #} | |
| <div class="sc-fade 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="min-w-0 flex-1 space-y-2.5"> | |
| {# Status / intent / confidence badges #} | |
| <div class="flex flex-wrap items-center gap-1.5"> | |
| {% if resp.escalated %} | |
| <span class="sc-badge sc-badge--escalate"> | |
| <svg class="h-3 w-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 11h-6"/></svg> | |
| Escalated to human | |
| </span> | |
| {% elif resp.auto_resolved %} | |
| <span class="sc-badge sc-badge--resolved"> | |
| <svg class="h-3 w-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg> | |
| Auto-resolved | |
| </span> | |
| {% endif %} | |
| <span class="sc-badge sc-badge--neutral">{{ resp.intent | replace('_', ' ') }}</span> | |
| </div> | |
| {# Answer bubble #} | |
| <div class="sc-bubble sc-bubble--agent text-sand-700 dark:text-sand-200"> | |
| {{ resp.answer }} | |
| </div> | |
| {# Confidence meter #} | |
| <div class="flex items-center gap-2 pl-1"> | |
| <span class="text-[11px] font-semibold text-sand-400 dark:text-sand-500">Confidence</span> | |
| <div class="sc-meter w-24"><span style="width: {{ (resp.confidence * 100) | round(0, 'floor') }}%"></span></div> | |
| <span class="text-[11px] font-bold text-sand-500 dark:text-sand-400">{{ '%.0f' % (resp.confidence * 100) }}%</span> | |
| </div> | |
| {# Refund / escalation decision card #} | |
| {% if resp.refund %} | |
| <div class="sc-decision sc-decision--{{ resp.refund.outcome }}"> | |
| <div class="flex items-center gap-2"> | |
| {% if resp.refund.outcome == 'approve' %} | |
| <svg class="h-4 w-4 text-emerald-600 dark:text-emerald-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg> | |
| {% elif resp.refund.outcome == 'deny' %} | |
| <svg class="h-4 w-4 text-red-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg> | |
| {% else %} | |
| <svg class="h-4 w-4 text-amber-600 dark:text-amber-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg> | |
| {% endif %} | |
| <span class="text-sm font-bold text-sand-800 dark:text-sand-100"> | |
| Refund decision: {{ resp.refund.outcome | upper }} | |
| {% if resp.refund.outcome == 'approve' %} | |
| · ${{ '%.2f' % resp.refund.refund_amount }} | |
| {% if resp.refund.fee_applied %}<span class="font-normal text-sand-500 dark:text-sand-400">(after ${{ '%.2f' % resp.refund.fee_applied }} return-shipping fee)</span>{% endif %} | |
| {% endif %} | |
| </span> | |
| </div> | |
| <p class="mt-1.5 text-sm text-sand-600 dark:text-sand-300">{{ resp.refund.reason }}</p> | |
| <div class="mt-2 flex items-center gap-1.5 text-xs text-sand-500 dark:text-sand-400"> | |
| <svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg> | |
| Per <span class="font-semibold text-sand-600 dark:text-sand-300">{{ resp.refund.policy_citation }}</span> | |
| </div> | |
| </div> | |
| {% endif %} | |
| {# Escalation explainer card (no refund object but escalated) #} | |
| {% if resp.escalated and not resp.refund %} | |
| <div class="sc-decision sc-decision--escalate flex items-start gap-2"> | |
| <svg class="mt-0.5 h-4 w-4 shrink-0 text-amber-600 dark:text-amber-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.81.36 1.6.7 2.34a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.74-1.27a2 2 0 0 1 2.11-.45c.74.34 1.53.57 2.34.7A2 2 0 0 1 22 16.92z"/></svg> | |
| <p class="text-sm text-sand-600 dark:text-sand-300"> | |
| Handed off to a human specialist — the agent escalates sensitive or low-confidence | |
| cases instead of guessing. | |
| </p> | |
| </div> | |
| {% endif %} | |
| {# Citations as chips #} | |
| {% if resp.citations %} | |
| <div> | |
| <p class="mb-1.5 flex items-center gap-1.5 text-xs font-semibold text-sand-400 dark:text-sand-500"> | |
| <svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg> | |
| Sources ({{ resp.citations | length }}) | |
| </p> | |
| <div class="flex flex-wrap gap-1.5"> | |
| {% for c in resp.citations %} | |
| <span class="sc-chip sc-chip--{{ c.kind }}" title="{{ c.snippet }}"> | |
| <span class="sc-chip-dot"></span>{{ c.title }} | |
| </span> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| {% endif %} | |
| </div> | |
| </div> | |