side: /chat — spoerg-mit-cv AI (frontend; backend /api/chat)
Build & Deploy / deploy (push) Successful in 1m42s
Build & Deploy / deploy (push) Successful in 1m42s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8f7741db20
commit
f4685a87f8
@@ -0,0 +1,61 @@
|
||||
---
|
||||
import Base from '../layouts/Base.astro';
|
||||
---
|
||||
<Base title="Spørg mit CV" description="En lille AI-chat der svarer på spørgsmål om mig, min erfaring og mit homelab.">
|
||||
<h1 class="text-4xl font-bold tracking-tight">Spørg mit CV</h1>
|
||||
<p class="mt-4 max-w-2xl text-muted">
|
||||
En lille AI der har læst mit CV og denne side, og svarer på spørgsmål om mig.. fx
|
||||
<em>“hvad har Asger lavet med Peppol?”</em> eller <em>“hvilken stack kører hans homelab?”</em>.
|
||||
Den ved kun noget om mig — alt andet må du google selv.
|
||||
</p>
|
||||
|
||||
<div id="chat-log" class="mt-8 space-y-3" aria-live="polite"></div>
|
||||
|
||||
<form id="chat-form" class="mt-6 flex gap-3">
|
||||
<input id="chat-input" type="text" required maxlength="500" autocomplete="off"
|
||||
placeholder="Spørg om erfaring, Peppol, homelab…"
|
||||
class="flex-1 rounded-xl border border-border bg-surface/60 px-4 py-2.5 outline-none focus:border-accent" />
|
||||
<button type="submit" class="rounded-xl bg-accent px-5 py-2.5 font-medium text-bg transition-transform hover:-translate-y-0.5">Send</button>
|
||||
</form>
|
||||
<p class="mt-3 text-xs text-muted/80">Svar genereres af en sprogmodel ud fra mit offentlige CV — tjek vigtige detaljer med mig direkte.</p>
|
||||
|
||||
<script is:inline>
|
||||
(function () {
|
||||
var form = document.getElementById('chat-form');
|
||||
if (!form || form.__wired) return; form.__wired = true;
|
||||
var history = [];
|
||||
function bubble(role, text) {
|
||||
var log = document.getElementById('chat-log');
|
||||
var d = document.createElement('div');
|
||||
d.className = 'rounded-2xl border border-border p-4 text-sm whitespace-pre-wrap ' +
|
||||
(role === 'user' ? 'bg-surface-2 ml-8' : 'bg-surface/60 mr-8');
|
||||
d.textContent = text;
|
||||
log.appendChild(d);
|
||||
d.scrollIntoView({ behavior: 'smooth', block: 'end' });
|
||||
return d;
|
||||
}
|
||||
form.addEventListener('submit', async function (e) {
|
||||
e.preventDefault();
|
||||
var input = document.getElementById('chat-input');
|
||||
var q = input.value.trim(); if (!q) return;
|
||||
input.value = '';
|
||||
bubble('user', q);
|
||||
history.push({ role: 'user', content: q });
|
||||
var wait = bubble('assistant', '…tænker');
|
||||
var btn = form.querySelector('button'); btn.disabled = true;
|
||||
try {
|
||||
var r = await fetch('/api/chat', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ messages: history.slice(-10) }),
|
||||
});
|
||||
var data = await r.json();
|
||||
if (!r.ok) { wait.textContent = data.error || 'Chatten er offline lige nu — prøv senere.'; return; }
|
||||
wait.textContent = data.reply;
|
||||
history.push({ role: 'assistant', content: data.reply });
|
||||
} catch (_) {
|
||||
wait.textContent = 'Kunne ikke nå chatten — prøv igen om lidt.';
|
||||
} finally { btn.disabled = false; input.focus(); }
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</Base>
|
||||
@@ -10,6 +10,9 @@ export async function GET() {
|
||||
{ type: 'page', title: 'Blog', url: '/blog' },
|
||||
{ type: 'page', title: 'Tags', url: '/tags' },
|
||||
{ type: 'page', title: 'Peppol-opslag', url: '/peppol' },
|
||||
{ type: 'page', title: 'Spørg mit CV (AI-chat)', url: '/chat' },
|
||||
{ type: 'page', title: 'Status (homelab)', url: '/status' },
|
||||
{ type: 'page', title: 'Now', url: '/now' },
|
||||
{ type: 'page', title: 'Uses', url: '/uses' },
|
||||
{ type: 'page', title: 'Kolofon', url: '/colophon' },
|
||||
...posts
|
||||
|
||||
Reference in New Issue
Block a user