fix persistence for storing profiles in backend db
2
internal/web/dist/index.html
vendored
@@ -8,7 +8,7 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Fira+Code:wght@300..700&family=Poiret+One&display=swap" rel="stylesheet">
|
||||
<script type="module" crossorigin src="/assets/index-DBj5_qOk.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-VWpE_J4S.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BPHlT-EN.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
BIN
screenshots/Screenshot 2025-08-26 at 12.25.27 PM (2).png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 251 KiB |
BIN
screenshots/scriberr-annotate transcript and take notes.png
Normal file
|
After Width: | Height: | Size: 682 KiB |
BIN
screenshots/scriberr-chat-with-your-recording-transcript.png
Normal file
|
After Width: | Height: | Size: 528 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 156 KiB |
BIN
screenshots/scriberr-homepage.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 107 KiB |
BIN
screenshots/scriberr-manage api keys.png
Normal file
|
After Width: | Height: | Size: 201 KiB |
BIN
screenshots/scriberr-summarize transcripts.png
Normal file
|
After Width: | Height: | Size: 139 KiB |
BIN
screenshots/scriberr-transcript page.png
Normal file
|
After Width: | Height: | Size: 239 KiB |
@@ -2,6 +2,7 @@ import { useState, useCallback } from "react";
|
||||
import { Button } from "./ui/button";
|
||||
import { ProfilesTable } from "./ProfilesTable";
|
||||
import { TranscriptionConfigDialog, type WhisperXParams } from "./TranscriptionConfigDialog";
|
||||
import { useAuth } from "../contexts/AuthContext";
|
||||
|
||||
interface TranscriptionProfile {
|
||||
id: string;
|
||||
@@ -17,6 +18,7 @@ export function ProfileSettings() {
|
||||
const [profileDialogOpen, setProfileDialogOpen] = useState(false);
|
||||
const [editingProfile, setEditingProfile] = useState<TranscriptionProfile | null>(null);
|
||||
const [refreshTrigger, setRefreshTrigger] = useState(0);
|
||||
const { getAuthHeaders } = useAuth();
|
||||
|
||||
const handleCreateProfile = useCallback(() => {
|
||||
setEditingProfile(null);
|
||||
@@ -28,13 +30,56 @@ export function ProfileSettings() {
|
||||
setProfileDialogOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleProfileSaved = useCallback(async (_params: WhisperXParams & { profileName?: string; profileDescription?: string }) => {
|
||||
// Profile saving logic would go here
|
||||
// For now, just close the dialog and refresh
|
||||
setRefreshTrigger((prev) => prev + 1);
|
||||
setProfileDialogOpen(false);
|
||||
setEditingProfile(null);
|
||||
}, []);
|
||||
const handleProfileSaved = useCallback(async (payload: WhisperXParams & { profileName?: string; profileDescription?: string }) => {
|
||||
try {
|
||||
const name = (payload.profileName || "").trim();
|
||||
const description = (payload.profileDescription || "").trim();
|
||||
if (!name) {
|
||||
alert("Profile name is required");
|
||||
return;
|
||||
}
|
||||
|
||||
const { profileName: _pn, profileDescription: _pd, ...paramRest } = payload as any;
|
||||
const body = {
|
||||
name,
|
||||
description: description || undefined,
|
||||
parameters: paramRest as WhisperXParams,
|
||||
};
|
||||
|
||||
let res: Response;
|
||||
if (editingProfile) {
|
||||
// Preserve current default flag unless changed elsewhere
|
||||
res = await fetch(`/api/v1/profiles/${editingProfile.id}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json", ...getAuthHeaders() },
|
||||
body: JSON.stringify({
|
||||
...body,
|
||||
id: editingProfile.id,
|
||||
is_default: editingProfile.is_default,
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
res = await fetch(`/api/v1/profiles`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...getAuthHeaders() },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
alert(`Failed to save profile: ${res.status} ${text}`);
|
||||
return;
|
||||
}
|
||||
|
||||
setRefreshTrigger((prev) => prev + 1);
|
||||
setProfileDialogOpen(false);
|
||||
setEditingProfile(null);
|
||||
} catch (e) {
|
||||
console.error("Failed to save profile", e);
|
||||
alert("Failed to save profile");
|
||||
}
|
||||
}, [editingProfile, getAuthHeaders]);
|
||||
|
||||
const handleProfileChange = useCallback(() => {
|
||||
setRefreshTrigger((prev) => prev + 1);
|
||||
@@ -64,6 +109,7 @@ export function ProfileSettings() {
|
||||
refreshTrigger={refreshTrigger}
|
||||
onProfileChange={handleProfileChange}
|
||||
onEditProfile={handleEditProfile}
|
||||
onCreateProfile={handleCreateProfile}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -27,15 +27,17 @@ interface TranscriptionProfile {
|
||||
}
|
||||
|
||||
interface ProfilesTableProps {
|
||||
refreshTrigger: number;
|
||||
onProfileChange: () => void;
|
||||
onEditProfile: (profile: TranscriptionProfile) => void;
|
||||
refreshTrigger: number;
|
||||
onProfileChange: () => void;
|
||||
onEditProfile: (profile: TranscriptionProfile) => void;
|
||||
onCreateProfile?: () => void;
|
||||
}
|
||||
|
||||
export function ProfilesTable({
|
||||
refreshTrigger,
|
||||
onProfileChange,
|
||||
onEditProfile,
|
||||
refreshTrigger,
|
||||
onProfileChange,
|
||||
onEditProfile,
|
||||
onCreateProfile,
|
||||
}: ProfilesTableProps) {
|
||||
const { getAuthHeaders } = useAuth();
|
||||
const [profiles, setProfiles] = useState<TranscriptionProfile[]>([]);
|
||||
@@ -148,13 +150,13 @@ export function ProfilesTable({
|
||||
Create your first transcription profile to save and reuse your
|
||||
preferred settings.
|
||||
</p>
|
||||
<Button
|
||||
onClick={() => {}}
|
||||
variant="outline"
|
||||
className="border-gray-300 dark:border-gray-600 text-gray-600 dark:text-gray-400"
|
||||
>
|
||||
Create Profile
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => onCreateProfile?.()}
|
||||
variant="outline"
|
||||
className="border-gray-300 dark:border-gray-600 text-gray-600 dark:text-gray-400"
|
||||
>
|
||||
Create Profile
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||