Skip to content

save synced audios#4320

Closed
mdmohsin7 wants to merge 4 commits intomainfrom
sync-files-save
Closed

save synced audios#4320
mdmohsin7 wants to merge 4 commits intomainfrom
sync-files-save

Conversation

@mdmohsin7
Copy link
Copy Markdown
Member

Audio files that were synced through offline sync were not being saved (like how realtime audio is saved when save to cloud is on). This PR adds the ability to save the audio files of offline synced conversations

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 functionality to save audio files from offline synced conversations, making their storage consistent with real-time audio. The changes involve importing new utility functions, adding a new function upload_wav_as_audio_chunks to handle WAV file processing and uploading, and integrating this new function into the conversation processing logic for both new and updated conversations. The overall approach seems sound, and the suggested improvement regarding error handling is valid and has been retained.

Comment thread backend/routers/sync.py
Comment on lines +675 to +676
except Exception as e:
print(f"Error uploading audio chunks for conversation {conversation_id}: {e}")
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

Catching a generic Exception can mask unexpected issues and make debugging harder. It's generally better to catch more specific exceptions that you anticipate, such as IOError or wave.Error for file operations, or Exception as a last resort after specific ones. Additionally, using print for error messages is not ideal for production systems; consider using a proper logging mechanism (e.g., Python's logging module) which allows for configurable log levels and destinations.

Suggested change
except Exception as e:
print(f"Error uploading audio chunks for conversation {conversation_id}: {e}")
except (IOError, wave.Error, Exception) as e:
logging.error(f"Error uploading audio chunks for conversation {conversation_id}: {e}")

@mdmohsin7 mdmohsin7 requested a review from beastoin January 21, 2026 10:23
@beastoin
Copy link
Copy Markdown
Collaborator

beastoin commented Jan 23, 2026

@mdmohsin7 Blocking issues before merge: upload_wav_as_audio_chunks rebuilds and overwrites audio_files per segment (backend/routers/sync.py:668/backend/routers/sync.py:671) while process_segment runs in parallel (backend/routers/sync.py:710/backend/routers/sync.py:749), so the last thread can snapshot incomplete chunks and clobber a fuller list; this can leave conversations missing audio. Also chunk sizing assumes 16k mono via fixed sample_rate (backend/routers/sync.py:648), so if WAV metadata differs or the last chunk is short, timestamps/durations drift—derive bytes/sec from the WAV header and pad or store actual duration so audio_files stays accurate.

Can you run backend/test.sh and share a quick demo clip after fixing?


by AI for @beastoin

@mdmohsin7
Copy link
Copy Markdown
Member Author

Done @beastoin

Already tested locally as well (convos get created alongside the audio files stored correctly and playing them back works)

@beastoin
Copy link
Copy Markdown
Collaborator

beastoin commented Feb 2, 2026

@mdmohsin7 In backend/routers/sync.py:619 and the new call sites around process_segment/sync_local_files, we now upload private-cloud chunks unconditionally, which bypasses the user’s “save to cloud”/private-cloud setting used in realtime (backend/routers/pusher.py); this is a privacy/data-integrity risk—please gate upload_wav_as_audio_chunks and the subsequent create_audio_files_from_chunks update on users_db.get_user_private_cloud_sync_enabled(uid) (or the same check you use in pusher) so offline sync only writes when enabled. Can you update that and ping me for re-review?


by AI for @beastoin

@beastoin
Copy link
Copy Markdown
Collaborator

Hey @mdmohsin7, sorry about this — we're closing this one as not planned for now. Thanks for putting in the work, appreciate it.

@beastoin beastoin closed this Feb 17, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Hey @mdmohsin7 👋

Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request.

After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:

  • Project standards — Ensuring consistency across the codebase
  • User needs — Making sure changes align with what our users need
  • Code best practices — Maintaining code quality and maintainability
  • Project direction — Keeping aligned with our roadmap and vision

Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out.

Thank you for being part of the Omi community! 💜

@mdmohsin7
Copy link
Copy Markdown
Member Author

mdmohsin7 commented Feb 17, 2026

Hey @mdmohsin7, sorry about this — we're closing this one as not planned for now. Thanks for putting in the work, appreciate it.

But we need this, right now users can't have playback or download audio of conversations that were synced offline because the audio of those conversations isn't stored even if private cloud sync is enabled. Overall playback and download experience is inconsistent because of this issue

@beastoin
Copy link
Copy Markdown
Collaborator

Hey 👋 — thanks for putting this together! Before we can review, could you share a quick live demo (screenshot, screen recording, or terminal output) showing this working on your local or dev environment?

In the AI era, writing code is the easy part — what really makes a PR stand out is proof that it works end-to-end. A short video or even a screenshot goes a long way in helping reviewers feel confident about merging.

Feel free to update this PR whenever you have something to show. Thanks! 🙏

@mdmohsin7
Copy link
Copy Markdown
Member Author

@greptile-apps review

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 7, 2026

Greptile Summary

This PR extends the offline sync pipeline to save audio files to cloud storage when Private Cloud Sync is enabled, mirroring the realtime WebSocket path. Each decoded WAV segment is split into 5-second PCM16 chunks and uploaded via upload_audio_chunk to the GCS bucket; after all threads finish, create_audio_files_from_chunks groups the chunks and writes audio_files metadata back to Firestore.

Remaining concerns:

  • WAV format validation is non-aborting — the check at line 648 logs a warning but allows execution to continue. A stereo or non-16bit WAV file would be uploaded with incorrect encoding, corrupting the audio data for the entire saved conversation.

  • Silent exception swallowing in upload_wav_as_audio_chunks — the broad except Exception at line 675 swallows both file-read and GCS-write failures without any way for the caller to detect partial or complete failure. If an upload fails mid-stream, create_audio_files_from_chunks will return an incomplete or empty list, and the API response provides no indication of the error to the user.

Confidence Score: 2/5

  • Not safe to merge without addressing the WAV format abort logic and silent exception handling, which can cause silent audio data corruption and loss of user visibility into sync failures.
  • Two significant issues remain: (1) the WAV format mismatch check at line 648 only logs a warning and allows processing to continue, which can silently upload corrupt audio from stereo or non-16bit files with no way to detect the error; (2) the exception handler at line 675 swallows all upload failures with only a print statement, leaving both the caller and API response unaware of partial or complete sync failure, potentially resulting in incomplete audio_files metadata written to Firestore. Both issues can degrade user experience and data integrity without surfacing actionable errors.
  • backend/routers/sync.py — specifically the WAV format validation at lines 648-651 (should return early on mismatch) and the exception handling at lines 640-676 (should propagate or signal failure to caller)

Last reviewed commit: 80f81ba

Comment thread backend/routers/sync.py
Comment on lines +648 to +651
if n_channels != 1 or sampwidth != 2:
print(
f"Warning: WAV format mismatch for {wav_path} - expected mono PCM16, got {n_channels}ch {sampwidth*8}bit"
)
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.

WAV format validation only logs a warning but does not abort. A stereo or non-16bit file will continue to line 653 and be processed as if it were mono PCM16, corrupting the audio data. This should be a hard guard, not just a log:

Suggested change
if n_channels != 1 or sampwidth != 2:
print(
f"Warning: WAV format mismatch for {wav_path} - expected mono PCM16, got {n_channels}ch {sampwidth*8}bit"
)
if n_channels != 1 or sampwidth != 2:
print(
f"Error: WAV format mismatch for {wav_path} - expected mono PCM16, got {n_channels}ch {sampwidth*8}bit. Skipping upload."
)
return

Comment thread backend/routers/sync.py
Comment on lines +640 to +676
try:
with wave.open(wav_path, 'rb') as wav_file:
n_channels = wav_file.getnchannels()
sampwidth = wav_file.getsampwidth()
framerate = wav_file.getframerate()
n_frames = wav_file.getnframes()

# Validate WAV format matches expected PCM16 mono
if n_channels != 1 or sampwidth != 2:
print(
f"Warning: WAV format mismatch for {wav_path} - expected mono PCM16, got {n_channels}ch {sampwidth*8}bit"
)

pcm_data = wav_file.readframes(n_frames)

# Calculate chunk size in bytes using actual WAV parameters
# PCM16 mono: 2 bytes per sample
bytes_per_second = framerate * n_channels * sampwidth
chunk_size = int(chunk_duration * bytes_per_second)

# Split into chunks and upload
offset = 0
chunk_index = 0
while offset < len(pcm_data):
chunk_data = pcm_data[offset : offset + chunk_size]
chunk_timestamp = start_timestamp + (chunk_index * chunk_duration)

upload_audio_chunk(chunk_data, uid, conversation_id, chunk_timestamp)

offset += chunk_size
chunk_index += 1

# Free memory
del pcm_data

except Exception as e:
print(f"Error uploading audio chunks for conversation {conversation_id}: {e}")
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.

The entire function body is wrapped in a bare except Exception as e: print(...) that swallows all errors. If any upload_audio_chunk call fails (network timeout, permission error, bucket misconfiguration), the exception is silently caught, the loop exits, and the function returns with no indication of failure. The caller in process_segment (lines 717, 756) cannot detect this failure, so create_audio_files_from_chunks will later return an empty or partial list, and the conversation's audio_files will either not be written or be incomplete—with no error surfaced to the API response.

Either raise the exception or return a success/failure flag so the caller can report meaningful errors:

    except Exception as e:
        print(f"Error uploading audio chunks for conversation {conversation_id}: {e}")
        raise  # let the caller decide how to handle partial uploads

Previously the validation only logged a warning and continued processing,
which would silently corrupt audio data for non-mono or non-PCM16 files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@beastoin
Copy link
Copy Markdown
Collaborator

Hey @mdmohsin7 👋 Friendly reminder — this PR has been quiet for a bit. If you don't need further assistance from the CTO, feel free to go ahead and merge it. Let's close the loop and not let it go stale. Thanks!

@beastoin
Copy link
Copy Markdown
Collaborator

Don't let your PR go stale. Unfortunately, I won't review further PRs from the internal team proactively, so please reopen and mention others who have review permissions. It's important to keep PRs from going stale.

@beastoin beastoin closed this Apr 27, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Hey @mdmohsin7 👋

Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request.

After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:

  • Project standards — Ensuring consistency across the codebase
  • User needs — Making sure changes align with what our users need
  • Code best practices — Maintaining code quality and maintainability
  • Project direction — Keeping aligned with our roadmap and vision

Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out.

Thank you for being part of the Omi community! 💜

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.

2 participants