Add Discord-native hybrid front-end for Jarvis (bot + bridge)
Some checks failed
Release / semantic-release (push) Successful in 59s
tests / Unit tests (Linux, Python 3.11) (push) Successful in 13m45s
Release / build-linux (push) Failing after 7m47s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Some checks failed
Release / semantic-release (push) Successful in 59s
tests / Unit tests (Linux, Python 3.11) (push) Successful in 13m45s
Release / build-linux (push) Failing after 7m47s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Transform isair/jarvis into a Discord-controlled voice assistant running on the Ubuntu VNC desktop, keeping the mature ~39k-line Python brain intact. - bot/ (Node + bun, discord.js): /자비스 slash commands (ephemeral), voice channel join + voice receive/playback, pluggable VNC screen broadcast (selfbot live / noVNC / screenshot) - bridge/ (Python, Flask): wraps jarvis STT + run_reply_engine + Piper TTS behind a thin localhost HTTP API - .env.example, scripts/ (start_bridge/start_bot/dev), README rewrite, docs/language-comparison.md and docs/vnc-xfce-setup.md Language decision: hybrid (Python brain + Node/bun Discord layer) because Discord blocks bot video; native screen broadcast only works via a Node selfbot library.
This commit is contained in:
82
src/jarvis/__init__.py
Normal file
82
src/jarvis/__init__.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Jarvis Voice Assistant
|
||||
|
||||
A modular voice assistant with conversation memory, tool integration,
|
||||
and natural language processing capabilities.
|
||||
"""
|
||||
|
||||
# =============================================================================
|
||||
# PyInstaller Windows fix - MUST be at the very top before any audio imports
|
||||
# =============================================================================
|
||||
# When bundled with PyInstaller on Windows, sounddevice uses ctypes to locate
|
||||
# PortAudio. The DLLs are extracted to sys._MEIPASS but won't be found by default.
|
||||
#
|
||||
# Python 3.8+ on Windows changed DLL loading behavior - PATH is no longer searched
|
||||
# for DLLs loaded via ctypes. We must use os.add_dll_directory() instead.
|
||||
#
|
||||
# See: https://github.com/pyinstaller/pyinstaller/issues/7065
|
||||
# See: https://github.com/spatialaudio/python-sounddevice/issues/378
|
||||
# See: https://docs.python.org/3/whatsnew/3.8.html#ctypes
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
|
||||
if getattr(_sys, 'frozen', False) and _sys.platform == 'win32':
|
||||
_meipass = getattr(_sys, '_MEIPASS', None)
|
||||
if _meipass:
|
||||
# Method 1: os.add_dll_directory (Python 3.8+, the proper solution)
|
||||
# This explicitly adds the directory to the DLL search path for ctypes
|
||||
if hasattr(_os, 'add_dll_directory'):
|
||||
try:
|
||||
_os.add_dll_directory(_meipass)
|
||||
# Also add _sounddevice_data/portaudio-binaries if it exists
|
||||
_portaudio_path = _os.path.join(_meipass, '_sounddevice_data', 'portaudio-binaries')
|
||||
if _os.path.isdir(_portaudio_path):
|
||||
_os.add_dll_directory(_portaudio_path)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Method 2: Modify PATH (legacy fallback, helps with subprocess spawning)
|
||||
_path = _os.environ.get('PATH', '')
|
||||
if _meipass not in _path:
|
||||
_os.environ['PATH'] = _meipass + _os.pathsep + _path
|
||||
del _path
|
||||
del _meipass
|
||||
del _os, _sys
|
||||
# =============================================================================
|
||||
|
||||
# Suppress HuggingFace symlink cache warning on Windows.
|
||||
# Most Windows users don't have Developer Mode enabled, so HF falls back to
|
||||
# copying files instead of symlinking. This is fine — just noisier.
|
||||
import os as _os
|
||||
if not _os.environ.get("HF_HUB_DISABLE_SYMLINKS_WARNING"):
|
||||
_os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1"
|
||||
del _os
|
||||
|
||||
from .config import load_settings
|
||||
|
||||
|
||||
def get_version() -> tuple[str, str]:
|
||||
"""Get the application version and release channel.
|
||||
|
||||
Returns:
|
||||
tuple of (version_string, channel) where channel is 'stable' or 'develop'.
|
||||
When running from source without a build, returns ('dev-local', 'develop').
|
||||
"""
|
||||
try:
|
||||
from ._version import VERSION, RELEASE_CHANNEL
|
||||
return VERSION, RELEASE_CHANNEL
|
||||
except ImportError:
|
||||
return "dev-local", "develop"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Lazy entrypoint to avoid importing heavy modules at package import time.
|
||||
|
||||
Importing `jarvis.daemon` here prevents it from being added to sys.modules
|
||||
during package import, which avoids runpy warnings when executing
|
||||
`python -m jarvis.daemon`.
|
||||
"""
|
||||
from .daemon import main as _main
|
||||
_main()
|
||||
|
||||
__all__ = ["main", "load_settings", "get_version"]
|
||||
Reference in New Issue
Block a user