Skip to content

fix: implement proper job status polling for audio processing#85

Merged
NotYuSheng merged 17 commits intomainfrom
fix/audio-processing-job-polling
Aug 7, 2025
Merged

fix: implement proper job status polling for audio processing#85
NotYuSheng merged 17 commits intomainfrom
fix/audio-processing-job-polling

Conversation

@NotYuSheng
Copy link
Copy Markdown
Owner

Summary

This PR implements robust job status polling for audio processing, ensuring reliable handling of long-running transcription tasks with proper error handling and timeout management.


Changes Made

  • Implement comprehensive job status polling mechanism
  • Add proper error handling for failed processing jobs
  • Include timeout management to prevent infinite polling
  • Enhanced user feedback during processing with status updates
  • Reliable transcript retrieval after job completion
  • Improved async/await pattern for better error propagation

Context / Rationale

The previous audio processing workflow lacked proper job polling, causing issues with:

  1. Long audio files that require extended processing time
  2. No feedback during processing, leading to user confusion
  3. Failed jobs not being handled gracefully
  4. Unreliable transcript retrieval after processing completion

This implementation provides:

  • Reliability: Proper polling ensures no lost jobs
  • User Experience: Clear feedback during processing
  • Error Handling: Graceful handling of failed jobs
  • Timeout Protection: Prevents infinite waiting

Related Docs or References

  • Addresses asynchronous job processing requirements
  • Improves reliability of audio transcription workflow

FastAPI Application Checklist (Delete if PR is not relevant)

  • Long-running operations support both job polling (e.g., via /status/{job_id} or /progress/{job_id}) and optional webhooks (if a callback_url is provided).
    • If callback_url is not provided, the client can retrieve status and results via polling endpoints.
  • Job results are persisted or recoverable if needed

General Checklist

  • I have tested these changes locally
  • I have updated relevant documentation or added comments where needed
  • I have linked relevant issues and tagged reviewers
  • I have followed coding conventions and naming standards

NotYuSheng and others added 17 commits August 6, 2025 09:07
- 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>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

This pull request significantly enhances the reliability and user experience of the audio processing workflow by introducing robust job status polling on the frontend. Concurrently, it modernizes the frontend deployment by transitioning to an Nginx-based serving architecture, improving performance and maintainability. The changes also include a comprehensive visual overhaul to provide a more polished and intuitive interface.

Highlights

  • Robust Audio Processing Polling: Implemented a comprehensive job status polling mechanism for audio processing, ensuring reliable handling of long-running transcription tasks. This includes proper error handling, timeout management, and enhanced user feedback during processing.
  • Frontend Architecture Shift to Nginx: The frontend Docker setup has been significantly refactored from a Node.js development server to a production-ready Nginx static file server. This involves a multi-stage Dockerfile, a new nginx.conf for serving React assets and proxying API requests, and updated Docker Compose configurations.
  • Enhanced User Experience for Audio Input: Introduced new UI controls for recording (start, pause, resume, stop), uploading, and processing audio. Users can now preview recorded or uploaded audio before processing, and there are dedicated buttons to discard recordings or uploads. The recording indicator now also shows a 'paused' state.
  • Visual and Theming Improvements: The application's CSS has undergone a substantial refresh, introducing new color variables, gradients for backgrounds and buttons, and improved styling for cards, buttons (including new discrete action buttons), and the dark mode toggle. The background particles animation colors have also been updated.
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

  1. 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.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a robust job status polling mechanism for audio processing, significantly improving the handling of long-running transcription tasks. The changes are well-structured, especially the move to async/await with try/catch blocks for better error handling and the major UI/UX enhancements for the recording and file upload flow.

My review focuses on a few key areas to further improve the implementation:

  • Configuration: Hardcoded polling parameters could be made more flexible.
  • Robustness: There's a potential logic gap in the polling function that could lead to misleading errors.
  • User Experience: Replacing alert() with in-app notifications would improve the user experience.
  • Best Practices: I've also included some suggestions regarding Docker and CSS best practices.

Overall, this is a strong contribution that makes the application much more reliable and user-friendly. Addressing the points below will help solidify this excellent work.

}
};

const pollJobStatus = async (uuid, maxAttempts = 30) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The polling parameters are hardcoded here (maxAttempts = 30) and within the setTimeout on line 411 (2000ms). This results in a fixed 60-second timeout, which may be insufficient for processing long audio files and could lead to a poor user experience if jobs appear to fail prematurely.

These values should be more flexible. Consider defining them as constants at the top of the file for easier configuration.

Comment on lines +398 to +405
if (transcriptData.full_transcript) {
const parsed = JSON.parse(transcriptData.full_transcript || "[]");
setTranscript(processTranscriptWithSpeakerIds(parsed));
setSelectedMeetingId(uuid);
fetchSummary(uuid);
fetchMeetingList();
return true;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There's a potential logic issue here. If the job status is 'completed' but transcriptData.full_transcript is not present in the response, the function will not return or throw. Instead, it will continue polling until it hits maxAttempts and then throw a misleading timeout error. You should handle this case explicitly by throwing an error if the transcript is missing after a job is marked as complete.

Suggested change
if (transcriptData.full_transcript) {
const parsed = JSON.parse(transcriptData.full_transcript || "[]");
setTranscript(processTranscriptWithSpeakerIds(parsed));
setSelectedMeetingId(uuid);
fetchSummary(uuid);
fetchMeetingList();
return true;
}
if (transcriptData.full_transcript) {
const parsed = JSON.parse(transcriptData.full_transcript || "[]");
setTranscript(processTranscriptWithSpeakerIds(parsed));
setSelectedMeetingId(uuid);
fetchSummary(uuid);
fetchMeetingList();
return true;
} else {
throw new Error('Job completed, but transcript data is missing.');
}

Comment thread frontend/Dockerfile
# Copy package files and install dependencies
COPY package.json package-lock.json ./
RUN npm ci
RUN npm ci --only=production
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using --only=production in a builder stage is unconventional. Build-time dependencies (like bundlers or test runners) are typically in devDependencies, and a build stage needs them. While this works for your current package.json setup where react-scripts is a production dependency, it's brittle and goes against standard practice.

For a builder stage, it's safer to install all dependencies to ensure the build process is robust.

RUN npm ci

}

.btn.btn-discrete {
background: var(--btn-discrete) !important;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of !important should be avoided as it breaks the natural CSS cascade and can make stylesheets difficult to maintain and debug. It's often a sign that the selector's specificity needs to be adjusted.

This comment also applies to other instances of !important in this file (e.g., lines 189, 194, 206, 214).

setSelectedFile(null);
} catch (err) {
console.error("Failed to process uploaded file:", err);
alert(`Failed to process file: ${err.message}`);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using window.alert() for error messages provides a poor user experience as it's a blocking and intrusive system dialog. This also occurs on line 496. It would be better to display errors gracefully within the application's UI, for example by using a state variable to hold the error message and rendering it in a dedicated component.

@NotYuSheng NotYuSheng merged commit 864e9bc into main Aug 7, 2025
1 check failed
@NotYuSheng NotYuSheng deleted the fix/audio-processing-job-polling branch August 7, 2025 02:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant