- `lib/url-fetch.ts`: fetchUrlContent aus decks-from-image herausgezogen — gemeinsam genutzte Logik für mana-search + direktes HTTP-Fetch-Fallback - `decks-generate.ts`: optionales `url`-Feld im Input-Schema; URL-Inhalt wird an den Prompt angehängt wenn vorhanden - `decks.ts` (web): `generateDeck()` akzeptiert jetzt `url?: string` - UI: imageUrl wird für Text-KI + Bild-KI als Kontext genutzt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
64 lines
2.3 KiB
TypeScript
64 lines
2.3 KiB
TypeScript
import type { Deck, DeckCreate, DeckUpdate } from '@cards/domain';
|
|
import { api, apiForm } from './client.ts';
|
|
|
|
export function listDecks(opts: { forkedFromMarketplace?: boolean } = {}) {
|
|
const qs = opts.forkedFromMarketplace ? '?forked_from_marketplace=true' : '';
|
|
return api<{ decks: Deck[]; total: number }>(`/api/v1/decks${qs}`);
|
|
}
|
|
|
|
export function getDeck(id: string) {
|
|
return api<Deck>(`/api/v1/decks/${id}`);
|
|
}
|
|
|
|
export function createDeck(input: DeckCreate) {
|
|
return api<Deck>('/api/v1/decks', { method: 'POST', body: input });
|
|
}
|
|
|
|
export function updateDeck(id: string, patch: DeckUpdate) {
|
|
return api<Deck>(`/api/v1/decks/${id}`, { method: 'PATCH', body: patch });
|
|
}
|
|
|
|
export function deleteDeck(id: string) {
|
|
return api<{ deleted: string }>(`/api/v1/decks/${id}`, { method: 'DELETE' });
|
|
}
|
|
|
|
export function generateDeck(input: { prompt: string; language?: 'de' | 'en'; count?: number; url?: string }) {
|
|
return api<{ deck: Deck; cards_created: number }>('/api/v1/decks/generate', {
|
|
method: 'POST',
|
|
body: input,
|
|
});
|
|
}
|
|
|
|
export function fetchDistractors(
|
|
deckId: string,
|
|
opts: { cardId?: string; count?: number; field?: string } = {},
|
|
) {
|
|
const params = new URLSearchParams();
|
|
if (opts.cardId) params.set('card_id', opts.cardId);
|
|
if (opts.count) params.set('count', String(opts.count));
|
|
if (opts.field) params.set('field', opts.field);
|
|
const qs = params.size ? `?${params}` : '';
|
|
return api<{ distractors: string[] }>(`/api/v1/decks/${deckId}/distractors${qs}`);
|
|
}
|
|
|
|
export function generateDeckFromImage(
|
|
files: File | File[],
|
|
opts: { language?: 'de' | 'en'; count?: number; url?: string },
|
|
) {
|
|
const arr = Array.isArray(files) ? files : [files];
|
|
|
|
// URL-only (no files): send as JSON — FormData without file parts fails in Bun
|
|
if (arr.length === 0) {
|
|
return api<{ deck: Deck; cards_created: number }>('/api/v1/decks/from-image', {
|
|
method: 'POST',
|
|
body: { language: opts.language, count: opts.count, url: opts.url },
|
|
});
|
|
}
|
|
|
|
const form = new FormData();
|
|
for (const f of arr) form.append('file', f);
|
|
if (opts.language) form.append('language', opts.language);
|
|
if (opts.count != null) form.append('count', String(opts.count));
|
|
if (opts.url) form.append('url', opts.url);
|
|
return apiForm<{ deck: Deck; cards_created: number }>('/api/v1/decks/from-image', form);
|
|
}
|