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 <noreply@anthropic.com>
This commit is contained in:
Michal Tuszowski
2026-07-08 00:33:13 +02:00
parent b266db5bf3
commit da8260d164
3 changed files with 24 additions and 7 deletions
+11
View File
@@ -189,6 +189,13 @@ DIR_PATH_SADOX = os.getenv("CONJURER_SADOX_DIR", DIR_PATH_SADOX)
ENCODING = os.getenv("CONJURER_ENCODING", ENCODING) ENCODING = os.getenv("CONJURER_ENCODING", ENCODING)
SEPARATOR_FILE_PATH = os.getenv("CONJURER_PATH_SEPARATOR", SEPARATOR_FILE_PATH) 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") 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") RADIO_HARBOR_ADDRESS = os.getenv("CONJURER_RADIO_HARBOR", "http://192.168.1.15:54321")
SKIP_TRACK = os.getenv("CONJURER_SKIP_ENDPOINT", "/skip") SKIP_TRACK = os.getenv("CONJURER_SKIP_ENDPOINT", "/skip")
@@ -247,6 +254,7 @@ def _ensure_runtime_layout() -> None:
LOGSTORE, LOGSTORE,
GRAPHICS_PATH, GRAPHICS_PATH,
MUSIC_FOLDER, MUSIC_FOLDER,
TRANSCRIPTS_PATH,
): ):
_ensure_dir(directory) _ensure_dir(directory)
@@ -327,6 +335,9 @@ else:
TOKEN = _resolve_token("discord", "DISCORD_TOKEN") 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: if spotipy:
_spotify_creds = _load_netrc_credentials("spotipy") _spotify_creds = _load_netrc_credentials("spotipy")
if _spotify_creds and SpotifyClientCredentials: if _spotify_creds and SpotifyClientCredentials:
+1
View File
@@ -6,6 +6,7 @@ CONJURER_NETRC_FILE=/secrets/.netrc
# Option B: pass tokens directly (these take precedence over netrc). # Option B: pass tokens directly (these take precedence over netrc).
# DISCORD_TOKEN= # DISCORD_TOKEN=
# OPENAI_API_KEY= # OPENAI_API_KEY=
# ASSEMBLYAI_API_KEY= # voice recognition; netrc machine 'assemblyai' works too
# YOUTUBE_USERNAME= # YOUTUBE_USERNAME=
# YOUTUBE_PASSWORD= # YOUTUBE_PASSWORD=
+12 -7
View File
@@ -1,6 +1,5 @@
import asyncio import asyncio
import logging import logging
import netrc
import time import time
import wave import wave
@@ -9,11 +8,17 @@ import discord
from discord.ext import commands, tasks, voice_recv from discord.ext import commands, tasks, voice_recv
from discord.opus import Decoder as OpusDecoder from discord.opus import Decoder as OpusDecoder
# Replace with your API key from constants import ASSEMBLYAI_API_KEY, TRANSCRIPTS_PATH
NETRC_FILE = "/home/pi/.netrc"
netrc_mod = netrc.netrc(NETRC_FILE) # Credentials come from constants (env ASSEMBLYAI_API_KEY, or the 'assemblyai'
authTokens = netrc_mod.authenticators("assemblyai") # machine in the netrc at CONJURER_NETRC_FILE). Raising here means the guarded
aai.settings.api_key = authTokens[2] # 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() discord.opus._load_default()
CHANNELS = OpusDecoder.CHANNELS 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. # rotate file after there is 0.5s between last received pcm for user.
# delete messsages after user disconnect # delete messsages after user disconnect
LOCATION = "/home/pi/Conjurer/transcripts/" LOCATION = TRANSCRIPTS_PATH
class CommunicationObject: class CommunicationObject: