alive-ai 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1102,7 +1102,12 @@ async def _send_response(self, response, emotion, chat_id, text, user_id="defaul
1102
1102
  await self.nervous.emit("chat_action_voice", {})
1103
1103
  vp = await self._voice.generate(response, mood=mood)
1104
1104
  if vp:
1105
- await self.nervous.emit("send_voice_file", {"file_path": vp, "chat_id": chat_id})
1105
+ await self.nervous.emit("send_voice_file", {
1106
+ "file_path": vp,
1107
+ "chat_id": chat_id,
1108
+ "fallback_text": response,
1109
+ "mood": mood,
1110
+ })
1106
1111
  return
1107
1112
  await self.nervous.emit("send_text", {"text": response, "mood": mood, "chat_id": chat_id})
1108
1113
 
@@ -359,12 +359,13 @@ class TelegramListener:
359
359
  print(f"[Telegram] Send text error: {e}")
360
360
 
361
361
  async def _send_voice_file(self, data: dict):
362
- """Send voice file (OGG format for Telegram)"""
362
+ """Send voice file, falling back to audio/text if Telegram rejects it."""
363
363
  if not self.app:
364
364
  return
365
365
 
366
366
  chat_id = data.get("chat_id", self.chat_id)
367
367
  file_path = data.get("file_path", "")
368
+ fallback_text = data.get("fallback_text", "")
368
369
 
369
370
  if not chat_id or not file_path:
370
371
  return
@@ -372,18 +373,32 @@ class TelegramListener:
372
373
  path = Path(file_path)
373
374
  if not path.exists():
374
375
  print(f"[Telegram] Voice file not found: {file_path}")
376
+ if fallback_text:
377
+ await self._send_text({"chat_id": chat_id, "text": fallback_text})
375
378
  return
376
379
 
377
380
  try:
378
- with open(path, "rb") as voice_file:
379
- await self.app.bot.send_voice(
381
+ if path.suffix.lower() == ".ogg":
382
+ with open(path, "rb") as voice_file:
383
+ await self.app.bot.send_voice(
384
+ chat_id=chat_id,
385
+ voice=voice_file,
386
+ caption=data.get("caption", "")
387
+ )
388
+ print(f"[Telegram] Sent voice: {file_path}")
389
+ return
390
+
391
+ with open(path, "rb") as audio_file:
392
+ await self.app.bot.send_audio(
380
393
  chat_id=chat_id,
381
- voice=voice_file,
394
+ audio=audio_file,
382
395
  caption=data.get("caption", "")
383
396
  )
384
- print(f"[Telegram] Sent voice: {file_path}")
397
+ print(f"[Telegram] Sent audio fallback: {file_path}")
385
398
  except Exception as e:
386
- print(f"[Telegram] Send voice error: {e}")
399
+ print(f"[Telegram] Send voice/audio error: {e}")
400
+ if fallback_text:
401
+ await self._send_text({"chat_id": chat_id, "text": fallback_text})
387
402
 
388
403
  async def _send_image(self, data: dict):
389
404
  """Send image file"""
@@ -8,6 +8,7 @@ import asyncio
8
8
  import re
9
9
  import tempfile
10
10
  import subprocess
11
+ import warnings
11
12
  from pathlib import Path
12
13
  from typing import Optional
13
14
  from concurrent.futures import ThreadPoolExecutor
@@ -113,17 +114,29 @@ class GTTS:
113
114
  tts.write_to_fp(mp3_buffer)
114
115
  mp3_buffer.seek(0)
115
116
 
116
- # Convert MP3 to OGG for Telegram
117
- # If pydub is available, convert to OGG
117
+ # Convert MP3 to OGG Opus for Telegram voice notes.
118
+ # pydub's default OGG codec can resolve to Vorbis, which Telegram
119
+ # does not want for voice notes and some ffmpeg builds do not ship.
118
120
  try:
121
+ warnings.filterwarnings("ignore", category=SyntaxWarning, module=r"pydub\..*")
119
122
  from pydub import AudioSegment
120
123
  audio = AudioSegment.from_mp3(mp3_buffer)
121
124
  ogg_buffer = io.BytesIO()
122
- audio.export(ogg_buffer, format="ogg")
125
+ audio.export(
126
+ ogg_buffer,
127
+ format="ogg",
128
+ codec="libopus",
129
+ bitrate="32k",
130
+ parameters=["-application", "voip"],
131
+ )
123
132
  ogg_buffer.seek(0)
124
133
  return ogg_buffer.read()
125
134
  except ImportError:
126
- # No pydub - return MP3, Telegram accepts it too
135
+ # No pydub - return MP3 and let the sender use send_audio.
136
+ mp3_buffer.seek(0)
137
+ return mp3_buffer.read()
138
+ except Exception as exc:
139
+ print(f"[GTTS] OGG Opus conversion failed, falling back to MP3: {exc}")
127
140
  mp3_buffer.seek(0)
128
141
  return mp3_buffer.read()
129
142
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alive-ai",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Local-first emotional AI runtime with memory, impulses, and a live dashboard.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://vindepemarte.github.io/alive-ai/",
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "alive-ai-runtime"
3
- version = "0.1.8"
3
+ version = "0.1.9"
4
4
  description = "Local-first emotional AI runtime with memory, impulses, and a live dashboard."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"