import type { ObjectMeta, Sentence, PictureWord } from './types' const DIRECTUS_URL = 'https://db.hejyou.com' export async function directusLogin(email: string, password: string): Promise { 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, status = 'new'): Promise { const res = await fetch(`/api/directus/pictures?status=${status}`, { 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 async function updatePictureStatus(pictureId: string, status: string, token: string): Promise { const res = await fetch(`/api/directus/pictures/${pictureId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, body: JSON.stringify({ status }), }) if (!res.ok) throw new Error('Fehler beim Aktualisieren des Status') } export function directusAssetUrl(mediaId: string, token: string): string { return `${DIRECTUS_URL}/assets/${mediaId}?access_token=${token}` } import type { DirectusObject, Selection } from './types' export async function getDirectusObjects(pictureId: string, token: string): Promise { 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 selections: Selection[] | null user_notes: string | null parent: string | null }, token: string): Promise { 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>, token: string ): Promise { 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 { 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 { 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 { 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 { 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 { 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 { 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> { 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 { 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 } export interface GenerateStats { words_created: number words_linked: number questions_created: number questions_linked: number } export async function generateQuestions( objId: string, prompt: string, token: string ): Promise<{ ok: boolean; stats: GenerateStats }> { const res = await fetch(`/api/object/${encodeURIComponent(objId)}/generate_questions`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, body: JSON.stringify({ prompt }), }) const data = await res.json() if (!res.ok) throw new Error(data.error || 'Fehler bei Generate') return data } export async function publishQuestions( objId: string, token: string ): Promise<{ ok: boolean; published_questions: number; published_words: number }> { const res = await fetch(`/api/object/${encodeURIComponent(objId)}/publish_questions`, { method: 'POST', headers: { Authorization: `Bearer ${token}` }, }) const data = await res.json() if (!res.ok) throw new Error(data.error || 'Fehler bei Publish') return data } export interface ObjectQuestion { id: string question_de: string answer_de: string short_answer_de: string | null distractor_words: string[] level: number status: string } export interface ObjectWord { id: string title_de: string level: number status: string } export async function getObjectQuestions(objId: string, token: string): Promise { const res = await fetch(`/api/object/${encodeURIComponent(objId)}/questions`, { headers: { Authorization: `Bearer ${token}` }, }) const data = await res.json() if (!res.ok) throw new Error('Fehler beim Laden der Fragen') return data.data as ObjectQuestion[] } export async function getObjectWords(objId: string, token: string): Promise { const res = await fetch(`/api/object/${encodeURIComponent(objId)}/words`, { headers: { Authorization: `Bearer ${token}` }, }) const data = await res.json() if (!res.ok) throw new Error('Fehler beim Laden der Wörter') return data.data as ObjectWord[] } export async function deleteQuestion(qId: string, token: string): Promise { const res = await fetch(`/api/question/${encodeURIComponent(qId)}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` }, }) if (!res.ok) throw new Error('Fehler beim Löschen der Frage') } export async function deleteWord(wId: string, token: string): Promise { const res = await fetch(`/api/word/${encodeURIComponent(wId)}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` }, }) if (!res.ok) throw new Error('Fehler beim Löschen des Worts') } export async function getPictureWords(pictureId: string, token: string): Promise { const res = await fetch(`/api/directus/pictures/${pictureId}/words`, { headers: { Authorization: `Bearer ${token}` }, }) const data = await res.json() if (!res.ok) throw new Error('Fehler beim Laden der Bild-Wörter') return data.data as PictureWord[] } export async function savePictureWords( pictureId: string, words: { title_de: string; level: number }[], token: string ): Promise<{ saved: number }> { const res = await fetch(`/api/directus/pictures/${pictureId}/words`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, body: JSON.stringify({ words }), }) const data = await res.json() if (!res.ok) throw new Error(data.error || 'Fehler beim Speichern der Wörter') return data } export async function purgeOrphans(objId: string, token: string): Promise<{ orphans_removed: number }> { const res = await fetch(`/api/object/${encodeURIComponent(objId)}/purge-orphans`, { method: 'POST', headers: { Authorization: `Bearer ${token}` }, }) const data = await res.json() if (!res.ok) throw new Error('Fehler beim Bereinigen') return data } export async function purgeAllOrphans(token: string): Promise<{ orphans_removed: number }> { const res = await fetch('/api/purge-all-orphans', { method: 'POST', headers: { Authorization: `Bearer ${token}` }, }) const data = await res.json() if (!res.ok) throw new Error('Fehler beim globalen Bereinigen') return data }