neuralnode 2.0.2__tar.gz → 2.0.4__tar.gz
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.
- {neuralnode-2.0.2 → neuralnode-2.0.4}/PKG-INFO +1 -2
- {neuralnode-2.0.2 → neuralnode-2.0.4}/README.md +0 -1
- {neuralnode-2.0.2 → neuralnode-2.0.4}/docs/documentation.md +0 -1
- neuralnode-2.0.4/examples/horus_tq_ready_gguf.py +59 -0
- neuralnode-2.0.4/neuralnode_horus_replica_telegram.ipynb +404 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/pyproject.toml +1 -1
- neuralnode-2.0.4/replica_output_85218.mp3 +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/__init__.py +3 -1
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/integrations/slack.py +3 -4
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/integrations/telegram.py +46 -1
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/integrations/whatsapp.py +16 -7
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/horus.py +355 -50
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/replica.py +12 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/speech/__init__.py +32 -24
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/tts/__init__.py +40 -32
- neuralnode-2.0.4/src/neuralnode/utils/__init__.py +5 -0
- neuralnode-2.0.4/src/neuralnode/utils/dependencies.py +80 -0
- neuralnode-2.0.2/src/neuralnode/utils/__init__.py +0 -1
- {neuralnode-2.0.2 → neuralnode-2.0.4}/.env.example +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/.github/workflows/tests.yml +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/Dockerfile +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/LICENSE +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/docker-compose.yml +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/docs/ecosystem_plan.md +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/docs/replica_voice_ids.csv +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/docs/replica_voice_ids.md +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/docs/telegram_guide.md +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/agent_with_tools.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/basic_chat.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/01_basic_usage.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/02_with_token.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/03_one_liner.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/04_custom_cache.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/05_4bit_quantization.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/06_8bit_quantization.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/07_multi_gpu.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/08_flash_attention.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/09_data_types.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/10_generation_params.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/11_streaming.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/12_chat_templates.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/13_offline_mode.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/14_force_download.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/15_model_info.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/16_cpu_offloading.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/17_cpu_only.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/18_production_setup.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/19_gguf_4bit.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/20_gguf_5bit.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/21_gguf_6bit.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/22_gguf_8bit.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/23_gguf_16bit.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/24_list_models.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/25_interactive_chat.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_codes_camples/README.md +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_download_guide.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_examples.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/horus_transformers_features.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/local_models.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/neuralnode_v21_complete_demo.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/shade_model_with_tools.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/telegram_bot_demo.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/thinking_mode_example.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/tts_demo.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/turboquant_example.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/examples/v3_features.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/nn.md +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/publish.bat +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/publish.sh +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/requirements_shade.txt +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/scripts/setup.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/debug_import.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/agents/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/chains/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/config/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/core/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/core/openai_blocker.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/diagnostics/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/integrations/discord.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/memory/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/memory/advanced.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/prompts/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/base.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/ai21.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/anthropic.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/cohere.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/deepseek.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/fireworks.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/google.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/groq.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/mistral.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/perplexity.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat/together.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/chat_models.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/embeddings.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/local/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/local_providers.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/text_generation.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/providers/universal_local.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/rag/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/rag/loaders.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/reasoning/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/thinking.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/tools/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/tools/advanced.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/tools/multisearch.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/tools/system/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/tools/system/operations.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/tools/web/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/turboquant.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/utils/logger.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/utils/metrics.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/vectorstores/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/neuralnode/vision/__init__.py +0 -0
- {neuralnode-2.0.2 → neuralnode-2.0.4}/src/nn/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuralnode
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: Comprehensive AI Framework with 50+ LLM Providers, Advanced Agents, Chains, Memory, RAG, and 100+ Tools
|
|
5
5
|
Project-URL: Homepage, https://assem.cloud/
|
|
6
6
|
Project-URL: Documentation, https://neuralnode.readthedocs.io
|
|
@@ -243,7 +243,6 @@ Supported IDs currently include:
|
|
|
243
243
|
- `tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-Q6_K.gguf`
|
|
244
244
|
- `tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-Q8_0.gguf`
|
|
245
245
|
- `tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-F16.gguf`
|
|
246
|
-
- `tokenaii/horus-instruct`
|
|
247
246
|
|
|
248
247
|
## Replica TTS
|
|
249
248
|
|
|
@@ -133,7 +133,6 @@ Available Horus model IDs:
|
|
|
133
133
|
- `tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-Q6_K.gguf`
|
|
134
134
|
- `tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-Q8_0.gguf`
|
|
135
135
|
- `tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-F16.gguf`
|
|
136
|
-
- `tokenaii/horus-instruct`
|
|
137
136
|
|
|
138
137
|
## Replica
|
|
139
138
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Horus ready-GGUF usage (including TQ* variants).
|
|
2
|
+
|
|
3
|
+
Run:
|
|
4
|
+
python examples/horus_tq_ready_gguf.py
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
import neuralnode as nn
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main() -> None:
|
|
15
|
+
# Example TQ model id (replace with the real published TQ GGUF file when available)
|
|
16
|
+
tq_model_id = "tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-TQ3_1S.gguf"
|
|
17
|
+
q4_model_id = "tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-Q4_K_M.gguf"
|
|
18
|
+
|
|
19
|
+
# Optional: register TQ in Horus listed models for nicer discovery.
|
|
20
|
+
nn.HorusModel.register_gguf_variant(
|
|
21
|
+
model_id=tq_model_id,
|
|
22
|
+
name="Horus 1.0 4B (TurboQuant TQ3_1S)",
|
|
23
|
+
size="4B",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
print("Registered models:")
|
|
27
|
+
for model_id in [tq_model_id, q4_model_id]:
|
|
28
|
+
print("-", model_id)
|
|
29
|
+
|
|
30
|
+
# Use any ready GGUF model directly by model_id.
|
|
31
|
+
model = nn.HorusModel(
|
|
32
|
+
model_id=q4_model_id,
|
|
33
|
+
cache_dir=r"D:\Work Space\NeuralNode\hf_cache",
|
|
34
|
+
local_files_only=True,
|
|
35
|
+
suppress_warnings=True,
|
|
36
|
+
suppress_native_output=True,
|
|
37
|
+
).load()
|
|
38
|
+
|
|
39
|
+
response = model.chat([{"role": "user", "content": "Say: Horus ready GGUF works."}])
|
|
40
|
+
print("\nChat preview:")
|
|
41
|
+
print(response.content[:200])
|
|
42
|
+
model.unload()
|
|
43
|
+
|
|
44
|
+
# Quick benchmark helper (latency-oriented).
|
|
45
|
+
benchmark = nn.HorusModel.benchmark_variants(
|
|
46
|
+
model_ids=[q4_model_id],
|
|
47
|
+
prompt="Explain TurboQuant in one line.",
|
|
48
|
+
runs=2,
|
|
49
|
+
cache_dir=r"D:\Work Space\NeuralNode\hf_cache",
|
|
50
|
+
local_files_only=True,
|
|
51
|
+
max_new_tokens=48,
|
|
52
|
+
)
|
|
53
|
+
print("\nBenchmark:")
|
|
54
|
+
print(json.dumps(benchmark, ensure_ascii=False, indent=2))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
main()
|
|
59
|
+
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"metadata": {},
|
|
6
|
+
"source": [
|
|
7
|
+
"# NeuralNode v2.0.2 - Horus Q8 + Replica + Thinking Mode + Telegram\n",
|
|
8
|
+
"\n",
|
|
9
|
+
"This notebook demonstrates:\n",
|
|
10
|
+
"- Loading Horus Q8 model\n",
|
|
11
|
+
"- Replica TTS integration (Female EN-US)\n",
|
|
12
|
+
"- Interactive chat with voice output\n",
|
|
13
|
+
"- Thinking mode toggle\n",
|
|
14
|
+
"- Optional Telegram bot integration"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"cell_type": "markdown",
|
|
19
|
+
"metadata": {},
|
|
20
|
+
"source": [
|
|
21
|
+
"# Install NeuralNode v2.0.2 and all dependencies\n",
|
|
22
|
+
"!pip install neuralnode==2.0.2\n",
|
|
23
|
+
"\n",
|
|
24
|
+
"# Install Horus + Replica dependencies\n",
|
|
25
|
+
"!pip install llama-cpp-python huggingface-hub torch transformers\n",
|
|
26
|
+
"\n",
|
|
27
|
+
"# Install Replica TTS dependency\n",
|
|
28
|
+
"!pip install edge-tts>=6.1.0"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"cell_type": "code",
|
|
33
|
+
"execution_count": null,
|
|
34
|
+
"metadata": {},
|
|
35
|
+
"outputs": [],
|
|
36
|
+
"source": [
|
|
37
|
+
"# Install NeuralNode v2.0.2\n",
|
|
38
|
+
"!pip install neuralnode==2.0.2\n",
|
|
39
|
+
"\n",
|
|
40
|
+
"# Install Horus extras for GGUF support\n",
|
|
41
|
+
"!pip install llama-cpp-python huggingface-hub torch transformers"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"cell_type": "markdown",
|
|
46
|
+
"metadata": {},
|
|
47
|
+
"source": [
|
|
48
|
+
"## Step 2: Import Libraries"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"cell_type": "code",
|
|
53
|
+
"execution_count": null,
|
|
54
|
+
"metadata": {},
|
|
55
|
+
"outputs": [],
|
|
56
|
+
"source": [
|
|
57
|
+
"import neuralnode as nn\n",
|
|
58
|
+
"import os\n",
|
|
59
|
+
"import time\n",
|
|
60
|
+
"from IPython.display import Audio, display, clear_output"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"cell_type": "markdown",
|
|
65
|
+
"metadata": {},
|
|
66
|
+
"source": [
|
|
67
|
+
"## Step 3: Configuration"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"cell_type": "code",
|
|
72
|
+
"execution_count": null,
|
|
73
|
+
"metadata": {},
|
|
74
|
+
"outputs": [],
|
|
75
|
+
"source": [
|
|
76
|
+
"# Configuration\n",
|
|
77
|
+
"MODEL_ID = \"tokenaii/Hours-1.0-4B-GGUF/Horus-1.0-4B-Q8_0.gguf\" # Q8 version\n",
|
|
78
|
+
"CACHE_DIR = \"/content/neuralnode_models\" # Colab path\n",
|
|
79
|
+
"REPLICA_VOICE = \"replic-aria-language{en-us}\" # Female EN-US\n",
|
|
80
|
+
"TELEGRAM_TOKEN = \"8517902003:AAHgTvh353QekvWFKX3744yH4-72kfwfe9A\"\n",
|
|
81
|
+
"\n",
|
|
82
|
+
"# Options\n",
|
|
83
|
+
"ENABLE_THINKING = True # Toggle thinking mode\n",
|
|
84
|
+
"ENABLE_TELEGRAM = False # Toggle Telegram bot\n",
|
|
85
|
+
"\n",
|
|
86
|
+
"print(\"✅ Configuration loaded\")\n",
|
|
87
|
+
"print(f\"Model: {MODEL_ID}\")\n",
|
|
88
|
+
"print(f\"Voice: {REPLICA_VOICE}\")\n",
|
|
89
|
+
"print(f\"Thinking Mode: {ENABLE_THINKING}\")\n",
|
|
90
|
+
"print(f\"Telegram Bot: {ENABLE_TELEGRAM}\")"
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"cell_type": "markdown",
|
|
95
|
+
"metadata": {},
|
|
96
|
+
"source": [
|
|
97
|
+
"## Step 4: Load Horus Q8 Model"
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"cell_type": "code",
|
|
102
|
+
"execution_count": null,
|
|
103
|
+
"metadata": {},
|
|
104
|
+
"outputs": [],
|
|
105
|
+
"source": [
|
|
106
|
+
"# Create cache directory\n",
|
|
107
|
+
"os.makedirs(CACHE_DIR, exist_ok=True)\n",
|
|
108
|
+
"\n",
|
|
109
|
+
"# Load Horus model with all features\n",
|
|
110
|
+
"print(\"⏳ Loading Horus Q8 model...\")\n",
|
|
111
|
+
"print(\"This may take 5-10 minutes on first download...\")\n",
|
|
112
|
+
"\n",
|
|
113
|
+
"model = nn.HorusModel(\n",
|
|
114
|
+
" model_id=MODEL_ID,\n",
|
|
115
|
+
" device=\"cpu\",\n",
|
|
116
|
+
" cache_dir=CACHE_DIR,\n",
|
|
117
|
+
" n_ctx=8192, # Original context window\n",
|
|
118
|
+
" verbose=False\n",
|
|
119
|
+
").load()\n",
|
|
120
|
+
"\n",
|
|
121
|
+
"print(\"✅ Model loaded successfully!\")\n",
|
|
122
|
+
"print(f\"Context Window: 8192 tokens\")\n",
|
|
123
|
+
"print(f\"Chat Template: horus_unified\")"
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"cell_type": "markdown",
|
|
128
|
+
"metadata": {},
|
|
129
|
+
"source": [
|
|
130
|
+
"## Step 5: Setup Replica TTS"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"cell_type": "code",
|
|
135
|
+
"execution_count": null,
|
|
136
|
+
"metadata": {},
|
|
137
|
+
"outputs": [],
|
|
138
|
+
"source": [
|
|
139
|
+
"# Initialize Replica TTS\n",
|
|
140
|
+
"tts = nn.ReplicaTTS(voice_id=REPLICA_VOICE)\n",
|
|
141
|
+
"\n",
|
|
142
|
+
"# Test voice\n",
|
|
143
|
+
"print(\"🔊 Testing Replica TTS...\")\n",
|
|
144
|
+
"tts.save_to_file(\"Hello! I'm ready to chat with you.\", \"/content/test_voice.mp3\")\n",
|
|
145
|
+
"display(Audio(\"/content/test_voice.mp3\", autoplay=True))\n",
|
|
146
|
+
"print(\"✅ Voice test complete!\")"
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"cell_type": "markdown",
|
|
151
|
+
"metadata": {},
|
|
152
|
+
"source": [
|
|
153
|
+
"## Step 6: Setup Thinking Mode (Optional)"
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"cell_type": "code",
|
|
158
|
+
"execution_count": null,
|
|
159
|
+
"metadata": {},
|
|
160
|
+
"outputs": [],
|
|
161
|
+
"source": [
|
|
162
|
+
"if ENABLE_THINKING:\n",
|
|
163
|
+
" # Wrap model with thinking mode\n",
|
|
164
|
+
" thinker = nn.ThinkingMode(\n",
|
|
165
|
+
" model,\n",
|
|
166
|
+
" steps=[\"understand\", \"plan\", \"execute\", \"verify\"],\n",
|
|
167
|
+
" show_thinking=True,\n",
|
|
168
|
+
" concise=True,\n",
|
|
169
|
+
" max_tokens_per_step=100,\n",
|
|
170
|
+
" max_final_tokens=200\n",
|
|
171
|
+
" )\n",
|
|
172
|
+
" chat_model = thinker\n",
|
|
173
|
+
" print(\"🧠 Thinking Mode: ENABLED\")\n",
|
|
174
|
+
" print(\"Thinking will be shown between <think> tags\")\n",
|
|
175
|
+
"else:\n",
|
|
176
|
+
" chat_model = model\n",
|
|
177
|
+
" print(\"🧠 Thinking Mode: DISABLED\")"
|
|
178
|
+
]
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"cell_type": "markdown",
|
|
182
|
+
"metadata": {},
|
|
183
|
+
"source": [
|
|
184
|
+
"## Step 7: Chat Function with Voice Output"
|
|
185
|
+
]
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"cell_type": "code",
|
|
189
|
+
"execution_count": null,
|
|
190
|
+
"metadata": {},
|
|
191
|
+
"outputs": [],
|
|
192
|
+
"source": [
|
|
193
|
+
"def chat_with_voice(user_message, show_thinking=ENABLE_THINKING):\n",
|
|
194
|
+
" \"\"\"Chat with Horus and get voice response\"\"\"\n",
|
|
195
|
+
" \n",
|
|
196
|
+
" print(f\"\\n👤 You: {user_message}\")\n",
|
|
197
|
+
" print(\"🤖 Horus is thinking...\")\n",
|
|
198
|
+
" \n",
|
|
199
|
+
" if show_thinking and ENABLE_THINKING:\n",
|
|
200
|
+
" # Get response with thinking\n",
|
|
201
|
+
" response = chat_model.chat(user_message)\n",
|
|
202
|
+
" \n",
|
|
203
|
+
" # Display thinking\n",
|
|
204
|
+
" if response.thinking:\n",
|
|
205
|
+
" print(\"\\n🧠 <think>\")\n",
|
|
206
|
+
" print(response.thinking)\n",
|
|
207
|
+
" print(\"</think>\")\n",
|
|
208
|
+
" \n",
|
|
209
|
+
" text_response = response.content\n",
|
|
210
|
+
" else:\n",
|
|
211
|
+
" # Normal chat\n",
|
|
212
|
+
" messages = [{\"role\": \"user\", \"content\": user_message}]\n",
|
|
213
|
+
" response = model.chat(messages, max_new_tokens=200)\n",
|
|
214
|
+
" text_response = response.content\n",
|
|
215
|
+
" \n",
|
|
216
|
+
" # Generate audio\n",
|
|
217
|
+
" audio_file = f\"/content/response_{int(time.time())}.mp3\"\n",
|
|
218
|
+
" tts.save_to_file(text_response, audio_file)\n",
|
|
219
|
+
" \n",
|
|
220
|
+
" # Play audio\n",
|
|
221
|
+
" print(\"\\n🔊 Audio Response:\")\n",
|
|
222
|
+
" display(Audio(audio_file, autoplay=True))\n",
|
|
223
|
+
" \n",
|
|
224
|
+
" # Display text\n",
|
|
225
|
+
" print(\"\\n📝 Text Response:\")\n",
|
|
226
|
+
" print(f\"🤖 Horus: {text_response}\")\n",
|
|
227
|
+
" \n",
|
|
228
|
+
" return text_response\n",
|
|
229
|
+
"\n",
|
|
230
|
+
"print(\"✅ Chat function ready!\")"
|
|
231
|
+
]
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"cell_type": "markdown",
|
|
235
|
+
"metadata": {},
|
|
236
|
+
"source": [
|
|
237
|
+
"## Step 8: Interactive Chat (Try it!)"
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"cell_type": "code",
|
|
242
|
+
"execution_count": null,
|
|
243
|
+
"metadata": {},
|
|
244
|
+
"outputs": [],
|
|
245
|
+
"source": [
|
|
246
|
+
"# Example 1: Simple greeting\n",
|
|
247
|
+
"chat_with_voice(\"Hello! Introduce yourself briefly.\")"
|
|
248
|
+
]
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"cell_type": "code",
|
|
252
|
+
"execution_count": null,
|
|
253
|
+
"metadata": {},
|
|
254
|
+
"outputs": [],
|
|
255
|
+
"source": [
|
|
256
|
+
"# Example 2: Ask a question\n",
|
|
257
|
+
"chat_with_voice(\"What is 15 times 23?\")"
|
|
258
|
+
]
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"cell_type": "code",
|
|
262
|
+
"execution_count": null,
|
|
263
|
+
"metadata": {},
|
|
264
|
+
"outputs": [],
|
|
265
|
+
"source": [
|
|
266
|
+
"# Example 3: Complex question (shows thinking if enabled)\n",
|
|
267
|
+
"chat_with_voice(\"Explain how photosynthesis works in simple terms.\")"
|
|
268
|
+
]
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"cell_type": "markdown",
|
|
272
|
+
"metadata": {},
|
|
273
|
+
"source": [
|
|
274
|
+
"## Step 9: Custom Chat (Enter your own message)"
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"cell_type": "code",
|
|
279
|
+
"execution_count": null,
|
|
280
|
+
"metadata": {},
|
|
281
|
+
"outputs": [],
|
|
282
|
+
"source": [
|
|
283
|
+
"# Type your own message here\n",
|
|
284
|
+
"your_message = \"Tell me a short joke\" # Change this to your message\n",
|
|
285
|
+
"\n",
|
|
286
|
+
"chat_with_voice(your_message)"
|
|
287
|
+
]
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"cell_type": "markdown",
|
|
291
|
+
"metadata": {},
|
|
292
|
+
"source": [
|
|
293
|
+
"## Step 10: Telegram Bot Setup (Optional)"
|
|
294
|
+
]
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
"cell_type": "code",
|
|
298
|
+
"execution_count": null,
|
|
299
|
+
"metadata": {},
|
|
300
|
+
"outputs": [],
|
|
301
|
+
"source": [
|
|
302
|
+
"if ENABLE_TELEGRAM:\n",
|
|
303
|
+
" print(\"🤖 Setting up Telegram Bot...\")\n",
|
|
304
|
+
" \n",
|
|
305
|
+
" # Create NeuralNode instance\n",
|
|
306
|
+
" ai = nn.NeuralNode(\n",
|
|
307
|
+
" provider=\"horus\",\n",
|
|
308
|
+
" model=MODEL_ID,\n",
|
|
309
|
+
" model_settings={\"cache_dir\": CACHE_DIR}\n",
|
|
310
|
+
" )\n",
|
|
311
|
+
" \n",
|
|
312
|
+
" # Create agent with thinking\n",
|
|
313
|
+
" agent = ai.agent(\n",
|
|
314
|
+
" agent_type=\"simple\",\n",
|
|
315
|
+
" skills=[\"datetime\"],\n",
|
|
316
|
+
" thinking=ENABLE_THINKING\n",
|
|
317
|
+
" )\n",
|
|
318
|
+
" \n",
|
|
319
|
+
" # Configure bot\n",
|
|
320
|
+
" bot_config = nn.TelegramBotConfig(\n",
|
|
321
|
+
" token=TELEGRAM_TOKEN,\n",
|
|
322
|
+
" enable_voice=True,\n",
|
|
323
|
+
" enable_documents=True,\n",
|
|
324
|
+
" reply_mode=\"both\", # text + voice\n",
|
|
325
|
+
" voice_reply_voice_id=REPLICA_VOICE,\n",
|
|
326
|
+
" )\n",
|
|
327
|
+
" \n",
|
|
328
|
+
" # Create bot\n",
|
|
329
|
+
" bot = nn.TelegramBot(\n",
|
|
330
|
+
" token=TELEGRAM_TOKEN,\n",
|
|
331
|
+
" agent=agent,\n",
|
|
332
|
+
" config=bot_config,\n",
|
|
333
|
+
" )\n",
|
|
334
|
+
" \n",
|
|
335
|
+
" print(\"✅ Telegram bot configured!\")\n",
|
|
336
|
+
" print(\"\\n🚀 To start the bot, run:\")\n",
|
|
337
|
+
" print(\" bot.start()\")\n",
|
|
338
|
+
" print(\"\\n⚠️ Note: This will block the notebook until stopped\")\n",
|
|
339
|
+
" print(\" Press Ctrl+C to stop\")\n",
|
|
340
|
+
" \n",
|
|
341
|
+
" # Ask before starting\n",
|
|
342
|
+
" start = input(\"\\nStart Telegram bot now? (y/n): \").lower().strip()\n",
|
|
343
|
+
" if start == \"y\":\n",
|
|
344
|
+
" print(\"\\n🟢 Starting Telegram bot...\")\n",
|
|
345
|
+
" print(\"You can now chat with Horus on Telegram!\")\n",
|
|
346
|
+
" try:\n",
|
|
347
|
+
" bot.start()\n",
|
|
348
|
+
" except KeyboardInterrupt:\n",
|
|
349
|
+
" print(\"\\n🛑 Bot stopped by user\")\n",
|
|
350
|
+
"else:\n",
|
|
351
|
+
" print(\"⏸️ Telegram bot disabled. Set ENABLE_TELEGRAM = True to enable.\")"
|
|
352
|
+
]
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"cell_type": "markdown",
|
|
356
|
+
"metadata": {},
|
|
357
|
+
"source": [
|
|
358
|
+
"## Summary & Quick Reference"
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"cell_type": "code",
|
|
363
|
+
"execution_count": null,
|
|
364
|
+
"metadata": {},
|
|
365
|
+
"outputs": [],
|
|
366
|
+
"source": [
|
|
367
|
+
"# Quick reference\n",
|
|
368
|
+
"print(\"═\" * 60)\n",
|
|
369
|
+
"print(\"NeuralNode v2.0.2 - Horus + Replica Demo\")\n",
|
|
370
|
+
"print(\"═\" * 60)\n",
|
|
371
|
+
"print(\"\\n✅ Features Ready:\")\n",
|
|
372
|
+
"print(f\" • Model: Horus Q8 (8192 context)\")\n",
|
|
373
|
+
"print(f\" • Voice: Replica {REPLICA_VOICE}\")\n",
|
|
374
|
+
"print(f\" • Thinking: {'ON' if ENABLE_THINKING else 'OFF'}\")\n",
|
|
375
|
+
"print(f\" • Telegram: {'ON' if ENABLE_TELEGRAM else 'OFF'}\")\n",
|
|
376
|
+
"print(\"\\n📌 Quick Commands:\")\n",
|
|
377
|
+
"print(\" chat_with_voice('Your message')\")\n",
|
|
378
|
+
"print(\"\\n📝 Notes:\")\n",
|
|
379
|
+
"print(\" • Change ENABLE_THINKING to toggle thinking mode\")\n",
|
|
380
|
+
"print(\" • Change ENABLE_TELEGRAM to toggle Telegram bot\")\n",
|
|
381
|
+
"print(\" • Voice responses auto-play\")\n",
|
|
382
|
+
"print(\" • Text responses shown below audio\")\n",
|
|
383
|
+
"print(\"═\" * 60)"
|
|
384
|
+
]
|
|
385
|
+
}
|
|
386
|
+
],
|
|
387
|
+
"metadata": {
|
|
388
|
+
"colab": {
|
|
389
|
+
"gpuType": "T4",
|
|
390
|
+
"provenance": []
|
|
391
|
+
},
|
|
392
|
+
"kernelspec": {
|
|
393
|
+
"display_name": "Python 3",
|
|
394
|
+
"language": "python",
|
|
395
|
+
"name": "python3"
|
|
396
|
+
},
|
|
397
|
+
"language_info": {
|
|
398
|
+
"name": "python",
|
|
399
|
+
"version": "3.10.0"
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
"nbformat": 4,
|
|
403
|
+
"nbformat_minor": 4
|
|
404
|
+
}
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "neuralnode"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.4"
|
|
8
8
|
description = "Comprehensive AI Framework with 50+ LLM Providers, Advanced Agents, Chains, Memory, RAG, and 100+ Tools"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
Binary file
|
|
@@ -42,7 +42,7 @@ Quick Start::
|
|
|
42
42
|
text = sr.listen()
|
|
43
43
|
"""
|
|
44
44
|
|
|
45
|
-
__version__ = "2.0.
|
|
45
|
+
__version__ = "2.0.4"
|
|
46
46
|
__author__ = "NeuralNode Contributors"
|
|
47
47
|
|
|
48
48
|
# ── Core types ────────────────────────────────────────────────────────────────
|
|
@@ -227,6 +227,7 @@ except ImportError:
|
|
|
227
227
|
|
|
228
228
|
# Logging helper
|
|
229
229
|
from .utils.logger import get_logger, setup_logging
|
|
230
|
+
from .utils.dependencies import ensure_feature_dependencies
|
|
230
231
|
|
|
231
232
|
|
|
232
233
|
|
|
@@ -681,6 +682,7 @@ __all__ = [
|
|
|
681
682
|
|
|
682
683
|
# Utilities
|
|
683
684
|
"get_logger", "setup_logging",
|
|
685
|
+
"ensure_feature_dependencies",
|
|
684
686
|
"check_openai_blocked",
|
|
685
687
|
]
|
|
686
688
|
|
|
@@ -182,10 +182,9 @@ class SlackBot:
|
|
|
182
182
|
handler = SocketModeHandler(self.app, self.app_token)
|
|
183
183
|
handler.start()
|
|
184
184
|
else:
|
|
185
|
-
# HTTP mode
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
pass
|
|
185
|
+
# HTTP mode (built-in Bolt web server)
|
|
186
|
+
self.logger.info(f"Starting Slack HTTP mode on port {port}")
|
|
187
|
+
self.app.start(port=port)
|
|
189
188
|
|
|
190
189
|
|
|
191
190
|
def create_slack_bot(
|
|
@@ -14,6 +14,8 @@ import json
|
|
|
14
14
|
import os
|
|
15
15
|
import re
|
|
16
16
|
import tempfile
|
|
17
|
+
import urllib.error
|
|
18
|
+
import urllib.request
|
|
17
19
|
from dataclasses import dataclass, field
|
|
18
20
|
from datetime import datetime
|
|
19
21
|
from pathlib import Path
|
|
@@ -22,6 +24,7 @@ from typing import Any, Dict, List, Optional
|
|
|
22
24
|
from ..agents import _strip_thinking
|
|
23
25
|
from ..core import BaseAgent, ensure_llm_response
|
|
24
26
|
from ..rag import load_documents
|
|
27
|
+
from ..utils.dependencies import ensure_feature_dependencies
|
|
25
28
|
|
|
26
29
|
try:
|
|
27
30
|
from telegram import Update
|
|
@@ -32,6 +35,29 @@ except ImportError:
|
|
|
32
35
|
TELEGRAM_AVAILABLE = False
|
|
33
36
|
|
|
34
37
|
|
|
38
|
+
def _refresh_telegram_imports() -> None:
|
|
39
|
+
global TELEGRAM_AVAILABLE, Update, Application, CommandHandler, ContextTypes, MessageHandler, filters
|
|
40
|
+
try:
|
|
41
|
+
from telegram import Update as _Update
|
|
42
|
+
from telegram.ext import (
|
|
43
|
+
Application as _Application,
|
|
44
|
+
CommandHandler as _CommandHandler,
|
|
45
|
+
ContextTypes as _ContextTypes,
|
|
46
|
+
MessageHandler as _MessageHandler,
|
|
47
|
+
filters as _filters,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
Update = _Update
|
|
51
|
+
Application = _Application
|
|
52
|
+
CommandHandler = _CommandHandler
|
|
53
|
+
ContextTypes = _ContextTypes
|
|
54
|
+
MessageHandler = _MessageHandler
|
|
55
|
+
filters = _filters
|
|
56
|
+
TELEGRAM_AVAILABLE = True
|
|
57
|
+
except ImportError:
|
|
58
|
+
TELEGRAM_AVAILABLE = False
|
|
59
|
+
|
|
60
|
+
|
|
35
61
|
@dataclass
|
|
36
62
|
class TelegramSession:
|
|
37
63
|
"""User session in Telegram bot."""
|
|
@@ -67,6 +93,8 @@ class TelegramBotConfig:
|
|
|
67
93
|
document_chunk_limit: int = 6
|
|
68
94
|
max_document_chars: int = 16000
|
|
69
95
|
download_dir: Optional[str] = None
|
|
96
|
+
validate_token_on_start: bool = True
|
|
97
|
+
auto_install_deps: bool = True
|
|
70
98
|
|
|
71
99
|
|
|
72
100
|
class TelegramBot:
|
|
@@ -79,6 +107,10 @@ class TelegramBot:
|
|
|
79
107
|
config: Optional[TelegramBotConfig] = None,
|
|
80
108
|
system_prompt: Optional[str] = None,
|
|
81
109
|
):
|
|
110
|
+
self.config = config or TelegramBotConfig(token=token)
|
|
111
|
+
if not TELEGRAM_AVAILABLE and self.config.auto_install_deps:
|
|
112
|
+
ensure_feature_dependencies("telegram", auto_install=True)
|
|
113
|
+
_refresh_telegram_imports()
|
|
82
114
|
if not TELEGRAM_AVAILABLE:
|
|
83
115
|
raise ImportError(
|
|
84
116
|
"python-telegram-bot required. Install with: pip install python-telegram-bot"
|
|
@@ -86,7 +118,6 @@ class TelegramBot:
|
|
|
86
118
|
|
|
87
119
|
self.token = token
|
|
88
120
|
self.agent = agent
|
|
89
|
-
self.config = config or TelegramBotConfig(token=token)
|
|
90
121
|
self.system_prompt = system_prompt or "You are a helpful AI assistant on Telegram."
|
|
91
122
|
|
|
92
123
|
self.sessions: Dict[int, TelegramSession] = {}
|
|
@@ -139,6 +170,16 @@ class TelegramBot:
|
|
|
139
170
|
target.mkdir(parents=True, exist_ok=True)
|
|
140
171
|
return target
|
|
141
172
|
|
|
173
|
+
def validate_token(self, timeout: int = 10) -> bool:
|
|
174
|
+
"""Validate BotFather token against Telegram `getMe` endpoint."""
|
|
175
|
+
url = f"https://api.telegram.org/bot{self.token}/getMe"
|
|
176
|
+
try:
|
|
177
|
+
with urllib.request.urlopen(url, timeout=timeout) as response:
|
|
178
|
+
payload = json.loads(response.read().decode("utf-8", errors="ignore"))
|
|
179
|
+
return bool(payload.get("ok"))
|
|
180
|
+
except (urllib.error.URLError, TimeoutError, ValueError):
|
|
181
|
+
return False
|
|
182
|
+
|
|
142
183
|
async def _download_telegram_file(self, file_id: str, filename: str) -> Path:
|
|
143
184
|
telegram_file = await self.application.bot.get_file(file_id)
|
|
144
185
|
target = self._get_download_dir() / filename
|
|
@@ -482,6 +523,8 @@ class TelegramBot:
|
|
|
482
523
|
if self._running:
|
|
483
524
|
print("Bot is already running.")
|
|
484
525
|
return
|
|
526
|
+
if self.config.validate_token_on_start and not self.validate_token():
|
|
527
|
+
raise ValueError("Invalid Telegram bot token. Verify your BotFather token and network connectivity.")
|
|
485
528
|
|
|
486
529
|
self.application = Application.builder().token(self.token).build()
|
|
487
530
|
self._setup_handlers()
|
|
@@ -494,6 +537,8 @@ class TelegramBot:
|
|
|
494
537
|
self._running = True
|
|
495
538
|
|
|
496
539
|
async def run_bot():
|
|
540
|
+
if self.config.validate_token_on_start and not self.validate_token():
|
|
541
|
+
raise ValueError("Invalid Telegram bot token. Verify your BotFather token and network connectivity.")
|
|
497
542
|
self.application = Application.builder().token(self.token).build()
|
|
498
543
|
self._setup_handlers()
|
|
499
544
|
await self.application.initialize()
|
|
@@ -191,13 +191,22 @@ class WhatsAppWebBot:
|
|
|
191
191
|
"""
|
|
192
192
|
self.logger.info("Starting WhatsApp Web (unofficial)...")
|
|
193
193
|
self.logger.warning("Using unofficial library - may break with WhatsApp updates")
|
|
194
|
-
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
194
|
+
|
|
195
|
+
# Initialize client from the installed whatsapp library and run it
|
|
196
|
+
# using whichever startup method is available in that version.
|
|
197
|
+
self.client = WhatsAppClient()
|
|
198
|
+
|
|
199
|
+
start_methods = ("start", "run", "run_forever", "listen")
|
|
200
|
+
for method_name in start_methods:
|
|
201
|
+
method = getattr(self.client, method_name, None)
|
|
202
|
+
if callable(method):
|
|
203
|
+
self.logger.info(f"WhatsApp Web client starting via `{method_name}()`")
|
|
204
|
+
method()
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
raise RuntimeError(
|
|
208
|
+
"Unsupported whatsapp-web client API. "
|
|
209
|
+
"Expected one of: start(), run(), run_forever(), listen()."
|
|
201
210
|
)
|
|
202
211
|
|
|
203
212
|
|