diff --git a/.vscode/launch.json b/.vscode/launch.json index 9b43d80..2af6171 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,23 +1,5 @@ { "configurations": [ - { - "type": "swift", - "request": "launch", - "args": [], - "cwd": "${workspaceFolder:amical}/packages/native-helpers/swift-helper", - "name": "Debug KeyTapHelper (packages/native-helpers/swift-helper)", - "program": "${workspaceFolder:amical}/packages/native-helpers/swift-helper/.build/debug/KeyTapHelper", - "preLaunchTask": "swift: Build Debug KeyTapHelper (packages/native-helpers/swift-helper)" - }, - { - "type": "swift", - "request": "launch", - "args": [], - "cwd": "${workspaceFolder:amical}/packages/native-helpers/swift-helper", - "name": "Release KeyTapHelper (packages/native-helpers/swift-helper)", - "program": "${workspaceFolder:amical}/packages/native-helpers/swift-helper/.build/release/KeyTapHelper", - "preLaunchTask": "swift: Build Release KeyTapHelper (packages/native-helpers/swift-helper)" - }, { "type": "swift", "request": "launch", diff --git a/.vscode/settings.json b/.vscode/settings.json index 44a73ec..a84c425 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ { "mode": "auto" } - ] + ], + "editor.formatOnSave": true } diff --git a/apps/desktop/src/components/transcriptions-list.tsx b/apps/desktop/src/components/transcriptions-list.tsx index 31ad9b9..7d43f24 100644 --- a/apps/desktop/src/components/transcriptions-list.tsx +++ b/apps/desktop/src/components/transcriptions-list.tsx @@ -36,18 +36,28 @@ export const TranscriptionsList: React.FC = () => { const [searchTerm, setSearchTerm] = useState(""); // tRPC React Query hooks - const transcriptionsQuery = api.transcriptions.getTranscriptions.useQuery({ - limit: 50, - offset: 0, - sortBy: "timestamp", - sortOrder: "desc", - search: searchTerm || undefined, - }); + const transcriptionsQuery = api.transcriptions.getTranscriptions.useQuery( + { + limit: 50, + offset: 0, + sortBy: "timestamp", + sortOrder: "desc", + search: searchTerm || undefined, + }, + { + refetchInterval: 2000, // Poll every 2 seconds, auto-pauses when out of focus + }, + ); const transcriptionsCountQuery = - api.transcriptions.getTranscriptionsCount.useQuery({ - search: searchTerm || undefined, - }); + api.transcriptions.getTranscriptionsCount.useQuery( + { + search: searchTerm || undefined, + }, + { + refetchInterval: 2000, // Poll every 2 seconds, auto-pauses when out of focus + }, + ); const utils = api.useUtils(); @@ -110,14 +120,6 @@ export const TranscriptionsList: React.FC = () => { return (
-
-
-
- - -
-
- {/* Search and Filter Bar */}
@@ -129,10 +131,6 @@ export const TranscriptionsList: React.FC = () => { className="pl-10" />
-
{/* Transcriptions Grid */} diff --git a/apps/desktop/src/main/main.ts b/apps/desktop/src/main/main.ts index a7f5143..c6738e4 100644 --- a/apps/desktop/src/main/main.ts +++ b/apps/desktop/src/main/main.ts @@ -351,6 +351,35 @@ app.on("ready", async () => { hasResult: !!transcription, }); + // Save transcription to database + if ( + transcription && + typeof transcription === "string" && + transcription.trim().length > 0 + ) { + try { + const { createTranscription } = await import( + "../db/transcriptions.js" + ); + const savedTranscription = await createTranscription({ + text: transcription, + timestamp: new Date(), + audioFile: filePath, + language: "en", // Default to English, could be made configurable + }); + logger.db.info("Transcription saved to database", { + transcriptionId: savedTranscription.id, + textLength: transcription.length, + audioFile: filePath, + }); + } catch (dbError) { + logError( + dbError instanceof Error ? dbError : new Error(String(dbError)), + "saving transcription to database", + ); + } + } + // Copy transcription to clipboard if (transcription && typeof transcription === "string") { logger.main.info("Transcription pasted to active application"); @@ -421,7 +450,7 @@ app.on("ready", async () => { }); }); - transcriptionSession.on("session-completed", (sessionResult) => { + transcriptionSession.on("session-completed", async (sessionResult) => { logger.ai.info("Transcription session completed", { sessionId: sessionResult.sessionId, finalTextLength: sessionResult.finalText.length, @@ -429,15 +458,40 @@ app.on("ready", async () => { totalProcessingTimeMs: sessionResult.totalProcessingTimeMs, }); - // Paste the final result to active application + // Save chunk-based transcription to database if ( sessionResult.finalText && sessionResult.finalText.trim().length > 0 ) { + try { + const { createTranscription } = await import( + "../db/transcriptions.js" + ); + const savedTranscription = await createTranscription({ + text: sessionResult.finalText, + timestamp: new Date(), + audioFile: null, // Chunk-based transcriptions don't have a single audio file + language: "en", // Default to English, could be made configurable + }); + logger.db.info("Chunk-based transcription saved to database", { + transcriptionId: savedTranscription.id, + sessionId: sessionResult.sessionId, + textLength: sessionResult.finalText.length, + totalChunks: sessionResult.chunkResults.length, + }); + } catch (dbError) { + logError( + dbError instanceof Error ? dbError : new Error(String(dbError)), + "saving chunk-based transcription to database", + ); + } + + // Paste the final result to active application logger.main.info( "Final transcription pasted to active application", { textLength: sessionResult.finalText.length, + sessionId: sessionResult.sessionId, }, ); swiftIOBridgeClientInstance!.call("pasteText", { diff --git a/apps/desktop/src/main/preload.ts b/apps/desktop/src/main/preload.ts index 3fe7f4c..e90684a 100644 --- a/apps/desktop/src/main/preload.ts +++ b/apps/desktop/src/main/preload.ts @@ -92,29 +92,7 @@ const api: ElectronAPI = { setFormatterConfig: (config: FormatterConfig) => ipcRenderer.invoke("set-formatter-config", config), - // Transcription Database API - getTranscriptions: (options?: { - limit?: number; - offset?: number; - sortBy?: "timestamp" | "createdAt"; - sortOrder?: "asc" | "desc"; - search?: string; - }) => ipcRenderer.invoke("get-transcriptions", options), - getTranscriptionById: (id: number) => - ipcRenderer.invoke("get-transcription-by-id", id), - createTranscription: ( - data: Omit, - ) => ipcRenderer.invoke("create-transcription", data), - updateTranscription: ( - id: number, - data: Partial>, - ) => ipcRenderer.invoke("update-transcription", id, data), - deleteTranscription: (id: number) => - ipcRenderer.invoke("delete-transcription", id), - getTranscriptionsCount: (search?: string) => - ipcRenderer.invoke("get-transcriptions-count", search), - searchTranscriptions: (searchTerm: string, limit?: number) => - ipcRenderer.invoke("search-transcriptions", searchTerm, limit), + // Transcription Database API (moved to tRPC) // Vocabulary Database API on: (channel: string, callback: (...args: any[]) => void) => { diff --git a/apps/desktop/src/types/electron-api.ts b/apps/desktop/src/types/electron-api.ts index e3ab97d..1d768ec 100644 --- a/apps/desktop/src/types/electron-api.ts +++ b/apps/desktop/src/types/electron-api.ts @@ -52,37 +52,7 @@ export interface ElectronAPI { config: import("../modules/formatter").FormatterConfig, ) => Promise; - // Transcription Database API - getTranscriptions: (options?: { - limit?: number; - offset?: number; - sortBy?: "timestamp" | "createdAt"; - sortOrder?: "asc" | "desc"; - search?: string; - }) => Promise; - getTranscriptionById: ( - id: number, - ) => Promise; - createTranscription: ( - data: Omit< - import("../db/schema").NewTranscription, - "id" | "createdAt" | "updatedAt" - >, - ) => Promise; - updateTranscription: ( - id: number, - data: Partial< - Omit - >, - ) => Promise; - deleteTranscription: ( - id: number, - ) => Promise; - getTranscriptionsCount: (search?: string) => Promise; - searchTranscriptions: ( - searchTerm: string, - limit?: number, - ) => Promise; + // Transcription Database API (moved to tRPC) on: (channel: string, callback: (...args: any[]) => void) => void; off: (channel: string, callback: (...args: any[]) => void) => void;