fix: lessons
This commit is contained in:
310
Les18-AI-Toolbox-Next/Les18-Docenttekst.md
Normal file
310
Les18-AI-Toolbox-Next/Les18-Docenttekst.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# Les 18 — Advanced AI Toolbox
|
||||
## Docenttekst (Klas A — 3 uur, fysiek, demo-driven, laatste les)
|
||||
|
||||
**Les:** 18 van 18
|
||||
**Onderwerp:** Voice + Vision + Image gen + Local LLMs + Edge AI + wrap-up
|
||||
**Duur:** 180 minuten
|
||||
**Demo-app:** Vijf mini-demo's, niet één
|
||||
|
||||
---
|
||||
|
||||
## VÓÓR DE LES (60 min)
|
||||
|
||||
1. Alle vijf demo's lokaal werkend op laptop
|
||||
2. OpenAI account (Whisper + Vision werkend)
|
||||
3. Fal.ai account (image gen)
|
||||
4. Ollama geïnstalleerd + llama4:8b gedownload (vooraf — duurt 10 min)
|
||||
5. Vercel AI Gateway demo-project klaar
|
||||
6. Browser tabs: ollama.com, fal.ai, vercel.com/docs/ai-gateway
|
||||
7. Mentaal voorbereid: laatste les, ruimte voor reflectie aan eind
|
||||
|
||||
---
|
||||
|
||||
## HET SCRIPT
|
||||
|
||||
### BLOK 1 — Welkom + Recap (10 min)
|
||||
|
||||
`[SLIDE 1]`
|
||||
|
||||
**Vertel:** "Welkom bij de allerlaatste les. Les 18. Vandaag: alle leuke modaliteiten die we nog niet hebben gezien. Voice, vision, image gen, local LLMs, edge AI."
|
||||
|
||||
`[SLIDE 2]`
|
||||
|
||||
**Vertel:** "Even kort terug. 18 lessen. Foundations 1-10, AI SDK 11, Tool Calling 12, Cursor+Vercel 13, Agents 14, RAG 15, MCP 16, Production Polish 17, vandaag.
|
||||
|
||||
Vandaag is anders dan voorgaande lessen. Geen één onderwerp dat we diep in gaan. Vijf modaliteiten, korte demo's, je weet wat mogelijk is. Voor je eindopdracht: kies wat past."
|
||||
|
||||
`[SLIDE 3]`
|
||||
|
||||
**Vertel:** "180 minuten. 25 min theorie en landschap. Vijf demo's van 20-25 min. Pauze rond minuut 80. Aan eind 25 min voor reflectie + vragen."
|
||||
|
||||
---
|
||||
|
||||
### BLOK 2 — Theorie + landschap (25 min)
|
||||
|
||||
`[SLIDE 4]`
|
||||
|
||||
**Vertel:** "Het landschap eind 2026. Verschillende providers, verschillende sterke punten.
|
||||
|
||||
OpenAI heeft GPT-5 voor algemeen, o3 voor reasoning, GPT-realtime voor voice. Anthropic Claude Opus 4.6 en Sonnet 4.6 — best voor code en lange context. Google Gemini 2.5 met 2 miljoen context window. Meta Llama 4 — open-source, je kunt 'm lokaal draaien.
|
||||
|
||||
Modaliteiten — text, vision, voice, image, video. En modi — cloud API, edge, lokaal.
|
||||
|
||||
Vandaag zien we alle drie de modi."
|
||||
|
||||
`[SLIDE 5]`
|
||||
|
||||
**Vertel:** "Waarom multimodal? Tekst is niet altijd genoeg. Mobile? Voice is sneller dan typen. Foto-upload? Vision. Marketing-assets? Image gen.
|
||||
|
||||
Denk per feature: welke modaliteit past het best? Niet alles is chat."
|
||||
|
||||
---
|
||||
|
||||
### BLOK 3 — DEMO 1: Voice (25 min)
|
||||
|
||||
`[SLIDE 6]` `[SCHERM: editor + browser]`
|
||||
|
||||
**Vertel:** "Whisper voor transcriptie. Drie regels code."
|
||||
|
||||
`*[Maak app/voice/page.tsx + api/transcribe/route.ts]*`
|
||||
|
||||
```typescript
|
||||
const result = await transcribe({
|
||||
model: openai.transcription("whisper-1"),
|
||||
audio: audioBlob,
|
||||
});
|
||||
```
|
||||
|
||||
`*[Demo: klik record, spreek, zie tekst verschijnen]*`
|
||||
|
||||
**Vertel:** "Werkt. Cost: $0.006 per minuut. Voor productie: ElevenLabs voor TTS-stemmen die natuurlijker klinken.
|
||||
|
||||
Volledige voice-loop? Drie calls. Whisper + LLM + TTS. Latency ongeveer 2-4 seconden. Voor 'echte' voice met interruptions: Realtime API. Complexer, magisch."
|
||||
|
||||
💬 *Vraag: 'Hoe duur is dit op schaal?'*
|
||||
|
||||
**Antwoord:** "Voor 1000 vragen van 30 seconden: Whisper $3, LLM $1, TTS $5. Negen dollar voor duizend voice-interacties. Schaalbaar."
|
||||
|
||||
---
|
||||
|
||||
### BLOK 4 — DEMO 2: Vision (20 min)
|
||||
|
||||
`[SLIDE 7]`
|
||||
|
||||
`*[Maak app/vision/page.tsx + api/analyze/route.ts]*`
|
||||
|
||||
```typescript
|
||||
const result = await generateText({
|
||||
model: openai("gpt-4o"),
|
||||
messages: [{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "Beschrijf wat er op deze foto staat." },
|
||||
{ type: "image", image: buffer },
|
||||
],
|
||||
}],
|
||||
});
|
||||
```
|
||||
|
||||
`*[Demo: upload foto van eten, krijg beschrijving]*`
|
||||
|
||||
**Vertel:** "Bouw varianten. Defect detection in fabrieken. OCR voor formulieren. Receipt scanning — bonnetjes naar gestructureerde data. Code-from-screenshot.
|
||||
|
||||
Cost: vision is 2-5× duurder dan text. Een 1024×1024 image = ~1100 tokens. Voor productie: resize client-side."
|
||||
|
||||
---
|
||||
|
||||
### BLOK 5 — Pauze (15 min)
|
||||
|
||||
`[SLIDE 8]`
|
||||
|
||||
---
|
||||
|
||||
### BLOK 6 — DEMO 3: Image generation (25 min)
|
||||
|
||||
`[SLIDE 9]`
|
||||
|
||||
**Vertel:** "Image generation. Flux is het beste open-source model. Via Fal.ai of Replicate."
|
||||
|
||||
`*[Fal account, key]*`
|
||||
|
||||
```bash
|
||||
pnpm add @ai-sdk/fal
|
||||
```
|
||||
|
||||
`*[app/generate/page.tsx]*`
|
||||
|
||||
```typescript
|
||||
const { image } = await generateImage({
|
||||
model: fal.image("fal-ai/flux/schnell"),
|
||||
prompt: "Retro festival-poster voor Polderfest 2027, oranje + cream, vintage typografie",
|
||||
size: "1024x1024",
|
||||
});
|
||||
```
|
||||
|
||||
`*[Demo: type prompt, klik generate, zie image]*`
|
||||
|
||||
**Vertel:** "Drie cent per image op schnell variant. Voor productie: save in Supabase Storage, gebruik CDN.
|
||||
|
||||
Goede prompts zijn specifiek. Stijl, palette, compositie, wat NIET te tonen. 'Een mooie afbeelding' werkt niet. 'Retro festival-poster, 70s rockconcert-flyer stijl, oranje en cream, decoratieve geometrische randen' wel."
|
||||
|
||||
---
|
||||
|
||||
### BLOK 7 — DEMO 4: Local LLMs (25 min)
|
||||
|
||||
`[SLIDE 10]`
|
||||
|
||||
**Vertel:** "Tijd om lokaal te draaien. Ollama."
|
||||
|
||||
`*[Terminal]*`
|
||||
|
||||
```bash
|
||||
brew install ollama # of via download
|
||||
ollama pull llama4:8b
|
||||
ollama run llama4:8b
|
||||
```
|
||||
|
||||
`*[Interactieve chat in terminal — werkt offline]*`
|
||||
|
||||
**Vertel:** "Dat draait lokaal op mijn M-series Mac. Geen internet, geen API-cost.
|
||||
|
||||
Via AI SDK:"
|
||||
|
||||
```bash
|
||||
pnpm add ollama-ai-provider
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { createOllama } from "ollama-ai-provider";
|
||||
const ollama = createOllama();
|
||||
|
||||
const result = await generateText({
|
||||
model: ollama("llama4:8b"),
|
||||
prompt: "...",
|
||||
});
|
||||
```
|
||||
|
||||
`*[Demo: chat-app met dropdown 'Cloud (gpt-4o-mini)' vs 'Local (llama4)'. Vergelijk antwoorden]*`
|
||||
|
||||
**Vertel:** "Lokaal model is iets minder slim dan GPT-5 voor complex. Voor 70% van vragen prima. Voor privacy-critical apps — healthcare, legal — is dit dé oplossing. Voor cost — als je veel calls maakt, lokaal is gratis na hardware-investering."
|
||||
|
||||
---
|
||||
|
||||
### BLOK 8 — DEMO 5: Edge AI + Gateway (20 min)
|
||||
|
||||
`[SLIDE 11]`
|
||||
|
||||
**Vertel:** "Twee edge-opties.
|
||||
|
||||
Vercel AI Gateway. Eén endpoint, alle providers. Automatic fallback bij OpenAI-down."
|
||||
|
||||
```typescript
|
||||
import { vercel } from "@ai-sdk/vercel";
|
||||
|
||||
const result = await generateText({
|
||||
model: vercel.fallback([
|
||||
"openai/gpt-4o",
|
||||
"anthropic/claude-sonnet-4.5",
|
||||
]),
|
||||
prompt: "...",
|
||||
});
|
||||
```
|
||||
|
||||
**Vertel:** "Als OpenAI down: switch automatisch naar Claude. Geen downtime voor je users.
|
||||
|
||||
Cloudflare Workers AI. LLMs op Cloudflare's edge. 250+ datacenters wereldwijd. Latency overal laag."
|
||||
|
||||
```typescript
|
||||
import { workersai } from "@ai-sdk/cloudflare";
|
||||
|
||||
const result = await generateText({
|
||||
model: workersai("@cf/meta/llama-3.1-8b-instruct"),
|
||||
prompt: "...",
|
||||
});
|
||||
```
|
||||
|
||||
**Vertel:** "Gratis tier 10k requests per dag. Voor MVP en lichte apps: gratis productie."
|
||||
|
||||
---
|
||||
|
||||
### BLOK 9 — Resources + community (10 min)
|
||||
|
||||
`[SLIDE 12]`
|
||||
|
||||
**Vertel:** "Hoe blijf je leren? Communities. r/LocalLLaMA op Reddit voor open-source updates. AI Engineer Foundation op Discord voor productie-focus. Latent Space — podcast en Discord.
|
||||
|
||||
Blogs. Simon Willison's blog is de absolute referentie. Daily updates. The Rundown AI newsletter. Twitter accounts: Karpathy, swyx, sama.
|
||||
|
||||
Voor diepere kennis. Karpathy's Zero to Hero op YouTube — bouw neural network from scratch. Gratis, briljant.
|
||||
|
||||
Conferenties. AI Engineer Summit in SF jaarlijks. NeurIPS voor research. In Nederland: Devbase, MAINSTAGE."
|
||||
|
||||
---
|
||||
|
||||
### BLOK 10 — Eindopdracht + Afsluiting (15 min)
|
||||
|
||||
`[SLIDE 13]`
|
||||
|
||||
**Vertel:** "Tijd voor eindopdracht. Wat we hebben:
|
||||
|
||||
Volledige toolkit. Next.js, TypeScript, Tailwind. Supabase. AI SDK. Tool calling. Agents. RAG. MCP. Production polish. Multimodal.
|
||||
|
||||
Voor je eindopdracht — moet bevatten Next.js stack, Supabase met auth en RLS, AI SDK met Tool Calling, externe API, deployed op Vercel.
|
||||
|
||||
Werk er gestaag aan. 8 tot 10 uur per week voor 4 tot 6 weken. Niet één laat weekend.
|
||||
|
||||
Pitch volgt na inleveren. Acht tot twaalf minuten demonstratie.
|
||||
|
||||
Eindopdracht-voorstel deze week via Teams indienen."
|
||||
|
||||
`[SLIDE 14]`
|
||||
|
||||
**Vertel:** "Een laatste woord.
|
||||
|
||||
18 lessen. 54 uur klassikaal samen. Plus jullie thuiswerk. Een vol vak.
|
||||
|
||||
Wat jullie nu kunnen. Een AI-app van scratch naar productie. Tool calling en agents. RAG en MCP. Production-niveau observability en evals. Multimodal features. Lokale modellen draaien.
|
||||
|
||||
Drie jaar geleden was dit een specialist-skill. Nu — jullie kunnen dit.
|
||||
|
||||
Voor je eindopdracht en daarna. Doe het ding waarvan je dacht: dat kan ik niet. Bouw iets dat je écht zelf zou gebruiken. Vraag hulp tijdig. En als je iets bouwt waar je trots op bent — laat het me weten. Echt waar.
|
||||
|
||||
Bedankt voor jullie inzet. Veel succes."
|
||||
|
||||
`[SLIDE 15]`
|
||||
|
||||
**Vertel:** "Open ruimte. Vragen over de stof. Vragen over je eindopdracht. Vragen over je carrière in AI development. Feedback op de leerlijn."
|
||||
|
||||
`*[Vragenronde — laat dit echt open. 10-15 min over]*`
|
||||
|
||||
---
|
||||
|
||||
## NA DE LES — Wrap-up
|
||||
|
||||
- Brightspace: eindopdracht-instructies + voorstel-template
|
||||
- Teams: nieuwe channel "Eindopdracht support"
|
||||
- Office hours-schema voor 4-6 weken
|
||||
- Bewaar deze 18 lessen als referentie voor Klas B / volgende cyclus
|
||||
- Voor jezelf: noteer wat werkte en wat minder — voor verbetering
|
||||
|
||||
---
|
||||
|
||||
## Veelvoorkomende fouten in demo's
|
||||
|
||||
| Fout | Oplossing |
|
||||
|------|-----------|
|
||||
| MediaRecorder API niet beschikbaar | Test in Chrome eerst, Safari heeft soms anders |
|
||||
| Fal API key issue | Sign up + generate key, gratis tier |
|
||||
| Ollama "connection refused" | `ollama serve` runnen, check `:11434` poort |
|
||||
| Vision image te groot | Resize naar <4MB, of compress JPEG |
|
||||
| Vercel AI Gateway niet beschikbaar | Vercel Pro account nodig in 2026 |
|
||||
|
||||
---
|
||||
|
||||
## Mentale model voor afsluiting
|
||||
|
||||
Voor reflectie aan eind van de les:
|
||||
|
||||
> 18 lessen leiden niet tot "AI-meester". Wel tot iemand die weet welke vragen te stellen, welke tools te kiezen, en hoe te beginnen. Verdere groei = blijven bouwen, vragen stellen, community + nieuwe modellen volgen.
|
||||
|
||||
Hou de toon praktisch, niet sentimenteel. Studenten waarderen oprechte erkenning + duidelijke volgende stap.
|
||||
130
Les18-AI-Toolbox-Next/Les18-Huiswerk.md
Normal file
130
Les18-AI-Toolbox-Next/Les18-Huiswerk.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Les 18 — Huiswerk
|
||||
## Eén modaliteit naar productie + reflectie
|
||||
|
||||
**Vak:** AI-Assisted Development
|
||||
**Deadline:** Geen — dit is de laatste les van de leerlijn
|
||||
**Inleveren:** Brightspace + Teams
|
||||
|
||||
---
|
||||
|
||||
## Doel
|
||||
|
||||
Twee dingen:
|
||||
|
||||
1. **Praktisch** — neem de demo uit de lesopdracht en breng 'm naar een werkende, gedeployde mini-app
|
||||
2. **Reflectief** — korte schriftelijke reflectie op de 18 lessen
|
||||
|
||||
---
|
||||
|
||||
## Onderdeel A — Demo afmaken + deployen (verplicht)
|
||||
|
||||
Pak je voice / vision / image / local demo uit de les en breng 'm verder.
|
||||
|
||||
### Eisen
|
||||
|
||||
- [ ] Demo draait lokaal zonder errors
|
||||
- [ ] Gedeployed op Vercel (alle vereiste env vars geconfigureerd)
|
||||
- [ ] Productie URL werkt en is publiek
|
||||
- [ ] README.md met beschrijving + installatie-instructies
|
||||
- [ ] Mooie UI — niet ruw, geen unstyled HTML
|
||||
|
||||
### Tips per modaliteit
|
||||
|
||||
**Voice:** denk aan UX — toon dat AI 'luistert' (rec-indicator), error states (mic permission), korte audio-clips opslaan (Supabase Storage).
|
||||
|
||||
**Vision:** image preview vóór analysis, loading state, resize images client-side voor cost.
|
||||
|
||||
**Image gen:** save generated images (Supabase Storage), gallery van eerdere generaties, regenerate-button.
|
||||
|
||||
**Local LLM:** alleen lokaal zinvol — voor productie ofwel local-only, ofwel Vercel deploy met fallback naar OpenAI.
|
||||
|
||||
---
|
||||
|
||||
## Onderdeel B — Reflectie (verplicht)
|
||||
|
||||
Schrijf in `REFLECTIE.md` (in repo-root) — max 500 woorden.
|
||||
|
||||
### Vragen
|
||||
|
||||
1. **Wat was de meest verrassende les?** Welke stof gaf je een "aha"-moment?
|
||||
2. **Wat ga je in je eindopdracht gebruiken?** Welke 2-3 concepten zijn voor jou meest direct toepasbaar?
|
||||
3. **Wat zou je willen leren dat we niet hebben gedaan?** Welke richting wil je verder verkennen?
|
||||
4. **Wat is de grootste verandering in je werk als AI Developer?** Wat doe je nu anders dan vóór deze leerlijn?
|
||||
|
||||
### Vorm
|
||||
|
||||
- Persoonlijk, eerlijk
|
||||
- Geen ChatGPT — eigen woorden
|
||||
- 300-500 woorden
|
||||
|
||||
---
|
||||
|
||||
## Onderdeel C — Eindopdracht voorstel (verplicht)
|
||||
|
||||
Lever via Teams je voorstel in voor de eindopdracht. Max 250 woorden:
|
||||
|
||||
1. Welk probleem lost jouw applicatie op?
|
||||
2. Wat doet de AI concreet met de data?
|
||||
3. Welke externe API ga je gebruiken?
|
||||
4. Vier kernfunctionaliteiten (inclusief registreren+inloggen en min 1 AI-feature)
|
||||
|
||||
Na goedkeuring kun je aan de slag met deelopdracht 1 van de eindopdracht.
|
||||
|
||||
---
|
||||
|
||||
## Inleveren
|
||||
|
||||
1. **GitHub repo URL** (lesopdracht-demo + Vercel deploy) — Brightspace
|
||||
2. **`REFLECTIE.md`** in repo-root
|
||||
3. **Eindopdracht-voorstel** via Teams (separate channel)
|
||||
|
||||
---
|
||||
|
||||
## Beoordeling
|
||||
|
||||
| Criterium | Punten |
|
||||
|-----------|--------|
|
||||
| A — Demo deployed + werkt op productie | 5 |
|
||||
| B — Reflectie persoonlijk + concreet | 3 |
|
||||
| C — Eindopdracht-voorstel ingeleverd | 2 |
|
||||
| **Totaal** | **10** |
|
||||
|
||||
Voldoende = 6+.
|
||||
|
||||
---
|
||||
|
||||
## Tijd-indicatie
|
||||
|
||||
| Onderdeel | Tijd |
|
||||
|-----------|------|
|
||||
| A — Demo + deploy | 60 min |
|
||||
| B — Reflectie | 30 min |
|
||||
| C — Eindopdracht voorstel | 30 min |
|
||||
| **Totaal** | **~2 uur** |
|
||||
|
||||
---
|
||||
|
||||
## Wat nu?
|
||||
|
||||
Dit was de laatste les. Wat je hierna doet:
|
||||
|
||||
- **Eindopdracht** — thuis, 4-6 weken, 8-10 uur/week
|
||||
- **Eindopdracht-pitch** — na inleveren, in 8-12 min demonstratie
|
||||
- **Beoordeling + feedback** — binnen 4 weken na inleveren
|
||||
- **Daarna** — je bent klaar voor de praktijk
|
||||
|
||||
---
|
||||
|
||||
## Tips voor je eindopdracht
|
||||
|
||||
- **Start klein, voeg toe** — eerst basisflow werkend, dan polish
|
||||
- **Push klein en vaak** — geen 1 grote commit aan eind
|
||||
- **Vraag hulp tijdig** — Slack, mail, office hours
|
||||
- **Test op productie** — niet alleen lokaal
|
||||
- **Schrijf je verantwoordingsdoc gaandeweg** — niet aan eind
|
||||
|
||||
---
|
||||
|
||||
## Bedankt
|
||||
|
||||
Bedankt voor jullie inzet de afgelopen 18 lessen. Veel succes met de eindopdracht. Tot bij de pitch!
|
||||
137
Les18-AI-Toolbox-Next/Les18-Huiswerk.pdf
Normal file
137
Les18-AI-Toolbox-Next/Les18-Huiswerk.pdf
Normal file
@@ -0,0 +1,137 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 5 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 12 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 11 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Contents 13 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 11 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 14 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 11 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 15 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 11 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 11 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607101945+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607101945+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Huiswerk) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Count 4 /Kids [ 4 0 R 6 0 R 7 0 R 8 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1941
|
||||
>>
|
||||
stream
|
||||
GauHL>>s99'Roe[3,]73E$b<,mi*9\b7*3)RPHt2f`tq96,]*hG/DU5^IP_B3sc3"FB`X>+s!6C45[TY'F908l?AHo]H>#&%hpFEi>AM/].gmNo:bipZC0#?f)sdd`!I=6Tk"(QSlckT^?p\,UqfQ0o=tNr;k*B?"2f1G5Qf@G`c!F9G2SR7]3o^Fq:sjen(9g6GdV=6^)sMMDuAY8^!QHln'K>U)i`edg43q?3j)2U(O.W-@IVm8Rg]"U:Lk'nj`ppb9.cpN&k7f`E-_OtEZpWo-M7rZmpZ"B>gP:lqUG3@'!*#M1fqYKeC3-oQ'eLD!:<qaMA.[;poO#/GGlO8SqGP]jO`tm>\^g#=-H6!_)J(4Li5KAOmR4FFmja7XS*+"N_MWsR^:h=D`[t/Ts[@(=RTuXCKD^\pMjY"QaJ?>ZUVOL,)`*5$3"i92h0%$9$Y#S0WI%mS2lCrTe`-1,95D3FkE+7-Co\]Z*V4mS9V]acGF0pHWdsiYd\OSm-P/EXHDqV=(=2/4PQWqdgha\1QR9X)U"'p?a]C\ID@plP8bo$eg*a]]9pr%E0p_.\k#@'<nb6O"]/MUGH'V&m8kTb<[GT8BfECd7Z@Xdp3bqG1kRWG7A<DR9#u\40[k;0O%L_W%n&*HUj;oTU>QK3W@O>ar=*UuHNA%Dr3/`bnWFRXO&Wj"[[8Ym,JU$<K!=P/eImH81LLWrNKL4b%W95WcP<AT?A5=*_ns-rl)O."Mj)Va:dlhnAMHeg<c5S\6+dK@7@'Th/[IU%]ElT*XX87'0b]ZUp/$XRfXU23g5Tsj]n"ao@q)Nn]\@sjGe%7hX^$@o`J5ps32BZa_`E,uHf<]pK:'qWK0NE,@<s'3)HOmgO,feU3Z84,-'Zbm>T+NN8J*="PFE=O8t"5/).NlM!b)Im&1*cu";>u&Z>)s'SZ)F%_t$um44>M`HUVV3-S4ii[]QZoEB._lll7!G3;-R=<o'=s)EQ&Qo"7Vua&d.@8>a90.?WG&Z7?UB9&l'u\@jC%#:DKiO/J2-g07j)8McG^k@G:?dUHB0*/c^S=:$[F1,W6nAX^LVeQD(=aChanAq34AhP/@Dn0Y81]ofI3-8LM@0hc+/B1`(>\(,qhW_At>fk`/aAF3H[`qCPB.F-^].D&o0Yjp249ll;NMNhj5/gY,n<-DOXnsSGJ,D.fg1>BQ'+pBqZGlH8.FAT0a%BiLB0,Qkn9:<S0%I2.C5`AWmOi=V'LXhWg!EPXlU/28nUZ[il_$R^Aj$?7`-)PW7@?E&k?120p$C,9!6D\.#(6UcmagtGQ,e>\&oQFefIZbEuC!GK1hsF$X/%9fcp:5K!c5T3,;:<)IJ0M=iJ6nQq,8p\hS]&p]Sk-K*%Z9%+n8GEO//nXXPN5YnU&(/rR=WjKf@uc+LI3rt)MBcnVEt!^WHQqh1!=L2N\GrP"-FkW-r6;"!9L`+#-J?8NDZ:,eRYhfO2j>F#7DaUIJCFd%`X"KNqqS90<6^%2$b10B(ObFals:kh;%r.6[[jODBN8XT:UHp\'l0l=i.;BWr2es#72r=.P"+"[Qk$lb\LLHYtNa92hHK5k0J<j6@.$Q":B_Gq1EDL(u..2Hq[B,T8&skpMXZ.ZX6a?LMDPN_`H4/G!99kWQTVu*'F"c(:6*3a"j-9_!1doh_ePJNX[HRV>3?Q2p'hh!+!=TR\45F&rBU6b$:!fNp@ShW1O],ed/1La?W?t@="Hs:eqg8*io2a8e?#);<>,.0pdn)hrZ_7.gcU?cmnb-dEs#;N]L\i'@4uk2cUCFA>3t`1G'D85/:Xgpl>0t+>T'AimZ:0p&JM*n/CmQ:.U*8.I2Ti+@:Hf3[n$EqE6SIj[H]bR';IJ(VVH%(R<U9bm1-I'Ojpf,.0*8G)_te;3$KA._^A5T$q4-EO86@*#uG=drK0ljE=jqH+"1oXT&:2f+i0~>endstream
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1734
|
||||
>>
|
||||
stream
|
||||
GauHL9m>;P&DcMNbit"6i*,\!h=NOPBq'0WS+b6O_a`:2;6VW%S#"<4Ij<\ZP5kV)9`j8VbG2Ul7X&Ig^ntI>rJ`R_dfI,\^jpDAN.JO*$\LX5%8MAC=PW(jl[e/N[aX8Eoc3Q*3]Y<uo.@_tHON5&Yen0Z2e5r+p-R\Z?P'FA1rB%,#m2^Im3$Me$CU(4re((gbNGD(FtM&7HhZuIr!SL24j.cV,<+p))5@qJ!O]<"\<bCP^k4oWSM+>'cf('[Y_XVuV=:80(emU>EZW$.F8-!D0i^$ZcXCbrK,8-PQ;Q7HQ64bqWmOU`=ko[AelFCk,'*dtA`4S*\1ln5`ijo6/+dYEW2Ih@:$<T9]<(#lo`l\Z2NTNI]Q=4G^5>;crVkt=eNR!gW`:&NBo89FWhtB6grfP`J6&gY/#?[O<BQ=7M4hjIR*n%$e5^ejk>h,u-0g:M@[s:[%qJeZQu%dN1kf1j,rM6s1X+aI>:Vtj6Y3^f\@uUKY$KrjmW-.pCg3UT2_7u,<%5X6^,fWm(j1c?i3YuP*QKU0J;9\2e?`+P`.uY\GMDk:bH$o1h0+>$\cD[J9shPOK?U$GOL'bipTkD/ZhK+D1FnA*6uU_O4#G5^="?^Weeg14)a)l0)iA$^q$rqlI"bI!;gA?65,I\1;R[9iYbLbfMZiX2HS1AJf8B1''>(h\mr4'/W(Wm8Mu,l7HhWEqSX[%33q@)C/[!p"f>ULSUUg*.r=gR5Lk<nTSHg]<TL@5&.$0T$;CpZgLuV9)V[,_j`fQ!2>ToJ%q+OK#ZYlWqbfdI7]aa5E*.ng:"!LuiQiJ!n&n,`V^)D)KO4>f4_T6GC,<_AlbW#(/]+.4YO)S,4/%>(!YJo`ubo;7E8]k9j[AHn_'?,dgB,b\_E"(Hj*GBNFdC*7#h%E1$lpd.5P>%aK^Tkm6KNs\m:2i%aY7ceJfLVYn+sup"Qnd0pNTOsH6*05Win(NTNl$sk$VQ9<QE1R#@RRFK.t#2>]7F37>ZGc4>-*tU20=t_=J<8MT0m1B/.9V0U#S5sI94d)]JZT)F\2u9OMPk)[+5]^n[)?]luAkE3Bp2OSa[K$+0m$AkbQ*IO0OeSp0,IZX`:dar.6,gW#q.'doT?NA%EtU\c$W+me5?Bd75G[mjFk-GVQ/_3D(d"Me]s8g_4-Y#b#8Xh,\$ka-g@r'tSd6:ZqqtEl%9l_Y5qfBC0GF.M$5e\o3)^Gi"=5HP+jWaWeEa!X:'YU=/Ob+0ql#nS247i%qclgfq)_k&I*Q!GhM@LJ[ck;mg.[47,J0WInfM)3J<>1rW;;5i'<eLma*mW!8dF[PI%f"lV'sQ?sak\oa2a&#dR;IRtd_S(1kCcQK[Tj%$qp9/FKsO!&$/mh0b<#VXJmL@S[F\=qH"iZ;]-CmU;[pQU2fk;geY.Mo'8;4;CS9R'Dq0-lQlcq@nHC=<:!P^08A;\nS^OT[?FH?Y=BS82@S7iR_YHd:TUoL2$>0V7::C:0r1Wn3t7e7;gHMPS?Xdr%&6al'bE]V8Deb9qM%jZ&sKYl\n!>;#]c(#V2MNSs4[`A/fSD7bR6*_0%MO\Bt)A,Z2pnPPUEk+h5+!rViM?h<W87bL35].mn)?EQI$>!.j*eM<PW`Cr\pf+hs8L#n@.iiFA8l][_0F-s]o6p$Bu#K=@3l#[^^`WN;dIE8Wkd%mcIc!8XacmY=MUHOQk<_.kb`\ZH2eb,\ZFf/?L5q*,j4V-N456hj0PQ~>endstream
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1489
|
||||
>>
|
||||
stream
|
||||
Gb!l_;01_T&BE]('`48(K$KNj=met]F(qejlZ@GE6dqBK;/?77@o:p4kt=6f=#LU42MA]3b[_Ut9ZHDSeUMdmP!^D.(TfpN)8P>6hYp3"1)LFNEl)8S)n[9brpC@F=Ni!4Ta\ek!D,WX")cU=+;.'f/>42=R)kWsQ]t%/876[L*7GapL>eUC"VQ_9Q5k^VOc\SEr?2c3@;&C[+d2g$=8>F[?:)R[4%uu+UGK9MX$pm<L7AB'MB`t^i9^26G9>dr*U,=">FWO&Q.,!-K$TCpnEqN+km*d6\TZlH?iks>5/<I_/gq<O&FV[YYV>0:]4p<e>)c4L+PcO,K+^Ai98!>.;8?'*@g_7E/9mDechKt,s'")$U<S?:?Ki$p^K3A5m&48D^VDM_#Q<5M`(C8WX0GYR\!.YQNS!Ipj@lD@=j5Sm_RL]pkK1aCH;RYQfJ3qObB6Vg8U!j"CDZH.8m^bMKhTg6qiB%\*.3_rY]H0nRk<(2kT_OYgdUUB!i!3=IbBDO6P"8*]`Rn7Bl0!%aV;Xi[Rct?eWF5iB44jqCo1C]-J3ZDA9OP)L#(X9Yh#))cG:2>S`:!clq"@G1Y*9lW@ncuV,Vo^<F\XR/MfUC^Z+^X8#VY'`3E^+NN`VC'OIhIH6e+(]'j9mc%^`0E/PrbZSQcVXiHGjk`et0G3oK)Z*f.T95*1oFMXsGC"Kk2HFS^kfq$ADX,BZh%j90>%Kfn070uJYi"U@2'1HqOE"E[Efnh%;S?SHJXN>?f-<VDuDc4!t]Jo56ieXOG`VuJSl4XrgAQg0kosMK:_`%\Iq$L!FA!%%)Ar77QoM"fqFPVou=QARibW-[*AFTN?@'OZ("<WZn$%b/$S9@X2M/^$e%<2#!#%*:@^JkBUilC)@$B[X/5u0i,Q)S/j9'fHsQ)_(8OR&'[O$:rF2VR,0$)q'UJ"0&'ZE6go#A7sU+7GQ[iAAOK7^;?gI&:o=R:Ji[6uhDB`-U^QEV&C;91h1uSr#MLj-%]VWN!m^d_#S:(O-^`lJ_kU*t>H(h_)=.G%N)+D-h,UlW@N!r;PJNl*t"%C_ft!LD2Cl.D,l/,69lBArEs8#<+Sh.LBEVMfl*7[CF_B`(]?=*^dXP[Ee2?3c3L/h@tYrctV;K47X@(i<;+6+pkE:68#Vu)6n1bM[H<e'N]2pSh>)^VA1/?T4HH.@pF=-B\B@0drj`?QVE4%[,.GEK<1h13#Qf-n]/ai<nDJq'+9.k.Ha?Z@U,Q]H3BM`m<."T*)sbf.SVqImBV0@_o)-NA?(0jbtU2^d,M5/q:COFgdhH*\dqDUbkO`hAI9YpEVE/oCkd;:64J<0]l*,m3Mf2!?K?1Cg!.a>?%CZLq0)iqAb$55_kBZljBre,I,1;7kd':l$;\,nUTr[$m^jUNe(pedX!@LY3d,*joK^?#8eon)Dg&Y@Q'k?TKRKEUV=&#M7Z+A"mj('8S9Z<iTDFbm?Oon"7Q^2p2=bIm:O)+%#7`iOMZ~>endstream
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 422
|
||||
>>
|
||||
stream
|
||||
Gar>B9iJn_&A@g>4E&;L:!tjiO#$"9N2&.,3I.T8JO4(U/NDdo2l5_g-9JbKpO0/sn5g[gC^Z17gcS+uKk(4`8L&N!I1go1Ul;T?!ejC&Yl_mQG>KrF&s4=NX'!4F9?q9c-crpO62<NVV+&X2$j-gA7TcQS:.E6kJ+Fg$V*)/_aI)bkr(3OHjMbY)lFb?T4IGT!-W@dYTdCp-)^3mDnFSi4?sG:oa];DAi3f[I>IA]Sb2RSr4$IU\mC9l"Z:6V9#gP]CO^tPtQ_<AehL'@Wkttd8AR;7\B*_EXi=CT=-XAVej<C:GoZ)X4f;/iUh,,0D,5S]h[Ke%KVraepTrMk/pI13#o(%]CbSfYSGr/Ab3Y^@+>S:Ym"e'k*EJ&,ca*B\KG4Rcf#nW9"`I#>e5'D4@Xfa8b9EPFTBI/LP~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 16
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000112 00000 n
|
||||
0000000219 00000 n
|
||||
0000000331 00000 n
|
||||
0000000536 00000 n
|
||||
0000000641 00000 n
|
||||
0000000846 00000 n
|
||||
0000001051 00000 n
|
||||
0000001256 00000 n
|
||||
0000001325 00000 n
|
||||
0000001611 00000 n
|
||||
0000001689 00000 n
|
||||
0000003722 00000 n
|
||||
0000005548 00000 n
|
||||
0000007129 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<9af241f85a8fc004d31ff2b8bf21662e><9af241f85a8fc004d31ff2b8bf21662e>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 10 0 R
|
||||
/Root 9 0 R
|
||||
/Size 16
|
||||
>>
|
||||
startxref
|
||||
7642
|
||||
%%EOF
|
||||
282
Les18-AI-Toolbox-Next/Les18-Lesopdracht.md
Normal file
282
Les18-AI-Toolbox-Next/Les18-Lesopdracht.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# Les 18 — Lesopdracht
|
||||
## Kies één modaliteit, bouw een mini-demo
|
||||
|
||||
**Duur:** 30 min in-class
|
||||
|
||||
---
|
||||
|
||||
## Doel
|
||||
|
||||
Pak één van de modaliteiten uit deze les en bouw daar een minimale werkende demo van. Voice, vision, image gen, of local LLM — jouw keuze.
|
||||
|
||||
---
|
||||
|
||||
## Opties
|
||||
|
||||
### Optie 1 — Voice transcriptie
|
||||
|
||||
Bouw een mic-button + transcribe. Werkende voice → text in een Next.js page.
|
||||
|
||||
```typescript
|
||||
// app/voice/page.tsx
|
||||
"use client";
|
||||
import { useState, useRef } from "react";
|
||||
|
||||
export default function VoicePage() {
|
||||
const [text, setText] = useState("");
|
||||
const [recording, setRecording] = useState(false);
|
||||
const recorder = useRef<MediaRecorder | null>(null);
|
||||
const chunks = useRef<Blob[]>([]);
|
||||
|
||||
async function start() {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
recorder.current = new MediaRecorder(stream);
|
||||
recorder.current.ondataavailable = (e) => chunks.current.push(e.data);
|
||||
recorder.current.onstop = async () => {
|
||||
const blob = new Blob(chunks.current, { type: "audio/webm" });
|
||||
chunks.current = [];
|
||||
const fd = new FormData();
|
||||
fd.append("audio", blob);
|
||||
const res = await fetch("/api/transcribe", { method: "POST", body: fd });
|
||||
const { text } = await res.json();
|
||||
setText(text);
|
||||
};
|
||||
recorder.current.start();
|
||||
setRecording(true);
|
||||
}
|
||||
|
||||
function stop() {
|
||||
recorder.current?.stop();
|
||||
setRecording(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="p-8">
|
||||
<button onClick={recording ? stop : start} className="bg-blue-600 text-white px-6 py-3 rounded-full">
|
||||
{recording ? "Stop" : "Start opnemen"}
|
||||
</button>
|
||||
<p className="mt-6">{text}</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
`app/api/transcribe/route.ts`:
|
||||
```typescript
|
||||
import { experimental_transcribe as transcribe } from "ai";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const fd = await req.formData();
|
||||
const audio = fd.get("audio") as Blob;
|
||||
const result = await transcribe({
|
||||
model: openai.transcription("whisper-1"),
|
||||
audio: new Uint8Array(await audio.arrayBuffer()),
|
||||
});
|
||||
return Response.json({ text: result.text });
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Optie 2 — Vision foto-analyse
|
||||
|
||||
Bouw een upload-form + analyse. User upload foto → AI beschrijft.
|
||||
|
||||
```typescript
|
||||
// app/vision/page.tsx
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function VisionPage() {
|
||||
const [desc, setDesc] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
async function analyze(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) return;
|
||||
setLoading(true);
|
||||
const fd = new FormData();
|
||||
fd.append("image", file);
|
||||
const res = await fetch("/api/analyze", { method: "POST", body: fd });
|
||||
const { description } = await res.json();
|
||||
setDesc(description);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="p-8">
|
||||
<input type="file" accept="image/*" onChange={analyze} />
|
||||
{loading && <p>Bezig...</p>}
|
||||
<p className="mt-6">{desc}</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
`app/api/analyze/route.ts`:
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const fd = await req.formData();
|
||||
const image = fd.get("image") as File;
|
||||
const buffer = await image.arrayBuffer();
|
||||
|
||||
const result = await generateText({
|
||||
model: openai("gpt-4o"),
|
||||
messages: [{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "Beschrijf wat er op deze foto staat in 3 zinnen." },
|
||||
{ type: "image", image: new Uint8Array(buffer) },
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
return Response.json({ description: result.text });
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Optie 3 — Image generation
|
||||
|
||||
Bouw een prompt-input → generate → preview.
|
||||
|
||||
```typescript
|
||||
// app/generate/page.tsx
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function GeneratePage() {
|
||||
const [prompt, setPrompt] = useState("");
|
||||
const [imageUrl, setImageUrl] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
async function generate() {
|
||||
setLoading(true);
|
||||
const res = await fetch("/api/generate", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ prompt }),
|
||||
});
|
||||
const { image } = await res.json();
|
||||
setImageUrl(`data:image/png;base64,${image}`);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="p-8 max-w-2xl mx-auto">
|
||||
<textarea value={prompt} onChange={(e) => setPrompt(e.target.value)}
|
||||
placeholder="Beschrijf je afbeelding..." rows={3}
|
||||
className="w-full border p-2 rounded" />
|
||||
<button onClick={generate} disabled={loading}
|
||||
className="mt-3 bg-blue-600 text-white px-4 py-2 rounded">
|
||||
{loading ? "..." : "Generate"}
|
||||
</button>
|
||||
{imageUrl && <img src={imageUrl} alt="" className="mt-6 rounded" />}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
`app/api/generate/route.ts`:
|
||||
```typescript
|
||||
import { experimental_generateImage as generateImage } from "ai";
|
||||
import { fal } from "@ai-sdk/fal";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { prompt } = await req.json();
|
||||
const result = await generateImage({
|
||||
model: fal.image("fal-ai/flux/schnell"),
|
||||
prompt,
|
||||
size: "1024x1024",
|
||||
});
|
||||
return Response.json({ image: result.image.base64 });
|
||||
}
|
||||
```
|
||||
|
||||
`pnpm add @ai-sdk/fal` — gratis tier op fal.ai.
|
||||
|
||||
---
|
||||
|
||||
### Optie 4 — Local LLM met Ollama
|
||||
|
||||
Run llama lokaal, chat ermee via je app.
|
||||
|
||||
```bash
|
||||
brew install ollama
|
||||
ollama pull llama4:8b
|
||||
ollama serve
|
||||
```
|
||||
|
||||
```bash
|
||||
pnpm add ollama-ai-provider
|
||||
```
|
||||
|
||||
```typescript
|
||||
// app/local/page.tsx + /api/local-chat
|
||||
import { createOllama } from "ollama-ai-provider";
|
||||
import { streamText } from "ai";
|
||||
|
||||
const ollama = createOllama();
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { messages } = await req.json();
|
||||
const result = streamText({
|
||||
model: ollama("llama4:8b"),
|
||||
messages,
|
||||
});
|
||||
return result.toUIMessageStreamResponse();
|
||||
}
|
||||
```
|
||||
|
||||
Frontend kan dezelfde `useChat` gebruiken als in Les 12.
|
||||
|
||||
---
|
||||
|
||||
## Eisen
|
||||
|
||||
Kies één optie. Aan het eind:
|
||||
|
||||
- [ ] Demo werkt lokaal
|
||||
- [ ] Eén feature compleet (transcribe, analyze, generate, of chat)
|
||||
- [ ] Geen errors in console
|
||||
- [ ] Optioneel: gedeeld in Teams met screenshot
|
||||
|
||||
---
|
||||
|
||||
## Tijdsindeling (30 min)
|
||||
|
||||
| Stap | Tijd |
|
||||
|------|------|
|
||||
| 1 — Project setup | 5 min |
|
||||
| 2 — Backend route | 10 min |
|
||||
| 3 — Frontend page | 10 min |
|
||||
| 4 — Test + debug | 5 min |
|
||||
|
||||
---
|
||||
|
||||
## Veelvoorkomende problemen
|
||||
|
||||
| Symptoom | Oplossing |
|
||||
|----------|-----------|
|
||||
| `MediaRecorder undefined` | Browser support — Chrome werkt, Safari iets anders |
|
||||
| Fal API key | Sign up + create key — gratis |
|
||||
| Ollama "connection refused" | `ollama serve` runnen + check `:11434` |
|
||||
| Vision error | Image te groot? Resize to <4MB |
|
||||
| Transcribe error op localhost | Gebruik buffer (Uint8Array) niet Blob direct |
|
||||
|
||||
---
|
||||
|
||||
## Klaar?
|
||||
|
||||
Dat was de laatste lesopdracht van de leerlijn. Voor je eindopdracht — wat je nu kunt:
|
||||
|
||||
- Multi-modal features toevoegen (voice/vision)
|
||||
- Lokale modellen voor privacy
|
||||
- Image generation voor branding
|
||||
- Edge AI voor performance
|
||||
|
||||
Veel succes!
|
||||
200
Les18-AI-Toolbox-Next/Les18-Lesopdracht.pdf
Normal file
200
Les18-AI-Toolbox-Next/Les18-Lesopdracht.pdf
Normal file
@@ -0,0 +1,200 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 6 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 15 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607101945+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607101945+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Lesopdracht) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Count 7 /Kids [ 5 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1151
|
||||
>>
|
||||
stream
|
||||
Gatm9a]@1d']&(*h@_nHY'J(u+3+[8`'`<')`C#g1]k&fOrAB=om%j_92adS@Y^PRW`SrNq^+%jpgW''[K^ugJ2cp70Fj"6@$4&_SAHq;j=VT\F!DD2@B"2cL_J_Xl;^`6dR61b(g(O/2%l]r`*-f)j#pn>J_J$'l\#9nRMm]-=JiIUO7!CM3Ch\a.';=nrILRMoGl6\4/CQE&I^8D+=a)m8LRM,_.!iY+$Q9e^i.cG2q_22(%>:/qs:>:F3Y47T>3O<mu-J^f<8S%%?&iS_$!^e8sGEL%XRE0l?6=.&a30)b0(LO"QV@.EJpRe5YVVUN)KeQs($p!NVD"\1ocTeK`W'NE2pgt,i75^5-?bR8R*qr#ZZb9]AoJ0_Cu3,NA9$h7;$Tf9.%\J1,t1RF@;n!ZRhe@UVQ?7IeX5]=EV_cJr(et=tWW5a5RY9R95Efs/2CqKG;F$[<"^6V94hP\JqWEZa^[Ua$nK!GNaiP7qY&f4b+uU(pe#m-4*bt@<ZOW._PW3J+F_0kg1AQ=FB=n8blgk1F'C0K+oalDHjijCgX`:;P&(t2],XU(rVWbN]>;c#t4bU8*G#f=SS,bY*Nda[m"^@iM,$gJG6RAQhf%WYH)<*"^RKL?EdS0#-lR@Z-hJ^U##5s/kD(IjE[80g\Vgtg0[-OrHg_"YfMEb&DR;^)iP#7l-7O1dSj0VCFY"rV:]UEI=-'Wgba<*qW2lIXaSmjFb_0T9>eBdVLF)Pn'W=l81rub;-'Jeo>o,<*H*[]b##r,p;B_'7g%#1_;g<nT>0CJ6e=I:ef_Bd)[@;u^?blb+p-VL6X-a-N8>fmdhn)g3.U2A5NX(:1&*TXX'.P%%A%qmchQgnp[5T6LV-^&Gb1'tG33d?q?-:Io)C/PR5Fql>/J]`AcVQ(-?!nmX+pc>"KoA1YY<M,:53mpG^/`NNA'gB(_Zq+^fcq8rXeMh-EkS0Xc`dn?[5cLndqfo.&ngMi:QZ&I^WMeoGbR@lH'F098sTfl2B:C1`H:*2Ep!+3%:II,qP\bAA+&[hu0*!]Bn1t-_>OUl,!aDSX)uNkMbJ*AFti)J"$mca75cB?#86'.cI9ri5-0&H^j[)Nn_of@LdJ)Q/:c<i<3?a:Q+&\3Ve4*PNrEjYr[&L&';SgoQc#~>endstream
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1694
|
||||
>>
|
||||
stream
|
||||
GasapD0)1+&H9tYf\r%K8RtBu8`Z%VY'8L.cLgtup.Lnd(s<C@"q#BW-C=a].r6oR1r6FE`j5;`G+W&`&HdnDf)/<E!3[b(I`$\UQn3ao,%0sOrgJ'r4i/LH+p8Nl)FPQ9'Y$B+Q<k&p,Vn?k"&0NX8q>9IBH:gFBVuPC:`3BJoGA,cWR:j(Atd`FOaTJ?k=@0q-tW%#qlPA%\JGjgoa]g5]FbQrY\d2WC*3dnTaG56K$jH+hql6-`R<8X<Dd;reQ+$-Z7tBF_=)=$:NLBYU,:C.R!a\291R>2'd4l3+OiU=4&ZsW]S\eDO7>!MA)KM3:T.`\,5KeIN\H%4.)&1gAW]B7]$HAa:*C,o,s9-=#ZdNnC85[UQ?beqB=M12;BQ8\<:s=7]-m-[[?0AtVdT\XXt`O:JE"&r+lf%dSHmsX6LDKt*[=;ChTp9K7X&*o7sE6hpndS)CVPd>GF<\W?;jJa[E84=NI[rV=\A=p.!dn38AlC4(ks;0TF3A`j"\J`3PI,o`/MlaBo&m0J"?2V?D/$`jGgjfXplXZC3&Y?2IM=)%Ka6#9ikn'=h"^Ds'fJRNni/tZ[`9_<5f4Bb/DCU-J"mK@H5Ne])k]'[10IQD4'Ku&[*tuMfkWD[)h3qP5l!A9LmPJE'M.]nZH>1UB*VXjL'[LCMrMOeAb8QiY'PJi2.aVT=u/""Zq^<>4#hZD-9j01g`/VTA+;]k_hF$bqK1["E,Wq8$KfgeHQNtE;GW`Vt&qnq-V4p=`utL\W9%6+MuQbPh`$)Y1EE0H:RHc.qTTa#^LDM%&c">nFHAX#>u/6AP3uoGBpL;Ci/4T*g5%r%'eWm<hS%D)LGu,6N?)8344jgfBG'!77C6P.I<:$3&OhWqmA=^UY^*7&+Ot;(+3Lj[=O+l3(6*B$=u``k(P)HWku@Ul#UnJHc_\92QdLa#7UJ[AP]%a,+ln6Nj%J"MeAGD[cn&J$I6r+l0EMYlhUs<,B!N80oLjLip!\';n+6H\4tD?1a2*[VJsD,@C-E@c.*5<CFbZ#Zfu/\q]kGep9$5"i&CHLhjE*>59N0Q$Af1DYYVcaN2.8V6QeE49'Ac?0BQK*h\=W+:T*MlfHGt/$!UaICb[<ib=t1@G1/kB+#S?Q@tf.BW(2;:VXCI5@;LO@pW%9ANboNoF],%lj#]\2`a0C$eF_dV0,$iZbjS;3<!VV:1r5Il52sRE@2$UocoQ^&ORI=S+/2J['9:6Wk-cX57h0XnSr:j(D?1f5$uj#VK6UAW>mhPPU,^J4,W_`McU[H/R1*OYNRJB0RC3qC"1sgD@ALm6%@0T54K<6QH`a\(&*^/HjS1-u`01PA+t_;@F93hKB$h8!*B"3Aa/Pf/3)CfRdm_Yt5U)*'6\[1)AaI"NZ(F1?*F[]@j_r!r?,^N<:K2=>^Q2IYbV,$bJ,VP95,ea[^gkHgi(n!$CGA+Dr^W8$5L/]/k6Q=_A.;9lF7GsM2-V-JZF)]YPW$#.n]b'K%@"?B'$@iLSWMLgL"<p""Mc(\rrm[r,fU4&L8)o:b2iPPr#rLp%'JLR:WJso#':I0Ze_m\B3=lF?.i`PTAR7O+&9l<!*Xot45bJkG<0oX)R/5RVVU3JCGf4_mAJ^q(Zs?4-77Jge'C2pKr1MFF)Z9B!_2"VJFMs<>/J?Dp@%bHEE0*B3rh+EbmCm7)kH?kn]:n%5I=G-B`~>endstream
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1842
|
||||
>>
|
||||
stream
|
||||
Gau`R?#SIU'Rf_Z\FW)HFq$l<+/H1f>I-5$JZS6>[kDkY0J_agP9iYlS#/[Sq^s0tQJF/cJROIraJ-Uo5BuW[LB5@)X8b[_JC>r,B+,W4Bai31*_ao=flV<n,!=f#o7=E7\fh:k](QZW`@(gQ+@4(9#*K<;Ka42[7*8=-a*g9.!MtPGd>.f8!>X#b,+0Ooi2cf/#rkH(*q=k*gu%#c-`q_=$!QfEc/splp]bMdl;1cI;!&--VG!;hI.cn24O4hTMD"K_Kt!r/dA;C3k5q6fJ>`7-:@gf=%q5;HVN7g0*iS7#ik(f7"[1I;?Hc'm!PMNl,ZEXp5^pa)DGUDk]&jA/_\Efj59c&l0YeBFf-]$+73g#*iBFE"YT.pT2!ODYdZGoVh7-bUc6+7ZUS>LI2t'/0DN1>c@6fG`Wa#'$'+F98i%,/&QT>Yg'nk;tUa&?^PeG+Z$V%V6U(Q3BPN#="CV,'8c1Yd,\fB8.A3\>$4(fUfFj3f.gT'HX>"D!*G^s@ZO!P2"1J=$&?5cpurf!bG/9PQ(qPPcB<^gS?Tg;]*]=Wd,ba1"aanVcPQUYVA9+m,tgU2VZQ)UR3q*cS7ebh(u=WW6,Jl"aKa7"82@YP!"0oSt4_lC;i,)B<'A<K'-f<=%)B9Q5#*PropC8EF:HO/rLNJB,u5*QL-5a5oHJTq[FTWV:(YViUTS<qEsb,F!(p2D,i/2#QKE-1a2e7tT9L`"I[6CZY=>VD&`3BW#E1qsk-%79'";XtjT;HKpKFFJ*<F#FmAfb_T<aBCQRANn`1@=*f@K2gKnU9iI<8VK$D^sM&\G9_H`e*e763mL+6oJO9U1*`EUV7N'h)NX3>7+nEc<?1>QVK^C?lOr/s^9MZ>GTn-^h2^036`J>1bcj:2!n4*ia3"Us#,=DP_`"L4hV83ZF1')uK>Z&Kh(V7:@1C-@?[%8fKt8n-1J8YZ"K;3Ind<]4")k(,];2aO+6Ot8:mjpo._Xlc\%Qd*]Ks]@^].[_B+\uOZSm<%YHC1W$s#fcX8.>6&,6`?irn4>\nn"hDF*ZNF6;o-bd\b%:\G3!Wk,DS<[Jnu6\`L`j#;)!s%bJSn(,2+-Q:UW[Knp_EO#Q/=$$67MPZa/VPBPsKl3RIf$8b=1,q1J.qg_#*!]G?31oI;F:,G&`)N?6qNp.p$bW?N`iD^!PU=IH6R:Wbq""BFmICbTIq+_r&m2,51l0+<bbFS&G7tIQ3,1S/kF9#BPo[FVj#"H)H:ZfL28h@W?q#=qhjNNnk?-r/U!i'PrqM!GI1m=?hXU)[o>A01G9Cbc-/#"^4`>f<!lldmoJ!^$$$FotT%nj4VBG5(E]k)MTLE]X):+'8HE"3(IeF)or93tK\+:D=YqjX'D'd?H4`\WKME1>kNbK@m8Mrtn"fP&S=CUa"T?2HV@?;NiBg\u\Or.ep+7+1CV'1a?"A4M@6a)-p-@Id,j_?d$9M4=)OP5c;WY!@EBD:""9E_.=B>A6llqs=uZ'ph%(@(ZL1slaU"^X>spRFR)lnh569lu6%N[b[>4_]RV_buuII!u?2X2o8A,+ma4g3A?4Q2)E_QLOUlY/.P<.n[&#\+6V8.=;uCYE.FZZ7S#)oUpt:qYGF9[-uUIID'DBbeVsrh0X&XgT$dsjL`nk^sQ%+),=^B<A2m#+-2<^3Bm6kF]u[.[].*u'F8-JD%%nOFCC3!)K[$[+jZTKE4g'=k8'Qg94&!,J9<s=i5#LT.S`b3QXiAf3HC"@J\:Dd<V3ld8%peb_>%PXCZF!_I?uKR0ZU&2@+Uu.rHADmo>F*3?%#)j2,_WGINuOP)A"6]epC-YPkiI(Eo3'rPJ]Ot#,Ap65Wh4G~>endstream
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1226
|
||||
>>
|
||||
stream
|
||||
Gat%";/b2I&:W673;CTEdL/WD,irIM)K`ds'MZ'IH^XW$fsINuQ5#3oRKiTV4&LlGB3DUp7Mq\@hgN07a<LpZ?QT2!G6$fI34n+a"jGT6,taPSJ03t%D1k4^/JGqPYW*AJC#"*OD5%(EKdmfd#K&A:/O:;8`hWeAq.\)23",%2&I6gCBd3Wf:R"`Vn;gEQ6(oSO8u9l44+='#Q_Nct&^C#>?o3L[Ms=/LM2WfCJb]eQ+0U.*KV-DHXd@XN\V8Adg#]VsKb,0Z?,Csc`GWlA\eCIg_#-n?huH_'%$OfYA'bap/ut8\HD"'e-8.-9#9Z60(8"Efkbq'):`:Q,q[mkg;ai/#a#;IBMB^1lMM1=FllrEOS)3#1NML!Bj'_.fTTDaB%kZpXc8$:fV9,>c&YOH>^f^*'Sh2onTUjRgkUcop4DZ7&g6dNEC]Is4XC]<S10](g\T[tiC5.5)d<-/1e9p#6T3XuYK4Z!i:)+"&9/./d-kOfLMg8O5HrlTY_ZO^k@9r$_gj\qc#]!N0@$9W8mp9$[%i-[3`Zm#I:6FX$aq%YS[U/oTes])@"g(Y+5jst@SFY=7_0ui5ZhhC<_KoQ?I9m]Yl0?mr@d<=I%">IjHX$Bd#s=0bAdftYAUjqdQ::1L]n5\r]?>4jqsP<PV;&]0I(#Cp:.CPdNPU:tHN]](ZAg0Koa3Y/0;aq@Qk6g0L5UFpa$@&L,W3U^s4jg0f(D--,\G>5pZLM[Ij(k'fT*/uSL9"GWK3f9>OT&8O+&LR`H3Be>`r1uJ'&A=Y$BZIXO@`WB2eW8ZD@DgNW9B<WE+$>Z?8lUW+YVs(^I4+Bf9o1E95Zr@'Zu<Ru@M_$$)<P")gei[tUa$YIgYdD<IUYmH4NJIFSJpPeY<h1]on32eTPADq8loH(\W5's-a\l3O4>U%T@,o)`CrQ5>6,Duu(F`9Df1'1qTW`TXET:KoEqTWiY03A8$jf;NF=D&#R@*K-XiPi6R'UAQb*P%\ZVn_WAIbX3_U@Vn/]a&0+^1$VjH1Npj4Bf^/;l`B!UJkhN@,2$25WQTnc9i\-Y0!C^BB@cGRo\gW-jmb/c!?Obc,i&]sg*GKCG^K104s%1_#!lL,(X7(HoS1^1VH61;P#t&C^'mM0[r#go7mp[\,*&VK9dor=,rW.Zf&!5im.57I#M'Ye;1"tlSJTi56O8!]&Kf>)LdZB(StYesbl@F=SGeW*4++J3M#IUe&n:8~>endstream
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1960
|
||||
>>
|
||||
stream
|
||||
Gau`TgN)%,&:N/3lu5!'3FdUC#_Jj^V>%@]\8drcIAo7:9L0:3hFphP>`J`rb<)PrU&<>B*g)&1ZNlEMfgAUjn3tNE0*M&f#5S]7Peh/BPS4P5/,4*B\f25.R*@3*VIPuG"6,cg+/Gr7"I:1IAM+/,Y_ck2i!q&nj#XtpSo%CF;?b7A,7;@)L@&q&%^gs75+-=%_&.ph`"KpMSmV)1$@4<:2*7U:r?E.c60gtIW$Wkr[;64_+cKc6s8EX[N`R_%eo;\F]0'*M3eo_*2LPB7IS_+d&18qjK@qj#Se_?QT\M;YATIYZoL`\7Z:JO7oNJEq8:o@oq$j[_TEs+F@rAhb0,tR=:fh%Zg1-E4,"!SK.:F!P]+C"4D-,D-a+=nIN+-6Te8Bg["ukoJLsoVhNS6*^)0'N09;m$X65$_W(7^9IU5hMqiY</s&&F&7gMqOH)]b<n`UZJf7jc"^/_=T`]:/0;)m)VA.2B%$a7U5ggp1H"im^EEgG>2+N%tF2MdKuPEm&PFA<Q.,'rb0p8l+M?OZ_BIIbS'4gEA2@Q4Vas;r@hnMK8+;^cZ$=_\#m^5>:&nLE5=N[lFYJ4Y5&A">*X%)of1@9[]*A(TuaE@CB0)<801f67q:GaC2W9]\JPmpo.R_QE-I8k@_"<#]3IKg.&Jt!&'A<*<&KjH]k!gVXi@#l(9YHf/=^dgAGc#8^o%kE,g^"LIg`:)O/;rlOT&s7SU0>pP<l%bCq%?9'E>@r"+-&K1l`+1Y3hf19E4u"`m@HF/NUmZ\QWfp7SD#;tA7N]JV^UC*`#JT9&ScErobXcV1qSW7$g.$l:ScV2rThEc6r*eRdaL[tf,j8<#^L0PO#d+B8.t?<i$SqYKSQ4!0i.$;qkUkr8.li<"IRHi8h4H&>8eQOi]X%]XQ%rVUI;P+cPCUSG1<:(KrqIh>\,G#4JKhPO#10Oa$#Mkab1L*-qXE5Uf94_oq#5(:8.\\'?Lod!^(]9/Kor;<U$3OF9##YuIr=P,#c>8!hK0sq1i>c2#?+1PMDZ?^l/jJg*p_X.O`<V[u$?p5XIk,?W:m1sa\8j>Y%Q!*fQL2*_7'*gk7S_R#n2Loa.OdeJaSe&UlVeS1sEF%^ARnM78paCcSRdR2Ug-Zj.^R!7S8*4;T*DE)L\qVF4-`p?Cb$">BTj1HZIG8^fJH:p!H>4H*$^FJpmg:/"qR9,-<?RVe8d32b&OJ<Fj83Z(1P]EVfFESR%q>/dG!B,IJcP8:'E^ZW5t;N*U4lcaTF^,.`>6lPN&#<1Rlj3k_DDG1pL1XK'OhR\5Ee$W>"j.J\.0'?RpfJ?4lj?h&+bVa2lk%0ApPX0",\\"gol-BR)sNg+aN9'Amd%h)[pp1FqC_u$=AEdAfS4YBo1ODHOIFmP,J96kZ)X-W,QPjkTbBeG>4uf-Vr[K%p+jhhR"<ZK+.=MVB$sQoJ^f@XbdM.A?6/bW>Bd0!)nX.VXWL9X?e"DNlC,W60h0X@t!hB@-A+/!*VR5'[D^WKs`/,r_HTL/t?.\4mA>j]Wc<cd..dGS2@r>@.@A@'H9iIci:T^VoZspL?Nu']X%pPWRH04.R\DVbFfk)4F$asp#,4nd=E0@XT-q*+"2MPK[HEle.9qtbM]R9;p-MED@$dX)Qt^j+esE-qe[nNM(Q_+d[t'.%m#^[K(Yr;6ntiMpQ=>`bg:a-Wk/X`U[C#ibD1N'OUsISUiA^a>B4qf/NH_decuu:#7]HSimE'8;I[OgTn81HiP_o21d%C$?XF#,XcAAo;F-rbqRB=s[XR.ZSBPUEh[9%I)N8Tm[in+b,akQT`ri`N/^GB$-(%n:mn7LD0BuM<M'8/M4!DV='UDXp<OPCjC_A$;aMe4,pW0VN<kidYYXJBtEZa[;S<Vb[I53@dDWQeYMB8JA%nam__r#QNk5#HdZ:D;O[:XfW@!MUP,]jcJG`Q3;rE;=7^i^40:`e#8d6FfBT9K~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1879
|
||||
>>
|
||||
stream
|
||||
Gb!#\968iG&AII3m._j(2?\OQ#eH3edO&\^ZqbG6Q`::ZJn3S_RAB13-NCaeOod(&''")RX^mhFK`1V$`<S,jph'4!0EHD^KulslN5K`<9Fq6R2t19;\eu)4\L1W)NhVQ[JbY7N6*VE+i(>2AmP@\h,K^ZB'I-6G$961R*qQ&OY]qp45WhV$-%IE+8gV68GDP<"<=@eYl/.hGm8M"eT?,SE1pd!F0V#s_V_"hm#\C1%_DHi6+/aV&L0q6_0#Pj`MrB(akjYm0)<W&'HOW4*>9.@e/e2<9"k+hg5n?r)PdlbC2F66a1<\iL@"I/=b:!fbp-@JC'\=ar\#+G2,g)qbUL+6DR_MQe-jZTEc4"PF@ltj*X\su8+:019Y(Ii\K((Oo5So:.E#St"V'3p$Z=1[P1Se!g1PnIT#c#V1QmmB!12\j)_UK4dij]N@89eI)ANLZgKVCr?)mZ:_#o1tUO/V`AE+I!o(Ft,8?:1j8'VQLRYQf=MG*98KNZ_<q&<@[>V0ZLt%ZGSB_@c0oM=JF9g<+WrFLU5mE`AC4GrH&!]G0;U$)0hq`S&G0:OLHt"NM[W_mud?kG$=I&>`qQ`%beF3k&2I>+/r#bbD&4)Ze#]-sYYe'6UQeIXUU?Qb']W6_u9C_TI*&#;tLW<!P$Dc<+-fNpOmimnH++`KgS^;_(3Eeg"hB+9+IJ'+!al2Y"gRFIX0#D)C-`5?lS[Y_l]*e:4)#VBi-fFPIs:`)ka'=^aL2-<U`CLrka,Y^*N!Zid(oY")5*PG4(aS[HSX[+.a<Kg@iCK;Bnpq#Pqp8WZHekcnj?qj/IIH.-dC@[,qV;8HlN$QW4CZrr]%?r:G@*.2$3#<r]K$hQnCIhTK5XY*/AqEnhfK4kf'QbDk0g<MjfQq+)F)hh^TmAqmRGe2k_Ccjd!;Fk*1UcY6rG;-#1C;Ql5e/ehUa#&Ig.LiF,9B#:&q/eMIoZ[]4l'mqjX4\YDhQIpb(L%mM)?UAoGk)^b?'^l@''&["K"E/*OHA7ZX"m>__'A1X+dCt*TS5""EJ8@;<bC@mlWfJfj&cZlOCWDQT<t;`N=Y@kE%j@9g5dOb+rsI%:p#WX@N0Y1^m@@M2mt5%\#WMk[bd2tHiNs:7e(aEL,3,t(`rVb;=4,*08&)D\[G`!CuJD(UZr[sO,:^JAW`gS:?QR:UbLDmFM*uVW)];[d7B3tV>b2Bl8tXn/G2H:MQV(/6!WDE%nIIU<IFs"'?GnWomC9Aed7B/m"E%dID]LHO@a!9236l/R=#U33ZYZN_7Jm3Hk9`b/OJ'%Nm#WoKe0DO:#HmYohm#QNRIXE:(&VBkI@$C$Y]M3\sHWLg`B_OnjiiD_r;qXSGGFnR-3indU@9`Z(A*'"m@W7)\4&_#'[YgY$,#D;]Cl;olr*3\fU4dM^I<hg]pl)O:/B?O#:Ns2Qho[/]/dDcpnYC62^6dhCNfL$f!Lt+C!>cRb?Yk(i]=r1$E^B3!QQCFoYe^=]%*YZO(0IhWNK8](OlcS`XObeRfIul8`26`jmOAne-/2$8AsQGBoTV?Wlo:=,Z#MO4`[^cF1d(YS7"QgRCZ6o+E"'Nh^]Q"mJiSU3'2IffnK?g'BEH7;CnfE\'477c!Cf6WtgOk4iuO']PV>8K>6iD1t)9Lb$u!i,Z(=\*g^&I^e^`g[M_-S=N_I^3qBl65!W2hbH&NkY8bJg\osN<5XPpqs-n;?0Mp$&';hQmT.anC#;,)n?.'IDpY*]iO*(r7CK5g!.$0;kW\d-DE86>AK0cB0`^*'mY>^O\S0?f8;$H21=m>CjT)g*2)&Vgr/.*s4EVjGFg0r;VhA"K[&7jT^tGb#ET(e@dn*V3p_:XAmZii'533(7mTfRF'??dfCF6j\+6is:&c~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1220
|
||||
>>
|
||||
stream
|
||||
GauHJgN)%,&:N/3D"D28%8;9p$"c5^Z(!^q@lLBhpdm+M\WUW'KE@=b\6kli71pnN<pe17Ui,8]3IAXE3B2-MqD4Q@SFtk%S-'SS*s%^%6N7Z^om8oL9_]fn*\^YUDCC$hDY4&mmUb>PbR[.`5resEJHVr3;^t`ha=dgD!#B#8[`<q&^(Vn$9QAB[rW@Y:q*GY#A=i7F]DcYpWX:CiIN';]fpi17(;*@VNTs-uE%g^R5D,`G^YW;4T4X%-1bg>2mtJ_o;SYPR!)>3*,;(Z-F0s!7^OuO?MP(&$4bn<c%(8GT0fS^Vl8?pI4\daA5mQHmWo=B)(N!i:n<rhe8_&=%aINk^n12qNF/i/E#uS1rkS>mY(h9IUL09Hh[q;!OrS@mU)ofHU?6K8P(g5rJ3t6X/jK%-<a3$k2O4gbAC:XebhlTuD*s<(l$ZMq'Lb#(BW?+1%[o4pgd10K\.6_$;odnnRcfTp9ZcD6!8=tT6L26Cao@2iHP)VQs:2RY<jUaVll800!KlNij0etXV$RPIqP[kUQ$DR2WZY#Vh?XD%@`jR]$a2HCO_%Q.Bp^M-58D=7[/99)?DtD#SI8ISr4P)$PI_1+ZhB.QJFgt#_)3f4;'dARI^rj!?A8HCNm,dhjVN>MlB,]Vp-He(m&sH0+7qI_NRfiR?J8#"^%LWDD&kZ3D1;RW2ml?`;g_U!nN=+T%aX^E!f'H7p2.c)n1"0V88p+s0.6bO)k/kA[_8,O1l>.PJ=SqfocLT%'6YmUUbTSj+:+%AA%a[-?T5ePfA.$4p1ns+CNkQlDTh_`?pOctsW7>jQRN]TU8RrXC;NSZWIFht6.H-Fh#SM9hQ?PdW!S<rjb_,"\$YGmY<W,YNVO!rH2:;"_K&sWXUHJekUKp1P2\:"Hn:+I29<,DuYZF.MS;u7]K]_&9OUVV(8P);?;&?Id3KRth?'3T(Un')KTsOS2U.pi`N57*f4PWfoP:YSIGa="N2mO'nAQHH./H(`TTM=4Rb-N=;)h19^cRZ2(Qa`I[J-WpI+C38T:8?1pH<+1Pb-X^rbtLf/1a5L?/`sFME+*]ZMgKEM0M-pFMgF1hNq^Pe^f@S)m"Xh/a^1F8:(\mY9N0*:H5*#bJ7P@Kq^4-4cKf&MiHeO:NCm*hYhB=US(`tr0AbPE+6<-QWP'^d:GF.b&"QFud#O'Ukq'[VI!`h13pPh4;`uk`Sf^Cgs0=uu]q8F%gIh~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 23
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000122 00000 n
|
||||
0000000229 00000 n
|
||||
0000000341 00000 n
|
||||
0000000418 00000 n
|
||||
0000000623 00000 n
|
||||
0000000728 00000 n
|
||||
0000000933 00000 n
|
||||
0000001138 00000 n
|
||||
0000001343 00000 n
|
||||
0000001549 00000 n
|
||||
0000001755 00000 n
|
||||
0000001961 00000 n
|
||||
0000002031 00000 n
|
||||
0000002320 00000 n
|
||||
0000002419 00000 n
|
||||
0000003662 00000 n
|
||||
0000005448 00000 n
|
||||
0000007382 00000 n
|
||||
0000008700 00000 n
|
||||
0000010752 00000 n
|
||||
0000012723 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<a091d7cd8a415e8f493ae7ffe4c57a53><a091d7cd8a415e8f493ae7ffe4c57a53>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 14 0 R
|
||||
/Root 13 0 R
|
||||
/Size 23
|
||||
>>
|
||||
startxref
|
||||
14035
|
||||
%%EOF
|
||||
465
Les18-AI-Toolbox-Next/Les18-Lesstof.md
Normal file
465
Les18-AI-Toolbox-Next/Les18-Lesstof.md
Normal file
@@ -0,0 +1,465 @@
|
||||
# Les 18 — Lesstof
|
||||
## Advanced AI Toolbox — voice, vision, image, local, edge
|
||||
|
||||
**Vak:** AI-Assisted Development
|
||||
**Vorige les:** Les 17 — AI Production Polish
|
||||
**Volgende les:** Geen — eindopdracht thuis
|
||||
|
||||
---
|
||||
|
||||
## Inhoud
|
||||
|
||||
1. [Het AI-landschap 2026](#1-het-ai-landschap-2026)
|
||||
2. [Voice — Whisper + TTS](#2-voice--whisper--tts)
|
||||
3. [Realtime API — voice chat met lage latency](#3-realtime-api--voice-chat-met-lage-latency)
|
||||
4. [Vision — foto's analyseren](#4-vision--fotos-analyseren)
|
||||
5. [Image generation — Flux + DALL-E](#5-image-generation--flux--dall-e)
|
||||
6. [Local LLMs — Ollama](#6-local-llms--ollama)
|
||||
7. [Edge AI — Vercel AI Gateway + Cloudflare Workers AI](#7-edge-ai--vercel-ai-gateway--cloudflare-workers-ai)
|
||||
8. [Wanneer welke modaliteit](#8-wanneer-welke-modaliteit)
|
||||
9. [Resources + community](#9-resources--community)
|
||||
|
||||
---
|
||||
|
||||
## 1. Het AI-landschap 2026
|
||||
|
||||
### Wat is er beschikbaar
|
||||
|
||||
**Models per provider (eind 2026):**
|
||||
|
||||
| Provider | Text | Vision | Voice | Image |
|
||||
|----------|------|--------|-------|-------|
|
||||
| OpenAI | GPT-5, o3 | GPT-5 | GPT-realtime, Whisper, TTS | DALL-E 4 |
|
||||
| Anthropic | Claude Opus 4.6, Sonnet 4.6 | Sonnet 4.6 | (via partners) | — |
|
||||
| Google | Gemini 2.5 Pro/Flash | 2.5 Pro | (via partners) | Imagen 3 |
|
||||
| Meta | Llama 4 (open) | Llama 4 Vision | — | — |
|
||||
| xAI | Grok 4 | Grok 4 Vision | — | Grok image |
|
||||
| Black Forest | — | — | — | Flux 1.1 Pro |
|
||||
| ElevenLabs | — | — | TTS (best in class) | — |
|
||||
|
||||
### Modi om te draaien
|
||||
|
||||
- **Cloud API** — direct via provider
|
||||
- **Edge** — Vercel AI Gateway, Cloudflare Workers AI
|
||||
- **Lokaal** — Ollama, llama.cpp, LM Studio
|
||||
|
||||
Vandaag zien we alle drie.
|
||||
|
||||
---
|
||||
|
||||
## 2. Voice — Whisper + TTS
|
||||
|
||||
### Whisper voor transcriptie (audio → text)
|
||||
|
||||
```typescript
|
||||
import { experimental_transcribe as transcribe } from "ai";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
|
||||
const result = await transcribe({
|
||||
model: openai.transcription("whisper-1"),
|
||||
audio: audioBlob, // Blob, Buffer, of file path
|
||||
});
|
||||
console.log(result.text);
|
||||
```
|
||||
|
||||
**Whisper varianten:**
|
||||
- `whisper-1` — OpenAI cloud, 99 talen, $0.006/minute
|
||||
- `whisper-large-v3` — open-source, lokaal te draaien
|
||||
- Distil-Whisper — sneller, ~6× kleiner
|
||||
|
||||
### TTS — text → audio
|
||||
|
||||
```typescript
|
||||
import { experimental_generateSpeech as speak } from "ai";
|
||||
|
||||
const result = await speak({
|
||||
model: openai.speech("tts-1-hd"),
|
||||
text: "Welkom bij Polderfest 2027!",
|
||||
voice: "alloy", // alloy, echo, fable, onyx, nova, shimmer
|
||||
});
|
||||
|
||||
// result.audio.uint8Array of result.audio.base64
|
||||
```
|
||||
|
||||
**Voor productie:** ElevenLabs voor natuurlijkere stemmen, of OpenAI tts-1-hd. Voor demo: tts-1 is goed genoeg.
|
||||
|
||||
### Volledige voice-loop
|
||||
|
||||
```typescript
|
||||
// 1. User spreekt → audio blob
|
||||
const transcription = await transcribe({ model, audio: audioBlob });
|
||||
|
||||
// 2. LLM antwoordt op tekst
|
||||
const { text } = await generateText({
|
||||
model: openai("gpt-4o-mini"),
|
||||
prompt: transcription.text,
|
||||
});
|
||||
|
||||
// 3. AI spreekt antwoord
|
||||
const speech = await speak({ model: openai.speech("tts-1"), text });
|
||||
|
||||
// 4. Play in browser
|
||||
const audio = new Audio(`data:audio/mp3;base64,${speech.audio.base64}`);
|
||||
audio.play();
|
||||
```
|
||||
|
||||
Latency: ~2-4 seconden total. Voor "echte" voice-chat met lagere latency: Realtime API.
|
||||
|
||||
---
|
||||
|
||||
## 3. Realtime API — voice chat met lage latency
|
||||
|
||||
### Wat is anders
|
||||
|
||||
Standaard voice-loop heeft 3 calls: Whisper + LLM + TTS. Elk een roundtrip.
|
||||
|
||||
OpenAI Realtime API = één persistent WebSocket. Audio streamt naar OpenAI, audio streamt terug. Latency 200-500ms.
|
||||
|
||||
**Features:**
|
||||
- Interruptions (user kan AI onderbreken)
|
||||
- Function calling (tools tijdens voice)
|
||||
- Verschillende voices
|
||||
- Multi-modal (text + voice in zelfde sessie)
|
||||
|
||||
### Setup (concept)
|
||||
|
||||
```typescript
|
||||
// Browser
|
||||
const ws = new WebSocket("wss://api.openai.com/v1/realtime?model=gpt-realtime");
|
||||
|
||||
ws.onopen = () => {
|
||||
ws.send(JSON.stringify({
|
||||
type: "session.update",
|
||||
session: { voice: "alloy", instructions: "Je bent een helpdesk." }
|
||||
}));
|
||||
};
|
||||
|
||||
ws.onmessage = (e) => {
|
||||
const event = JSON.parse(e.data);
|
||||
if (event.type === "response.audio.delta") {
|
||||
playAudio(event.delta); // streaming audio
|
||||
}
|
||||
};
|
||||
|
||||
// User microphone audio → ws.send(audio)
|
||||
```
|
||||
|
||||
Voor demo: complex maar magisch. Voor productie: hire een specialist of gebruik bestaande wrappers.
|
||||
|
||||
---
|
||||
|
||||
## 4. Vision — foto's analyseren
|
||||
|
||||
### Basis call
|
||||
|
||||
```typescript
|
||||
const result = await generateText({
|
||||
model: openai("gpt-4o"),
|
||||
messages: [{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "Beschrijf wat er op deze foto staat." },
|
||||
{ type: "image", image: "https://example.com/foto.jpg" },
|
||||
// of: { type: "image", image: buffer }, voor lokale file
|
||||
],
|
||||
}],
|
||||
});
|
||||
```
|
||||
|
||||
### Multiple images
|
||||
|
||||
```typescript
|
||||
content: [
|
||||
{ type: "text", text: "Vergelijk deze twee foto's." },
|
||||
{ type: "image", image: url1 },
|
||||
{ type: "image", image: url2 },
|
||||
],
|
||||
```
|
||||
|
||||
### Use cases
|
||||
|
||||
- **OCR** — tekst uit foto's halen
|
||||
- **Defect detection** — productie-foto's checken
|
||||
- **Visual search** — "toon producten zoals deze"
|
||||
- **Accessibility** — automatische alt-tekst
|
||||
- **Receipt scanning** — bonnetjes naar gestructureerde data
|
||||
- **Code from screenshot** — Excel-screenshot → JSON
|
||||
|
||||
### Cost
|
||||
|
||||
Vision is 2-5× duurder dan tekst voor zelfde input. Reden: image wordt naar veel tokens omgezet (een 1024×1024 plaatje = ~1100 tokens).
|
||||
|
||||
### Provider keuze
|
||||
|
||||
- GPT-4o — beste algemeen, snel
|
||||
- Claude Sonnet 4.6 — beste voor diagrammen en tabellen
|
||||
- Gemini 2.5 — goed + cheap
|
||||
|
||||
---
|
||||
|
||||
## 5. Image generation — Flux + DALL-E
|
||||
|
||||
### Flux via Fal
|
||||
|
||||
```typescript
|
||||
import { experimental_generateImage as generateImage } from "ai";
|
||||
import { fal } from "@ai-sdk/fal";
|
||||
|
||||
const { image } = await generateImage({
|
||||
model: fal.image("fal-ai/flux/dev"),
|
||||
prompt: "Een retro festival-poster voor Polderfest 2027, oranje en cream kleuren, vintage typografie",
|
||||
size: "1024x1024",
|
||||
});
|
||||
|
||||
// image.base64 of image.url
|
||||
```
|
||||
|
||||
**Flux varianten:**
|
||||
- `flux/schnell` — snelle, goedkope variant (~$0.003/image)
|
||||
- `flux/dev` — middle ground
|
||||
- `flux/pro` — hoogste kwaliteit (~$0.05/image)
|
||||
|
||||
### DALL-E via OpenAI
|
||||
|
||||
```typescript
|
||||
const { image } = await generateImage({
|
||||
model: openai.image("dall-e-3"),
|
||||
prompt: "...",
|
||||
size: "1024x1024",
|
||||
quality: "hd",
|
||||
});
|
||||
```
|
||||
|
||||
DALL-E is duurder maar bekender. Voor productie: Flux meestal de winnaar (kwaliteit + cost).
|
||||
|
||||
### Goede prompts
|
||||
|
||||
**Slecht:** "Een mooie afbeelding"
|
||||
|
||||
**Goed:** "Een retro festival-poster, stijl van 70s rockconcert-flyers, hoofdtitel 'POLDERFEST 2027' in art-deco lettertype, oranje en cream kleurpallet, decoratieve geometrische randen, geen mensen, op afgeleefd papier"
|
||||
|
||||
Specifieker = beter. Style, palette, compositie, wat NIET te tonen.
|
||||
|
||||
### Use cases
|
||||
|
||||
- Landing page hero-images
|
||||
- Social media posts on-the-fly
|
||||
- Avatar-generatie per user
|
||||
- Product-mockups
|
||||
- Email illustrations
|
||||
|
||||
### Storage
|
||||
|
||||
Images zijn groot. Voor productie:
|
||||
- Generate → upload to Supabase Storage of S3
|
||||
- Save URL in database
|
||||
- Gebruik CDN voor delivery
|
||||
|
||||
---
|
||||
|
||||
## 6. Local LLMs — Ollama
|
||||
|
||||
### Wat is Ollama
|
||||
|
||||
Tool om open-source LLMs lokaal te runnen. Eén command per model. Werkt op macOS, Linux, Windows.
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
# Install
|
||||
brew install ollama # macOS
|
||||
# of via download van ollama.com
|
||||
|
||||
# Pull a model
|
||||
ollama pull llama4:8b
|
||||
ollama pull qwen3:14b
|
||||
ollama pull mistral-small:24b
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
ollama run llama4:8b
|
||||
# Interactieve chat in terminal — 100% lokaal
|
||||
```
|
||||
|
||||
### Via AI SDK
|
||||
|
||||
```bash
|
||||
pnpm add ollama-ai-provider
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { createOllama } from "ollama-ai-provider";
|
||||
|
||||
const ollama = createOllama({
|
||||
baseURL: "http://localhost:11434/api",
|
||||
});
|
||||
|
||||
const result = await generateText({
|
||||
model: ollama("llama4:8b"),
|
||||
prompt: "Wat zijn de hoofdfuncties van een AI Developer?",
|
||||
});
|
||||
```
|
||||
|
||||
### Wanneer lokaal
|
||||
|
||||
**Voordelen:**
|
||||
- Privacy — data verlaat je laptop niet
|
||||
- Cost — geen API-cost
|
||||
- Offline — werkt zonder internet
|
||||
- Latency — vaak snel op M-series Mac
|
||||
|
||||
**Nadelen:**
|
||||
- Kwaliteit < GPT-5 / Claude voor complex
|
||||
- Hardware vereist (8GB+ RAM voor klein, 32GB+ voor groot)
|
||||
- Eerste keer downloaden duurt lang (5-50GB per model)
|
||||
|
||||
**Use cases:**
|
||||
- POC zonder cost
|
||||
- Privacy-critical apps (healthcare, legal)
|
||||
- Offline tools (developer tooling)
|
||||
- Cost-sensitive massa-apps
|
||||
|
||||
### Aanrader modellen 2026
|
||||
|
||||
| Model | Size | Best voor |
|
||||
|-------|------|-----------|
|
||||
| `llama4:8b` | 5GB | Algemeen, klein |
|
||||
| `qwen3:14b` | 9GB | Code, reasoning |
|
||||
| `mistral-small:24b` | 15GB | Best kwaliteit / size |
|
||||
| `llama4:70b` | 40GB | Top kwaliteit |
|
||||
|
||||
---
|
||||
|
||||
## 7. Edge AI — Vercel AI Gateway + Cloudflare Workers AI
|
||||
|
||||
### Vercel AI Gateway
|
||||
|
||||
Eén endpoint voor alle providers. Voordelen:
|
||||
|
||||
- **Unified API** — switch providers met 1 line change
|
||||
- **Fallback chains** — als OpenAI down, automatisch Claude
|
||||
- **Cost optimization** — cheapest available model
|
||||
- **Key management** — Vercel beheert keys, jij niet
|
||||
- **Caching** — built-in response caching
|
||||
|
||||
```typescript
|
||||
import { vercel } from "@ai-sdk/vercel";
|
||||
|
||||
// Direct gebruik
|
||||
const result = await generateText({
|
||||
model: vercel("openai/gpt-4o"),
|
||||
prompt: "...",
|
||||
});
|
||||
|
||||
// Met fallback
|
||||
const result = await generateText({
|
||||
model: vercel.fallback([
|
||||
"openai/gpt-4o",
|
||||
"anthropic/claude-sonnet-4.5",
|
||||
"google/gemini-2.5-flash",
|
||||
]),
|
||||
prompt: "...",
|
||||
});
|
||||
```
|
||||
|
||||
### Cloudflare Workers AI
|
||||
|
||||
LLMs op Cloudflare's edge (250+ datacenters wereldwijd). Lage latency overal.
|
||||
|
||||
```bash
|
||||
pnpm add @ai-sdk/cloudflare
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { workersai } from "@ai-sdk/cloudflare";
|
||||
|
||||
const result = await generateText({
|
||||
model: workersai("@cf/meta/llama-3.1-8b-instruct"),
|
||||
prompt: "...",
|
||||
});
|
||||
```
|
||||
|
||||
**Models beschikbaar:**
|
||||
- Llama 4 (klein + groot)
|
||||
- Mistral, Qwen
|
||||
- Whisper (voice)
|
||||
- Stable Diffusion (image gen)
|
||||
|
||||
**Cost:** gratis tier 10k requests/dag. Daarna betaal per gebruik.
|
||||
|
||||
### Wanneer edge
|
||||
|
||||
- Globale app, latency belangrijk
|
||||
- Cost-sensitive (free tiers ruim)
|
||||
- Geen vendor lock-in
|
||||
- Vercel deploy stack (logical extension)
|
||||
|
||||
---
|
||||
|
||||
## 8. Wanneer welke modaliteit
|
||||
|
||||
Vuistregel — denk per feature:
|
||||
|
||||
| Feature | Beste modaliteit |
|
||||
|---------|------------------|
|
||||
| FAQ-zoeken | Text RAG |
|
||||
| Foto-upload met analyse | Vision |
|
||||
| Handsfree input | Voice |
|
||||
| Marketing-asset generen | Image gen |
|
||||
| Real-time conversation | Voice (Realtime API) |
|
||||
| Privacy-critical data | Local LLM |
|
||||
| Globale snelle response | Edge AI |
|
||||
| Massa goedkope calls | Edge AI of Local |
|
||||
|
||||
Niet één tool voor alles — combineer.
|
||||
|
||||
---
|
||||
|
||||
## 9. Resources + community
|
||||
|
||||
### Communities
|
||||
|
||||
- **r/LocalLLaMA** — Reddit, dagelijkse model-updates
|
||||
- **AI Engineer Foundation** — Discord, productie-focus
|
||||
- **Latent Space** — podcast + Discord, breed
|
||||
- **Hugging Face Discord** — modellen + papers
|
||||
- **AI SDK Discord** — Vercel's eigen
|
||||
|
||||
### Blogs + nieuws
|
||||
|
||||
- **Simon Willison** — https://simonwillison.net (#1 AI blog)
|
||||
- **Latent Space** — wekelijks podcast
|
||||
- **The Rundown AI** — daily newsletter
|
||||
- **Stratechery** — strategisch perspectief (paid)
|
||||
|
||||
### Twitter/X-accounts
|
||||
|
||||
- @karpathy, @swyx, @sama, @AnthropicAI, @OpenAIDevs, @simonw
|
||||
|
||||
### Voor diepere kennis
|
||||
|
||||
- **Karpathy Zero to Hero** — neural networks vanaf nul (YouTube, gratis)
|
||||
- **Andrew Ng Courses** — Coursera, structureel
|
||||
- **Hugging Face NLP course** — gratis, hands-on
|
||||
|
||||
### Conferenties
|
||||
|
||||
- **AI Engineer Summit** — SF, jaarlijks
|
||||
- **NeurIPS, ICLR** — research-focus
|
||||
- **Devbase, MAINSTAGE** — Nederlands
|
||||
|
||||
---
|
||||
|
||||
## Bronnen — alle docs
|
||||
|
||||
- **AI SDK voice + vision:** https://ai-sdk.dev/docs/ai-sdk-core/transcription
|
||||
- **AI SDK image gen:** https://ai-sdk.dev/docs/ai-sdk-core/image-generation
|
||||
- **Ollama models library:** https://ollama.com/library
|
||||
- **Vercel AI Gateway:** https://vercel.com/docs/ai/ai-gateway
|
||||
- **Cloudflare Workers AI:** https://developers.cloudflare.com/workers-ai
|
||||
- **Fal models:** https://fal.ai/models
|
||||
- **Replicate models:** https://replicate.com
|
||||
- **OpenAI Realtime:** https://platform.openai.com/docs/guides/realtime
|
||||
- **ElevenLabs:** https://elevenlabs.io
|
||||
277
Les18-AI-Toolbox-Next/Les18-Lesstof.pdf
Normal file
277
Les18-AI-Toolbox-Next/Les18-Lesstof.pdf
Normal file
@@ -0,0 +1,277 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 5 0 R /F4 6 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/BaseFont /Symbol /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/Contents 26 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Contents 27 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Contents 30 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 19 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607101945+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607101945+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (Lesstof) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Count 11 /Kids [ 4 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R
|
||||
16 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1970
|
||||
>>
|
||||
stream
|
||||
Gatm<>C5*_%"6a2^qMtUm6XeuFeSMpX_I(F?.7A?*gSsf2IieM-!-7nk2-[pFgL+di];7!MZc<c!!Eg(_8-r<T9BGompgV8L&tp?^'3fU/rW;>0t+f!2Y1)0H=1gQn;r2AEqK\5bY#_CD*MPS"lTTm#[D<P[=nki0H:l31k8iJm7W@h*V`AP>d+D)I,R:-cY]:/SD(A6h[_Zd=7ur3?>05$F_IXtUGA(,'rXSPGAW+]JHt3=%/t_UGmJ>pR4K]V/5+on17+2M#rdeHE'As,nm3Zr;W]W?r"[4)eH?nhXtL?<+06t5aeC2i>GL7/R`/tD[%lO]HEbuYZcXhk;`b7JNh5.o?H^B/$d/uAj&60qHjFTOpo:7PCL;&355R%=RKlHqm<B[PA(rp!joGpbd7.h`UmfDoQAO/V:9839VT!8W3UL>jb<[osr2et[0@bptB?`":W_J1T*3h:n%'EMsTJoW$ST.WN"4>*5!o"<I-X,jfXJD<,RMLUjH"aE@/P`@kBd`ddlq3[YH^"lk!cr5@d1BAK]qElujSc,<3/=]'"st+dej_$0EBVd$1CaGSkVtk1V_1eS1:Km9ouu"kJa.j&pSn\iOATQhCAj[A'6sfVE=ljJ)8qGH-=J7kB9Gu`"@f/1`>Q`G[[n!?/ejg":h9eH8lqZgi1A+1JT$jL]5+%3JW;X[279M,n"9k@"EBk(H3M+f;eVD*.j_bL%R*C,^TAC0[49+B;Jt^!S$)'@+-Q5iLl5/+lWUZWBt8:G#Il`#`*Z)8*(J=W3IRnIcJ`BN@C=8:p9BG8*<n`c8jil?/:P0UYm1q`NXLfin$?O/g%$i&^/Jhje*A<Y.Xdm_=-F7q*3QRm0'<$B*<uktaE/nY^c;bH7@[,ZjYW%j(-!`*X16dpQk(."2G;N:D3,&T?lMbF'u1G_$U!8D5@.gZK._9J(:^o0VTN>4KhpG<\fku+ITqS`AIL:3A?@4@*pKc]ee8/<Z/hPjX;,.tnp%$qpSj0j=s/`JOr7JgRE08IG:@+'Q.;QFaDReqS9CbtlRUrH!E+lId;b:]eH1(XhO:)8-<2o8@j[Iqkr`0EG8f!GCSlu31M?/cNDq//SnI6[,t73l2S)Z&krMa+CH;@j<gG5+OslkF^PnI\AXNMTc/<5,k-?70gia:[[AO9S@.,@k=WbH9Ob!*oDpnW2*Z)neiE$kW5:Og8goFaJ*_[(fA\"qSF:e&-+Qe(`o-4isPYk>u$R@?+6N^Sg"H7%$$]KS0\5![%17^NW2fOp]6V+SC8`^X4:/IH/EDhY^G7HcmF5/t)TuX$_-@Efb[oo-t;F$I9a^ZK8R4;jZ`,J%0<-LX^hS%RZP<ekg5S&oD5--39bbMK6_4,!.*>cZ[o?iA!./Y.6>aVmMkQqqIA/Za#OaFc\RKD^InA;I'Dq)"<KE$@_7#OS:pPEM],Y8aT+dm6*$hcEr0B`GfjTiR>@dt0"KfQmbW5q+L1/X+!\<nA47u[<e$#YU/8VDl,lR]f7H*_30cW=EZLcPX;I=^2>n`o;]N$i/a$muQt3-Ob5)WR`7Rcr]eG0"AZ1?:Jg;i/-)K1t\Y/2Bor\<M!4]HP@Kkp<p-[(UfPT*05f"7qY:5KY0S@;lUuLe5$WXO=W.4%"fc6e-n,Y'ZbX^R=*=JN7I_'qh76"FcTo;&ct7S&7XY##<bWC1c<"hAn"G]2NAnY&Tqj$c!JQU@.O1].[$GpFsEf1Z<W"Y]nc"-3Yf@ZcocQG`"_'1aNCEic^s?)W#62iIqL]Th[tXBWldh\prbK8)FcdHUXqBTaa3A_2;lPVXJ9&.R`#E4K657Fe)M=O6-+VLEHZJpaSj&"h)U[cr35KAJHNF0$6P]n%`[8^!Cji2\-JYDS5,Klhs_YCNiNX^`(><X"j.i+QE\,GGGbbD'`siGZN;U1W>dn\A/M3A-1PHYY)Ahnc.q#$Um0lgKo$P`ai4oY"mg<YcV5>r=;,QH!L~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1950
|
||||
>>
|
||||
stream
|
||||
Gb!;dD/\/e&H;*)E<u9Sko<0g.#Mao@*.,5):Gou]_%,5J[&oZN@_W'S7F.]hnGlBD+daS!Z`1@OX8m*mlB7J_bdT,7C0bX-,B$f%SnKL#3.^?:,n3YiRN2BEBon!/pDiud]u"?`3[]!`/?neNZc2K*X-8g7(OAJUdRgN!^f-&V(T\)k0F5GLat#XEZgN+6Ace3Rg@#QBhfWk]P[Va5AApELa]o'2tJsH6O?qHWiXpE=O_=2(b]=mqjYbbpbc7=A9o7b!W8A*H?u.!KJ=:'cJYP5eNpRjnNMmr_"a=#TOF&mM%G?PC%PXX8K,ip,B),L%i)='JThsI*Od$1Lib2.Om`Z3l3UT`omlQ^T]T7sE8Dp/4;2EJ[]cMCZ[+3MiX61,XOf(C"k@+L[A'bhAiYGlA7[dFMB$>HT`FA^CtmgddB,Y!g1k@W@_8q/*p`^16dilJE#c%o^%;t&$JU9&k7DC_%H5C#l?6=bUVrk5p>Khe(/7p^'.d!Zn/_SS]Ze;kQsRh\b+JC#0#W5Ge9\"Nc"`dL-Xm2p;&JTJI-qA3@A-Jj%S39I);b2s<[pj3*@I'L^=\Zb=FBM1#i<]3oe_OA5tA.0jJAqaqOrs%a8nu!_im>3f6r_geO$/ED^#'Y]S0OT$R+/.QmL"q?L(QR%(Hj2&(FJXLWL+^?eFI0Klp&S;(5l9FRN04Z<'qSj(9M07qW@M/*'IckQZ8BW"%G#@4G4tJZ3A=h^[[rAD$U8i,PEe2fKDK3pCBA"iNa$gP6,DY@N?f=0f\C8=ftMH_?%8B>/o/;I9SeAA`J2ProJUYHBBTI=`34>];g>^b!7;Y_!t6'FVOfl<9N.;uJZQr@f?n8nR,YB#nlVN9<_OkjZXW!.2Of24p6.lnZ$N>Tc%O[m:Q..g^gnU01(t6"h(m?6t+1K'&##qmsn,E9J2cfne_B[#em'$suL\+/1'W)J66P^2E*3]64CrATRh;=gU&;COODDfh6WP>g@1u]Q?-,Y1r3:SaRN"f%N!KS#OXF<kRIHR=!>-#"NV'k#14Wjs4m-,Ag*tCYZNQ@ac'f_:H*5>H[We]WYp95MC[7WT0rf$o^@MWP2;\O!"hU4A\S^hFI)F:+b,^_E7P-+oEu[IidDo't!"N':9@jK'Yh$X47L$?c,=DT)$co5Fod;?.uC1HLY&"F;+MI$>2s_i#aLC\C7+&^m(h%8S:<RKcNbS%)k9>#\U4OGl/V>C6,[L(s<q2">W$-8+->`TAW9JIK]#IrLV^aD`[GhmAsRh2Mts7@hg?>fO(I=H8\`7kFgIDHW+k"*)V*iAJ%#aIC_-[3aaZ#&5*@=?k@'M:Z+42Y'F!k;.b@A(r@8?m_NqZZ.Wc"Tm@I_\?q3(rMZ/*JlpfKRnmQD1EFsYL-!8]nWY%NT=G*fL,jM?`[US$Tur#Q$(@l4JcR1#P`;lKg6bmD28qj(CCF82CS>+1WBX,_f7TV]*&!=.(6Q36)NT-%11V(Wg@/X="[ddMMW,=6J\K1LpQmp7<Ua)#rE!)\#rM'6_`Yr$\#9/;([^7t>Qpm841l[seLH;$/&*k2ZgnWig!*t)\Bgu?#j4_sN6,rd`rt&'F#H.?6DQ/'#M26K5CpCEIbMRn)1HmV8a[-uGa5N;Y`*0TG[>nCN>dYja`-]$0;&EY2q]99Ct?%OCGT#Fc-#?tIQ7n4WtE/++lo8UfCQP57hEpRmUHc3WO1\Z<>oM;\)r0*RISUerLTsRf.pT.TLf\H-Gqr\,VS-n)cbZo_q_A/\A)6d%B?H&W7Y0[Wl+#u</MlbWYbSNW>'7iY#QrobZ@J',SsCs.7W6@J2OCF&c?#Kb7]ST#[aM+]-15d7K==T66G":m=?sVG`Y=/Ug(nu1.LgO3rXWUX!dJ)Q[Y+o_*M3@);6@caC;@ir$s*PhVSIi%pN.X-_mDf2J_rckX'G:1gZULn8rE<>.>[`rW@)I:4<~>endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2010
|
||||
>>
|
||||
stream
|
||||
Gb!#\>Ar7S'Roe[3&C9dZo0.,eBLE(;Ja/NUhdQOc&7.<[M`;S,e=WE1^gnP^-h0p\TM@o"+nL3A5gu<k<$0A0GGLS;>YR+!k]DenL4Xa?uujB'+UdYpiY*^g`amS!V_,SU#STN8E?3]aQK*&4J2B\M^X6R5f/$R%k.h&-j5:N"T]&TQZ2nt6\,BS'8.>r83K30IsBfr5%CO['@6EJn"6fM$]TEDnLNqPbjlR(i=9%BC8AG237J<u(o>UVrS>LMpeB"E0jQ2m^^$FRksE:TYlIPEi"u2X->Fju,8f7Pk_2m\'$C.a+o&m^cuW>(>$[I]0#Tlt"Lp#an'Qcq"J8\+q:$Xla'J=bLJWaq5.[Z&Q>SVKl(C6Io5HjE[)7NhFD\@MFEm#:#<,;8s*`mG-YT]:oq#lq=edMjN,r`&2/<f_T'&ElS@Z)_e6()!TW$,%UdI]bL994U7[UO02=3@B@hS^ffNLGQ6*pAHm4::VO3FX5p[K\faQBNj_C?d6!K0Le..cu38#Ylr)m;5,WEd>(aKHHF30fmIae*XBa]rM)\WW<m+:9Mt;CpcG>j!SjY)']nG%X7G,]_;Z.'uSfhM!R?EHeN6;jA(9e%8^0)IA'+'sTCaNdLM]C\,rQ4:IXC"-BON9SS).Ru*LH(<!`7e[cUE_.(t9+8$_Bk68ek74WXeIapgL?HH`7kU5m0>c;0[o4s0e1PZ,uFnZ1&*qA&/XQ4e,nPl5JOX04pgBT]%#5bqABW::7[?r5F%k>3gg4r@M&Uc&CELK'jMmXJT-%X6AWTW%2BMX^,B"7(TNsDYu)OY8P)'C-SZWN?4SE]Mgcc$o4d;Rj0LdLrc?g2p2gQ_^#[W[%&(t<`cj&9cJNlc.TWo&16]oPeIYfbL44k6eW>%P-ZgT<X628L?"SVp'j50'dnd-GhG`&C>GD7%Y&?(1GGl0g<-YijOc6GSJMa]&_m7>M>=.ljX2orpoMS<GOT]-2K,$R28j?$q.Xmar$%b-A1]/SSG9#WPE:/=t$?LB`T5X8NgDS.X%/p-7cE;+ND"=M)='#MW5qnts027?s>\$^qgZ?^i]CIr/5VNA,"?lacn.i01bFR=_+84qocm<gHChe50_U].L'BAtEAcqG'`qCdl/c;3T$.Rekfo][]f#0!\rTa"&12XD+a.l9o*"/c0+oe1rR.Dbq8:mi^+ike^_'S#>$EKgrI?(kM;M[idGSMcD[afVu-r/do?_)%0"Mpq2=KhY(RBV&EI\>U*M19,j*"`!MrI(Mt:%bZB,+eKBjXGX#bUYpu-<Pcg*)[bOZ;Z$YQ=M=Z65hIb+:q%3_e&i8Ir$!G=-$(P+D^LYn;\GB)%24gn$[MN2,2%Sb1`5W*g,fiJq#*W<J(Ag(t9nF+_ZJ8bR-?%k]Hli#Gc%Hj"HfI(k\Z\VKli2?>U>+\?DkH_ICNF7dkR)/JpU21!h96aTR^kG<1j$6k5ADf%Bs`)EV3+L@L@@,@E%!!kS]M;I_Ps`u]WO6taDOF#dtQ/18e$WE)pV,l!ImY&BUfmtjPoM+&p,Q[O=^e,gqWupg$n2KCC?urYbXDgYnA@[GMBe$0OjRf(7lGhIe+Efg=H3M%_k=<E0q4#q7J[P2;;%-[!5qm<$OdpCX!6kORcQW$H/@=(rFfI`[&jgV/=@.@5PP@3&rQV@V4\9S]s"bY6/6-,OZ1:bIR$G;l^4@.r_\#m!@0o1I)V3(e;#._j-`sWp*Dr;O/\*Ek)m``q`BjeL4MH=`[6ZI(bs!l9[2r_SC5_ZoA1qn<?JJD0VrkB29M/LC`Za:?a_?[IcHPG!1C5:1MO5,jOP[Pjl'FfkosjEB\%]Sn'uV6e]u]UkCkR0G+'6dU<1:hV(Xm99C)U1;,*.jDl]Un^2t)K]%U2#BQ[+8MErlg!gL:VT.V3N_$QU8HCld_1l0YjnL5rjuaa.NNOY&r.lXZ?,Ut5_8qn'*c>YIkSXF".m.b?oGS6ZH4bu?Ql/e.<kO"4`*Y:17[Sl\MKi4dhV/igrW/r.iIL~>endstream
|
||||
endobj
|
||||
23 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1780
|
||||
>>
|
||||
stream
|
||||
Gb!#[?#SIU'ReT:\F@\3U8(;;U8SLWcsR74U2*i[m2kCQ0J[JqOX3_blXiTbq^s0tP24&K;4sC!=:n9`&"\-o\Rn+sc)T*/")ouIaX%&/@C?:cLk+/OpgrUcm1:n\00CA[U2Ibt"Km/=^2akU,`r*<(b"Y_jU2WW&Z#O4*1uhNk!O#oq8?],HqA`4J10PO,sQb5-'E=k/VkccE;Y(sT<dDZ6oNG$R.VO>_]>gMWjV+!6CI"`0\aD<ea)tUiR`0_MK#,`0t]#X'<XuqF7-rPkO>hR@,a"!q&.DZ@J7W#kSY+5@1(FI2#>W77@>cD,JWPEP\:Uk")mZ3pD,#m_X^u-PXbnK]KKY'+6`7f0II4E3h0I/1TE]<p(55^9tAMV4q?$e1g)h'4)fYPH_CT$<;>$-@?^p.d:odAaqc!&i?[3ro`-n1nGO9YFtIljU@uE@WJ+[l.]D63;>WMMdhN1\V&QpnAZB$'oVeuif#G8$l:l*um0]<IDISA5?`Do6Znk05?_Kj!?t-c_@r7h+ZK_>tS[DC]Z$k6F9J-JO'bZb0VBC59"XN#b9>D(tZFX3d'=c-4?1CaN[EhZA":Zj!/[@eO])njkQlZ*5Y26&7N@F&NdB4nC-PN%>"R@tn&IHq2j9(n47`T)I0gBO'Ko)_.XSdO^1n('8E8!<NMKi5+f(k/.^*I$Xl4A.C8J<$E`],'dcX?SoHlDJu79,Auo76(f_Bb'8pr2">Y=MOQ;6l(F\+B-O)36"U^1b^jPdd&@LJ`VN)5RYmAd_n5dF/+H![1MoBWX+PT>N&OO@GqOW8fkN*Bf)^dE&e*M-h(/r5-778P1\(r7]*B_A"q>"EsqX\KZSXpL2t(c\>k:5+t0BA%Wc79Kg7g-Ve.g\6.Sm(iD$G]eU=]k#"*IgU`tA\uIQcM\VWoO(8S4R$l5-KB<F`Ta0&2!>.XIhUmaP2A0ec=Cbi$S\cd67>?7"dG%*S&hNQN@pKV!lM8@fb$(%9=Pl<K-MB&A9,JiQFt1@FoEOUm.Q=8B$]dj1=*m&*Dg#E<'#<%mT]F1P<XK))Cp"5j]L.R-9bc`([S@K7B)n3laea>T>N7a<AFn=`UQ)n"X=P?jbC/(gAZID+G(BGX!A-YoV=hW$H$c0\3@rB$4i]V;A?kq9)m(h,e5[3"!nE#V:D^J>YUS09:'\6!MTga9N[(Vg']YIhb.#b-2J,g$SLb39Eh/o0(ZZ1nkTN!O.\"9Q)mBqK)buD`#8t]c]rN$*f,4t?.C)WG%hQpk9YW)C-T\t1"ALWkY,d/'1g`+5>j*@]+@N(Gp<38<:B0W'JpE;OcXZnsJg#qT9",fbR-3"hg'HCI4%-G7m1@[Jd*<KqI!t#ui]o/3N^XT9`g10.:.HV]Ht%,\\s`@r%]a2K9)tt@i>h,#!lkX008L;[F\"E;.V$`Qidn-)kCER7iNZ(HVm4e)/Je;H<Z_WC,rm972gYEHA[/F7qf/=J;aYE2(VIAa58!JMH3lZm@[?&r+>*P%Wr<.E.A`=)JNuG`S"@A#.F$LR_Hub]?'^m!jig53H*<[sX>=mfXbJtZMN<1Z"Jj64#Q7qFQV1$<mO:miaJa*)ULVM#MTlqCQhBt%5\,<5ZFW$&^Fs)@LU4k2/;.ljZI%4/hf%.B&KZCL8B!7d1<Kn]pA]XErP8DWVI#krmF??if2A8^Rn[`&m>@aUp84\%G(k+ZB]n\#;rBr'4gsMa46(m8IrFnCM50C+]#i-d0oZf1U<AU$ih;CejtRg^FjqujD"0eqrD#E;\i1*YrrUqT1Nr~>endstream
|
||||
endobj
|
||||
24 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1856
|
||||
>>
|
||||
stream
|
||||
Gb!#\D/\/e&H;*)EA.U@l!dhl-q_WY?s/q7)1j2Ph0o\b0J[LOO[N!.h(2"lgNSlmfhVInUd^U%Y\]30]BAVSgg)<fpnHk_PQ:X<LY`=@b+Ls%apEk&)'&BTs0N%Fbi^#Y2fRQ6!=<'/#MH&@JgZ?[=\']THkQ2oGX+h3KE3bhkPNba9Yp3eMZWF&is-Pp5Wo^8HfnZY(dliDGX@(-ce%jof"@*#g,_'sHD<1L6#0;V<0n8RHG0X_"?Na45FfT_Au,!2CeP9+MbHS"!\PA^iU@OfWL8Xg6tL_lrs8Q><l'qq/cp\Kr)KG'.aJJYXFsj"O\R3I9*3tC#Nl^&X3L3@7KUopk]uK%=ul6CFVU)Bga_Z]=<Eeo$EOn%mrJYpbZ2BOFBNJ@%7,Um[8)"Z;Gr8+.Aa<snFQ5P@+6]"2lFLs9.QEA13G4Kmr(&2V8T,cTT-,O!\5u5Z%UZrC]p=#UUR)d"d2UqP<rR<"\a%>6W9AEEu<)&V&Se-^unJuG-:.^?sfn,M@(3!!\`9'l]Fsu1RR0MeZFs(@hi9f`U8S\_`l]F5jTS75*[k`8nQIq4n*W'9KIs4;ReS>cI#k*WkASJ)a#/7\ZQ0H5E$e^)h"Pm?2V;U]:9W`ObH8b;]t+p>NYr$fZ\V%fQ1=/K`+q?8l#f8,FPDi*N_h\A^XNm+&rfMPSkUg(E(5BROOL2'F\Lq\%1H(^$mEt*#Sl6bY3V+5Y,TQ2T9u4*8a.6mOiZK^!46#/G$e#!VIK.leVC&HT9m;_:)@>06DYF2*3QtP'*H19A5QKKpu+C=II9ZGfV#KR@nV/?1631Nt%sb9T]a),d$COba8fV<BN[IlZ=m6#eX.>PobHNj@I*7P7<C!d:Q"i:`(J/*)&+SQGJl]UD>uHTap*`O1iCUQ4gM<?G]c9*N))H\OX@72@Fu$UG"AYdh_P_Rbk(#]n>^$*n<@M+1/U6,P]uGpuA++jecW%U^]te,F)XBpE<=4r63gbJ`r,'3Q3Ou=4/=4m%'JnQ?b[@Eg4Zk_,?-Y6=-X9H].OgAGOT.W^Na'B*b[B4#1ON^Xr`]:;3:O\8[8IKkF+^^Oboe_md6F2!uci)-30l&NDAAAY`4h8__fr[\(Le)moRoiRqB.GW/4(Tiebf]1AYq4jt$=jQ;5jdEFQp+m5QL9W1<GJO<dcXaFT5^(sJ#KR('K6IOl-?O_t=>28+g@h12XR]00rLHGM+8hf-9[@/u<L4o+oPbR;US.\m_W2CD+\Q`oc/8/'\eDa!RU;RRoV;'9^R'Y-S+Y*a)%*l`@qYUE>ibR$^\'!sf^?0gc+Y87rA[Nl7V-&EsA<[Cne0g:FK]NoJPDRBgp^HElk?!X=EZsJXlV(2V?HF0f(VWl96sJsMYNn^87[N-I.QkGFCPZj&>fL\[GOrXn&(bt2$XElW#,SQK].e'(a"^Mpb/gBheYm8q?\82$EM?[RF4pB%?*OYAk<ZmUOT5\G<:PN.6$.7`NSh?GpP,(/]n)W[0DG1LMtDC+NMNsQ*''0RE<,B9jO$X9R=QO0XIc-@$$J4/DG.j[0JSl"HOEE9q>4PTR:8sBVm's#$!bLXqc5741Q@M:D)[&n7(@\BgQ:`*Kbi<Ij2QPTG<g+Qik(.La1kmIm>)h$a3"<jApa14="CW/X5ZUOA?H%?1TZ(%ZW0n+7k%!5F%Y+k"RZtkMS3PtAVsFE_<rA"$F-DoRJ/\1`s9=rHmj%SLI,fiiq6f6m;ugF?e3A81Jr5F@5IfR-\j[AgT-p0]k>n,4iS01FKbF*U'H;fMf<:*l/5^P5`^JQKX;f_fU.fgs/nT.=;ORg;>)mPH"3=3h-g%%rN;0Ul>k%=j*[TL_p^\Z5jLYV$TnO~>endstream
|
||||
endobj
|
||||
25 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1734
|
||||
>>
|
||||
stream
|
||||
Gb!;d8TW?O'Y`m7]ZLD5Yo@h$CG@[OB&Z(U49Vm>M_?+8fhirmNL#5_n_`N;,VN;ZP73^+i[np<gV1/*38!l_c$,BQr&oTILE*gSaUG]&>aUIX33g2"9_]fN4^a;WSPT:o*V0NTgrdJ)R3.<JK<t_-!uG4aR?XBJ6$,E.""4^mcRfVXnEiKP^a/Z%l//4ZQnJT!G+%OjiD'/D5AAUTRGV^KC:8%i7QYj-e;C<e17NWA#EoRBDi[+'_&GPX1-3rHKo]5bd:ib_+Tcn2":'1&WEru;&!Jf:4?!="R(C!W'E$cLdh.mWV.VBDGA<`1$N(>;mg6fV#@DRfq&X0l@#'EJ`OO/[TAWlN[P/YF/AdSWO4H\>/2mi<BNJuKj\"8=Y*W2aqoj6N?unahpI*SI/`b+hJ`etnQ>6s<*#\OUA0-'QVNh@d'k4Sb81i*g.5u/!CM*9D<b0m!AQ$*Al.XOgX]bZC=f5:68*8@5qo']bDrT;ZZAXMJLP78n>km64b]T`rNP?[.QPFn',ZAc;+7L)F99iI1`uGIeiK798p:fE)"&"qd^c^4gGf(.:dkR^QJRU!.#tnG;Ha-2l!=kX5l$iZqls,VI:*;W9MaD'7l6YdO`qFRP3X/n6QDA*_%>g2$_Yn5`G**/Q\Oj,fr(F0?Uq.`[VsuCfjfbBU1#;kNB?ZR>bEt4W"kr_D`3m_I`3?4/G$Bf^?[E$]7\dd2OqQcc/n-@S;lY?]4NEtp(jscC0YkYM<$_[`@9S/7%'cm5$8KD/P37R/g,m&+2Bo^0%u>=1:&!<ueaHPqp,83!D$@TJ]>YQ5=@'AP1"puVOVDQ$>j`Bpa\C0lq6pVe;B!J3OG2ON2&5Oj,@q=!&,(aF;q1(86-W.9dl>J4HhU@V$+DADLn36:bI?\5?r^m-Oh[%ePn"Sj(bGMKQY.aPW#PlNKL/2lPeReGeR4\L@8Z`L.etWuaIt%FHZqS5(k+FaN[Grc&Nk[k?^fJC6ka(++iT=@='#drK.^,PL-Y=)!`]Hf.FuIidMAlIR,(^R'']g'*HXah-Ib$eLa^9U:Q#EFbY*#N(McmS3MqV=(`$kK?u[8n"b1o?N#*<WZ\3@mTQ54-Pt?dOFd8,DA;me&:SF?lW!Sm@LJ(X`gS<^1.YLFWR,9+jgsGk.)=Xn!LfB5cUOV+8_dGj5h:u<PrtPrO26/:m-."'g@C^N,fqR^XZr8"K>Es</T5cLZL9(XUD+&A3Bh(@]:3;AI*]0Et4":k:o6`$gf!6>4NB0\1k%5GX$;;M-T^tHlMC)na@[\O6cEt!\#FY;N6<1$&FJAof:7;ok0!>_C2pE!/e![V0ocUTt[;BuH;0f8[579^GKXO"cP[UGP'Tt;TbK@>NL:pfchJXoaNZ\8+&iZtlGKb&N?$4rlnWgj,<_N4RSE2FX['"9U6G"a!I3)HuItNE&h$s&(%3<_'fu!?!N$I.!W#)F60m,u'f*c^fbmHLu!Zh!ScL7=o@mr2u`t'C5O<CEhB'fDce,D4r'QnF+ruA\*$^1R4*(qog\D;)3-GPY:II9Akn)!"!Wt"gD_I$a!4Ll$*^-713Ni5U27fSeAUP%S`<LMQH0*IW2CAb7ZopOr-3`=d81mdVf"Lbgrb<(,/0ooR]ef9hXV65^^>OtdAXp>BWd\>%30FG^sj71o`X;R!g9p]]lfF0rREF'4b3rVRgj$&Eb]`,K'W:iD&H)r[BH]5;do7%X:A$"t7%?Y&s#>>k^3W~>endstream
|
||||
endobj
|
||||
26 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1741
|
||||
>>
|
||||
stream
|
||||
Gb!;d=``%_&:W67kR+^t$&ch[RZU)1ma`.4.09f`i5I@%4Ea,7+iuVn`IHdr/LN^pW!X(tOk!Lih-]o0!Q>j*s*>j(K/!e,0OQ5dB>=W^0Kt'.A)ib=9\YfK!l>u#>n`%;M]YLQ7Kf#OCtEbH3)gM\$4m[lNoN0.,+k)n6E4I;f3gk>9r0(b36\ZKq[,P8[V;IN5qLc60D!fh3JD`2Z"r[Pbj(2)n-N,WeOnqT:hE9,`ZZ>94FMD^cf2L\]^n)mi,,'#mlZA^BhGmb%$1$Y#B?Ke,8bo`n_HMt:T1K<FMX:/6;M]hjmfDbEi.uJUd4VV]YXq4&o=m4$Nj!p$\RMo#%<b,2MS-C<adVt@phFh6);+()FDRrZn3j`KL6-eNmu)+-<*gpV`;pWT$bt'ZO#`]NM'(2`"Icq=u^#0oh]Ei90lG29jfY!*N/Whm=`k^QY4[jQiM&.>AO5`S*m%aS/Z#['sB+C_^>N@Z<eu"lAFdObU'F69H.5C#$[>f\c]uMQE).\SE,D0A&0aJ<F50B8G*>fM@JPf:n[r@3tNn1oZ_86[S)9m*4+4UKsL=c9]K+e`+fWP("EAB(PfUk=[aGnB8*;O:C2s3>WT:,ZNXO6+H34EO2IJ$a\B*NXF3bLmdd+i3?NG9RohdA_d;=%[*fO.0sQMK\R&kYr@C`E0ZZQhrlA=XZa$tjf55jB_2D<$FnrV/(DP$O(d9D<V_"dPS.8mZU,@(_'af\$@Z$f8b^pLp=r-E_Z`jaG[Ua52$X#^D=jU!&Ao;P@Ao9')'1P&h\(o2sl7?4/f.GI#R2&P[lVr/?O2qjg\]V2#!D+H/GYg[eU\#'&iX;T7]p6W_>6mGsH1):jE$W,BoR),h$JQnf7=TjijCZ1!E))i1(Q([3mgTh7N=Oea)S?n'%1b%$h=dB&eOC/t+fOY47d#?n#>#gerTW$ZYV@/g<LEgXe%rOeQuLZ44/*J!BlCLk-^P?d_nDb._nEVFL3l:]SM8d^]&f_&qZW87/[OSp8Y"r4'tdMH>b>'dn-ruD*5]PB<$(tF)_Do7#dZ+fHfV?s(LE&I6F.s8ZY%;>nEUOL%Y,'>dr/TcN8WVVc]caq(rW!QcJpGt0hd09Wl.-3GD#kSgZ3%/_`-I-.XtBf/V4u@<@d1o0\6orC9GVRF2$8l[ESfR?"Hu*E,p3M!rKgpBTKK8ZN1'4*%!\#ml^aLJ,[IoVAaFFT1rsVVuZdtgqU4Vf!bU.pVjM#':2%s&J4H@"b[tg$h%(0Bq9.18=ObF2;NM'/)T*HdH^X2%A>aV0c<"jD,o)W[$YY%'[cL;VNG"+enbk^%DRN.)V_\A1Tt6PKLr`)8C!%1R)=6]G/o09$U7;_V=M?"$c,g($C3^^'NWaS%=q.B3.]0&q,RT:\2h%]-,4'#07!@)JYdC,?FIf*n\@N?%]<!HHVS^pDWK=3C_lf.Y5DJfoE(-tNY)&,e&+U-g6jeh(>\j?mnOF(US]`38mO[tBfr+:n7%LDZp;,;b.FDHeMad";njD+?E.dN7;kQ)&Q\gg0"NO:'%<9&M\@'o?`Cie2%II;iT]$?@)3Bq#&8^aB8LR7Gg&qbrV?3UWb3fPY#MD/*7TE<)i)_f#CjVVq_'EP0*:N2pMbm@W$Q#H`c41&qOP7cYthW1_aQ;0S,_Ch:ehf7gc5HObqTXX^nOUH!3Qpa,.#,GmG19^?rk%en-"XW@s3k2PKd!Me,K7+;fm3ZYeg'nZ`AsH)#j\ta<QB~>endstream
|
||||
endobj
|
||||
27 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1901
|
||||
>>
|
||||
stream
|
||||
Gb!#\gN)%,&:N/3m.a.I/VjBm!-G+pFj_O0Rl!^3U^pHI?j`&.o:h>R>pkhcn+%Zcer=[<EGN[n"YL;1/f)'SU>XsfQ@FMmi8FgY:FK$DP;uH73)#p]j2p5sJ2"ebpOKcrEIA&0GDdP6(P<Pe6%mR3$HeK!8If!&U6Mj3iB/QgK[dg8_12TL_NB]X;:H7OCs@0\?jrCa`"U#FS6tkd"[/K6RN9hXh?\iO[!&H8FZFH?-U!hb0`:>"]4^VSZ7oFc9TftDk,AZQ3D:<SE:s]h105er<[Ktaaa9C;-l2#sEhUh`+`Dus2d)Foo*XQD?J&A4l2\K:#]A$&^*(R>3(=s-46>kPK5qKmEXu9Y"7,ai>ZFKYYU:I2%e,)1p^(/7QFf2J;CQN]m#lH>nL.DEZPHO/4lGrjpoDnNl/6.fUc,]5%RI:!),,fYUVhHskgZ+fBGNY!*q/3@g#Lk[U[;6/EqJI@*no73Nk&+K3*W:V3F_$f@0c8K^TV\H;3L%9betB:j->0dB:0eUHb$QBl]$T%>GjKQQo<1qX^'VnmWXq_FAtip9ZO-(@;quPB#;p5\8=q+FhTkN*bSagLM@^P_c1:VfSK'pFqq47`YZ6\LgSXgFDBi>:QhdqQ`I=*Ac*Zg=]!a_60UdAi4Uo&_\YaDG8EFm0UU)Y)r!=FUY0ML1.djgACdUg9pW[sP&tL)B"dg1Zbu,]:r6%!R\-VO*eLf1p[hl)^"Vs,>aWU"p]N39A)lC/"F.5Zrbu^`pQY54(:C^1bG$nBKV:WHXj^DcA(fMT!n4N\Nbk#Z3ZM^n%`;5rbGLk#qh%dNQ<SNPX[AQsS&6)K^"Y,r]kd@43dkNgF7/[@W=1/rWb'VH;4R5bnFo']'r@:U#F_?nE(c=en;,!N:C"gjlh-*og1,`,6?oiOBR-aK:eHXtZ.jdXK$&c62(4-pg>L.)]^%CsY7s!u.`7Fbj4V9`qP9>mmn=XeYk[umkN5t*^j#8r9J0uL&6g[_Oe`d?D//_4m+L5.g%+6"Qg_[=dp)IY@!Qp2q7CdKa&CTb0pm3o8o.at)Sgu6@$N'?()o_4i#N;:FYiQ%J%orjkchUM1m@kik*pMcoig+#'hf"i#q$/=`cc7E%*i0Z=j_OPXHG*G[X#)n6O/aq&\F8f_,A;]F$S,tir0"`?L*UPG_2?'Y(MYL)&m5#K:l)d]j-sBF*O!U@rK_\GnTAsiaW'3217JH'SZQRU#.R3KsH>AQ.sB/7(8>(G8pZ`m&QiskUUL;I?%qig(4Sj#M"8nkC5?JW+BIE2#]Jlm<N!UcHXe)'RQOaa\Ld-I1NS?q'#M$?.7\RkB4"6.uZ'`cS'.&O)0bI,[2R7L.Asfr^DFrpX!"+PeE8WL\_'6Ec\@W;(1#sb#[m#3:9-ji)3UX\JYb[>WKdAG,XZ_JiMPJh%@''#mTe+%u_*\d\)8.`]3P]$cuY)1T^8G;8]%E6)aKE31rYhe[b(S?r"=7JGhgB4ub.GH@G0Sqen/j%^n2UY=5]`e@$q%M9dR`GQJl%*PW6@2HhDoX.S=M9&@lJ:Ql'EIaiP*bq@#dnBq!BFk7NEeJ.OmRgR4=<`0JCC":)\1&PQ\'BHAOkNShVkZL4@10Mc1!N'"+jP+75_[iED[4PcqPG3;hR(r7Wn5Bjfa"Xm+U&n>G3iumG*?O2"Gc^:WZ-#R!3LV"]oUqlj;Mt<.)YV!\Q(Po*+loS?.]PgBMMfL<l#C('W?dLGq?$&/KF4mhoF#KUo=B\t`qS:e8+UX5AirD_a6Nt`NA-PRUZq9o_^NAL]K@SW$Ga[\oRtk\Uu4MmkrR+VBsP%\3%4[p#bRc!K36(X"61F7Y#I"(,"WQD).R$XYoPRYNDNJbb<?ot-.6@@%J3_?N\RV)`Aa8nO^m_CNYHh'JAFHXlMW"~>endstream
|
||||
endobj
|
||||
28 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1887
|
||||
>>
|
||||
stream
|
||||
Gb!Sl?ZV]+&:`<0f^VVr,W`h_^l_<'i\\('NnhX2lFc?B"=G)Q":CZp\s[s?mK!C2ObDQ9\4nR0Lu\4/mdG>(_8;7=r"!E?D[(0$AqNfd0F"!Y#(o,;4Qq1\&F*,b\Nh-P3<99r39CIO8LFPj,@3V;)n=uCmPA8+-Cb;\.+7q*m6`4/r2aB1nNG(Y$ja=JO*fd242dm.75NqL?>uONdZ5@?!od56Tpk'r1;b,UAQ6q)@DoHWhhAlT]"e5fI0&fbM9Nl,1fa%Wc=D0p@7[@.V\ei'/u;2'1-:6,/I\3g!?4_#a3b%9he(T/H*5V9alL.&`/0"PK>A:KE6Z4oQ!1mh$$RtUSi7.f98DB=DVJ\&1BL@tN/ri=ET;`?:F]X<@jTJrT@.O*ZQ*i8;IHs@p6H%&f&Cn79M>kq9T2;M^OMY=3ep2u%lq^E,%9-#Y4WbYTg^@CD7!Hf9WDb@haYLn!e#X3PgD/lmiYoY9IS>lXbXW7"(#Y6Cs*;Nbbt;@k,$1t%ON<l0!5F5lS.3LF0T%M*QBZufIYPZlOf%XroOPpmg2)KRR7H0lT8WeA'M*c3Zcd;nN50eMsAs5kIap&C)Y:b$9M957c@(D77GYgfmF5j2k?\=bbpEPaVf`(Llb&M<?)s/$qNX#lIAt"\as>q!tduk>/\*:R\#1T1u%R;lPHUh#QK64!h6^LGJ27o":jrBmX'(U!k6l_CJ_4%#h:kVSE^ii@:hC&SiCCi5T&OO(/^!&o/+qc"]f3>M\s1F3(mn'oPGS/?L<KQ2.tMg/or#eE8J?f\\rQ:?AK-@,hE=Dq*Jfj&]@;[)C@5U3nA<os3S[OQbtR!j%r?@Fo\j*P3QUgc*2Qe3ZOd9U_Y=MM4*Qf`:!.m01Ne2,1K-#itmIs:s9#_G#T+:ka]24#tKZ1UDD;&qY3*6IaqU-Y#Q9)4,VI''YQ?#k:e[S;*5j*OhKP.K_:2AI't3G.NYe"WCCT*+5UdZ%OQ+,LQD$3kWH5#J$5"F(5QgKHUHBENYN4GHoC=dQ&HB$%[/G<p$d407"eP=FCmD9*bEo6N0u3G$b0B^jFA]/H9+tC=cY?"dnQ?BK7jh?VK"!p7YX+#21Nf:O'7L,KX^Jr]ZB+i6*'"5Bho;dG$&pqY;p#nS4uS(/%?;FR'r\8[Vol_bHc'YlXJ]Y*Ts)*oX/O1&TBrfA?PNf85'<%7B"![F+bAZ'UX,=j="6Ndg'tmN:K]]qF@[N-]oYeV45c6*P%[lXSdPkf==LD!cprWk:c,gFsN>D-<Y^XrP%gFUhDEJ8KR2BBj1FS-=r=/3FLF_%\pgh+4ST49OK<5.*Y#Ri=oLUmhs]ZAJRlAOdrKE%WWQ-VAM+S:>ui4!a@Jpan/F9k:fLJgGS9_IVsGsk7@<G=*pe]l=m4\-a8>jPuL[r)FU9./S!THDNqJ%4W`dpKfQ$l"C5*QnrZVC"h'Gfd#1R]TJtmNV6cg8XqF)<ct9ZLU%RaG,h79=m.'kR4X;^7:_9bt?.W&7[<'>kGs(9*CLul$[&Sg5gM,dc?[CA%iY8*\:Q^X@HXQ_^?[l+rF8$eBR7@=uJpR/14EgHEiVauP3$?su9%g+D]g#FUh<G)dMQ[<08-L)1cZa:t`\](]V`O2sYi8(S3'2[^KY#?2NNB(^@tP&6AQ\&pY'2(HncJ^KAA6E-]IU!tdjXWoc&9uUHRWq1dr@/-M*.-T5hYFtMYLZ:ZgAFcQBU53.9'*`1C6%Z0$UW"pDR>\W+ZP`&4I%hK#R!OM_+qb''PRbH_88M&`32t$kH*c^#lG!MnFqST:5`WroH<UA_bjR8"N8*(ECW]31mZK]qkV[]WU"8;eQa0(]:na[ZGRq+EUJQ1T,J?b7VtV_g.$IYc=sBf$pM+<Ud7S6_O#eW"g.M~>endstream
|
||||
endobj
|
||||
29 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1685
|
||||
>>
|
||||
stream
|
||||
Gb!Sl>Bed\&:WeDbW5R)Ba_qdNA#]0Bp4i7V/9VPQdZbi(.O.C=NM&BJ%t"O"G.eYc,hCD&0DCFB'/u&5&!F#`"sm%LJr`P&[]jj&.:s;+HGErW"3O9`]jpME\5W%J78>P*EZ\PG5_^rD@#I9L)X4q!T3MXhfHU'M;e>_%i3I^4Q:p$0Rh[t@!Jj=q$n6*l+"I>1#Flob<j[<d;e"#rqso'5Beb7gr_^#Z[CeB3.b*q/Q]>#_^$8+"/@<8$pK1,_$:i6*DWD(i:g3UE0A(^bOV=\K6Q[:-$%#T$Q*0ck[eX>APpKj%%I%KqP&D8FXkGn,%#$-"U/A<XRHrJh!iKC/]7%E%RU1,_BqTqLMG"QQ@S,$C5D!<*)_<BfU;uS<X%>PCbF@@&^ED3Br4uq!g_jbJ`?lk_5Bu)%&PeS#u;F7=([l>P_EfQ_04!fZ.:;&22,/<kSbn#O=#g5^l*6m=VS344li7hESAR2*;JF\F4Dt#moq[oCgdP%75"Fm3F'48(`ets0V#;AY6,(>OhIr6%(]KYTGr-c-m:U'o`Mj73?Y4:b4g4V,.Vt17HKfq'QnUTi!f5*mZ@>k+O/C.7S3gi$e&[mKlVL]"_5\WbI2_0>g,=VZaP3rS'(go'6;?C[r`ZIX/J[lF?VD:Jn^XP&7'^Lq`2n(:N,uH'?ak($W:0As4d[L<Id"\HpKFB<b=A@>7E7OZ"(?qL@6MY]t1bDmt:@R$#f?VQ1"+Zo<p\o';IoKPErX8(G(o`>BV=Ii'au2]'/nQVf#r(/u4[dP:frOn[&T7NEO-%Y'!Uk/88\%Lo*9'o+Ah%Mgo1$_"^bGc9to:$Co:5?q=O[H6h?e*D.&(@A[S"KpY!)YmdsE#h].J+gA1n+9Hs:;5>n9d?)o!4d/`6Fc+_\7,Urt(@?q417p5fKrkI;rfG+?HOT'SpEHj<pks5iQp:X`'Me_@#X;-1s&\!::&*\ZO1PMn`_`4i?SsMY1U5o\enrb'r$PG,dmV4O"sGtLk'MokA"&Glkp$b=+eM@-J++`BHCHlgdWD?n\(`qc40OAW,!RNHr'Ks1cm9n4rPd)8<c`FiDGpqr3c:3$9c.-n[Nt#;3NN`OU-,si_<*deBtDlh*1]2$;hYp@';f[5K@Rqk)!,N7\JELn^(Fk5FY]^SWla_3C1V`fGFff!H&d:LcP?sW4@Z,n.$j8qO&N.C-h4tVjioY_1R_'VS+&nnDu\'(F@u)N($S-.)%X>Br:YEU7(7rB[E_8V_K>j,QMG(`IET7#Lbh^Q#1lNS^'B.RqoBf@#^#cM73MNQPf+%F52`c]+9fq&:%4:jV*`kKTn8:jA-nR_?SWR3Q`LKJ(+n-"GFp)kj0"1PS&6A'\(JL]WqY13V#4(u^8"e=T9/#?3B:\K?99VIqHpIBcQfNP^8/=H'.P3^Op;sK/c-t9HniWM(Ai7LA8Njl\Oq.T_]<@<Blt)u_;"Il$!3@kip_'FFZMcZl?sO.U%c!F;'2oLRSaep*phg7pu96Zo9*k<fMC>[?o[Gc5HBii^`oY=]I<NX8E)Z7na,X%K>d>I"9.c6i2Ml+@$b/DRpT_n,f;d&f.VQZ%mNS_pmGB0lSk!%o"K\pY.57M2[E_HJ!@EaFDXG4VO_3uI;`Plce<V](-5EB[_1NZdY+eXiDUXNLtO$3.&OIm3`EC$Og6C.nK3h6-1V~>endstream
|
||||
endobj
|
||||
30 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 705
|
||||
>>
|
||||
stream
|
||||
GauHH9lldX&A@sBm*X'O";4$6\b.1b1QuOA$r&Cc-s0k\@C^t8dsk^J^inut*TmFNE7++.pYKY=+`n+hIoZSt80M)C^]`(*0LZ](CUd&N^Lr?V_J'E,&n."95Y9IS@#N\V@YRuO&e#uF88no8?mJ,aJ@I_e0aFa%5FZ(HS:t3E5Q\u"Y_2iZ0g],ZMIOSgJ+J#9U8=2!f!BES]C!C="R\]q;'Urb*:k#q$Kb]6m]YQ,.9)k?N7%..Yprs8n3@87pK-iU4Y(A-b.`N#-_tBlJNZiP.#P7eY<f?l>rO,!5eb@7>YDkW&)l)BGef4LMF8F^B>$A:rGa4$2^.ff+PRY?q8,FQ?-YuBp,Igm>F**W%%t><o*<M8.usKX,E-)j"l9tU7-nl9\;9e3(,3MN>#l7cZW+L?>s;G+s'5>F4*bmL29i#4#Qj&(;.ci$O$-*0J<N$^rh7o"o'_jgP\tEhBA'4"3?nFTLO/2XPLY48h**L'Zk4*6S^)q_eql#,eE1J5C[&k5LU"UYXdp]WSQHB>=/0T$l&BuQZHm)B@S"_?1M!G,U*0oDqiNl+67t-9GG#<_OW0/Aj:8RmP^B;d]$/r(ri]us7(2J(&PXU"qT'U_^5Z=.\\D'@2eAhGCYiaXjMk6A?2:lZG:u5O<%_2<4R!Esm$Q.Z2jnZbh+Y#Ujl8o#Q&j<F#*n>$aK8f'q[5&\"I/~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 31
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000122 00000 n
|
||||
0000000229 00000 n
|
||||
0000000341 00000 n
|
||||
0000000546 00000 n
|
||||
0000000623 00000 n
|
||||
0000000728 00000 n
|
||||
0000000933 00000 n
|
||||
0000001138 00000 n
|
||||
0000001343 00000 n
|
||||
0000001549 00000 n
|
||||
0000001755 00000 n
|
||||
0000001961 00000 n
|
||||
0000002167 00000 n
|
||||
0000002373 00000 n
|
||||
0000002579 00000 n
|
||||
0000002785 00000 n
|
||||
0000002855 00000 n
|
||||
0000003140 00000 n
|
||||
0000003271 00000 n
|
||||
0000005333 00000 n
|
||||
0000007375 00000 n
|
||||
0000009477 00000 n
|
||||
0000011349 00000 n
|
||||
0000013297 00000 n
|
||||
0000015123 00000 n
|
||||
0000016956 00000 n
|
||||
0000018949 00000 n
|
||||
0000020928 00000 n
|
||||
0000022705 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<18c18010543f3b7d15dd1d9c569e1c22><18c18010543f3b7d15dd1d9c569e1c22>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 18 0 R
|
||||
/Root 17 0 R
|
||||
/Size 31
|
||||
>>
|
||||
startxref
|
||||
23501
|
||||
%%EOF
|
||||
430
Les18-AI-Toolbox-Next/Les18-Slide-Overzicht.md
Normal file
430
Les18-AI-Toolbox-Next/Les18-Slide-Overzicht.md
Normal file
@@ -0,0 +1,430 @@
|
||||
# Les 18 — Advanced AI Toolbox
|
||||
## Slide Overzicht (Klas A — 3 uur fysiek, demo-driven, **laatste les!**)
|
||||
|
||||
**Lesvorm:** Tim demonstreert klassikaal. Studenten kijken. Korte demo's, geen lange theorie.
|
||||
**Demo-app:** Vijf kleine demo-apps — voice, vision, image gen, local LLMs, edge AI
|
||||
**Vervolg op:** Les 17 — AI Production Polish
|
||||
**Aansluit op:** Eindopdracht (thuis)
|
||||
|
||||
---
|
||||
|
||||
## Slide 1: Title
|
||||
### Les 18 — Advanced AI Toolbox
|
||||
|
||||
**Visual:** "Les 18" BLUE, "Advanced AI Toolbox" BLACK, subtitle "Wat er nog meer mogelijk is — voice, vision, image, local, edge"
|
||||
|
||||
---
|
||||
|
||||
## Slide 2: Terugblik 18 lessen
|
||||
### Wat we samen hebben gedaan
|
||||
|
||||
| Lessen | Topic |
|
||||
|--------|-------|
|
||||
| 1-10 | Foundations (Next.js, TS, Supabase basics) |
|
||||
| 11 | AI SDK basics |
|
||||
| 12 | Tool Calling |
|
||||
| 13 | Cursor + Vercel deploy |
|
||||
| 14 | Agents |
|
||||
| 15 | RAG + Embeddings |
|
||||
| 16 | MCP servers |
|
||||
| 17 | Production Polish |
|
||||
| **18** | **Vandaag: Advanced AI Toolbox** |
|
||||
|
||||
**Vandaag:** alles wat we nog NIET hebben gezien. Demo-driven, korte introducties, je weet wat mogelijk is.
|
||||
|
||||
---
|
||||
|
||||
## Slide 3: Planning
|
||||
### Vandaag — 180 minuten
|
||||
|
||||
| Onderwerp | Duur |
|
||||
|-----------|------|
|
||||
| Terugblik 18 lessen | 10 min |
|
||||
| Theorie: het AI-landschap 2026 | 15 min |
|
||||
| **Live Demo 1** — Voice (Whisper + TTS) | 25 min |
|
||||
| **Live Demo 2** — Vision (GPT-4o foto-analyse) | 20 min |
|
||||
| **Pauze** | 15 min |
|
||||
| **Live Demo 3** — Image generation (Flux) | 25 min |
|
||||
| **Live Demo 4** — Local LLMs (Ollama) | 25 min |
|
||||
| **Live Demo 5** — Edge AI (Vercel AI Gateway) | 20 min |
|
||||
| Wat nu? Resources + community | 10 min |
|
||||
| Vragen + afsluiting cyclus | 15 min |
|
||||
|
||||
---
|
||||
|
||||
## Slide 4: Het AI-landschap 2026
|
||||
### Waar staan we nu?
|
||||
|
||||
**Modellen (eind 2026):**
|
||||
- **OpenAI:** GPT-5, o3 reasoning, GPT-5-mini, GPT-realtime (voice)
|
||||
- **Anthropic:** Claude Opus 4.6, Sonnet 4.6, Haiku 4.5
|
||||
- **Google:** Gemini 2.5 Pro (2M context), Gemini Flash
|
||||
- **Meta:** Llama 4 (open-source)
|
||||
- **xAI:** Grok 4, Grok 4 Vision
|
||||
|
||||
**Modaliteiten:**
|
||||
- Text (alle modellen)
|
||||
- Vision (GPT-4o, Claude, Gemini)
|
||||
- Voice (GPT-realtime, ElevenLabs)
|
||||
- Image generation (DALL-E 4, Flux, Midjourney)
|
||||
- Video (Sora, Veo, Runway Gen-4)
|
||||
|
||||
**Modi:**
|
||||
- API direct
|
||||
- Edge (Vercel AI Gateway, Cloudflare AI)
|
||||
- Lokaal (Ollama, llama.cpp)
|
||||
|
||||
---
|
||||
|
||||
## Slide 5: Waarom multimodal?
|
||||
### Tekst is niet genoeg
|
||||
|
||||
**Wat krijg je met multimodal:**
|
||||
- **Voice input** — handsfree, sneller dan typen, voor mobile dominant
|
||||
- **Vision** — user upload foto, AI analyseert (defect-detectie, OCR, beschrijving)
|
||||
- **Image gen** — assets ter plaatse genereren (landing pages, social media, avatars)
|
||||
- **Voice output** — voor accessibility en cars/IoT
|
||||
- **Real-time** — conversational, geen wachten op response
|
||||
|
||||
**In je apps:** denk niet "chat only" — vraag je af welke modaliteit het best past per feature.
|
||||
|
||||
---
|
||||
|
||||
## Slide 6: LIVE DEMO 1 — Voice (Whisper + TTS)
|
||||
### ~25 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
|
||||
**Whisper voor transcriptie:**
|
||||
```typescript
|
||||
import { experimental_transcribe as transcribe } from "ai";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
|
||||
const result = await transcribe({
|
||||
model: openai.transcription("whisper-1"),
|
||||
audio: audioBlob,
|
||||
});
|
||||
console.log(result.text);
|
||||
```
|
||||
|
||||
**TTS voor uitspraak:**
|
||||
```typescript
|
||||
import { experimental_generateSpeech as speak } from "ai";
|
||||
|
||||
const audio = await speak({
|
||||
model: openai.speech("tts-1"),
|
||||
text: "Welkom bij Polderfest!",
|
||||
voice: "alloy",
|
||||
});
|
||||
```
|
||||
|
||||
**Demo-app:** voice-chat met Polderfest. Mic-button → spreek vraag → Whisper → LLM → TTS → spreekt antwoord. Volledige loop in 2 seconden.
|
||||
|
||||
**Realtime API (kort):** voor lagere latency en interruptions. Vereist WebRTC, complexer maar voelt magisch.
|
||||
|
||||
---
|
||||
|
||||
## Slide 7: LIVE DEMO 2 — Vision (GPT-4o foto-analyse)
|
||||
### ~20 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
|
||||
```typescript
|
||||
import { generateText } from "ai";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
|
||||
const result = await generateText({
|
||||
model: openai("gpt-4o"),
|
||||
messages: [{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "Beschrijf wat er op deze foto staat." },
|
||||
{ type: "image", image: imageUrl }, // of base64 buffer
|
||||
],
|
||||
}],
|
||||
});
|
||||
```
|
||||
|
||||
**Demo-cases:**
|
||||
- Upload foto van eten → AI noemt ingrediënten
|
||||
- Upload screenshot van error → AI legt fout uit
|
||||
- Upload handtekening → AI beschrijft stijl
|
||||
|
||||
**Use cases in productie:**
|
||||
- Defect-detectie in fabrieken
|
||||
- OCR voor formulieren
|
||||
- Visual search ("toon me schoenen zoals deze")
|
||||
- Accessibility — alt-tekst automatisch genereren
|
||||
|
||||
**Cost:** vision is duurder dan text — check pricing per provider.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8: Pauze
|
||||
### 15 min
|
||||
|
||||
---
|
||||
|
||||
## Slide 9: LIVE DEMO 3 — Image generation
|
||||
### ~25 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
|
||||
**Flux via Replicate of Fal:**
|
||||
```typescript
|
||||
import { experimental_generateImage as generateImage } from "ai";
|
||||
import { fal } from "@ai-sdk/fal";
|
||||
|
||||
const { image } = await generateImage({
|
||||
model: fal.image("fal-ai/flux/dev"),
|
||||
prompt: "Een poster voor Polderfest 2027, retro stijl, oranje + cream kleuren",
|
||||
size: "1024x1024",
|
||||
});
|
||||
|
||||
// image.base64 of image.url
|
||||
```
|
||||
|
||||
**DALL-E 4 via OpenAI:**
|
||||
```typescript
|
||||
const { image } = await generateImage({
|
||||
model: openai.image("dall-e-3"),
|
||||
prompt: "...",
|
||||
size: "1024x1024",
|
||||
});
|
||||
```
|
||||
|
||||
**Demo-app:** form met prompt-input → generate button → image preview + download.
|
||||
|
||||
**Use cases:**
|
||||
- Landing page hero-images
|
||||
- Social media posts on-the-fly
|
||||
- Avatar generation per user
|
||||
- Product mockups
|
||||
- Marketing visuals
|
||||
|
||||
**Tips:**
|
||||
- Specifieke prompts werken beter (stijl, kleur, compositie)
|
||||
- Flux Pro voor hoogste kwaliteit, Flux Schnell voor speed
|
||||
- Cost: $0.02-0.10 per image, schaal-bewust
|
||||
|
||||
---
|
||||
|
||||
## Slide 10: LIVE DEMO 4 — Local LLMs (Ollama)
|
||||
### ~25 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
|
||||
**Ollama installeren:**
|
||||
```bash
|
||||
# macOS
|
||||
brew install ollama
|
||||
|
||||
# Download een model
|
||||
ollama pull llama4:8b
|
||||
ollama pull qwen3:14b
|
||||
```
|
||||
|
||||
**Run lokaal:**
|
||||
```bash
|
||||
ollama run llama4:8b
|
||||
# Interactieve chat — runt op je laptop, geen internet
|
||||
```
|
||||
|
||||
**Via AI SDK:**
|
||||
```typescript
|
||||
import { createOllama } from "ollama-ai-provider";
|
||||
|
||||
const ollama = createOllama();
|
||||
|
||||
const result = await generateText({
|
||||
model: ollama("llama4:8b"),
|
||||
prompt: "Wat zijn de hoofdfuncties van een AI Developer?",
|
||||
});
|
||||
```
|
||||
|
||||
**Wanneer lokaal:**
|
||||
- **Privacy** — geen data naar third party
|
||||
- **Cost** — geen API-cost (alleen elektriciteit)
|
||||
- **Offline** — werkt zonder internet
|
||||
- **Latency** — afhankelijk van hardware, op M-series Mac vaak snel
|
||||
|
||||
**Nadelen:**
|
||||
- Kwaliteit < GPT-5 / Claude voor complex
|
||||
- Hardware vereist (8GB+ RAM voor klein model, 32GB+ voor groot)
|
||||
- Trager dan API voor grote modellen
|
||||
|
||||
**Demo-app:** chat-form met dropdown "Cloud (gpt-4o-mini)" of "Local (llama4)". Vergelijk antwoorden side-by-side.
|
||||
|
||||
---
|
||||
|
||||
## Slide 11: LIVE DEMO 5 — Edge AI + AI Gateway
|
||||
### ~20 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
|
||||
**Vercel AI Gateway:**
|
||||
- Eén endpoint, alle providers
|
||||
- Automatic fallback bij outages
|
||||
- Cost optimization
|
||||
- Provider-agnostic key management
|
||||
|
||||
```typescript
|
||||
import { vercel } from "@ai-sdk/vercel";
|
||||
|
||||
const result = await generateText({
|
||||
model: vercel("openai/gpt-4o"), // routed via Vercel
|
||||
prompt: "...",
|
||||
});
|
||||
|
||||
// Of fallback chain:
|
||||
const result = await generateText({
|
||||
model: vercel.fallback([
|
||||
"openai/gpt-4o",
|
||||
"anthropic/claude-sonnet-4.5", // fallback if OpenAI down
|
||||
]),
|
||||
prompt: "...",
|
||||
});
|
||||
```
|
||||
|
||||
**Cloudflare Workers AI:**
|
||||
- Lokale modellen op Cloudflare edge — ms latency wereldwijd
|
||||
- Veel modellen gratis tier
|
||||
- Voor: globale apps die snel willen zijn
|
||||
|
||||
```typescript
|
||||
import { workersai } from "@ai-sdk/cloudflare";
|
||||
|
||||
const result = await generateText({
|
||||
model: workersai("@cf/meta/llama-3.1-8b-instruct"),
|
||||
prompt: "...",
|
||||
});
|
||||
```
|
||||
|
||||
**Wanneer edge:**
|
||||
- Globale app, latency belangrijk
|
||||
- Cost-sensitive (free tiers ruimer)
|
||||
- Geen vendor lock-in
|
||||
|
||||
---
|
||||
|
||||
## Slide 12: Wat nu? Resources + community
|
||||
### Hoe blijf je leren?
|
||||
|
||||
**Communities (2026):**
|
||||
- **r/LocalLLaMA** — Reddit, dagelijkse update over open-source modellen
|
||||
- **AI Engineer Foundation** — Discord, productie-focus
|
||||
- **Latent Space** — podcast + Discord, breed
|
||||
- **Hugging Face Discord** — modellen + papers
|
||||
- **AI SDK Discord** — Vercel's eigen, direct contact
|
||||
|
||||
**Nieuwsbronnen:**
|
||||
- **Simon Willison's blog** — beste AI-blog 2024-2026
|
||||
- **Latent Space** — wekelijkse podcast
|
||||
- **The Rundown AI** — daily newsletter
|
||||
- **Twitter/X:** @karpathy, @swyx, @sama, @AnthropicAI
|
||||
|
||||
**Voor diepere kennis:**
|
||||
- **Karpathy's Zero to Hero** — neural networks vanaf nul (YouTube, gratis)
|
||||
- **Andrew Ng's courses** — Coursera, structureel
|
||||
- **Hugging Face NLP course** — gratis, hands-on
|
||||
|
||||
**Conferenties:**
|
||||
- AI Engineer Summit (jaarlijks, SF)
|
||||
- NeurIPS, ICLR (research-focus)
|
||||
|
||||
---
|
||||
|
||||
## Slide 13: Eindopdracht reminder
|
||||
### Volgende stap
|
||||
|
||||
**Wat je nu hebt:**
|
||||
- Volledige toolkit voor moderne AI-apps
|
||||
- 17 lesopdrachten + huiswerkopdrachten aan deelgenomen
|
||||
- Eigen mini-projecten gebouwd
|
||||
|
||||
**Wat nog komt:**
|
||||
- **Eindopdracht** — thuis bouwen (geen klassikale werkdagen)
|
||||
- Eindopdracht moet bevatten:
|
||||
- Next.js + TypeScript + Tailwind
|
||||
- Supabase (DB + Auth + RLS)
|
||||
- Vercel AI SDK met Tool Calling
|
||||
- Externe API
|
||||
- Deployed naar Vercel
|
||||
|
||||
**Praktische tips:**
|
||||
- Werk er gestaag aan — 8-10 uur/week voor 4-6 weken
|
||||
- Push klein en vaak
|
||||
- Vraag hulp tijdig (Slack, mail, office hours)
|
||||
- Begin met je voorstel (in te leveren via Teams)
|
||||
|
||||
---
|
||||
|
||||
## Slide 14: De afsluiting
|
||||
### Bedankt en succes!
|
||||
|
||||
**Wat we samen hebben gedaan:**
|
||||
- 18 lessen, ~54 uur klassikaal
|
||||
- Van localhost naar productie
|
||||
- Van simple fetch naar agents + RAG + MCP
|
||||
- Van mock-data naar productie-app met observability
|
||||
|
||||
**Wat je nu zelfstandig kunt:**
|
||||
- Volledige AI-app van scratch naar productie
|
||||
- Multi-modal features (voice, vision, image gen)
|
||||
- Observability + evals + security in productie
|
||||
- Lokale LLMs draaien
|
||||
- Open-source AI ecosysteem navigeren
|
||||
|
||||
**Voor je eindopdracht en daarna:**
|
||||
- Doe het ding waarvan je dacht: dat kan ik niet
|
||||
- Vraag hulp + deel je werk
|
||||
- Blijf bouwen
|
||||
|
||||
**Bedankt voor jullie inzet de afgelopen 18 lessen. Succes!**
|
||||
|
||||
---
|
||||
|
||||
## Slide 15: Vragen?
|
||||
### Open ruimte
|
||||
|
||||
**~15 min voor:**
|
||||
- Vragen over leerstof
|
||||
- Vragen over eindopdracht
|
||||
- Vragen over je carrière in AI development
|
||||
- Feedback op de leerlijn
|
||||
|
||||
---
|
||||
|
||||
## Slide Summary
|
||||
|
||||
| # | Title | Type |
|
||||
|---|-------|------|
|
||||
| 1 | Title | Opening |
|
||||
| 2 | Terugblik 18 lessen | Recap |
|
||||
| 3 | Planning | 180-min |
|
||||
| 4 | AI landschap 2026 | Theorie |
|
||||
| 5 | Waarom multimodal | Theorie |
|
||||
| 6 | **DEMO 1** — Voice | Demo |
|
||||
| 7 | **DEMO 2** — Vision | Demo |
|
||||
| 8 | Pauze | Break |
|
||||
| 9 | **DEMO 3** — Image gen | Demo |
|
||||
| 10 | **DEMO 4** — Local LLMs | Demo |
|
||||
| 11 | **DEMO 5** — Edge AI | Demo |
|
||||
| 12 | Wat nu? Resources | Reflectie |
|
||||
| 13 | Eindopdracht reminder | Praktijk |
|
||||
| 14 | Afsluiting cyclus | Closing |
|
||||
| 15 | Vragen | Open |
|
||||
|
||||
---
|
||||
|
||||
## Bronnen
|
||||
|
||||
- **AI SDK Voice + Vision:** https://ai-sdk.dev/docs/ai-sdk-core/transcription, /speech
|
||||
- **Ollama:** https://ollama.com/library
|
||||
- **Vercel AI Gateway:** https://vercel.com/docs/ai/ai-gateway
|
||||
- **Fal (image gen):** https://fal.ai/models
|
||||
- **Replicate:** https://replicate.com
|
||||
- **Simon Willison blog:** https://simonwillison.net
|
||||
- **Latent Space podcast:** https://www.latent.space
|
||||
- **AI Engineer:** https://www.ai.engineer
|
||||
- **r/LocalLLaMA:** https://reddit.com/r/LocalLLaMA
|
||||
BIN
Les18-AI-Toolbox-Next/Les18-Slides.pdf
Normal file
BIN
Les18-AI-Toolbox-Next/Les18-Slides.pdf
Normal file
Binary file not shown.
BIN
Les18-AI-Toolbox-Next/Les18-Slides.pptx
Normal file
BIN
Les18-AI-Toolbox-Next/Les18-Slides.pptx
Normal file
Binary file not shown.
Reference in New Issue
Block a user