Jemand lädt eine Datei namens urlaub.png hoch
Eine Person fügt Ihrem Chatfeld eine Datei namens urlaub.png hinzu. Sie wissen nicht, was darin steckt. Es kann ein Foto sein oder ein Programm mit einem Bildnamen.
Ein Bild sicher an ein Modell zu senden heißt, es zu prüfen, bevor es Ihren Server verlässt. Diese Lektion zeigt die Prüfungen.
Am Ende dieser Lektion
Notiz
Ich kann eine Anfrage bauen, die ein Bild trägt, und eine Datei ablehnen, die eine Regel verletzt, bevor sie gesendet wird.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Base64 | eine Art, Bytes als schlichte Buchstaben und Ziffern zu schreiben | |
| Medientyp | eine Angabe, was für eine Datei es ist | image/png |
| Erste Bytes | der Anfang einer Datei, der sagt, was sie wirklich ist | |
| Nutzlast | die Daten, die eine Anfrage trägt | |
| Grenze | das Meiste, was der Dienst annimmt |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Bild reist als Text
Eine Anfrage ist meist Text, ein Bild aber besteht aus Bytes. Base64 macht aus je 3 Bytes 4 schlichte Zeichen, sodass die Anfrage Text bleibt.
Das hat seinen Preis. Der Text ist um ein Drittel länger als die Bytes. Eine Grenze für die Bytes ist also keine Grenze für die Anfrage.
Wie base64 eine Datei wachsen lässt
| Bytes | Zeichen | Warum |
|---|---|---|
| 3 | 4 | Eine Gruppe aus 3 wird zu 4 |
| 4 | 8 | Eine zweite Gruppe wird angefangen |
| 28 | 40 | Zehn Gruppen zu je 4 |
| 3.000 | 4.000 | Etwa ein Drittel mehr |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Trauen Sie den ersten Bytes, nicht dem Namen
Ein Name ist nur das, was jemand getippt hat. Die ersten Bytes einer Datei legt ihr Format fest. Eine PNG-Datei beginnt immer mit denselben 8 Bytes, eine JPEG-Datei mit 3.
Bestimmen Sie den Medientyp also aus den ersten Bytes. Widerspricht der Name, lehnen Sie die Datei ab oder sagen es zumindest.
Ein häufiger Fehler
Warnung
Viele vertrauen dem Dateinamen und dem Typ, den der Browser meldet. Beides tippt der Absender. Prüfen Sie die ersten Bytes auf Ihrem eigenen Server, denn ein Programm namens urlaub.png bestünde eine Prüfung des Namens.
Erst prüfen, dann senden
Führen Sie jede Prüfung aus, bevor ein einziges Byte hinausgeht. Sammeln Sie alle Probleme in einer Liste mit fester Reihenfolge, damit die Person alles auf einmal beheben kann. Nur eine Datei ohne Probleme wird kodiert und in die Nutzlast gelegt.
Eine abgelehnte Anfrage kostet trotzdem Zeit, und das Modell sieht nie eine Datei, die Sie nicht geprüft haben.
Modell-Helfer schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const basis = process.env.AI_URL || \"http://ai:4000\";' '// Die Token einer Antwort oder null, wenn sie keine nennt.' 'function zaehlen(daten, name) {' ' return daten.usage && typeof daten.usage[name] === \"number\" ? daten.usage[name] : null;' '}' > model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Modell-Helfer schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function fragen(nachrichten, probe, max) {' ' try {' ' const res = await fetch(basis + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: nachrichten, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"Status \" + res.status);' ' const d = await res.json();' ' return { text: d.choices[0].message.content, eingabe: zaehlen(d, \"prompt_tokens\"), ausgabe: zaehlen(d, \"completion_tokens\"), aufgezeichnet: false };' ' } catch (fehler) {' ' console.log(\"Aufgezeichnete Probe: Kein Modell hat geantwortet (\" + fehler.message + \").\");' ' return { text: probe, eingabe: null, ausgabe: null, aufgezeichnet: true };' ' }' '}' 'module.exports = { fragen };' >> model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Prüf-Skript schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' 'const kopf = [137, 80, 78, 71, 13, 10, 26, 10];' 'const png = Buffer.concat([Buffer.from(kopf), Buffer.alloc(40, 7)]);' 'const falsch = Buffer.concat([Buffer.from(\"MZ\"), Buffer.alloc(40, 7)]);' 'const riesig = Buffer.concat([Buffer.from(kopf), Buffer.alloc(142, 7)]);' 'const GRENZE = 100;' > senden2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Prüf-Skript schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function erkennen(b) {' ' if (b.length >= 8 && b[0] === 137 && b[1] === 80 && b[2] === 78 && b[3] === 71) return \"png\";' ' if (b.length >= 3 && b[0] === 255 && b[1] === 216 && b[2] === 255) return \"jpeg\";' ' return \"unbekannt\";' '}' 'function pruefen(b) {' ' const probleme = [];' ' if (b.length > GRENZE) probleme.push(\"zu groß\");' ' if (erkennen(b) === \"unbekannt\") probleme.push(\"Typ nicht erlaubt\");' ' return probleme;' '}' >> senden2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Prüf-Skript schreiben, Teil 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const liste = [[\"katze.png\", png], [\"notizen.png\", falsch], [\"riesig.png\", riesig]];' ' for (const eintrag of liste) {' ' const b = eintrag[1];' ' console.log(eintrag[0] + \": \" + erkennen(b) + \", \" + b.length + \" Bytes, base64 \" + b.toString(\"base64\").length + \" Zeichen\");' ' console.log(\" Probleme: \" + JSON.stringify(pruefen(b)));' ' }' >> senden2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Prüf-Skript schreiben, Teil 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' const teil = { type: \"image\", media_type: \"image/png\", data: png.toString(\"base64\").slice(0, 12) + \"...\" };' ' console.log(JSON.stringify({ messages: [{ role: \"user\", content: [{ type: \"text\", text: \"Beschreiben Sie es.\" }, teil] }] }));' ' const frage = \"Schreiben Sie einen kurzen, freundlichen Satz, der einer Person sagt, dass ihr Bild zu groß zum Senden war.\";' ' const antwort = await fragen([{ role: \"user\", content: frage }], \"Das Bild ist zu groß zum Senden, bitte wählen Sie ein kleineres.\", 40);' ' console.log(\"Antwort: \" + antwort.text);' '}' 'main();' >> senden2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Drei Dateien prüfen
docker exec -w /home/node/project agent node senden2.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Zeilen, die der Run druckt
| Zeile | Was sie zeigt |
|---|---|
| katze.png: png, 48 Bytes, base64 64 Zeichen | Echte PNG-Bytes, und aus 48 Bytes wurden 64 Zeichen |
| notizen.png: unbekannt ... Typ nicht erlaubt | Der Name sagt png, die Bytes nicht |
| riesig.png: png, 150 Bytes ... zu groß | Richtiger Typ, über der Grenze von 100 |
| {"messages":[...]} | Der Anfragetext, mit gekürzten Daten |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.