Bild-Upload und KI-Erkennung im Chat: Die komplette Lösung von Design bis Implementierung
Bild-Upload und KI-Erkennung im Chat: Die komplette Lösung von Design bis Implementierung
In KI-Interaktionssystemen: Wie können Benutzer Bilder hochladen und die KI diese direkt erkennen? Diese Frage hat mich auch lange beschäftigt, aber zum Glück haben wir im HagiCode-Projekt einige Lösungen gefunden. Heute sprechen wir über dieses Bild-Upload- und Erkennungssystem – von der benutzerdefinierten Protokollentwürfung bis zur Dateisystemspeicherung und der Frontend-Backend-separaten Vorschau. Dies ist auch eine vollständige technische Dokumentation.
Hintergrund
In dieser Ära des KI-Chat-Hype sind visuelle Informationen tatsächlich ein wichtiger Träger für die Benutzerabsicht. Nur unterstützen die meisten traditionellen Chat-Systeme reine Texteingabe, was dazu führt, dass Benutzer visuelle Kontexte nicht direkt zur KI-Analyse übergeben können – ein wenig bedauerlich.
HagiCode stieß während der Entwicklung auf ein ähnliches Dilemma: Benutzer konnten beim Chatten oder Erstellen von Hauptmeinungen keine Bilder hochladen, die KI konnte nicht auf lokale visuelle Informationen der Benutzer zugreifen, und es fehlte der geschlossene Kreislauf von Bildeingabe, Speicherung, Rendering und KI-Kontextübergabe.
Diese Probleme sind eigentlich nicht besonders groß, sie erfordern nur etwas Zeit und Geduld zur Lösung. Wir haben einen vollständigen Bild-Upload- und Erkennungsablauf entworfen und implementiert, damit Claude und andere KIs direkt Screenshots erkennen und analysieren können, die Benutzer hochladen. Im Folgenden werde ich die Implementierungsdetails dieser Lösung langsam erläutern.
Über HagiCode
Die in diesem Artikel vorgestellte Lösung stammt aus unserer praktischen Erfahrung im HagiCode-Projekt. HagiCode ist ein Open-Source-KI-Coding-Assistent-Projekt, das auf einem OpenSpec-basierten Workflow-Design basiert und sich der Bereitstellung einer intelligenteren Coderfahrung verschrieben hat.
Analyse
Technische Herausforderungen
Bevor wir mit der Implementierung beginnen, müssen wir zunächst die Haupt-Herausforderungen klären – schließlich schadet es nicht, die Werkzeuge vorher zu schärfen.
Cross-Module-Kooperation: Der Bild-Upload betrifft mehrere Module wie Frontend-UI, Upload-Service, Backend-API, Dateispeicherung, Nachrichtenpersistenz und KI-Executions-Mapping. Jedes Modul hat seine eigenen Zuständigkeiten und Schnittstellen, und eine abgestimmte Gesamtlösung muss entworfen werden.
Speicherstrategie-Auswahl: Sollen Bilder in der Datenbank oder im Dateisystem gespeichert werden? Bei Dateisystemwahl – wie soll die Verzeichnisstruktur entworfen werden? Wie kann sie in den bestehenden OpenSpec-Workflow integriert werden? All dies muss sorgfältig abgewogen werden.
Referenzprotokoll-Design: Es wird eine Standard-Bildreferenzmethode benötigt, die sowohl vom Frontend gerendert werden kann als auch vom KI-Executions-Pfad korrekt geparst werden kann. Direkter Dateipfad verwenden? HTTP-URL? Oder ein spezielles Protokoll entwerfen?
KI-Fähigkeitskompatibilität: Verschiedene KI-Executoren unterstützen Multimodalität in unterschiedlichem Maße. Einige Executoren unterstützen nativ Bildeingaben, andere können nur Text verarbeiten. Wie kann eine einheitliche Adapterschicht entworfen werden, um sicherzustellen, dass alle Executoren Bildinformationen korrekt verarbeiten?
Designentscheidungen
Nach ausführlicher Diskussion und Abwägung trafen wir die folgenden Schlüssel-Designentscheidungen.
Entscheidung 1: Dateisystemspeicherung
Wir entschieden uns dafür, Bilder im Dateisystem statt in der Datenbank zu speichern. Die Verzeichnisstruktur ist wie folgt aufgebaut:
<System-Root>/images/<sessionId>/├── <timestamp>-<uuid>.jpg└── <timestamp>-<uuid>.pngDie Gründe sind eigentlich ziemlich klar: Implementierung vereinfachen, Datenbank-Aufblähung vermeiden, Dateien können direkt von der KI gelesen werden. Außerdem eign sich Bilddaten von Natur aus nicht für die Datenbank – das Dateisystem ist die natürlichere Wahl. Das ist wie Bücher ins Regal stellen, nicht in ein Notizbuch stopfen – derselbe Grundsatz.
Entscheidung 2: Benutzerdefiniertes Protokoll hagiimag://
Um Konflikte mit HTTP-URLs zu vermeiden und die Referenzsemantik klarer zu machen, entwarfen wir ein benutzerdefiniertes Bildreferenzprotokoll:
hagiimag://session-abc123/20260301-143022-a1b2c3d4Das Format dieses Protokolls ist hagiimag://<sessionId>/<imageId>, mit klarer Semantik, einfach zu parsen und zu routen. Bei diesem Format erkennen Entwickler sofort, dass es sich um eine Bildreferenz handelt, nicht um eine normale URL. Solche kleinen Design-Details sind manchmal ziemlich nützlich.
Entscheidung 3: Frontend-Vorschau und KI-Zugriff getrennt
Bei der Implementierung stellten wir fest, dass Frontend und KI unterschiedliche Zugriffanforderungen an Bilder haben: Das Frontend benötigt eine Vorschau über HTTP-API, während die KI lokale Dateipfade direkt lesen muss. Daher entwarfen wir getrennte Zugriffsmethoden:
- Frontend verwendet
/api/Images/{sessionId}/{imageId}/contentfür Vorschau - KI verwendet vom Server geparste lokale Dateipfade
So wird sowohl die Sicherheit gewährleistet (Serverpfade werden nicht offengelegt) als auch die Benutzerfreundlichkeit berücksichtigt (Browser können direkt zugreifen). Schließlich müssen Sicherheit und Benutzerfreundlichkeit immer ausbalanciert werden.
Entscheidung 4: Sofortiger Upload-Strategie
Eine weitere wichtige Entscheidung war der Upload-Zeitpunkt. Wir entschieden uns, den Upload sofort beim Auswählen oder Einfügen eines Bildes auszulösen, und beim Senden der Nachricht nur bereits erfolgreich hochgeladene Bilder zu referenzieren.
Der Vorteil ist die Fehlerbehandlung im Voraus – die Nachrichten-Send-API bleibt einfach, der JSON-Vertrag wird kompakt gehalten. Benutzer wissen vor dem Senden, ob der Bild-Upload erfolgreich war – bessere Benutzererfahrung. Dieser Design-Ansatz “vorsorgen im Voraus” ist vielleicht oft anwendbar.
Lösung
Architektur-Design
Basierend auf den oben genannten Entscheidungen entwarfen wir die folgende Gesamtarchitektur:
Frontend-Schicht├── ConversationInputArea ◄─────── useImageAttachmentManager│ │ ││ ├── Dateiauswahl ├── Anhänge-Status-Management│ ├── Clipboard-Einfügen ├── Upload/Wiederholen/Löschen│ └── Anhang-Vorschau └── Bildreferenz-Generierung│Service-Schicht├── ImageUploadService│ ├── uploadImage() ◄─────── ImagesController│ ├── deleteImage() ││ ├── parseHagiImageUrl() ◄─────── Protokoll-Link parsen│ └── buildPreviewUrl() ││Backend-Schicht├── ImagesController ◄─────── ImagesDomainService│ │ ││ ├── POST /upload ├── Dateivalidierung│ ├── GET /{sessionId}/{imageId} ├── Bildspeicherung│ ├── DELETE ├── Bildkomprimierung│ └── GET /content └── Referenzparsing│KI-Executions-Schicht├── ImageContentBlock ◄─────── StructuredMessageDomainService│ │ ││ ├── Multimodale Executoren ├── Bildblock-Parsing│ └── Text-Executor-Fallback └── Pfadhinweis-GenerierungDiese Architektur zeigt klar den vollständigen Datenfluss vom Frontend zur KI. Jede Schicht hat klare Zuständigkeiten und interagiert über Standardschnittstellen. Gute Architektur ist eigentlich so: jeder erledigt seine Aufgabe, stört sich nicht gegenseitig, Kommunikation läuft reibungslos.
Schlüsselprozesse
Bild-Upload-Prozess:
- Benutzer wählt Bild über Dateiauswahl oder Clipboard-Einfügen
- Frontend validiert Dateityp und -größe (unterstützt JPEG/PNG/WEBP/GIF, 10MB pro Datei)
- Upload-API wird aufgerufen, Bild wird im Verzeichnis
/images/{sessionId}/gespeichert - API gibt
hagiimag://-Referenz und Vorschau-URL zurück - Frontend zeigt Vorschau-Thumbnail im Anhänge-Balken, Benutzer kann vor dem Senden vorschauen
KI-Erkennungsprozess:
- Benutzer sendet Nachricht mit Bildreferenz
- Backend parsed
hagiimag://-Protokoll-Link, extrahiert sessionId und imageId - Bildreferenz wird auf
ImageContentBlockabgebildet - Verarbeitungsart wird basierend auf Executor-Fähigkeiten gewählt:
- Multimodale Executoren: strukturierte Bildeingabe übergeben
- Text-Executoren: Fallback auf Bildpfad-Hinweis
So ist ein vollständiger geschlossener Kreislauf entstanden: Benutzer lädt Bild hoch → KI erkennt Bild → KI gibt Analyseergebnis zurück. Ein solcher reibungsloser Ablauf bietet oft eine bessere Benutzererfahrung.
Praxis
Frontend-Implementierung
Im Frontend stellen wir einen speziellen Hook zur Verfügung, um den Bildanhänge-Status zu verwalten:
import { useImageAttachmentManager } from '@/hooks/useImageAttachmentManager';
function ChatInput() { const { attachments, uploadedImages, hasBlockingAttachments, isUploading, selectFiles, removeAttachment, clearAttachments, } = useImageAttachmentManager({ ownerId: sessionId, mapUploadedImage: (response) => response, uploadOptions: { compress: false }, });
const handleFileSelect = (files: File[]) => { selectFiles(files); };
const handlePaste = (e: ClipboardEvent) => { const files = Array.from(e.clipboardData?.files || []) .filter(f => f.type.startsWith('image/')); if (files.length > 0) { handleFileSelect(files); } };
return ( <div> {/* Anhänge-Leiste */} {attachments.map(att => ( <AttachmentItem key={att.localId} file={att.file} status={att.status} onRemove={() => removeAttachment(att.localId)} /> ))}
{/* Eingabefeld */} <textarea onPaste={handlePaste} />
{/* Upload-Button */} <button onClick={() => fileInputRef.current?.click()}> Bild hochladen </button> </div> );}Dieser Hook kapselt die gesamte Logik des Anhangs-Managements, einschließlich Upload-Status-Tracking, Fehler-Wiederholung, Anhang-Löschen usw. Die Verwendung ist sehr einfach –只需几个 Methoden aufrufen, um den gesamten Prozess abzuschließen. Gutes API-Design ist eigentlich so: einfach zu bedienen, ohne Flexibilität zu verlieren.
Benutzerdefiniertes Protokoll parsen:
// sessionId und imageId aus benutzerdefiniertem Protokoll extrahierenconst parsed = parseHagiImageUrl("hagiimag://session-abc123/20260301-143022-uuid");// Rückgabe: { sessionId: "session-abc123", imageId: "20260301-143022-uuid" }
// Vorschau-URL aufbauenconst previewUrl = buildPreviewUrl(parsed.sessionId, parsed.imageId);// Rückgabe: "/api/Images/session-abc123/20260301-143022-uuid/content"Mit diesen beiden Hilfsfunktionen kann das Frontend einfach zwischen hagiimag://-Protokoll und HTTP-URL konvertieren. Wenn diese Konvertierungslogik gut gekapselt ist, ist die Verwendung viel bequemer.
Backend-Implementierung
Das Backend verwendet ASP.NET Core, der Kern sind ImagesController und ImagesDomainService:
[HttpPost("upload")][RequestSizeLimit(50 * 1024 * 1024)]public async Task<ActionResult<ImageUploadResponseDto>> Upload( [FromForm] UploadImageFormRequest input){ // 1. Anfrage validieren if (file == null || file.Length == 0) throw new UserFriendlyException("No file provided");
// 2. Dateityp und -größe validieren var (isValid, errorMessage) = _imagesDomainService.ValidateImage( file.FileName, file.ContentType, file.Length); if (!isValid) throw new UserFriendlyException(errorMessage);
// 3. Im Dateisystem speichern await using var stream = file.OpenReadStream(); var result = await _imagesDomainService.UploadImageAsync( stream, sessionId, file.FileName, file.ContentType, CurrentUserId, compress: input.Compress);
// 4. Ergebnis zurückgeben return Ok(result);}Diese Implementierung folgt dem typischen Web-API-Entwicklungsmuster: validieren, verarbeiten, zurückgeben. Zu beachten ist, dass wir ein 50MB-Request-Größen-Limit festgelegt haben, um böswillige Large-File-Uploads zu verhindern. In der Netzwerkwelt ist Vorsicht immer richtig.
Zu beachtende Punkte
Bei der Implementierung müssen einige Details besonders beachtet werden:
Berechtigungsprüfung: Der Bildzugriff muss die Benutzeridentität validieren, um sicherzustellen, dass nur auf Bilder der eigenen Sitzung zugegriffen werden kann. Dies ist eine grundlegende Sicherheitsanforderung, nicht weglassen. Bei Sicherheit – lieber einmal zu viel als zu wenig.
**Pfadsicherheit: sessionId und imageIdstreng validieren, um Path-Traversal-Angriffe zu verhindern. Zum Beispiel Pfade mit../` ablehnen, um zu verhindern, dass Benutzer auf beliebige Dateien im System zugreifen. Wenn solche Randbedingungen gut behandelt werden, wird das System robuster.
Dateibereinigung: Beim Löschen von Sitzungen müssen zugehörige Bilder synchron bereinigt werden, um die Ansammlung von Waisendateien zu vermeiden. Nach langem Lauf können diese Dateien viel Speicherplatz belegen. Rechtzeitige Bereinigung ist auch eine gute Gewohnheit.
Komprimierungsstrategie: Für Screenshot-ähnliche Dateinamen (wie screenshot.png) wird automatisch Komprimierung aktiviert, um Speicherplatz zu sparen. Diese Strategie kann je nach Bedarf angepasst werden. Speicherplatz – sparen, wo man kann.
Fallback-Behandlung: Executoren ohne Multimodal-Unterstützung müssen Bildpfad-Hinweise erhalten, dürfen Bildinformationen nicht stillschweigend verwerfen. Dies ist wichtig, sonst denken Benutzer, die KI habe ihr Bild ignoriert. Bei Benutzererfahrung entscheiden Details über Erfolg oder Misserfolg.
Status-Management: Hochladende Anhänge blockieren das Senden von Nachrichten, fehlgeschlagene Anhänge ermöglichen Wiederholung oder Löschung. Dieses Design gewährleistet die Kohärenz der Benutzererfahrung. Wenn das Status-Management klar ist, fühlen sich Benutzer nicht verwirrt.
Zusammenfassung
Mit dieser vollständigen Bild-Upload- und Erkennungslösung hat HagiCode einen vollständigen geschlossenen Kreislauf von Benutzereingabe bis KI-Erkennung realisiert. Die Kern-Highlights der gesamten Lösung sind:
- Benutzerdefiniertes
hagiimag://-Protokoll realisierte die Standardisierung von Bildreferenzen - Dateisystemspeicher vereinfachte die Implementierung und verbesserte die Performance
- Frontend-Vorschau und KI-Zugriff getrennt balancieren Sicherheit und Benutzerfreundlichkeit
- Sofortiger Upload optimierte die Benutzererfahrung
- Kompatibles Design von Multimodal und Text-Fallback gewährleistet Flexibilität
Diese Lösung läuft in HagiCode stabil, das Benutzer-Feedback ist positiv. Wenn Sie ähnliche Funktionen implementieren, hoffe ich, dass diese Erfahrungen für Sie nützlich sind.
Technische Lösungen haben kein absolut richtig oder falsch, nur passend oder nicht passend. Den für das eigene Projekt passenden Weg zu finden, ist am wichtigsten.
Referenzen
- HagiCode GitHub: github.com/HagiCode-org/site
- HagiCode Website: hagicode.com
- OpenSpec Workflow-Dokumentation: docs.hagicode.com
开始使用 HagiCode
一次安装,几分钟上手
HagiCode for Windows 在 Microsoft Store 免费提供。打开商店即可安装并保持更新;也可以先对比各版本与定价,再决定从哪个渠道开始。