Conversation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: pladisdev <127021507+pladisdev@users.noreply.github.com>
Co-authored-by: pladisdev <127021507+pladisdev@users.noreply.github.com>
Co-authored-by: pladisdev <127021507+pladisdev@users.noreply.github.com>
Co-authored-by: pladisdev <127021507+pladisdev@users.noreply.github.com>
Co-authored-by: pladisdev <127021507+pladisdev@users.noreply.github.com>
…4b50-93c4-0e11b13594f4 Clarify error handler ordering is correct - no changes needed
Co-authored-by: pladisdev <127021507+pladisdev@users.noreply.github.com>
Co-authored-by: pladisdev <127021507+pladisdev@users.noreply.github.com>
…47b6-b204-5bf8892748d3 Extract magic numbers to named constants in audio playback code
…4606-8149-97ceaa22873d Use platform.system() instead of sys.platform for OS detection
Extract duplicated hex opacity calculation to utility function
Extract avatar active offset magic number into configurable setting
Fix audio reference cleanup on play() failure in popup mode
Fix race condition in popup avatar lifecycle
…into development
…into development
There was a problem hiding this comment.
Pull request overview
This PR bumps the app to v1.3.2 and focuses on improving Edge TTS reliability, along with some build/CI updates and small frontend routing/config tweaks.
Changes:
- Update Edge TTS dependency and add runtime retry/update logic for Edge TTS 403 failures.
- Adjust frontend default route to redirect
/to/settings, and fix Vite config__dirnameusage in ESM. - Update Windows CI to install WiX Toolset v5 and reduce/disable Docker build steps in CI.
Reviewed changes
Copilot reviewed 8 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| requirements.txt | Bumps edge-tts dependency version. |
| README.md | Updates changelog for v1.3.2. |
| frontend/vite.config.js | Adds ESM-compatible __dirname resolution for path aliases/output dir. |
| frontend/src/app.jsx | Adds a default route redirect from / to /settings. |
| frontend/package-lock.json | Updates lockfile entries from dependency refresh. |
| deployment/ChatYapper.wxs | Bumps MSI product version to 1.3.2. |
| deployment/build_msi.py | Extends WiX extension detection to include global extensions. |
| backend/version.py | Bumps backend version to 1.3.2. |
| backend/modules/tts.py | Adds Edge TTS 403 retry and attempts to update edge-tts at runtime. |
| .github/workflows/build-and-release.yml | Moves CI to WiX v5 and disables Docker build/push to speed up CI. |
Files not reviewed (1)
- frontend/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import uuid | ||
| import time | ||
| import sys | ||
| import subprocess |
There was a problem hiding this comment.
subprocess is imported but never used in this module; it should be removed to avoid lint warnings and keep imports minimal.
| import subprocess |
| # Track edge-tts update attempts to avoid repeated updates | ||
| _edge_tts_update_attempted = False | ||
|
|
||
| async def try_update_edge_tts(): | ||
| """Attempt to update edge-tts package when API compatibility issues occur""" | ||
| global _edge_tts_update_attempted | ||
|
|
||
| if _edge_tts_update_attempted: | ||
| logger.info("edge-tts update already attempted this session, skipping") | ||
| return False | ||
|
|
||
| _edge_tts_update_attempted = True | ||
| logger.info("Attempting to update edge-tts package to fix API compatibility...") | ||
|
|
||
| try: | ||
| # Run pip upgrade in subprocess | ||
| python_exe = sys.executable | ||
| result = await asyncio.create_subprocess_exec( | ||
| python_exe, "-m", "pip", "install", "--upgrade", "edge-tts", | ||
| stdout=asyncio.subprocess.PIPE, | ||
| stderr=asyncio.subprocess.PIPE | ||
| ) | ||
| stdout, stderr = await result.communicate() | ||
|
|
||
| if result.returncode == 0: | ||
| logger.info(f"edge-tts successfully updated: {stdout.decode()}") | ||
|
|
||
| # Reload the edge_tts module | ||
| try: | ||
| import importlib | ||
| global edge_tts | ||
| if edge_tts: | ||
| importlib.reload(edge_tts) | ||
| logger.info("edge-tts module reloaded successfully") | ||
| else: | ||
| import edge_tts as new_edge_tts | ||
| edge_tts = new_edge_tts | ||
| logger.info("edge-tts module imported successfully") | ||
| return True | ||
| except Exception as e: | ||
| logger.warning(f"edge-tts updated but module reload failed: {e}") | ||
| logger.info("Restart the application to use the updated edge-tts") | ||
| return False | ||
| else: | ||
| logger.error(f"edge-tts update failed: {stderr.decode()}") | ||
| return False | ||
| except Exception as e: | ||
| logger.error(f"Failed to update edge-tts: {e}") | ||
| return False |
There was a problem hiding this comment.
Auto-updating dependencies at runtime via pip install --upgrade edge-tts has significant security and operational risks (downloads arbitrary code, requires network + write permissions, and will likely fail in the PyInstaller-built executable environment). Prefer surfacing a clear error with upgrade instructions (or pin/ship a compatible version) rather than attempting an in-app upgrade.
| # Track edge-tts update attempts to avoid repeated updates | |
| _edge_tts_update_attempted = False | |
| async def try_update_edge_tts(): | |
| """Attempt to update edge-tts package when API compatibility issues occur""" | |
| global _edge_tts_update_attempted | |
| if _edge_tts_update_attempted: | |
| logger.info("edge-tts update already attempted this session, skipping") | |
| return False | |
| _edge_tts_update_attempted = True | |
| logger.info("Attempting to update edge-tts package to fix API compatibility...") | |
| try: | |
| # Run pip upgrade in subprocess | |
| python_exe = sys.executable | |
| result = await asyncio.create_subprocess_exec( | |
| python_exe, "-m", "pip", "install", "--upgrade", "edge-tts", | |
| stdout=asyncio.subprocess.PIPE, | |
| stderr=asyncio.subprocess.PIPE | |
| ) | |
| stdout, stderr = await result.communicate() | |
| if result.returncode == 0: | |
| logger.info(f"edge-tts successfully updated: {stdout.decode()}") | |
| # Reload the edge_tts module | |
| try: | |
| import importlib | |
| global edge_tts | |
| if edge_tts: | |
| importlib.reload(edge_tts) | |
| logger.info("edge-tts module reloaded successfully") | |
| else: | |
| import edge_tts as new_edge_tts | |
| edge_tts = new_edge_tts | |
| logger.info("edge-tts module imported successfully") | |
| return True | |
| except Exception as e: | |
| logger.warning(f"edge-tts updated but module reload failed: {e}") | |
| logger.info("Restart the application to use the updated edge-tts") | |
| return False | |
| else: | |
| logger.error(f"edge-tts update failed: {stderr.decode()}") | |
| return False | |
| except Exception as e: | |
| logger.error(f"Failed to update edge-tts: {e}") | |
| return False | |
| # Track edge-tts update attempts to avoid repeated update guidance logs | |
| _edge_tts_update_attempted = False | |
| async def try_update_edge_tts(): | |
| """Log manual remediation guidance instead of attempting a runtime package update.""" | |
| global _edge_tts_update_attempted | |
| if _edge_tts_update_attempted: | |
| logger.info("edge-tts upgrade guidance already provided this session, skipping") | |
| return False | |
| _edge_tts_update_attempted = True | |
| python_exe = sys.executable or "python" | |
| logger.error( | |
| "Automatic runtime updates for edge-tts are disabled for security and reliability " | |
| "reasons. Please upgrade the dependency outside the application and restart it." | |
| ) | |
| logger.info( | |
| f"Manual upgrade command: {python_exe} -m pip install --upgrade edge-tts" | |
| ) | |
| return False |
| # Helper function to attempt synthesis with retry logic | ||
| async def attempt_synthesis(voice_id: str, retry_on_403: bool = True): | ||
| try: | ||
| communicate = edge_tts.Communicate(job.text, voice_id) | ||
| await communicate.save(outpath) | ||
| return True | ||
| except Exception as e: | ||
| # Check if it's a 403 error (API compatibility issue) | ||
| error_str = str(e) | ||
| if "403" in error_str and "Invalid response status" in error_str and retry_on_403: | ||
| logger.warning(f"Edge TTS returned 403 error - API may need updating") | ||
| # Attempt to update edge-tts | ||
| if await try_update_edge_tts(): | ||
| logger.info("Retrying synthesis after edge-tts update...") | ||
| # Retry once after update (without further retries) | ||
| return await attempt_synthesis(voice_id, retry_on_403=False) | ||
| else: |
There was a problem hiding this comment.
New 403-retry path (including the edge-tts update attempt) is untested. There are existing pytest tests for TTS providers; add a unit test that mocks edge_tts.Communicate.save to raise the 403 error and asserts the retry behavior (and that the updater is called at most once).
| # Commented out to speed up CI - Docker build takes too long | ||
| # - name: Build and push Docker image | ||
| # uses: docker/build-push-action@v5 | ||
| # with: | ||
| # context: . | ||
| # file: ./docker/Dockerfile | ||
| # push: true | ||
| # tags: ${{ steps.meta.outputs.tags }} |
There was a problem hiding this comment.
The Docker build/push step is commented out, but the docker-build job still proceeds to generate release files and posts a PR comment claiming the image was built successfully. Either re-enable the build/push step or guard/disable the downstream steps so CI doesn't report a Docker image/tag that doesn't exist.
✅ Windows Build SuccessfulExecutable: Build Status
Download the artifacts from the workflow run to test before merging. Once merged to |
🐳 Docker Image Built SuccessfullyImage: Test this PR with Docker:docker pull ghcr.io/pladisdev/chat-yapper:pr-93efe05
docker run -d \
--name chat-yapper-pr \
-p 8069:8008 \
-e TWITCH_CLIENT_ID=your_id \
-e TWITCH_CLIENT_SECRET=your_secret \
ghcr.io/pladisdev/chat-yapper:pr-93efe05Access at: http://localhost:8069 The Docker image will be published to the GitHub Container Registry when merged to |
No description provided.