Files
hejyou_content_creation/frontend/src/api.ts
admin 343d6a2389 Objekte direkt in Directus speichern + neuer Annotationsworkflow
- DirectusObject Typ + CanvasObject Interface in types.ts
- DrawCanvas nutzt CanvasObject (generisch, nicht mehr ObjectMeta-gebunden)
- Flask: /api/directus/objects (GET/POST), /api/directus/objects/<id> (PATCH/DELETE)
- Flask: /api/directus/setup-m2m (einmalig: m2m für categories/questions)
- api.ts: getDirectusObjects, createDirectusObject, updateDirectusObject, deleteDirectusObject
- DrawIt: Objekte werden in Directus gespeichert (mit picture, bbox/polygon, user_notes, parent)
- DrawIt: Linke Sidebar zeigt Objektliste mit Notizen-Editor und Löschen-Button
- DrawIt: Rechte Sidebar: Modus, user_notes Textarea, Parent-Dropdown, Auswahlen
- Directus: user_notes Feld (textarea), action/resolution/confidence/media versteckt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 20:26:46 +02:00

190 lines
6.6 KiB
TypeScript

import type { ObjectMeta, Sentence } from './types'
const DIRECTUS_URL = 'https://db.hejyou.com'
export async function directusLogin(email: string, password: string): Promise<string> {
const res = await fetch('/api/directus/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
})
const data = await res.json()
if (!res.ok) throw new Error(data.errors?.[0]?.message || 'Login fehlgeschlagen')
return data.data.access_token
}
export interface DirectusPicture {
id: string
media: string
status: string
}
export async function getDirectusPictures(token: string): Promise<DirectusPicture[]> {
const res = await fetch('/api/directus/pictures', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Fehler beim Laden der Directus-Bilder')
const data = await res.json()
return data.data as DirectusPicture[]
}
export function directusAssetUrl(mediaId: string, token: string): string {
return `${DIRECTUS_URL}/assets/${mediaId}?access_token=${token}`
}
import type { DirectusObject, BBox, Point } from './types'
export async function getDirectusObjects(pictureId: string, token: string): Promise<DirectusObject[]> {
const res = await fetch(`/api/directus/objects?picture_id=${pictureId}`, {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Fehler beim Laden der Objekte')
const data = await res.json()
return data.data as DirectusObject[]
}
export async function createDirectusObject(payload: {
picture: string
bbox: BBox | null
polygon: Point[] | null
user_notes: string | null
parent: string | null
}, token: string): Promise<DirectusObject> {
const res = await fetch('/api/directus/objects', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify({ ...payload, status: 'draft' }),
})
const data = await res.json()
if (!res.ok) throw new Error(data.errors?.[0]?.message || 'Fehler beim Speichern')
return data.data as DirectusObject
}
export async function updateDirectusObject(
objId: string,
payload: Partial<Pick<DirectusObject, 'user_notes' | 'parent'>>,
token: string
): Promise<DirectusObject> {
const res = await fetch(`/api/directus/objects/${objId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify(payload),
})
const data = await res.json()
if (!res.ok) throw new Error(data.errors?.[0]?.message || 'Fehler beim Aktualisieren')
return data.data as DirectusObject
}
export async function deleteDirectusObject(objId: string, token: string): Promise<void> {
const res = await fetch(`/api/directus/objects/${objId}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Fehler beim Löschen')
}
export async function getImages(mode: 'draw' | 'generate'): Promise<string[]> {
const res = await fetch(`/api/images?mode=${mode}`)
if (!res.ok) throw new Error('Fehler beim Laden der Bilder')
const data = await res.json()
return data.images as string[]
}
export async function getObjects(filename: string): Promise<ObjectMeta[]> {
const res = await fetch(`/api/objects?filename=${encodeURIComponent(filename)}`)
if (!res.ok) throw new Error('Fehler beim Laden der Objekte')
const data = await res.json()
return (data.objects || []) as ObjectMeta[]
}
export async function cropImage(payload: {
filename: string
selections: Array<{
number: number
mode: string
bbox?: { x: number; y: number; width: number; height: number } | null
polygon?: Array<{ x: number; y: number }> | null
}>
title_de: string
position_de: string
action_de: string
condition_de: string
}): Promise<{ id: string; image_file: string; meta_file: string }> {
const res = await fetch('/api/crop', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
const data = await res.json()
if (!res.ok) throw new Error(data.error || 'Fehler beim Speichern des Ausschnitts')
return data
}
export async function saveImage(filename: string): Promise<{ old_name: string; new_name: string }> {
const res = await fetch('/api/image/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ filename }),
})
const data = await res.json()
if (!res.ok) throw new Error(data.error || 'Fehler beim Speichern des Bildes')
return data
}
export async function updateObjectMeta(
objId: string,
meta: { title_de: string; position_de: string; action_de: string; condition_de: string }
): Promise<void> {
const res = await fetch(`/api/object/${encodeURIComponent(objId)}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(meta),
})
if (!res.ok) throw new Error('Fehler beim Aktualisieren der Metadaten')
}
export async function updateHierarchy(objId: string, hierarchy: number): Promise<void> {
const res = await fetch(`/api/object/${encodeURIComponent(objId)}/hierarchy`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hierarchy }),
})
if (!res.ok) throw new Error('Fehler beim Aktualisieren der Hierarchie')
}
export async function updateParent(objId: string, parentId: string | null): Promise<void> {
const res = await fetch(`/api/object/${encodeURIComponent(objId)}/parent`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ parent_id: parentId }),
})
if (!res.ok) throw new Error('Fehler beim Aktualisieren der Parent-Relation')
}
export async function generateDetails(objId: string): Promise<Partial<ObjectMeta>> {
const res = await fetch(`/api/object/${encodeURIComponent(objId)}/generate_details`, {
method: 'POST',
})
const data = await res.json()
if (!res.ok) throw new Error(data.error || 'Fehler bei KI-Details')
return data
}
export async function getSentences(objId: string): Promise<Sentence[]> {
const res = await fetch(`/api/object/${encodeURIComponent(objId)}/sentences`)
if (!res.ok) throw new Error('Fehler beim Laden der Sätze')
const data = await res.json()
return (data.sentences || []) as Sentence[]
}
export async function generateSentence(
objId: string
): Promise<{ sentence: Sentence; count: number }> {
const res = await fetch(`/api/object/${encodeURIComponent(objId)}/generate_sentence`, {
method: 'POST',
})
const data = await res.json()
if (!res.ok) throw new Error(data.error || 'Fehler bei KI-Sentence')
return data
}