learning_ai_notes/web/src/lib/prompt-client.ts

196 lines
6.2 KiB
TypeScript

"use client";
import { createNotesApiClient } from "@/lib/api-helpers";
import type {
PromptTemplate,
RunPromptInput,
RunPromptOutput,
SimilarNote,
KnowledgeGap,
} from "@/lib/types";
// ── Template CRUD ─────────────────────────────────────────────
export async function listPromptTemplates(): Promise<PromptTemplate[]> {
const api = createNotesApiClient();
const res = await api.fetch<{ items: PromptTemplate[] }>("/note-prompts");
return res.items;
}
export async function getPromptTemplate(id: string): Promise<PromptTemplate> {
const api = createNotesApiClient();
return api.fetch<PromptTemplate>(`/note-prompts/${encodeURIComponent(id)}`);
}
export async function createPromptTemplate(
input: Omit<PromptTemplate, "id" | "isBuiltin">,
): Promise<PromptTemplate> {
const api = createNotesApiClient();
return api.fetch<PromptTemplate>("/note-prompts", {
method: "POST",
body: JSON.stringify(input),
});
}
export async function deletePromptTemplate(id: string): Promise<void> {
const api = createNotesApiClient();
await api.fetch(`/note-prompts/${encodeURIComponent(id)}`, { method: "DELETE" });
}
// ── Run prompts ───────────────────────────────────────────────
export async function runPrompt(input: RunPromptInput): Promise<RunPromptOutput> {
const api = createNotesApiClient();
return api.fetch<RunPromptOutput>("/note-prompts/run", {
method: "POST",
body: JSON.stringify(input),
});
}
// ── Run prompts (streaming) ───────────────────────────────────
export async function runPromptStream(
input: RunPromptInput,
onToken: (content: string) => void,
onDone: (meta: Partial<RunPromptOutput>) => void,
onError?: (message: string) => void,
): Promise<void> {
const api = createNotesApiClient();
const baseUrl = (api as unknown as { baseUrl?: string }).baseUrl ?? "";
const token = typeof window !== "undefined" ? localStorage.getItem("access_token") : null;
const headers: Record<string, string> = { "Content-Type": "application/json" };
if (token) headers["Authorization"] = `Bearer ${token}`;
const res = await fetch(`${baseUrl}/note-prompts/run-stream`, {
method: "POST",
headers,
body: JSON.stringify(input),
});
if (!res.ok || !res.body) {
onError?.(res.statusText || "Stream failed");
return;
}
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n\n");
buffer = lines.pop() ?? "";
for (const line of lines) {
if (!line.startsWith("data: ")) continue;
try {
const payload = JSON.parse(line.slice(6));
if (payload.type === "token") onToken(payload.content);
else if (payload.type === "done") onDone(payload);
else if (payload.type === "error") onError?.(payload.message);
} catch { /* skip malformed */ }
}
}
}
// ── History ──────────────────────────────────────────────────
export interface PromptHistoryItem {
id: string;
noteId: string;
workspaceId: string;
toolName?: string;
state: string;
reason?: string;
afterSummary?: string;
createdAt: string;
}
export async function listPromptHistory(
workspaceId: string,
limit = 20,
): Promise<{ items: PromptHistoryItem[]; total: number }> {
const api = createNotesApiClient();
return api.fetch(`/note-prompts/history?workspaceId=${encodeURIComponent(workspaceId)}&limit=${limit}`);
}
// ── Intelligence endpoints ────────────────────────────────────
export async function suggestTags(
noteId: string,
workspaceId: string,
): Promise<string[]> {
const api = createNotesApiClient();
const res = await api.fetch<{ tags: string[] }>(
`/notes/${encodeURIComponent(noteId)}/suggest-tags`,
{ method: "POST", body: JSON.stringify({ workspaceId }) },
);
return res.tags;
}
export async function checkDuplicates(
noteId: string,
workspaceId: string,
threshold = 0.85,
): Promise<SimilarNote[]> {
const api = createNotesApiClient();
const res = await api.fetch<{ duplicates: SimilarNote[] }>(
`/notes/${encodeURIComponent(noteId)}/check-duplicates`,
{ method: "POST", body: JSON.stringify({ workspaceId, threshold }) },
);
return res.duplicates;
}
export async function suggestLinks(
noteId: string,
workspaceId: string,
threshold = 0.6,
): Promise<SimilarNote[]> {
const api = createNotesApiClient();
const res = await api.fetch<{ suggestions: SimilarNote[] }>(
`/notes/${encodeURIComponent(noteId)}/suggest-links`,
{ method: "POST", body: JSON.stringify({ workspaceId, threshold }) },
);
return res.suggestions;
}
export async function getReadingTime(
noteId: string,
workspaceId: string,
): Promise<{ wordCount: number; readingTimeMinutes: number }> {
const api = createNotesApiClient();
return api.fetch(`/notes/${encodeURIComponent(noteId)}/reading-time?workspaceId=${encodeURIComponent(workspaceId)}`);
}
export async function compareNotes(
noteIds: string[],
workspaceId: string,
): Promise<RunPromptOutput> {
const api = createNotesApiClient();
return api.fetch<RunPromptOutput>("/notes/compare", {
method: "POST",
body: JSON.stringify({ noteIds, workspaceId }),
});
}
export async function mergeNotes(
noteIds: string[],
workspaceId: string,
): Promise<RunPromptOutput> {
const api = createNotesApiClient();
return api.fetch<RunPromptOutput>("/notes/merge", {
method: "POST",
body: JSON.stringify({ noteIds, workspaceId }),
});
}
export async function getKnowledgeGaps(
workspaceId: string,
): Promise<{ gaps: KnowledgeGap[]; topicMap: Record<string, number> }> {
const api = createNotesApiClient();
return api.fetch(`/workspaces/${encodeURIComponent(workspaceId)}/knowledge-gaps`, {
method: "POST",
});
}