-
Notifications
You must be signed in to change notification settings - Fork 6
Add speaker management frontend page #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,172 @@ | ||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * Proxy routes for the diarization/speaker recognition service. | ||||||||||||||||||||||||||||||||||||
| * Forwards requests to the diarization service (default: http://localhost:8085). | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
| import type { Request, Response } from "express"; | ||||||||||||||||||||||||||||||||||||
| import { authenticateOr401 } from "../lib/auth/core.server.ts"; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Get diarization service URL from environment or use default | ||||||||||||||||||||||||||||||||||||
| const DIARIZATION_SERVICE_URL = ( | ||||||||||||||||||||||||||||||||||||
| Deno.env.get("DIARIZATION_SERVER_URL") || | ||||||||||||||||||||||||||||||||||||
| Deno.env.get("SPEAKER_SERVICE_URL") || | ||||||||||||||||||||||||||||||||||||
| "http://localhost:8085" | ||||||||||||||||||||||||||||||||||||
| ).replace(/\/$/, ""); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * Proxy handler for diarization service requests. | ||||||||||||||||||||||||||||||||||||
| * Supports both GET and POST requests, forwarding to the speaker recognition service. | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
| export async function apiDiarizationProxyHandler( | ||||||||||||||||||||||||||||||||||||
| req: Request, | ||||||||||||||||||||||||||||||||||||
| res: Response | ||||||||||||||||||||||||||||||||||||
| ): Promise<void> { | ||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||
| // Authenticate the request | ||||||||||||||||||||||||||||||||||||
| await authenticateOr401(req, res); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Extract the path after /api/diarization | ||||||||||||||||||||||||||||||||||||
| const subPath = req.params[0] || ""; | ||||||||||||||||||||||||||||||||||||
| const targetUrl = `${DIARIZATION_SERVICE_URL}/${subPath}`; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Build query string if present | ||||||||||||||||||||||||||||||||||||
| const queryString = new URLSearchParams(req.query as Record<string, string>).toString(); | ||||||||||||||||||||||||||||||||||||
| const fullUrl = queryString ? `${targetUrl}?${queryString}` : targetUrl; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| console.log(`[diarization-proxy] ${req.method} ${fullUrl}`); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Prepare headers (forward auth if needed, but diarization service is internal) | ||||||||||||||||||||||||||||||||||||
| const headers: Record<string, string> = { | ||||||||||||||||||||||||||||||||||||
| "Accept": "application/json", | ||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Handle different request types | ||||||||||||||||||||||||||||||||||||
| let body: BodyInit | undefined; | ||||||||||||||||||||||||||||||||||||
| const contentType = req.headers["content-type"] || ""; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (req.method !== "GET" && req.method !== "HEAD") { | ||||||||||||||||||||||||||||||||||||
| if (contentType.includes("multipart/form-data")) { | ||||||||||||||||||||||||||||||||||||
| // For multipart requests, we need to reconstruct the form data | ||||||||||||||||||||||||||||||||||||
| // This is tricky with Express - we'll pass through the raw request | ||||||||||||||||||||||||||||||||||||
| // Actually, since Express parses the body, we need to handle this differently | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // For file uploads, we need to handle this specially | ||||||||||||||||||||||||||||||||||||
| // The frontend should send directly to the diarization service for file uploads | ||||||||||||||||||||||||||||||||||||
| // Or we need to use a middleware like multer | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // For now, let's handle JSON requests and simple form data | ||||||||||||||||||||||||||||||||||||
| res.status(400).json({ | ||||||||||||||||||||||||||||||||||||
| error: "File upload proxy not yet implemented. Please use direct upload to diarization service." | ||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+48
to
+59
|
||||||||||||||||||||||||||||||||||||
| // For multipart requests, we need to reconstruct the form data | |
| // This is tricky with Express - we'll pass through the raw request | |
| // Actually, since Express parses the body, we need to handle this differently | |
| // For file uploads, we need to handle this specially | |
| // The frontend should send directly to the diarization service for file uploads | |
| // Or we need to use a middleware like multer | |
| // For now, let's handle JSON requests and simple form data | |
| res.status(400).json({ | |
| error: "File upload proxy not yet implemented. Please use direct upload to diarization service." | |
| }); | |
| // Delegate multipart/form-data (file upload) handling to the dedicated | |
| // enrollment handler, which is implemented below in this file. | |
| // This avoids returning a misleading "not implemented" error while | |
| // reusing the existing logic for enrollment via file upload. | |
| await apiDiarizationEnrollHandler(req, res); |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error checking for "Unauthorized" by comparing error message strings is fragile. The authenticateOr401 function throws a Response object via permissionDenied, not an Error with message "Unauthorized". This catch block will never match. The error handler middleware already handles Response objects correctly (see errorHandler.ts line 55-62), so this check can be removed.
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as line 90-92: the "Unauthorized" error check will never match because authenticateOr401 throws a Response object, not an Error. This check can be removed as the error handler middleware will properly handle authentication failures.
| if (error instanceof Error && error.message === "Unauthorized") { | |
| return; | |
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -23,6 +23,7 @@ import { authJwtLoginHandler } from "@/routes/auth.jwt.login.ts"; | |||||
| import { wellKnownOauthAuthorizationServerHandler } from "@/routes/[.]well-known.oauth-authorization-server.ts"; | ||||||
| import { wellKnownOauthProtectedResourceHandler } from "@/routes/[.]well-known.oauth-protected-resource.ts"; | ||||||
| import { apiChatHandler } from "@/routes/api.chat.ts"; | ||||||
| import { apiDiarizationProxyHandler, apiDiarizationEnrollHandler } from "@/routes/api.diarization.ts"; | ||||||
|
||||||
| import { apiDiarizationProxyHandler, apiDiarizationEnrollHandler } from "@/routes/api.diarization.ts"; | |
| import { apiDiarizationProxyHandler } from "@/routes/api.diarization.ts"; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||
| import { Link, Navigate, Outlet, useLocation } from "react-router-dom"; | ||||||
| import { Clock, Home, Package, Settings, MessageSquare, Activity, Mic } from "lucide-react"; | ||||||
| import { Clock, Home, Package, Settings, MessageSquare, Activity, Mic, Users } from "lucide-react"; | ||||||
|
||||||
| import { Clock, Home, Package, Settings, MessageSquare, Activity, Mic, Users } from "lucide-react"; | |
| import { Clock, Package, Settings, MessageSquare, Activity, Mic, Users } from "lucide-react"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message suggests users should "use direct upload to diarization service", but this is misleading since the diarization service is an internal backend service not accessible to frontend clients. The frontend must go through the backend proxy for authentication. This error message should be removed once proper multipart handling is implemented.