refactor: move environment variables to docker-compose and remove example.env#75
Conversation
- Add CSS shadow variables for light and dark modes - Apply shadows to header card, main cards, and buttons - Add subtle hover animations with lift effect on buttons - Style transcript entries with shadows and rounded corners - Enhance visual hierarchy and modern design aesthetics 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add subtle opacity reduction (50%) for disabled buttons - Include not-allowed cursor for better UX indication - Prevent hover animations on disabled state - Clean, minimal approach without color changes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Slow down particle movement speed from 6 to 2 for subtler motion - Add organizational color variety to particles using brand palette - Keep original white connecting lines with full opacity unchanged - Particles now use: #2998D5, #265289, #75797C, #bba88e, #c42030, #FFFFFF 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed sun icon visibility in light mode (☀️) - Corrected CSS logic for checked/unchecked states - Light mode: sun icon on left with blue gradient - Dark mode: moon icon on right with gray gradient - Smooth transitions between states with proper icon positioning 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace flat colors with subtle linear gradients for visual depth - Add gradient backgrounds to app container, cards, and components - Enhance button styling with gradient backgrounds and hover effects - Improve transcript entries with gradient backgrounds - Maintain organizational color palette while adding modern visual appeal - Keep accessibility and contrast standards intact 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add professional styling to model selector dropdown - Implement proper focus and hover states with organizational colors - Use solid backgrounds for better cross-browser compatibility - Improve responsive layout with better spacing and alignment - Add consistent typography using Barlow font family - Support both light and dark theme modes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace plain #bba88e borders with subtle gradient border effects - Use CSS pseudo-elements for sophisticated gradient border technique - Fix rectangular shadow issue by moving shadows to pseudo-elements - Apply proper border-radius calculations for clean rounded corners - Add theme-aware gradient variations for light and dark modes - Improve visual depth and premium appearance of all cards 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove ugly red color (#c42030) from particle palette - Increase particle opacity from 1.0 to 0.9 for much sharper appearance - Make connecting lines more prominent (opacity 0.8, width 2.5px) - Use darker shade of #bba88e (#8a7c6b) for connecting lines - Reduce app background opacity to 50-60% so particles show through - Improve particle backgrounds with more contrasting gradients - Clean color palette: #2998D5, #265289, #75797C, #bba88e, #FFFFFF 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Convert recording, upload, and transcription buttons to discrete red design - Use #F4393B for discrete buttons with icon-only interface and tooltips - Implement prominent transcription button (#D32F2F) when file is uploaded - Add "Process Audio" text to transcription button for better UX clarity - Fix CSS specificity issues with \!important to override gradient backgrounds - Ensure consistent button sizing (2.5rem width) across all states - Support both light and dark mode themes with proper red color scheme 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace confusing MicOff icon with Square icon for stop recording - Fix recording timer vertical alignment with action buttons - Move recording indicator inside button group for better layout - Add smooth hover effects to transcript/summary tabs - Implement tab-like appearance with rounded top corners - Add subtle blue background and border hints on tab hover - Improve overall controls container alignment and spacing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Implement pause/resume recording functionality with MediaRecorder API - Add professional HTML5 audio player with timeline scrubbing and volume control - Enable manual control over when to process recorded audio (no auto-processing) - Add discard recording option for better user control - Improve button state management for different recording phases: * Default: [Mic] [Upload] [Process Audio] * Recording: [Pause] [Stop] [Process Audio] * Preview: [Trash] [Upload] [Process Audio] + Audio Player - Add visual feedback for paused recording state (orange dot, timer shows "(Paused)") - Style audio player to match app theme with custom controls - Handle proper cleanup of audio URLs to prevent memory leaks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Refactored Dockerfile to use multi-stage build with nginx - Added nginx.conf with production-ready configuration including gzip, security headers, and API proxying - Updated docker-compose.yml port mapping from 3000:3000 to 80:80 - Removed unnecessary volume mounts for frontend container - This addresses HTTPS requirements for getUserMedia API and improves production deployment 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove invalid 'must-revalidate' value from gzip_proxied directive - Change frontend port mapping from 80:80 to 3000:80 - Comment out GPU deployment configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add audio player that displays when file is uploaded - Allow users to preview uploaded audio before processing - Add discard functionality for uploaded files - Integrate same audio controls as recording feature - Auto-clear uploaded file after processing - Update button states to handle upload workflow 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace emoji trash icon with Trash2 React icon component - Change button style from btn-danger to btn-discrete for consistency - Add tooltip for better user experience - Use btn-icon class for consistent icon styling - Match visual style of other action buttons (mic, upload) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Automatically select meeting after successful audio processing - Set selectedMeetingId in both uploadFile and processAudio functions - Ensures transcript appears immediately without manual selection - Improves user experience by eliminating extra click step 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add pollJobStatus function to handle asynchronous job processing - Replace synchronous processing assumption with proper status checking - Handle backend responses that return 200 but indicate errors - Add user-friendly error messages for failed processing - Implement timeout protection (60 seconds max polling) - Support both immediate transcript and job polling workflows - Auto-select processed meeting when job completes successfully Fixes issue where loading bar didn't properly wait for job completion and backend errors weren't properly detected despite 200 HTTP status. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add separate location block for /jobs/ to handle sub-paths
- Fix routing for endpoints like /jobs/{uuid}/status and /jobs/{uuid}/transcript
- Maintain existing /jobs endpoint for job creation
- Ensure proper proxy_pass URLs for both patterns
- Add CORS handling for all job-related endpoints
Previously only /jobs was routed to backend, causing 404s for
status polling and other job management endpoints.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add \!important declarations to meeting button styles (.btn-past-1 through .btn-past-4) - Override both background-color and background properties to prevent base .btn interference - Force white text color with \!important for proper contrast - Update hover states with consistent darker shades - Apply fixes to both light and dark mode variants Previously meeting buttons were invisible in light mode due to CSS inheritance conflicts between base .btn styles and specific button colors. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add dark mode specific hover styling for model select dropdown - Change hover border color from blue to gold (#bba88e) in dark mode - Update focus state to match gold theme in dark mode - Maintain blue hover in light mode for consistency 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
… items - Increase CSS specificity by using .btn.btn-past-X selectors - Add \!important to color property in hover states - Override base .btn hover styles that were making buttons invisible - Ensure white text color is maintained in all states - Fix issue where non-selected meeting items weren't visible in light mode 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Increase text truncation limit from 20 to 35 characters - Expand button width from 15vw to 22vw for more text space - Add max-width (280px) and min-width (180px) for better responsiveness - Allow meeting names to display more characters before truncation - Improve readability of meeting titles in sidebar 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Change meeting button colors from simple 1-2-3-4 repeat pattern - Implement gradient pattern: 1-2-3-4-3-2-1-2-3-4-3-2... - Creates smooth visual flow from light to dark and back - Improves visual hierarchy and aesthetic appeal in meetings list - Pattern repeats every 6 buttons for consistent gradient effect 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove public /logs endpoint from backend API for security - Add PYTHONUNBUFFERED=1 to Docker backend service to fix log buffering - Backend logs will now appear properly in docker logs output 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Move environment variables from .env files into docker-compose.yml with defaults - Refactor USE_AUTH_TOKEN to HF_TOKEN for clarity (Hugging Face token) - Simplify LLM_API_URL to base URL only, move /v1/chat/completions to backend code - Remove env_file references from docker-compose services - Remove obsolete example.env file since vars are now in docker-compose.yml - Update backend to construct full API endpoint from base URL 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Summary of Changes
Hello @NotYuSheng, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
I've refactored the project's environment variable management to centralize configuration within docker-compose.yml, eliminating the need for separate .env files and providing sensible defaults. This change streamlines the deployment process and clarifies variable naming. Concurrently, I've significantly upgraded the frontend's deployment strategy by implementing a multi-stage Docker build with Nginx, enhancing performance and maintainability. These changes are complemented by a series of UI/UX improvements and a more robust audio processing workflow, including new recording controls and job status polling, to provide a smoother and more informative user experience.
Highlights
- Centralized Environment Variable Management: Environment variables such as
USE_AUTH_TOKEN,LLM_API_URL, andLLM_MODEL_NAMEhave been moved from separate.envfiles directly intodocker-compose.yml. This centralizes configuration with sensible defaults, simplifying the setup process for new developers and improving overall environment management. - Backend API Refinements and Variable Renaming: The backend's handling of the
LLM_API_URLhas been refined; it now expects a base URL, with the full/v1/chat/completionspath being constructed dynamically within thebackend/main.pycode. Additionally, theUSE_AUTH_TOKENvariable was renamed toHF_TOKENfor clearer identification of its purpose. The/logsendpoint was also removed. - Frontend Deployment Overhaul with Nginx: The frontend deployment strategy has been significantly overhauled to utilize a multi-stage Docker build with Nginx. This change improves performance by serving static files efficiently and aligns with best practices for production deployments. A new
nginx.conffile was introduced to manage routing, API proxying, and other web server configurations. - Enhanced User Interface and Experience: The user interface has received substantial updates, including new CSS variables, linear gradients, and shadows for a more modern aesthetic. Key UI elements such as a dark mode toggle, audio preview capabilities for both recorded and uploaded files, and refined recording controls (pause, resume, discard) have been added or improved, enhancing the overall user experience.
- Robust Audio Processing Workflow with Job Polling: The audio processing workflow has been made more robust. The frontend now supports pausing and resuming live recordings, and users can discard recorded audio or uploaded files before processing. A new job polling mechanism has been implemented to provide real-time feedback on the status of transcription jobs, improving the reliability and transparency of the audio processing pipeline.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Code Review
This pull request is a significant refactor that improves the project's deployment and environment variable management by moving configurations to docker-compose.yml and introducing a production-ready multi-stage Docker build for the frontend using nginx. The changes are generally positive, enhancing clarity and following best practices. However, I've identified a few critical issues, primarily in the backend, where the removal of a logging function breaks other parts of the application, and a hardcoded CUDA device setting could cause crashes without a GPU. There are also opportunities to improve maintainability in the nginx configuration and the React components by reducing code duplication and addressing the use of !important in the CSS.
| - frontend | ||
| deploy: | ||
| resources: | ||
| reservations: | ||
| devices: | ||
| - driver: nvidia | ||
| count: all | ||
| capabilities: [gpu] |
There was a problem hiding this comment.
The deploy configuration for GPU resources has been commented out. However, backend/main.py still has DEVICE = "cuda:0" hardcoded on line 49. If the service is deployed on a machine without a GPU or without the docker daemon configured for GPU access, the backend will crash when trying to move the model to the CUDA device. The backend code should be made more robust to handle the absence of a GPU, for example by checking torch.cuda.is_available() and falling back to CPU if necessary, or by making the device configurable via an environment variable.
| base_url = str(os.getenv("LLM_API_URL")) | ||
| url = f"{base_url.rstrip('/')}/v1/chat/completions" |
There was a problem hiding this comment.
os.getenv("LLM_API_URL") can return None. str(None) evaluates to the string 'None', which will result in an invalid URL like 'None/v1/chat/completions'. This will cause a request error. It's better to check if the environment variable is set and handle the error gracefully.
| base_url = str(os.getenv("LLM_API_URL")) | |
| url = f"{base_url.rstrip('/')}/v1/chat/completions" | |
| base_url = os.getenv("LLM_API_URL") | |
| if not base_url or base_url == "CHANGEME": | |
| raise ValueError("LLM_API_URL environment variable not set or is default.") | |
| url = f"{base_url.rstrip('/')}/v1/chat/completions" |
| location /jobs/ { | ||
| proxy_pass http://backend:8000/jobs/; | ||
| proxy_set_header Host $host; | ||
| proxy_set_header X-Real-IP $remote_addr; | ||
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| proxy_set_header X-Forwarded-Proto $scheme; | ||
|
|
||
| # Handle preflight requests for CORS | ||
| if ($request_method = 'OPTIONS') { | ||
| add_header 'Access-Control-Allow-Origin' '*'; | ||
| add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH'; | ||
| add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization'; | ||
| add_header 'Access-Control-Max-Age' 1728000; | ||
| add_header 'Content-Type' 'text/plain; charset=utf-8'; | ||
| add_header 'Content-Length' 0; | ||
| return 204; | ||
| } | ||
| } | ||
|
|
||
| # Also handle exact /jobs endpoint (without trailing slash) | ||
| location /jobs { | ||
| proxy_pass http://backend:8000/jobs; | ||
| proxy_set_header Host $host; | ||
| proxy_set_header X-Real-IP $remote_addr; | ||
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| proxy_set_header X-Forwarded-Proto $scheme; | ||
|
|
||
| # Handle preflight requests for CORS | ||
| if ($request_method = 'OPTIONS') { | ||
| add_header 'Access-Control-Allow-Origin' '*'; | ||
| add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH'; | ||
| add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization'; | ||
| add_header 'Access-Control-Max-Age' 1728000; | ||
| add_header 'Content-Type' 'text/plain; charset=utf-8'; | ||
| add_header 'Content-Length' 0; | ||
| return 204; | ||
| } | ||
| } |
There was a problem hiding this comment.
The configuration for /jobs/ and /jobs is duplicated. You can combine these into a single location block to improve maintainability and reduce redundancy.
# Proxy API requests to backend
location /jobs/ {
proxy_pass http://backend:8000/jobs/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Handle preflight requests for CORS
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
# Also handle exact /jobs endpoint (without trailing slash)
location = /jobs {
proxy_pass http://backend:8000/jobs;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Handle preflight requests for CORS
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
|
|
||
| # Handle preflight requests for CORS | ||
| if ($request_method = 'OPTIONS') { | ||
| add_header 'Access-Control-Allow-Origin' '*'; |
There was a problem hiding this comment.
Using a wildcard * for Access-Control-Allow-Origin is overly permissive and can pose a security risk. It's recommended to restrict this to the specific domain of your frontend application in a production environment. You should consider using a variable like $http_origin and validating it against a whitelist of allowed origins.
| .btn.btn-past-1 { | ||
| background-color: #2998d5 !important; | ||
| background: #2998d5 !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| [data-theme="dark"] .btn-past-1 { | ||
| background-color: #2998d5; | ||
| color: #fff; | ||
| [data-theme="dark"] .btn.btn-past-1 { | ||
| background-color: #2998d5 !important; | ||
| background: #2998d5 !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| .btn-past-2 { | ||
| background-color: #2880bb; | ||
| color: #fff; | ||
| .btn.btn-past-2 { | ||
| background-color: #2880bb !important; | ||
| background: #2880bb !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| [data-theme="dark"] .btn-past-2 { | ||
| background-color: #2880bb; | ||
| color: #fff; | ||
| [data-theme="dark"] .btn.btn-past-2 { | ||
| background-color: #2880bb !important; | ||
| background: #2880bb !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| .btn-past-3 { | ||
| background-color: #2769a2; | ||
| color: #fff; | ||
| .btn.btn-past-3 { | ||
| background-color: #2769a2 !important; | ||
| background: #2769a2 !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| [data-theme="dark"] .btn-past-3 { | ||
| background-color: #2769a2; | ||
| color: #fff; | ||
| [data-theme="dark"] .btn.btn-past-3 { | ||
| background-color: #2769a2 !important; | ||
| background: #2769a2 !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| .btn-past-4 { | ||
| background-color: #265289; | ||
| color: #fff; | ||
| .btn.btn-past-4 { | ||
| background-color: #265289 !important; | ||
| background: #265289 !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| [data-theme="dark"] .btn-past-4 { | ||
| background-color: #265289; | ||
| color: #fff; | ||
| [data-theme="dark"] .btn.btn-past-4 { | ||
| background-color: #265289 !important; | ||
| background: #265289 !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| .btn-past-1:hover { | ||
| background-color: #1b75bb; | ||
| .btn.btn-past-1:hover { | ||
| background-color: #1b75bb !important; | ||
| background: #1b75bb !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| .btn-past-2:hover { | ||
| background-color: #4a9fd0; | ||
| .btn.btn-past-2:hover { | ||
| background-color: #1e6a9b !important; | ||
| background: #1e6a9b !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| .btn-past-3:hover { | ||
| background-color: #4783b8; | ||
| .btn.btn-past-3:hover { | ||
| background-color: #1e5288 !important; | ||
| background: #1e5288 !important; | ||
| color: #fff !important; | ||
| } | ||
|
|
||
| .btn-past-4:hover { | ||
| background-color: #3b6daa; | ||
| .btn.btn-past-4:hover { | ||
| background-color: #1e3f70 !important; | ||
| background: #1e3f70 !important; | ||
| color: #fff !important; | ||
| } |
There was a problem hiding this comment.
The use of !important is generally discouraged as it can lead to CSS that is difficult to maintain and debug. It seems to be used here to override the base button styles. Consider refactoring the CSS to achieve the desired styling through higher specificity or by restructuring the selectors to avoid the need for !important.
| // eslint-disable-next-line no-unused-vars | ||
| const [isPlayingRecording, setIsPlayingRecording] = useState(false); | ||
| // eslint-disable-next-line no-unused-vars | ||
| const [isPlayingUpload, setIsPlayingUpload] = useState(false); |
There was a problem hiding this comment.
| const uploadFile = async () => { | ||
| if (!selectedFile) return; | ||
| speakerColorMap.current = {}; | ||
| setLoading(true); | ||
| const formData = new FormData(); | ||
| formData.append("file", selectedFile); | ||
|
|
||
| try { | ||
| const formData = new FormData(); | ||
| formData.append("file", selectedFile); | ||
|
|
||
| fetch(`${API_BASE_URL}/jobs`, { | ||
| method: "POST", | ||
| body: formData, | ||
| }) | ||
| .then((result) => result.json()) | ||
| .then((data) => { | ||
| setTranscript( | ||
| Array.isArray(data.transcript) | ||
| ? processTranscriptWithSpeakerIds(data.transcript) | ||
| : [], | ||
| ); | ||
| const response = await fetch(`${API_BASE_URL}/jobs`, { | ||
| method: "POST", | ||
| body: formData, | ||
| }); | ||
|
|
||
| const data = await response.json(); | ||
|
|
||
| // Check if the response indicates success and has expected data | ||
| if (data.error || (!data.uuid && !data.transcript)) { | ||
| throw new Error(data.error || 'Invalid response from server'); | ||
| } | ||
|
|
||
| // If we get a transcript immediately, use it | ||
| if (data.transcript && Array.isArray(data.transcript)) { | ||
| setTranscript(processTranscriptWithSpeakerIds(data.transcript)); | ||
| setSelectedMeetingId(data.uuid); | ||
| fetchSummary(data.uuid); | ||
| fetchMeetingList(); | ||
| setLoading(false); | ||
| }) | ||
| .catch((err) => { | ||
| console.error("Failed to fetch transcription.", err); | ||
| setLoading(false); | ||
| }); | ||
| } else if (data.uuid) { | ||
| // Otherwise, poll for status | ||
| await pollJobStatus(data.uuid); | ||
| } else { | ||
| throw new Error('No transcript or job ID returned'); | ||
| } | ||
|
|
||
| setSelectedFile(null); | ||
| } catch (err) { | ||
| console.error("Failed to process uploaded file:", err); | ||
| alert(`Failed to process file: ${err.message}`); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }; | ||
|
|
||
| const processAudio = async (audioBlob) => { | ||
| setIsProcessing(true); | ||
| const formData = new FormData(); | ||
| formData.append("file", audioBlob); | ||
|
|
||
| try { | ||
| const formData = new FormData(); | ||
| formData.append("file", audioBlob); | ||
|
|
||
| fetch(`${API_BASE_URL}/jobs`, { | ||
| method: "POST", | ||
| body: formData, | ||
| }) | ||
| .then((result) => result.json()) | ||
| .then((data) => { | ||
| setTranscript( | ||
| Array.isArray(data.transcript) | ||
| ? processTranscriptWithSpeakerIds(data.transcript) | ||
| : [], | ||
| ); | ||
| const response = await fetch(`${API_BASE_URL}/jobs`, { | ||
| method: "POST", | ||
| body: formData, | ||
| }); | ||
|
|
||
| const data = await response.json(); | ||
|
|
||
| // Check if the response indicates success and has expected data | ||
| if (data.error || (!data.uuid && !data.transcript)) { | ||
| throw new Error(data.error || 'Invalid response from server'); | ||
| } | ||
|
|
||
| // If we get a transcript immediately, use it | ||
| if (data.transcript && Array.isArray(data.transcript)) { | ||
| setTranscript(processTranscriptWithSpeakerIds(data.transcript)); | ||
| setSelectedMeetingId(data.uuid); | ||
| fetchSummary(data.uuid); | ||
| fetchMeetingList(); | ||
| setIsProcessing(false); | ||
| }) | ||
| .catch((err) => { | ||
| console.error("Failed to fetch transcription -", err); | ||
| setIsProcessing(false); | ||
| }); | ||
| } else if (data.uuid) { | ||
| // Otherwise, poll for status | ||
| await pollJobStatus(data.uuid); | ||
| } else { | ||
| throw new Error('No transcript or job ID returned'); | ||
| } | ||
| } catch (err) { | ||
| console.error("Failed to process recorded audio:", err); | ||
| alert(`Failed to process recording: ${err.message}`); | ||
| } finally { | ||
| setIsProcessing(false); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Summary
This PR refactors environment variable management by moving variables from .env files into docker-compose.yml with sensible defaults, improving container orchestration and simplifying deployment.
Changes Made
Context / Rationale
This refactor improves the deployment experience by:
Related Docs or References
General Checklist