From da8260d1644ba7877dc96ddd6aeedd5d9e5e348c Mon Sep 17 00:00:00 2001 From: Michal Tuszowski Date: Wed, 8 Jul 2026 00:33:13 +0200 Subject: [PATCH] fix: voice_recognition uses constants for credentials and paths The cog did its own netrc read from a hardcoded /home/pi/.netrc at import time, crashing on any other host. Now: - constants.py: ASSEMBLYAI_API_KEY resolved like every other token (env ASSEMBLYAI_API_KEY -> netrc machine 'assemblyai' at CONJURER_NETRC_FILE); new TRANSCRIPTS_PATH (env CONJURER_TRANSCRIPTS_PATH, defaults next to the log file, created by the runtime layout) - voice_recognition_commands.py: drop the hardcoded netrc read and transcript dir; when the key is missing raise a clear RuntimeError so the guarded loader disables ONLY this cog with a readable reason - bot.env.example: document ASSEMBLYAI_API_KEY Co-Authored-By: Claude Opus 4.8 --- constants.py | 11 +++++++++++ docker/env/bot.env.example | 1 + voice_recognition_commands.py | 19 ++++++++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/constants.py b/constants.py index c59cd83..bf95609 100644 --- a/constants.py +++ b/constants.py @@ -189,6 +189,13 @@ DIR_PATH_SADOX = os.getenv("CONJURER_SADOX_DIR", DIR_PATH_SADOX) ENCODING = os.getenv("CONJURER_ENCODING", ENCODING) SEPARATOR_FILE_PATH = os.getenv("CONJURER_PATH_SEPARATOR", SEPARATOR_FILE_PATH) +# Voice-recognition transcript dumps. Defaults next to the log file (so on the +# Pi it lands in /home/pi/Conjurer/transcripts/, in docker under /data). +TRANSCRIPTS_PATH = os.getenv( + "CONJURER_TRANSCRIPTS_PATH", + os.path.join(os.path.dirname(LOGFILE) or ".", "transcripts") + os.sep, +) + FILE_SERVICE_ADDRESS = os.getenv("CONJURER_FILE_SERVICE", "http://192.168.1.15:5000") RADIO_HARBOR_ADDRESS = os.getenv("CONJURER_RADIO_HARBOR", "http://192.168.1.15:54321") SKIP_TRACK = os.getenv("CONJURER_SKIP_ENDPOINT", "/skip") @@ -247,6 +254,7 @@ def _ensure_runtime_layout() -> None: LOGSTORE, GRAPHICS_PATH, MUSIC_FOLDER, + TRANSCRIPTS_PATH, ): _ensure_dir(directory) @@ -327,6 +335,9 @@ else: TOKEN = _resolve_token("discord", "DISCORD_TOKEN") +# Voice recognition (AssemblyAI). None = the voice cog reports and disables. +ASSEMBLYAI_API_KEY = _resolve_token("assemblyai", "ASSEMBLYAI_API_KEY") + if spotipy: _spotify_creds = _load_netrc_credentials("spotipy") if _spotify_creds and SpotifyClientCredentials: diff --git a/docker/env/bot.env.example b/docker/env/bot.env.example index bcad6fa..000f6d9 100644 --- a/docker/env/bot.env.example +++ b/docker/env/bot.env.example @@ -6,6 +6,7 @@ CONJURER_NETRC_FILE=/secrets/.netrc # Option B: pass tokens directly (these take precedence over netrc). # DISCORD_TOKEN= # OPENAI_API_KEY= +# ASSEMBLYAI_API_KEY= # voice recognition; netrc machine 'assemblyai' works too # YOUTUBE_USERNAME= # YOUTUBE_PASSWORD= diff --git a/voice_recognition_commands.py b/voice_recognition_commands.py index 4ff2921..f408a33 100644 --- a/voice_recognition_commands.py +++ b/voice_recognition_commands.py @@ -1,6 +1,5 @@ import asyncio import logging -import netrc import time import wave @@ -9,11 +8,17 @@ import discord from discord.ext import commands, tasks, voice_recv from discord.opus import Decoder as OpusDecoder -# Replace with your API key -NETRC_FILE = "/home/pi/.netrc" -netrc_mod = netrc.netrc(NETRC_FILE) -authTokens = netrc_mod.authenticators("assemblyai") -aai.settings.api_key = authTokens[2] +from constants import ASSEMBLYAI_API_KEY, TRANSCRIPTS_PATH + +# Credentials come from constants (env ASSEMBLYAI_API_KEY, or the 'assemblyai' +# machine in the netrc at CONJURER_NETRC_FILE). Raising here means the guarded +# extension loader logs the reason and disables ONLY this cog. +if not ASSEMBLYAI_API_KEY: + raise RuntimeError( + "AssemblyAI API key not configured (netrc machine 'assemblyai' or " + "ASSEMBLYAI_API_KEY env) - voice recognition stays disabled" + ) +aai.settings.api_key = ASSEMBLYAI_API_KEY discord.opus._load_default() CHANNELS = OpusDecoder.CHANNELS @@ -23,7 +28,7 @@ SAMPLING_RATE = OpusDecoder.SAMPLING_RATE # rotate file after there is 0.5s between last received pcm for user. # delete messsages after user disconnect -LOCATION = "/home/pi/Conjurer/transcripts/" +LOCATION = TRANSCRIPTS_PATH class CommunicationObject: