mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
f9615fa74e
The import preview only showed counts + skipped-row errors with no way to fix anything. Now every parsed record is editable before import: - backend: shared validatePatientImport() (used by the previewImport tool) + POST /api/ai/import/validate for dry-run re-validation; the import preview payload now carries the original records (and the source record on each invalid row) so the UI can edit them. - frontend: the import card gets a "Review & edit" dialog listing every record with a ready / needs-fixing badge; opening one reuses the full PatientFormDialog in a new non-persisting review mode (editable file number) and re-validates on save, so skipped rows can be fixed and included. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import { apiFetch } from "@/lib/api-client";
|
|
import type { Effort } from "@/lib/ai-models";
|
|
|
|
// Mirrors backend/src/types/ai.ts. Per-user AI configuration fetched from and
|
|
// saved to /api/ai/config. Provider API keys are write-only: they are never
|
|
// returned, only `apiKeySet` reports which providers have a stored key.
|
|
|
|
export type AiMode = "api" | "local";
|
|
export type ApiProvider = "openai" | "anthropic" | "gemini";
|
|
export type VeilLevel = "off" | "names" | "full";
|
|
|
|
export type AiConfig = {
|
|
mode: AiMode;
|
|
provider: ApiProvider;
|
|
ollamaBaseUrl: string;
|
|
ollamaModel: string;
|
|
defaultModel: string;
|
|
defaultEffort: Effort;
|
|
veilLevel: VeilLevel;
|
|
apiKeySet: Record<ApiProvider, boolean>;
|
|
};
|
|
|
|
export type AiConfigPatch = Partial<
|
|
Omit<AiConfig, "apiKeySet">
|
|
> & {
|
|
// Plaintext key for the currently selected provider; "" clears it.
|
|
apiKey?: string;
|
|
};
|
|
|
|
export async function getAiConfig(): Promise<AiConfig> {
|
|
const res = await apiFetch<{ config: AiConfig }>("/api/ai/config");
|
|
return res.config;
|
|
}
|
|
|
|
export async function saveAiConfig(patch: AiConfigPatch): Promise<AiConfig> {
|
|
const res = await apiFetch<{ config: AiConfig }>("/api/ai/config", {
|
|
method: "PUT",
|
|
body: JSON.stringify(patch),
|
|
});
|
|
return res.config;
|
|
}
|
|
|
|
export async function testAiConnection(input: {
|
|
mode: AiMode;
|
|
provider?: ApiProvider;
|
|
ollamaBaseUrl?: string;
|
|
}): Promise<{ ok: boolean; message: string }> {
|
|
return apiFetch<{ ok: boolean; message: string }>("/api/ai/test", {
|
|
method: "POST",
|
|
body: JSON.stringify(input),
|
|
});
|
|
}
|
|
|
|
// Commit records the clinician approved in a chat import preview. The backend
|
|
// re-validates and writes via the audited patient service.
|
|
export async function commitImport(
|
|
records: unknown[],
|
|
): Promise<{ created: string[]; failed: { fileNumber?: string; error: string }[] }> {
|
|
return apiFetch("/api/ai/import", {
|
|
method: "POST",
|
|
body: JSON.stringify({ records }),
|
|
});
|
|
}
|
|
|
|
// Re-validate edited import records (dry run) so the review UI can refresh which
|
|
// rows are ready vs. need fixing. Writes nothing.
|
|
export async function validateImport(records: unknown[]): Promise<{
|
|
valid: unknown[];
|
|
invalid: { index: number; errors: string[]; record: unknown }[];
|
|
total: number;
|
|
}> {
|
|
return apiFetch("/api/ai/import/validate", {
|
|
method: "POST",
|
|
body: JSON.stringify({ records }),
|
|
});
|
|
}
|