mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:01:09 +02:00
feat(kontext): URL import helpers — API client + appendContent
Frontend plumbing for the Kontext "Aus URL" inline panel (the UI
itself was committed earlier as part of 003f75f7e):
- kontext/api.ts: new module-scoped fetch wrapper that talks to
/api/v1/context/import-url with a Bearer token. Kept in kontext/
rather than a shared helper because it's the only caller; moving
it to `context/` would mix two unrelated modules again.
- kontext/stores/kontext.svelte.ts: new appendContent(chunk) method.
The singleton row is encrypted at rest, so we decrypt the current
content before concatenating with a '\n\n---\n\n' separator and
writing back — going through setContent() to keep encryption +
Dexie hook behaviour consistent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
121a0c0a6f
commit
12072c6b6c
2 changed files with 54 additions and 1 deletions
44
apps/mana/apps/web/src/lib/modules/kontext/api.ts
Normal file
44
apps/mana/apps/web/src/lib/modules/kontext/api.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Kontext API client — talks to apps/api `POST /api/v1/context/import-url`.
|
||||
*
|
||||
* The server route lives under /context for historical reasons (shared
|
||||
* crawler + LLM wrapper). Only the kontext singleton consumes it.
|
||||
*/
|
||||
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { getManaApiUrl } from '$lib/api/config';
|
||||
|
||||
export type CrawlMode = 'single' | 'deep';
|
||||
|
||||
export interface ImportInput {
|
||||
url: string;
|
||||
mode: CrawlMode;
|
||||
summarize: boolean;
|
||||
}
|
||||
|
||||
export interface ImportResponse {
|
||||
title: string;
|
||||
content: string;
|
||||
sourceUrl: string;
|
||||
crawlMode: CrawlMode;
|
||||
crawledAt: string;
|
||||
pageCount: number;
|
||||
}
|
||||
|
||||
export async function crawlUrlViaApi(input: ImportInput): Promise<ImportResponse> {
|
||||
const token = await authStore.getValidToken();
|
||||
if (!token) throw new Error('not authenticated');
|
||||
const res = await fetch(`${getManaApiUrl()}/api/v1/context/import-url`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const body = (await res.json().catch(() => ({}))) as { error?: string };
|
||||
throw new Error(body.error || `import failed (${res.status})`);
|
||||
}
|
||||
return (await res.json()) as ImportResponse;
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { kontextDocTable } from '../collections';
|
||||
import { encryptRecord } from '$lib/data/crypto';
|
||||
import { encryptRecord, decryptRecords } from '$lib/data/crypto';
|
||||
import { KONTEXT_SINGLETON_ID, type LocalKontextDoc } from '../types';
|
||||
|
||||
export const kontextStore = {
|
||||
|
|
@ -30,4 +30,13 @@ export const kontextStore = {
|
|||
await encryptRecord('kontextDoc', diff);
|
||||
await kontextDocTable.update(KONTEXT_SINGLETON_ID, diff);
|
||||
},
|
||||
|
||||
async appendContent(chunk: string): Promise<void> {
|
||||
await this.ensureDoc();
|
||||
const row = await kontextDocTable.get(KONTEXT_SINGLETON_ID);
|
||||
const [decrypted] = row ? await decryptRecords('kontextDoc', [row]) : [];
|
||||
const current = decrypted?.content ?? '';
|
||||
const separator = current.trim() ? '\n\n---\n\n' : '';
|
||||
await this.setContent(`${current}${separator}${chunk}`);
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue