# Byg en Chat-assistent med AI
Kan du huske i Star Trek, da besætningen afslappet talte med skibets computer, stillede den komplekse spørgsmål og fik gennemførte svar? Hvad der virkede som ren science fiction i 1960’erne, er nu noget, du kan bygge ved hjælp af webteknologier, du allerede kender.
I denne lektion skaber vi en AI-chatassistent ved hjælp af HTML, CSS, JavaScript og en backend-integration. Du vil opdage, hvordan de samme færdigheder, du har lært, kan forbinde til kraftfulde AI-tjenester, som kan forstå kontekst og generere meningsfulde svar.
Tænk på AI som adgang til et enormt bibliotek, der ikke blot kan finde information, men også syntetisere det til sammenhængende svar, der er skræddersyet til dine specifikke spørgsmål. I stedet for at gennemgå tusindvis af sider får du direkte, kontekstuelle svar.
Integrationen sker gennem velkendte webteknologier, der arbejder sammen. HTML skaber chatgrænsefladen, CSS håndterer det visuelle design, JavaScript styrer brugerinteraktioner, og en backend-API forbinder det hele til AI-tjenester. Det ligner, hvordan forskellige sektioner i et orkester samarbejder for at skabe en symfoni.
Vi bygger i bund og grund en bro mellem naturlig menneskelig kommunikation og maskinbehandling. Du lærer både den tekniske implementering af AI-tjenesteintegration og designmønstrene, der gør interaktioner intuitive.
Ved slutningen af denne lektion vil AI-integration føles mindre som en mystisk proces og mere som en hvilken som helst anden API, du kan arbejde med. Du vil forstå de grundlæggende mønstre, der driver applikationer som ChatGPT og Claude, ved at bruge de samme webudviklingsprincipper, du allerede har lært.
## ⚡ Hvad Du Kan Nå på de Næste 5 Minutter
**Hurtig Startvej for Travle Udviklere**
```mermaid
flowchart LR
A[⚡ 5 minutter] --> B[Få GitHub-token]
B --> C[Test AI legeplads]
C --> D[Kopiér Python-kode]
D --> E[Se AI-svar]
```
- **Minut 1**: Besøg [GitHub Models Playground](https://github.com/marketplace/models/azure-openai/gpt-4o-mini/playground) og opret en personlig adgangstoken
- **Minut 2**: Test AI-interaktioner direkte i playground-grænsefladen
- **Minut 3**: Klik på fanen "Code" og kopier Python-koden
- **Minut 4**: Kør koden lokalt med din token: `GITHUB_TOKEN=your_token python test.py`
- **Minut 5**: Se dit første AI-svar genereres fra din egen kode
**Hurtig Testkode**:
```python
import os
from openai import OpenAI
client = OpenAI(
base_url="https://models.github.ai/inference",
api_key="your_token_here"
)
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Hello AI!"}],
model="openai/gpt-4o-mini"
)
print(response.choices[0].message.content)
```
**Hvorfor det betyder noget**: På 5 minutter vil du opleve magien ved programmeret AI-interaktion. Dette repræsenterer grundstenen, der driver alle AI-applikationer, du bruger.
Sådan vil dit færdige projekt se ud:

## 🗺️ Din Læringsrejse Gennem AI-applikationsudvikling
```mermaid
journey
title Fra Webudvikling til AI-Integration
section Forståelse af AI-Grundlag
Opdag generative AI-koncepter: 4: You
Udforsk GitHub Models platform: 6: You
Mestre AI-parametre og prompts: 8: You
section Backend Integration
Byg Python API-server: 5: You
Implementer AI-funktionskald: 7: You
Håndter asynkrone operationer: 8: You
section Frontend Udvikling
Skab moderne chatgrænseflade: 6: You
Mestre realtidsinteraktioner: 8: You
Byg responsiv brugeroplevelse: 9: You
section Professionel Anvendelse
Udrul komplet AI-system: 7: You
Optimer ydelsesmønstre: 8: You
Skab produktionsklar app: 9: You
```
**Dit Mål for Rejsen**: Ved lektionens afslutning har du bygget en komplet AI-drevet applikation med de samme teknologier og mønstre, der driver moderne AI-assistenter som ChatGPT, Claude og Google Bard.
## Forstå AI: Fra Mystik til Mestring
Før vi dykker ned i koden, lad os forstå, hvad vi arbejder med. Hvis du har brugt API’er før, kender du det grundlæggende mønster: sende en anmodning, modtage et svar.
AI-API’er følger en lignende struktur, men i stedet for at hente forudlagrede data fra en database genererer de nye svar baseret på mønstre lært fra enorme mængder tekst. Tænk på det som forskellen mellem et bibliotekskatalog og en kyndig bibliotekar, der kan syntetisere information fra flere kilder.
### Hvad er "Generativ AI" Egentlig?
Tænk på, hvordan Rosetta-stenen gjorde det muligt for forskere at forstå egyptiske hieroglyffer ved at finde mønstre mellem kendte og ukendte sprog. AI-modeller arbejder på samme måde – de finder mønstre i enorme tekstmængder for at forstå, hvordan sprog fungerer, og bruger derefter disse mønstre til at generere passende svar på nye spørgsmål.
**Lad mig forklare det med en simpel sammenligning:**
- **Traditionel database**: Som at bede om din fødselsattest – du får det samme dokument hver gang
- **Søgemaskine**: Som at bede en bibliotekar finde bøger om katte – de viser dig, hvad der er tilgængeligt
- **Generativ AI**: Som at spørge en vidende ven om katte – de fortæller dig interessante ting med deres egne ord, tilpasset det, du vil vide
```mermaid
graph LR
A[Dit Spørgsmål] --> B[AI Model]
B --> C[Mønster Genkendelse]
C --> D[Indholds Generering]
D --> E[Kontekstuel Respons]
F[Træningsdata
Bøger, Artikler, Web] --> B
```
### Hvordan AI-modeller Lærer (Den Enkle Version)
AI-modeller lærer gennem eksponering for enorme datasæt indeholdende tekst fra bøger, artikler og samtaler. Gennem denne proces identificerer de mønstre i:
- Hvordan tanker struktureres i skriftlig kommunikation
- Hvilke ord der ofte optræder sammen
- Hvordan samtaler typisk flyder
- Kontekstuelle forskelle mellem formel og uformel kommunikation
**Det svarer til, hvordan arkæologer afkoder gamle sprog**: de analyserer tusinder af eksempler for at forstå grammatik, ordforråd og kulturel kontekst, og bliver til sidst i stand til at tolke nye tekster ved hjælp af disse lærte mønstre.
### Hvorfor GitHub Models?
Vi bruger GitHub Models af en praktisk årsag – det giver os adgang til AI på virksomhedsniveau uden at skulle opsætte vores egen AI-infrastruktur (hvilket du for resten ikke har lyst til lige nu!). Tænk på det som at bruge en vejr-API i stedet for selv at oprette vejrstationer overalt.
Det er i bund og grund "AI-som-en-Service", og det bedste? Det er gratis at komme i gang med, så du kan eksperimentere uden bekymring om store regninger.
```mermaid
graph LR
A[Frontend Chat UI] --> B[Din Backend API]
B --> C[GitHub Models API]
C --> D[AI Modelbehandling]
D --> C
C --> B
B --> A
```
Vi bruger GitHub Models til vores backend-integration, som giver adgang til professionelle AI-kapaciteter gennem en udviklervenlig grænseflade. [GitHub Models Playground](https://github.com/marketplace/models/azure-openai/gpt-4o-mini/playground) fungerer som et testmiljø, hvor du kan prøve forskellige AI-modeller og forstå deres egenskaber, før du implementerer dem i kode.
## 🧠 AI-applikationsudviklingsøkosystem
```mermaid
mindmap
root((AI Udvikling))
Forståelse af AI
Generative Modeller
Mønster Genkendelse
Indhold Generering
Kontekst Forståelse
Svar Syntese
AI Parametre
Temperatur Kontrol
Token Grænser
Top-p Filtrering
System Prompter
Backend Arkitektur
API Integration
GitHub Modeller
Autentificering
Forespørgsels Håndtering
Fejl Håndtering
Python Infrastruktur
FastAPI Framework
Async Operationer
Miljø Sikkerhed
CORS Konfiguration
Frontend Oplevelse
Chat Interface
Real-time Opdateringer
Besked Historik
Bruger Feedback
Indlæsnings Tilstande
Moderne Web Teknologi
ES6 Klasser
Async/Await
DOM Manipulation
Event Håndtering
Professionelle Mønstre
Sikkerheds Bedste Praksis
Token Håndtering
Input Validering
XSS Forebyggelse
Fejlgrænser
Produktionsberedskab
Ydelsesoptimering
Responsivt Design
Tilgængelighed
Test Strategier
```
**Kerneprincip**: AI-applikationsudvikling kombinerer traditionelle webudviklingsfærdigheder med AI-tjenesteintegration for at skabe intelligente applikationer, der føles naturlige og responsive for brugerne.

**Det der gør playground så nyttig:**
- **Prøv** forskellige AI-modeller som GPT-4o-mini, Claude og andre (alle gratis!)
- **Test** dine idéer og prompts inden du skriver kode
- **Få** klar-til-brug kodeeksempler i dit foretrukne programmeringssprog
- **Juster** indstillinger som kreativitet og svarlængde for at se, hvordan de påvirker output
Når du har prøvet lidt, klik bare på fanen "Code" og vælg dit programmersprog for at få den nødvendige implementeringskode.

## Opsætning af Python Backend Integration
Lad os nu implementere AI-integrationen med Python. Python er fremragende til AI-applikationer pga. sin simple syntaks og kraftfulde biblioteker. Vi starter med koden fra GitHub Models playground og refaktorerer den derefter til en genanvendelig, produktionsklar funktion.
### Forstå den Grundlæggende Implementering
Når du henter Python-koden fra playground, får du noget, der ligner dette. Bare rolig, hvis det virker meget til at starte med – lad os gennemgå det stykke for stykke:
```python
"""Run this model in Python
> pip install openai
"""
import os
from openai import OpenAI
# For at godkende med modellen skal du generere et personligt adgangstoken (PAT) i dine GitHub-indstillinger.
# Opret dit PAT-token ved at følge instruktionerne her: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
client = OpenAI(
base_url="https://models.github.ai/inference",
api_key=os.environ["GITHUB_TOKEN"],
)
response = client.chat.completions.create(
messages=[
{
"role": "system",
"content": "",
},
{
"role": "user",
"content": "What is the capital of France?",
}
],
model="openai/gpt-4o-mini",
temperature=1,
max_tokens=4096,
top_p=1
)
print(response.choices[0].message.content)
```
**Det der sker i denne kode:**
- **Vi importerer** de nødvendige værktøjer: `os` til at læse miljøvariabler og `OpenAI` til at kommunikere med AI
- **Vi opsætter** OpenAI-klienten til at pege på GitHubs AI-servere i stedet for direkte OpenAI
- **Vi autentificerer** med en særlig GitHub-token (mere om det om lidt!)
- **Vi strukturerer** vores samtale med forskellige "roller" – tænk på det som at sætte scenen for et skuespil
- **Vi sender** vores anmodning til AI med nogle finjusteringsparametre
- **Vi udtrækker** det faktiske svartekst fra al den data, der kommer tilbage
### Forståelse af Beskedsroller: AI-samtalens Rammeværk
AI-samtaler bruger en specifik struktur med forskellige "roller", der tjener forskellige formål:
```python
messages=[
{
"role": "system",
"content": "You are a helpful assistant who explains things simply."
},
{
"role": "user",
"content": "What is machine learning?"
}
]
```
**Tænk på det som at instruere et skuespil:**
- **System-rollen**: Som scenemanuskript for en skuespiller – den fortæller AI, hvordan den skal opføre sig, hvilken personlighed den skal have og hvordan den skal svare
- **Bruger-rollen**: Det egentlige spørgsmål eller besked fra den, der bruger din applikation
- **Assistent-rollen**: AIs svar (det sender du ikke, men det vises i samtalehistorikken)
**Virkelighedsfaglig analogi**: Forestil dig, at du præsenterer en ven for en anden til en fest:
- **Systembesked**: "Det her er min ven Sarah, hun er læge og er rigtig god til at forklare medicinske begreber i enkle termer"
- **Brugerbesked**: "Kan du forklare, hvordan vacciner virker?"
- **Assistentbesked**: Sarah svarer som en venlig læge, ikke som advokat eller kok
### Forstå AI-parametre: Finjustering af Svaradfærd
De numeriske parametre i AI-API-kald kontrollerer, hvordan modellen genererer svar. Disse indstillinger giver dig mulighed for at justere AIs adfærd til forskellige formål:
#### Temperatur (0,0 til 2,0): Kreativitetsdrejeknappen
**Hvad den gør**: Styrer, hvor kreativ eller forudsigelig AIs svar bliver.
**Tænk på det som en jazzmusikers improvisationsniveau:**
- **Temperatur = 0,1**: Spiller den nøjagtige samme melodi hver gang (meget forudsigelig)
- **Temperatur = 0,7**: Tilføjer nogle smagfulde variationer, mens det stadig er genkendeligt (balanceret kreativitet)
- **Temperatur = 1,5**: Fuld eksperimentel jazz med uventede drejninger (meget uforudsigeligt)
```python
# Meget forudsigelige svar (godt til faktuelle spørgsmål)
response = client.chat.completions.create(
messages=[{"role": "user", "content": "What is 2+2?"}],
temperature=0.1 # Vil næsten altid sige "4"
)
# Kreative svar (godt til brainstorm)
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Write a creative story opening"}],
temperature=1.2 # Vil generere unikke, uventede historier
)
```
#### Max Tokens (1 til 4096+): Kontrol af Svarets Længde
**Hvad den gør**: Sætter en grænse for, hvor langt AIs svar kan være.
**Tænk på tokens som omtrent svarende til ord** (ca. 1 token = 0,75 ord på engelsk):
- **max_tokens=50**: Kort og godt (som en sms)
- **max_tokens=500**: Et pænt afsnit eller to
- **max_tokens=2000**: En detaljeret forklaring med eksempler
```python
# Korte, præcise svar
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Explain JavaScript"}],
max_tokens=100 # Tvinger en kort forklaring
)
# Detaljerede, omfattende svar
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Explain JavaScript"}],
max_tokens=1500 # Muliggør detaljerede forklaringer med eksempler
)
```
#### Top_p (0,0 til 1,0): Fokusparameteren
**Hvad den gør**: Kontrollerer, hvor fokuseret AI er på de mest sandsynlige svar.
**Forestil dig at AI har et kæmpe ordforråd, rangeret efter sandsynlighed:**
- **top_p=0,1**: Overvejer kun de 10 % mest sandsynlige ord (meget fokuseret)
- **top_p=0,9**: Overvejer 90 % af mulige ord (mere kreativ)
- **top_p=1,0**: Overvejer alt (maksimal variation)
**For eksempel**: Hvis du spørger "Himmelen er normalt..."
- **Lav top_p**: Siger næsten altid "blå"
- **Høj top_p**: Kan sige "blå", "skyet", "uendelig", "foranderlig", "smuk" osv.
### Sætte Det Hele Sammen: Parameterkombinationer til Forskellige Brug
```python
# For faktuelle, konsistente svar (som en dokumentationsbot)
factual_params = {
"temperature": 0.2,
"max_tokens": 300,
"top_p": 0.3
}
# Til kreativ skrivehjælp
creative_params = {
"temperature": 1.1,
"max_tokens": 1000,
"top_p": 0.9
}
# Til samtaleorienterede, hjælpsomme svar (afbalanceret)
conversational_params = {
"temperature": 0.7,
"max_tokens": 500,
"top_p": 0.8
}
```
```mermaid
quadrantChart
title AI Parameteroptimeringsmatrix
x-axis Lav Kreativitet --> Høj Kreativitet
y-axis Kort Respons --> Lang Respons
quadrant-1 Kreativt Indhold
quadrant-2 Detaljeret Analyse
quadrant-3 Hurtige Fakta
quadrant-4 Samtale-AI
Documentation Bot: [0.2, 0.3]
Customer Service: [0.4, 0.4]
General Assistant: [0.7, 0.5]
Creative Writer: [0.9, 0.9]
Brainstorming Tool: [0.8, 0.8]
```
**Hvorfor disse parametre er vigtige**: Forskellige applikationer har brug for forskellige typer svar. En kundeservicebot bør være konsekvent og faktuel (lav temperatur), mens en kreativ skriveassistent skal være fantasifuld og varieret (høj temperatur). At forstå disse parametre giver dig kontrol over din AIs personlighed og svarstil.
```
**Here's what's happening in this code:**
- **We import** the tools we need: `os` for reading environment variables and `OpenAI` for talking to the AI
- **We set up** the OpenAI client to point to GitHub's AI servers instead of OpenAI directly
- **We authenticate** using a special GitHub token (more on that in a minute!)
- **We structure** our conversation with different "roles" – think of it like setting the scene for a play
- **We send** our request to the AI with some fine-tuning parameters
- **We extract** the actual response text from all the data that comes back
> 🔐 **Security Note**: Never hardcode API keys in your source code! Always use environment variables to store sensitive credentials like your `GITHUB_TOKEN`.
### Creating a Reusable AI Function
Let's refactor this code into a clean, reusable function that we can easily integrate into our web application:
```python
import asyncio
from openai import AsyncOpenAI
# Use AsyncOpenAI for better performance
client = AsyncOpenAI(
base_url="https://models.github.ai/inference",
api_key=os.environ["GITHUB_TOKEN"],
)
async def call_llm_async(prompt: str, system_message: str = "You are a helpful assistant."):
"""
Sends a prompt to the AI model asynchronously and returns the response.
Args:
prompt: The user's question or message
system_message: Instructions that define the AI's behavior and personality
Returns:
str: The AI's response to the prompt
"""
try:
response = await client.chat.completions.create(
messages=[
{
"role": "system",
"content": system_message,
},
{
"role": "user",
"content": prompt,
}
],
model="openai/gpt-4o-mini",
temperature=1,
max_tokens=4096,
top_p=1
)
return response.choices[0].message.content
except Exception as e:
logger.error(f"AI API error: {str(e)}")
return "I'm sorry, I'm having trouble processing your request right now."
# Backward compatibility function for synchronous calls
def call_llm(prompt: str, system_message: str = "You are a helpful assistant."):
"""Synchronous wrapper for async AI calls."""
return asyncio.run(call_llm_async(prompt, system_message))
```
**Forstå denne forbedrede funktion:**
- **Accepterer** to parametre: brugerens prompt og en valgfri systembesked
- **Tilbyder** en standard systembesked for generel assistentadfærd
- **Bruger** korrekte Python typeangivelser til bedre kodetekst
- **Inkluderer** en detaljeret docstring, der forklarer funktionens formål og parametre
- **Returnerer** kun svarindholdet, så det er nemt at bruge i vores web-API
- **Vedligeholder** de samme modelparametre for konsistent AI-adfærd
### Magien ved Systemprompter: Programmering af AI-personlighed
Hvis parametre styrer, hvordan AI tænker, styrer systemprompter, hvem AI tror, den er. Dette er ærligt talt en af de fedeste dele ved at arbejde med AI – du giver AI en komplet personlighed, fagligt niveau og kommunikationsstil.
**Tænk på systemprompter som at caste forskellige skuespillere til forskellige roller**: I stedet for én generisk assistent kan du skabe specialiserede eksperter til forskellige situationer. Brug for en tålmodig lærer? En kreativ brainstormingpartner? En seriøs forretningsrådgiver? Bare skift systemprompten!
#### Hvorfor Systemprompter Er Så Kraftfulde
Her er det fascinerende: AI-modeller er trænet på utallige samtaler, hvor folk påtager sig forskellige roller og ekspertiseniveauer. Når du giver AI en specifik rolle, er det som at trykke på en kontakt, der aktiverer alle de lærte mønstre.
**Det svarer til metode-skuespil for AI**: Sig til en skuespiller "du er en klog, gammel professor" og se, hvordan de automatisk tilpasser kropsholdning, ordvalg og manerer. AI gør noget bemærkelsesværdigt lignende med sprog.
#### Skabelse af Effektive Systemprompter: Kunsten og Videnskaben
**Anatomien af en god systemprompt:**
1. **Rolle/Identitet**: Hvem er AI?
2. **Ekspertise**: Hvad ved den?
3. **Kommunikationsstil**: Hvordan taler den?
4. **Specifikke instruktioner**: Hvad skal den fokusere på?
```python
# ❌ Uklar systemprompt
"You are helpful."
# ✅ Detaljeret, effektiv systemprompt
"You are Dr. Sarah Chen, a senior software engineer with 15 years of experience at major tech companies. You explain programming concepts using real-world analogies and always provide practical examples. You're patient with beginners and enthusiastic about helping them understand complex topics."
```
#### Systemprompt-eksempler med kontekst
Lad os se, hvordan forskellige systemprompter skaber helt forskellige AI-personligheder:
```python
# Eksempel 1: Den tålmodige lærer
teacher_prompt = """
You are an experienced programming instructor who has taught thousands of students.
You break down complex concepts into simple steps, use analogies from everyday life,
and always check if the student understands before moving on. You're encouraging
and never make students feel bad for not knowing something.
"""
# Eksempel 2: Den kreative samarbejdspartner
creative_prompt = """
You are a creative writing partner who loves brainstorming wild ideas. You're
enthusiastic, imaginative, and always build on the user's ideas rather than
replacing them. You ask thought-provoking questions to spark creativity and
offer unexpected perspectives that make stories more interesting.
"""
# Eksempel 3: Den strategiske forretningsrådgiver
business_prompt = """
You are a strategic business consultant with an MBA and 20 years of experience
helping startups scale. You think in frameworks, provide structured advice,
and always consider both short-term tactics and long-term strategy. You ask
probing questions to understand the full business context before giving advice.
"""
```
#### Se Systemprompter i Aktion
Lad os teste det samme spørgsmål med forskellige systemprompter for at se de dramatiske forskelle:
**Spørgsmål**: "Hvordan håndterer jeg brugerautentifikation i min webapp?"
```python
# Med lærer-prompt:
teacher_response = call_llm(
"How do I handle user authentication in my web app?",
teacher_prompt
)
# Typisk svar: "Godt spørgsmål! Lad os opdele autentificering i simple trin.
# Tænk på det som en natklub dørmand, der tjekker ID'er..."
# Med forretningsprompt:
business_response = call_llm(
"How do I handle user authentication in my web app?",
business_prompt
)
# Typisk svar: "Set fra et strategisk perspektiv er autentificering afgørende for bruger
# tillid og overholdelse af regler. Lad mig skitsere en ramme, der tager højde for sikkerhed,
# brugeroplevelse og skalerbarhed..."
```
#### Avancerede Systemprompt-teknikker
**1. Kontekstopsætning**: Giv AI baggrundsinformation
```python
system_prompt = """
You are helping a junior developer who just started their first job at a startup.
They know basic HTML/CSS/JavaScript but are new to backend development and databases.
Be encouraging and explain things step-by-step without being condescending.
"""
```
**2. Outputformatering**: Fortæl AI'en, hvordan svar skal struktureres
```python
system_prompt = """
You are a technical mentor. Always structure your responses as:
1. Quick Answer (1-2 sentences)
2. Detailed Explanation
3. Code Example
4. Common Pitfalls to Avoid
5. Next Steps for Learning
"""
```
**3. Begrænsningsindstilling**: Definer, hvad AI'en IKKE skal gøre
```python
system_prompt = """
You are a coding tutor focused on teaching best practices. Never write complete
solutions for the user - instead, guide them with hints and questions so they
learn by doing. Always explain the 'why' behind coding decisions.
"""
```
#### Hvorfor dette er vigtigt for din chatassistent
Forståelse af systemprompter giver dig utrolig magt til at skabe specialiserede AI-assistenter:
- **Kundeservicebot**: Hjælpsom, tålmodig, politik-kyndig
- **Læringsvejleder**: Opmuntrende, trin-for-trin, tjekker forståelse
- **Kreativ partner**: Fantasifuld, bygger videre på ideer, spørger "hvad nu hvis?"
- **Teknisk ekspert**: Præcis, detaljeret, sikkerhedsbevidst
**Den centrale indsigt**: Du kalder ikke bare en AI API – du skaber en brugerdefineret AI-personlighed, der tjener dit specifikke brugsscenarie. Det er det, der gør moderne AI-applikationer skræddersyede og nyttige i stedet for generiske.
### 🎯 Pædagogisk tjek-in: AI-personlighedsprogrammering
**Pause og reflekter**: Du har netop lært at programmere AI-personligheder via systemprompter. Dette er en grundlæggende færdighed i moderne AI-applikationsudvikling.
**Hurtig selvvurdering**:
- Kan du forklare, hvordan systemprompter adskiller sig fra almindelige brugermeddelelser?
- Hvad er forskellen på temperatur- og top_p-parametre?
- Hvordan ville du skabe en systemprompt for et specifikt brugsscenarie (f.eks. en kodevejleder)?
**Virkelighedsnær forbindelse**: De systemprompt-teknikker, du har lært, bruges i alle større AI-applikationer – fra GitHub Copilots kodeassistance til ChatGPT's samtalegrænseflade. Du mestrer de samme mønstre, som AI-produktteams bruger hos store tech-virksomheder.
**Udfordrende spørgsmål**: Hvordan kunne du designe forskellige AI-personligheder til forskellige brugertyper (begynder vs ekspert)? Overvej, hvordan det samme underliggende AI-model kunne betjene forskellige målgrupper via prompt-engineering.
## Byg Web API'en med FastAPI: Dit Højtydende AI-kommunikationsknudepunkt
Lad os nu bygge backend'en, der forbinder din frontend med AI-tjenester. Vi vil bruge FastAPI, et moderne Python-framework, som er fremragende til at bygge API’er til AI-applikationer.
FastAPI tilbyder flere fordele for denne type projekt: indbygget asynkron støtte til håndtering af samtidige forespørgsler, automatisk API-dokumentationsgenerering og fremragende ydeevne. Din FastAPI-server fungerer som en mellemliggende del, der modtager forespørgsler fra frontend, kommunikerer med AI-tjenesterne og returnerer formaterede svar.
### Hvorfor FastAPI til AI-applikationer?
Du tænker måske: "Kan jeg ikke bare kalde AI direkte fra min frontend JavaScript?" eller "Hvorfor FastAPI frem for Flask eller Django?" Gode spørgsmål!
**Her er hvorfor FastAPI er perfekt til det, vi bygger:**
- **Async som standard**: Kan jonglere flere AI-forespørgsler samtidig uden at hænge fast
- **Automatisk dokumentation**: Besøg `/docs` og få en flot, interaktiv API-dokumentationsside gratis
- **Indbygget validering**: Fanger fejl, før de skaber problemer
- **Lynhurtig**: Et af de hurtigste Python-frameworks overhovedet
- **Moderne Python**: Bruger alle de nyeste og bedste Python-funktioner
**Og her er hvorfor vi overhovedet har brug for en backend:**
**Sikkerhed**: Dit AI API-nøgle er som en adgangskode – hvis du lægger den i frontend JavaScript, kan alle, der ser din hjemmesides kildekode, stjæle den og bruge dine AI-kreditter. Backend'en holder følsomme legitimationsoplysninger sikre.
**Ratebegrænsning & kontrol**: Backend'en lader dig styre, hvor ofte brugere kan sende forespørgsler, implementere brugerautentifikation og tilføje logning for at spore brug.
**Databehandling**: Du vil måske gemme samtaler, filtrere upassende indhold eller kombinere flere AI-tjenester. Backend'en er stedet, hvor denne logik hører hjemme.
**Arkitekturen minder om en klient-server-model:**
- **Frontend**: Brugergrænsefladelag til interaktion
- **Backend API**: Forespørgselsbehandling og routering
- **AI-tjeneste**: Ekstern udregning og svargenerering
- **Miljøvariabler**: Sikker konfigurations- og legitimationslagring
### Forståelse af forespørgsels- og svarflowet
Lad os følge, hvad der sker, når en bruger sender en besked:
```mermaid
sequenceDiagram
participant User as 👤 Bruger
participant Frontend as 🌐 Frontend
participant API as 🔧 FastAPI Server
participant AI as 🤖 AI Service
User->>Frontend: Taster "Hej AI!"
Frontend->>API: POST /hello {"message": "Hej AI!"}
Note over API: Validerer forespørgsel
Tilføjer systemprompt
API->>AI: Sender formateret forespørgsel
AI->>API: Returnerer AI svar
Note over API: Behandler svar
Logger samtale
API->>Frontend: {"response": "Hej! Hvordan kan jeg hjælpe?"}
Frontend->>User: Viser AI besked
```
**Forstå hvert trin:**
1. **Brugerinteraktion**: Personen skriver i chatgrænsefladen
2. **Frontend-behandling**: JavaScript fanger input og formaterer det som JSON
3. **API-validering**: FastAPI validerer automatisk forespørgslen vha. Pydantic-modeller
4. **AI-integration**: Backend tilføjer kontekst (systemprompt) og kalder AI-tjenesten
5. **Svarhåndtering**: API modtager AI-svar og kan ændre det efter behov
6. **Frontend-visning**: JavaScript viser svaret i chatgrænsefladen
### Forståelse af API-arkitekturen
```mermaid
sequenceDiagram
participant Frontend
participant FastAPI
participant AI Function
participant GitHub Models
Frontend->>FastAPI: POST /hello {"message": "Hej AI!"}
FastAPI->>AI Function: call_llm(message, system_prompt)
AI Function->>GitHub Models: API forespørgsel
GitHub Models->>AI Function: AI svar
AI Function->>FastAPI: svar tekst
FastAPI->>Frontend: {"response": "Hej! Hvordan kan jeg hjælpe?"}
```
```mermaid
flowchart TD
A[Brugerinput] --> B[Frontend Validering]
B --> C[HTTP POST Anmodning]
C --> D[FastAPI Router]
D --> E[Pydantic Validering]
E --> F[AI Funktionskald]
F --> G[GitHub Models API]
G --> H[Svarbehandling]
H --> I[JSON Svar]
I --> J[Frontend Opdatering]
subgraph "Sikkerhedslag"
K[CORS Middleware]
L[Miljøvariabler]
M[Fejlhåndtering]
end
D --> K
F --> L
H --> M
```
### Oprettelse af FastAPI-applikationen
Lad os bygge vores API trin for trin. Opret en fil med navnet `api.py` med følgende FastAPI-kode:
```python
# api.py
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from llm import call_llm
import logging
# Konfigurer logning
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Opret FastAPI-applikation
app = FastAPI(
title="AI Chat API",
description="A high-performance API for AI-powered chat applications",
version="1.0.0"
)
# Konfigurer CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Konfigurer passende til produktion
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Pydantic-modeller til anmodnings-/responsvalidering
class ChatMessage(BaseModel):
message: str
class ChatResponse(BaseModel):
response: str
@app.get("/")
async def root():
"""Root endpoint providing API information."""
return {
"message": "Welcome to the AI Chat API",
"docs": "/docs",
"health": "/health"
}
@app.get("/health")
async def health_check():
"""Health check endpoint."""
return {"status": "healthy", "service": "ai-chat-api"}
@app.post("/hello", response_model=ChatResponse)
async def chat_endpoint(chat_message: ChatMessage):
"""Main chat endpoint that processes messages and returns AI responses."""
try:
# Udtræk og valider besked
message = chat_message.message.strip()
if not message:
raise HTTPException(status_code=400, detail="Message cannot be empty")
logger.info(f"Processing message: {message[:50]}...")
# Kald AI-service (bemærk: call_llm bør laves asynkron for bedre ydeevne)
ai_response = await call_llm_async(message, "You are a helpful and friendly assistant.")
logger.info("AI response generated successfully")
return ChatResponse(response=ai_response)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error processing chat message: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=5000, reload=True)
```
**Forståelse af FastAPI-implementeringen:**
- **Importer** FastAPI for moderne webframework-funktionalitet og Pydantic for datavalidering
- **Opretter** automatisk API-dokumentation (tilgængelig på `/docs`, når serveren kører)
- **Aktiverer** CORS-middleware for at tillade frontend-forespørgsler fra forskellige oprindelser
- **Definerer** Pydantic-modeller til automatisk validering af forespørgsler/svar og dokumentation
- **Bruger** asynkrone endpoints for bedre ydeevne ved samtidige forespørgsler
- **Implementerer** korrekte HTTP-statuskoder og fejlhåndtering med HTTPException
- **Inkluderer** struktureret logning til overvågning og fejlfinding
- **Tilbyder** et health check-endpoint til overvågning af servicestatus
**Nøglefordele ved FastAPI over traditionelle frameworks:**
- **Automatisk validering**: Pydantic-modeller sikrer data-integritet før behandling
- **Interaktive docs**: Besøg `/docs` for automatisk genereret, testbar API-dokumentation
- **Typsikkerhed**: Python type hints forebygger runtime-fejl og forbedrer kodekvalitet
- **Async support**: Håndter flere AI-forespørgsler samtidigt uden blokering
- **Ydeevne**: Markant hurtigere forespørgselsbehandling til realtidsapplikationer
### Forståelse af CORS: Webens sikkerhedsvagt
CORS (Cross-Origin Resource Sharing) er som en sikkerhedsvagt ved en bygning, der tjekker, om besøgende må komme ind. Lad os forstå, hvorfor det betyder noget, og hvordan det påvirker din applikation.
#### Hvad er CORS, og hvorfor findes det?
**Problemet**: Forestil dig, at enhver hjemmeside kunne sende forespørgsler til din banks hjemmeside på dine vegne uden din tilladelse. Det ville være et sikkerhedsmareridt! Browsere forhindrer dette som standard gennem "Same-Origin Policy."
**Same-Origin Policy**: Browsere tillader kun, at websider sender forespørgsler til samme domæne, port og protokol, som de blev indlæst fra.
**Virkelighedslignelse**: Det er som sikkerheden i en lejlighedsbygning – kun beboere (samme oprindelse) kan som standard komme ind. Vil du lade en ven (anden oprindelse) besøge, skal du eksplicit fortælle sikkerhedsvagten, at det er i orden.
#### CORS i dit udviklingsmiljø
Under udvikling kører din frontend og backend på forskellige porte:
- Frontend: `http://localhost:3000` (eller file:// hvis HTML åbnes direkte)
- Backend: `http://localhost:5000`
Disse betragtes som "forskellige oprindelser," selvom de kører på samme computer!
```python
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(__name__)
CORS(app) # Dette fortæller browsere: "Det er i orden, at andre oprindelser foretager forespørgsler til dette API"
```
**Hvad CORS-konfiguration gør i praksis:**
- **Tilføjer** særlige HTTP-headere til API-svar, der fortæller browsere "denne cross-origin-forespørgsel er tilladt"
- **Håndterer** "preflight" forespørgsler (browsere tjekker nogle gange tilladelser, før den egentlige forespørgsel sendes)
- **Forhindrer** den frygtede fejlkode "blokeret af CORS-politik" i din browserkonsol
#### CORS-sikkerhed: Udvikling vs produktion
```python
# 🚨 Udvikling: Tillader ALLE oprindelser (praktisk men usikkert)
CORS(app)
# ✅ Produktion: Tillad kun dit specifikke frontend-domæne
CORS(app, origins=["https://yourdomain.com", "https://www.yourdomain.com"])
# 🔒 Avanceret: Forskellige oprindelser for forskellige miljøer
if app.debug: # Udviklingstilstand
CORS(app, origins=["http://localhost:3000", "http://127.0.0.1:3000"])
else: # Produktionstilstand
CORS(app, origins=["https://yourdomain.com"])
```
**Hvorfor det betyder noget**: I udvikling er `CORS(app)` som at lade din hoveddør stå ulåst – bekvemt, men ikke sikkert. I produktion vil du specificere præcis hvilke hjemmesider, der må tale med din API.
#### Almindelige CORS-scenarier og løsninger
| Scenario | Problem | Løsning |
|----------|---------|----------|
| **Lokal udvikling** | Frontend kan ikke nå backend | Tilføj CORSMiddleware til FastAPI |
| **GitHub Pages + Heroku** | Udrullet frontend kan ikke nå API | Tilføj din GitHub Pages URL til CORS oprindelser |
| **Custom domæne** | CORS-fejl i produktion | Opdater CORS oprindelser til at matche dit domæne |
| **Mobilapp** | App kan ikke nå web-API | Tilføj dit apps domæne eller brug `*` med omhu |
**Pro tip**: Du kan tjekke CORS-headere i browserens udviklerværktøjer under fanen Netværk. Kig efter headere som `Access-Control-Allow-Origin` i svaret.
### Fejlhåndtering og validering
Bemærk, hvordan vores API inkluderer korrekt fejlhåndtering:
```python
# Bekræft, at vi har modtaget en besked
if not message:
return jsonify({"error": "Message field is required"}), 400
```
**Nøgleprincipper for validering:**
- **Tjekker** for påkrævede felter før behandling af forespørgsler
- **Returnerer** meningsfulde fejlbeskeder i JSON-format
- **Bruger** passende HTTP-statuskoder (400 for dårlige forespørgsler)
- **Giver** klar feedback, der hjælper frontend-udviklere med at debugge problemer
## Opsætning og kørsel af din backend
Nu hvor vi har AI-integration og FastAPI-server klar, lad os få det hele til at køre. Opsætningsprocessen involverer installation af Python-afhængigheder, konfiguration af miljøvariabler og start af din udviklingsserver.
### Python-miljøopsætning
Lad os opsætte dit Python-udviklingsmiljø. Virtuelle miljøer er som Manhattan-projektets afdelte tilgang – hvert projekt får sin egen isolerede plads med specifikke værktøjer og afhængigheder, som forhindrer konflikter mellem projekter.
```bash
# Gå til din backend-mappe
cd backend
# Opret et virtuelt miljø (som at oprette et rengøringsrum til dit projekt)
python -m venv venv
# Aktivér det (Linux/Mac)
source ./venv/bin/activate
# På Windows, brug:
# venv\Scripts\activate
# Installer det gode stuff
pip install openai fastapi uvicorn python-dotenv
```
**Hvad vi lige gjorde:**
- **Oprettede** vores egen lille Python-boble, hvor vi kan installere pakker uden at påvirke andet
- **Aktiverede** den, så terminalen ved at bruge dette specifikke miljø
- **Installerede** det væsentlige: OpenAI til AI-magi, FastAPI til vores web-API, Uvicorn til faktisk at køre den, og python-dotenv til sikker håndtering af hemmeligheder
**Nøgletillæg forklaret:**
- **FastAPI**: Moderne, hurtigt web-framework med automatisk API-dokumentation
- **Uvicorn**: Lynhurtig ASGI-server, der kører FastAPI-applikationer
- **OpenAI**: Officiel bibliotek til GitHub Models og OpenAI API-integration
- **python-dotenv**: Sikker indlæsning af miljøvariabler fra .env-filer
### Miljøkonfiguration: Hold hemmeligheder sikre
Før vi starter API'en, skal vi tale om en af de vigtigste lektioner i webudvikling: hvordan man faktisk holder sine hemmeligheder hemmelige. Miljøvariabler er som et sikkert pengeskab, som kun din applikation har adgang til.
#### Hvad er miljøvariabler?
**Tænk på miljøvariabler som en sikkerhedsboks** – du lægger dine værdifulde ting deri, og kun du (og din app) har nøglen til at få dem ud. I stedet for at skrive følsomme oplysninger direkte i koden (hvor bogstaveligt talt alle kan se dem), opbevarer du dem sikkert i miljøet.
**Her er forskellen:**
- **Den forkerte måde**: Skrive din adgangskode på en seddel og sætte den på din skærm
- **Den rigtige måde**: Holde din adgangskode i en sikker adgangskodehåndtering, som kun du kan tilgå
#### Hvorfor miljøvariabler betyder noget
```python
# 🚨 GØR ALDRIG DETTE - API-nøgle synlig for alle
client = OpenAI(
api_key="ghp_1234567890abcdef...", # Alle kan stjæle denne!
base_url="https://models.github.ai/inference"
)
# ✅ GØR DETTE - API-nøgle gemt sikkert
client = OpenAI(
api_key=os.environ["GITHUB_TOKEN"], # Kun din app kan få adgang til denne
base_url="https://models.github.ai/inference"
)
```
**Hvad der sker, når du hardcoder hemmeligheder:**
1. **Versionskontrol-eksponering**: Alle med adgang til dit Git-repository ser din API-nøgle
2. **Offentlige repositories**: Hvis du pusher til GitHub, er din nøgle synlig for hele internettet
3. **Teamdeling**: Andre udviklere på projektet får adgang til din personlige API-nøgle
4. **Sikkerhedsbrud**: Hvis nogen stjæler din API-nøgle, kan de bruge dine AI-kreditter
#### Opsætning af din miljøfil
Opret en `.env`-fil i din backend-mappe. Denne fil gemmer dine hemmeligheder lokalt:
```bash
# .env fil - Denne bør ALDRIG committes til Git
GITHUB_TOKEN=your_github_personal_access_token_here
FASTAPI_DEBUG=True
ENVIRONMENT=development
```
**Forståelse af .env-filen:**
- **Én hemmelighed per linje** i formatet `KEY=value`
- **Ingen mellemrum** omkring lighedstegnet
- **Ingen citationstegn** nødvendigt omkring værdier (som regel)
- **Kommentarer** starter med `#`
#### Oprettelse af dit GitHub Personlige Adgangstoken
Dit GitHub-token er som en særlig adgangskode, der giver din applikation tilladelse til at bruge GitHubs AI-tjenester:
**Trin-for-trin tokenoprettelse:**
1. **Gå til GitHub Settings** → Developer settings → Personal access tokens → Tokens (classic)
2. **Klik på "Generate new token (classic)"**
3. **Sæt udløbsdato** (30 dage til test, længere til produktion)
4. **Vælg scopes**: Marker "repo" og eventuelle andre nødvendige tilladelser
5. **Generer token** og kopier det med det samme (det kan ikke ses igen!)
6. **Indsæt i din .env-fil**
```bash
# Eksempel på hvordan dit token ser ud (dette er falsk!)
GITHUB_TOKEN=ghp_1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R
```
#### Indlæsning af miljøvariabler i Python
```python
import os
from dotenv import load_dotenv
# Indlæs miljøvariabler fra .env-fil
load_dotenv()
# Nu kan du få adgang til dem sikkert
api_key = os.environ.get("GITHUB_TOKEN")
if not api_key:
raise ValueError("GITHUB_TOKEN not found in environment variables!")
client = OpenAI(
api_key=api_key,
base_url="https://models.github.ai/inference"
)
```
**Hvad denne kode gør:**
- **Indlæser** din .env-fil og gør variabler tilgængelige i Python
- **Tjekker** om det nødvendige token findes (god fejlhåndtering!)
- **Kaster** en klar fejl, hvis token mangler
- **Bruger** token sikkert uden at eksponere det i koden
#### Git-sikkerhed: .gitignore-filen
Din `.gitignore`-fil fortæller Git, hvilke filer der aldrig skal trackes eller uploades:
```bash
# .gitignore - Tilføj disse linjer
.env
*.env
.env.local
.env.production
__pycache__/
venv/
.vscode/
```
**Hvorfor det er afgørende**: Når du tilføjer `.env` til `.gitignore`, ignorerer Git din miljøfil og forhindrer, at du utilsigtet uploader dine hemmeligheder til GitHub.
#### Forskellige miljøer, forskellige hemmeligheder
Professionelle applikationer bruger forskellige API-nøgler til forskellige miljøer:
```bash
# .env.udvikling
GITHUB_TOKEN=your_development_token
DEBUG=True
# .env.produktion
GITHUB_TOKEN=your_production_token
DEBUG=False
```
**Hvorfor det betyder noget**: Du vil undgå, at dine udviklingseksperimenter påvirker din produktions AI-brugsgrænse, og du ønsker forskellige sikkerhedsniveauer for forskellige miljøer.
### Start af din udviklingsserver: Giv liv til din FastAPI
Nu kommer det spændende øjeblik – at starte din FastAPI-udviklingsserver og se din AI-integration blive levende! FastAPI bruger Uvicorn, en lynhurtig ASGI-server, der er specielt designet til asynkrone Python-applikationer.
#### Forståelse af FastAPI-serverens opstartsproces
```bash
# Metode 1: Direkte Python-udførelse (inkluderer automatisk genindlæsning)
python api.py
# Metode 2: Brug af Uvicorn direkte (mere kontrol)
uvicorn api:app --host 0.0.0.0 --port 5000 --reload
```
Når du kører denne kommando, sker følgende bag kulisserne:
**1. Python loader din FastAPI-applikation**:
- Importerer alle nødvendige biblioteker (FastAPI, Pydantic, OpenAI osv.)
- Loader miljøvariabler fra din `.env`-fil
- Opretter FastAPI-applikationsinstansen med automatisk dokumentation
**2. Uvicorn konfigurerer ASGI-serveren**:
- Binder til port 5000 med asynkron anmodningshåndtering
- Sætter anmodningsrouting op med automatisk validering
- Aktiverer hot reload til udvikling (genstarter ved filændringer)
- Genererer interaktiv API-dokumentation
**3. Serveren begynder at lytte**:
- Din terminal viser: `INFO: Uvicorn running on http://0.0.0.0:5000`
- Serveren kan håndtere flere samtidige AI-forespørgsler
- Din API er klar med automatisk dokumentation på `http://localhost:5000/docs`
#### Hvad du bør se, når alt fungerer
```bash
$ python api.py
INFO: Will watch for changes in these directories: ['/your/project/path']
INFO: Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit)
INFO: Started reloader process [12345] using WatchFiles
INFO: Started server process [12346]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
**Forståelse af FastAPI-uddata:**
- **Vil overvåge ændringer**: Auto-reload aktiveret til udvikling
- **Uvicorn kører**: Højtydende ASGI-server er aktiv
- **Starter genloader-processen**: Filovervågning til automatisk genstart
- **Applikationsstart fuldført**: FastAPI-app initialiseret med succes
- **Interaktive docs tilgængelige**: Besøg `/docs` for automatisk API-dokumentation
#### Test af din FastAPI: Flere kraftfulde tilgange
FastAPI tilbyder flere praktiske måder at teste din API på, inklusiv automatisk interaktiv dokumentation:
**Metode 1: Interaktiv API-dokumentation (Anbefalet)**
1. Åbn din browser og gå til `http://localhost:5000/docs`
2. Du vil se Swagger UI med alle dine endpoints dokumenteret
3. Klik på `/hello` → "Try it out" → Indtast en testbesked → "Execute"
4. Se svaret direkte i browseren med korrekt formatering
**Metode 2: Grundlæggende browser-test**
1. Gå til `http://localhost:5000` for roden af endpoint
2. Gå til `http://localhost:5000/health` for at tjekke serverens helbred
3. Dette bekræfter, at din FastAPI-server kører korrekt
**Metode 2: Kommandolinjetest (Avanceret)**
```bash
# Test med curl (hvis tilgængelig)
curl -X POST http://localhost:5000/hello \
-H "Content-Type: application/json" \
-d '{"message": "Hello AI!"}'
# Forventet svar:
# {"response": "Hej! Jeg er din AI-assistent. Hvordan kan jeg hjælpe dig i dag?"}
```
**Metode 3: Python-testscripts**
```python
# test_api.py - Opret denne fil for at teste din API
import requests
import json
# Test API-endpointet
url = "http://localhost:5000/hello"
data = {"message": "Tell me a joke about programming"}
response = requests.post(url, json=data)
if response.status_code == 200:
result = response.json()
print("AI Response:", result['response'])
else:
print("Error:", response.status_code, response.text)
```
#### Fejlfinding af almindelige opstartsproblemer
| Fejlmeddelelse | Hvad det betyder | Hvordan du løser det |
|---------------|------------------|---------------------|
| `ModuleNotFoundError: No module named 'fastapi'` | FastAPI ikke installeret | Kør `pip install fastapi uvicorn` i dit virtuelle miljø |
| `ModuleNotFoundError: No module named 'uvicorn'` | ASGI-server ikke installeret | Kør `pip install uvicorn` i dit virtuelle miljø |
| `KeyError: 'GITHUB_TOKEN'` | Miljøvariabel ikke fundet | Tjek din `.env`-fil og `load_dotenv()`-opkald |
| `Address already in use` | Port 5000 er optaget | Stop andre processer, der bruger port 5000, eller skift port |
| `ValidationError` | Anmodningsdata matcher ikke Pydantic-modellen | Tjek at din anmodning matcher den forventede skema |
| `HTTPException 422` | Ubehandlingsbar enhed | Anmodningsvalidering fejlede, tjek `/docs` for korrekt format |
| `OpenAI API error` | AI-serviceens autentificering fejlede | Bekræft at din GitHub-token er korrekt og har rette tilladelser |
#### Udviklingsbest practices
**Hot Reloading**: FastAPI med Uvicorn tilbyder automatisk genindlæsning, når du gemmer ændringer i dine Python-filer. Det betyder, at du kan ændre din kode og teste med det samme uden manuelt at genstarte.
```python
# Aktivér hot reloading eksplicit
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True) # debug=True aktiverer hot reload
```
**Logging til udvikling**: Tilføj logging for at forstå, hvad der sker:
```python
import logging
# Opsæt logning
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@app.route("/hello", methods=["POST"])
def hello():
data = request.get_json()
message = data.get("message", "")
logger.info(f"Received message: {message}")
if not message:
logger.warning("Empty message received")
return jsonify({"error": "Message field is required"}), 400
try:
response = call_llm(message, "You are a helpful and friendly assistant.")
logger.info(f"AI response generated successfully")
return jsonify({"response": response})
except Exception as e:
logger.error(f"AI API error: {str(e)}")
return jsonify({"error": "AI service temporarily unavailable"}), 500
```
**Hvorfor logging hjælper**: Under udvikling kan du se præcis hvilke forespørgsler, der kommer ind, hvad AI’en svarer med, og hvor fejl opstår. Det gør fejlfinding meget hurtigere.
### Konfiguration til GitHub Codespaces: Skyudvikling gjort nemt
GitHub Codespaces er som en kraftfuld udviklingscomputer i skyen, som du kan tilgå fra enhver browser. Hvis du arbejder i Codespaces, er der et par ekstra trin for at gøre din backend tilgængelig for dit frontend.
#### Forståelse af netværket i Codespaces
I et lokalt udviklingsmiljø kører alt på samme computer:
- Backend: `http://localhost:5000`
- Frontend: `http://localhost:3000` (eller file://)
I Codespaces kører dit udviklingsmiljø på GitHubs servere, så "localhost" har en anden betydning. GitHub opretter automatisk offentlige URL’er til dine tjenester, men du skal konfigurere dem korrekt.
#### Trin-for-trin Codespaces-konfiguration
**1. Start din backend-server**:
```bash
cd backend
python api.py
```
Du vil se den velkendte FastAPI/Uvicorn opstartsmeddelelse, men bemærk, at den kører inde i Codespace-miljøet.
**2. Konfigurer port-synlighed**:
- Kig efter fanen "Ports" i nederste panel i VS Code
- Find port 5000 på listen
- Højreklik på port 5000
- Vælg "Port Visibility" → "Public"
**Hvorfor gøre den offentlig?** Som standard er Codespace-porte private (kun tilgængelige for dig). At gøre den offentlig tillader, at dit frontend (som kører i browseren) kan kommunikere med din backend.
**3. Få din offentlige URL**:
Efter at have gjort porten offentlig, vil du se en URL som:
```
https://your-codespace-name-5000.app.github.dev
```
**4. Opdater din frontend-konfiguration**:
```javascript
// I din frontend app.js, opdater BASE_URL:
this.BASE_URL = "https://your-codespace-name-5000.app.github.dev";
```
#### Forståelse af Codespace-URL’er
Codespace-URL’er følger et forudsigeligt mønster:
```
https://[codespace-name]-[port].app.github.dev
```
**Nedbrudt i dele:**
- `codespace-name`: En unik identifikator for din Codespace (ofte inkluderer dit brugernavn)
- `port`: Portnummer, som din service kører på (5000 for vores FastAPI-app)
- `app.github.dev`: GitHubs domæne for Codespace-applikationer
#### Test af din Codespace-opsætning
**1. Test backenden direkte**:
Åbn din offentlige URL i en ny browsertab. Du bør se:
```
Welcome to the AI Chat API. Send POST requests to /hello with JSON payload containing 'message' field.
```
**2. Test med browserens udviklerværktøjer**:
```javascript
// Åbn browserkonsollen og test din API
fetch('https://your-codespace-name-5000.app.github.dev/hello', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({message: 'Hello from Codespaces!'})
})
.then(response => response.json())
.then(data => console.log(data));
```
#### Codespaces vs Lokal udvikling
| Aspekt | Lokal udvikling | GitHub Codespaces |
|--------|-----------------|-------------------|
| **Opsætningstid** | Længere (installer Python, afhængigheder) | Øjeblikkelig (forudkonfigureret miljø) |
| **URL-adgang** | `http://localhost:5000` | `https://xyz-5000.app.github.dev` |
| **Portkonfiguration** | Automatisk | Manuel (gør porte offentlige) |
| **Filpersistens** | Lokal maskine | GitHub repository |
| **Samarbejde** | Vanskeligt at dele miljø | Let at dele Codespace-link |
| **Internetafhængighed** | Kun til AI API-kald | Krævet til alt |
#### Tips til udvikling i Codespace
**Miljøvariabler i Codespaces**:
Din `.env`-fil fungerer på samme måde i Codespaces, men du kan også sætte miljøvariabler direkte i Codespace:
```bash
# Indstil miljøvariabel for den aktuelle session
export GITHUB_TOKEN="your_token_here"
# Eller tilføj til din .bashrc for vedvarende effekt
echo 'export GITHUB_TOKEN="your_token_here"' >> ~/.bashrc
```
**Portstyring**:
- Codespaces registrerer automatisk, når din applikation begynder at lytte på en port
- Du kan videresende flere porte samtidigt (nyttigt, hvis du senere tilføjer en database)
- Porte forbliver tilgængelige, så længe din Codespace kører
**Udviklingsworkflow**:
1. Foretag kodeændringer i VS Code
2. FastAPI genindlæses automatisk (takket være Uvicorns reload-tilstand)
3. Test ændringer øjeblikkeligt via den offentlige URL
4. Commit og push, når du er klar
> 💡 **Pro tip**: Bogmærk din Codespace backend-URL under udvikling. Da Codespace-navne er stabile, vil URL’en ikke ændre sig, så længe du bruger samme Codespace.
## Opret frontend chat-interface: Hvor mennesker møder AI
Nu bygger vi brugergrænsefladen – den del, der bestemmer, hvordan folk interagerer med din AI-assistent. Ligesom designet af den oprindelige iPhone-grænseflade fokuserer vi på at gøre kompleks teknologi intuitiv og naturlig at bruge.
### Forståelse af moderne frontend-arkitektur
Vores chat-interface bliver det, vi kalder en “Single Page Application” eller SPA. I stedet for den gammeldags tilgang, hvor hvert klik indlæser en ny side, opdaterer vores app glat og øjeblikkeligt:
**Gamle hjemmesider**: Som at læse en fysisk bog – du bladre til helt nye sider
**Vores chat-app**: Som at bruge din telefon – alt flyder og opdateres gnidningsfrit
```mermaid
graph TD
A[Bruger skriver besked] --> B[JavaScript fanger input]
B --> C[Valider og formater data]
C --> D[Send til backend API]
D --> E[Vis indlæsningsstatus]
E --> F[Modtag AI-svar]
F --> G[Opdater chatgrænseflade]
G --> H[Klar til næste besked]
```
```mermaid
classDiagram
class ChatApp {
+beskeder: HTMLElement
+formular: HTMLElement
+input: HTMLElement
+sendKnap: HTMLElement
+BASE_URL: string
+API_ENDPOINT: string
+constructor()
+initialiserEventLyttere()
+håndterIndsendelse(event)
+kaldAPI(besked)
+tilføjBesked(tekst, rolle)
+escapeHtml(tekst)
+rulTilBund()
+sætIndlæsning(erIndlæser)
}
ChatApp --> DOM : manipulerer
ChatApp --> FastAPI : sender forespørgsler
```
### De tre søjler i frontend-udvikling
Enhver frontend-applikation – fra simple websites til komplekse apps som Discord eller Slack – er bygget på tre kerne-teknologier. Tænk på dem som fundamentet for alt, du ser og interagerer med på webben:
**HTML (Struktur)**: Dette er dit fundament
- Bestemmer, hvilke elementer der findes (knapper, tekstområder, containere)
- Giver mening til indholdet (dette er en overskrift, dette er en formular osv.)
- Skaber den grundlæggende struktur, som alt andet bygger på
**CSS (Præsentation)**: Dette er din indretningsarkitekt
- Får alt til at se smukt ud (farver, skrifttyper, layout)
- Håndterer forskellige skærmstørrelser (mobil, laptop, tablet)
- Skaber bløde animationer og visuel feedback
**JavaScript (Adfærd)**: Dette er din hjerne
- Reagerer på brugerhandlinger (klik, skrivning, scroll)
- Kommunikerer med din backend og opdaterer siden
- Gør alting interaktivt og dynamisk
**Tænk på det som arkitektonisk design:**
- **HTML**: Det strukturelle blueprint (definerer rum og forhold)
- **CSS**: Det æstetiske og miljømæssige design (visuel stil og brugeroplevelse)
- **JavaScript**: De mekaniske systemer (funktionalitet og interaktivitet)
### Hvorfor moderne JavaScript-arkitektur er vigtigt
Vores chat-applikation vil bruge moderne JavaScript-mønstre, som du vil se i professionelle applikationer. At forstå disse koncepter hjælper dig som udvikler:
**Klasselignende arkitektur**: Vi organiserer vores kode i klasser, som at lave blueprints til objekter
**Async/Await**: Moderne måde at håndtere operationer, der tager tid (f.eks. API-kald)
**Event-drevet programmering**: Vores app reagerer på brugerhandlinger (klik, tastetryk) fremfor at køre i en løkke
**DOM-manipulation**: Dynamisk opdatering af websides indhold baseret på brugerinteraktioner og API-respons
### Projektstrukturopsætning
Opret en frontend-mappe med denne organiserede struktur:
```text
frontend/
├── index.html # Main HTML structure
├── app.js # JavaScript functionality
└── styles.css # Visual styling
```
**Forstå arkitekturen:**
- **Adskiller** bekymringer mellem struktur (HTML), adfærd (JavaScript) og præsentation (CSS)
- **Bevarer** en enkel filstruktur, som er let at navigere og ændre
- **Følger** bedste webudviklingspraksis for organisering og vedligeholdelse
### Opbygning af HTML-fundamentet: Semantisk struktur for tilgængelighed
Lad os starte med HTML-strukturen. Moderne webudvikling fremhæver “semantisk HTML” – brugen af HTML-elementer, der klart beskriver deres formål, ikke kun deres udseende. Det gør din applikation tilgængelig for skærmlæsere, søgemaskiner og andre værktøjer.
**Hvorfor semantisk HTML er vigtigt**: Forestil dig, at du skulle beskrive din chat-app til en person over telefonen. Du ville sige “der er en header med titlen, et hovedområde hvor samtaler vises, og en formular nederst til at skrive beskeder.” Semantisk HTML bruger elementer, der matcher denne naturlige beskrivelse.
Opret `index.html` med denne gennemtænkte markup:
```html
Ask me anything!