Update main.py
Browse files
main.py
CHANGED
@@ -2,53 +2,63 @@ import os
|
|
2 |
import logging
|
3 |
import asyncio
|
4 |
import nest_asyncio
|
5 |
-
|
6 |
-
|
7 |
-
from huggingface_hub import InferenceClient, login
|
8 |
-
import langid
|
9 |
|
10 |
# Import Telegram bot components
|
11 |
from telegram import Update, Bot
|
12 |
from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
# -------------------------
|
15 |
# Configure logging
|
16 |
# -------------------------
|
17 |
-
logging.basicConfig(
|
18 |
-
format="%(asctime)s - %(levelname)s - %(message)s", level=logging.INFO
|
19 |
-
)
|
20 |
logger = logging.getLogger(__name__)
|
21 |
|
22 |
# -------------------------
|
23 |
-
#
|
24 |
# -------------------------
|
25 |
-
|
26 |
-
if
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
-
login(token=HF_HUB_TOKEN)
|
30 |
-
client = InferenceClient(api_key=HF_HUB_TOKEN)
|
31 |
-
|
32 |
-
# Get Telegram Bot Token
|
33 |
-
TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
|
34 |
-
if not TOKEN:
|
35 |
-
raise ValueError("Missing Telegram Bot Token. Please set TELEGRAM_BOT_TOKEN.")
|
36 |
-
|
37 |
-
# Get Webhook Domain (e.g., your-space.hf.space)
|
38 |
-
WEBHOOK_DOMAIN = os.getenv("WEBHOOK_DOMAIN")
|
39 |
-
if not WEBHOOK_DOMAIN:
|
40 |
-
raise ValueError("Missing Webhook Domain. Please set WEBHOOK_DOMAIN.")
|
41 |
-
|
42 |
-
# Construct the full webhook URL.
|
43 |
-
# We use the Telegram bot token as a unique path.
|
44 |
-
WEBHOOK_URL = f"https://{WEBHOOK_DOMAIN}/{TOKEN}"
|
45 |
|
|
|
|
|
46 |
|
47 |
# -------------------------
|
48 |
-
#
|
49 |
# -------------------------
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
51 |
try:
|
|
|
52 |
lang, _ = langid.classify(user_input)
|
53 |
if lang == "he":
|
54 |
return "hebrew"
|
@@ -60,94 +70,103 @@ def detect_language(user_input: str):
|
|
60 |
logger.error(f"Language detection error: {e}")
|
61 |
return "unsupported"
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
if language == "hebrew":
|
71 |
-
|
72 |
-
content = "תענה בקצרה אבל תשתף את תהליך קבלת ההחלטות שלך, " + text
|
73 |
-
model = "microsoft/Phi-3.5-mini-instruct"
|
74 |
elif language == "english":
|
75 |
-
|
76 |
-
content = "keep it short but tell your decision making process, " + text
|
77 |
-
model = "mistralai/Mistral-Nemo-Instruct-2407"
|
78 |
else:
|
79 |
return "Sorry, I only support Hebrew and English."
|
80 |
|
81 |
-
|
82 |
-
|
83 |
try:
|
84 |
-
#
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
)
|
92 |
-
return completion.choices[0].message.content
|
93 |
except Exception as e:
|
94 |
-
logger.error(f"Error generating response: {e}")
|
95 |
return "Error: Could not generate response."
|
96 |
|
97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
# -------------------------
|
99 |
# Telegram Bot Handlers
|
100 |
# -------------------------
|
101 |
async def start(update: Update, context: CallbackContext):
|
102 |
-
|
|
|
|
|
103 |
await update.message.reply_text("Hello! Tell me your decision-making issue, and I'll try to help.")
|
104 |
-
logger.info("
|
105 |
|
106 |
|
107 |
async def handle_message(update: Update, context: CallbackContext):
|
|
|
|
|
|
|
|
|
108 |
user_text = update.message.text
|
109 |
-
logger.info(f"
|
110 |
-
|
111 |
-
# Generate a response using our Hugging Face chat logic.
|
112 |
-
response_text = generate_response(user_text)
|
113 |
logger.info(f"Generated response: {response_text}")
|
114 |
-
|
115 |
await update.message.reply_text(response_text)
|
116 |
|
117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
# -------------------------
|
119 |
# Main function to run the Telegram Bot using Webhook mode
|
120 |
# -------------------------
|
121 |
async def main():
|
122 |
-
# Build the
|
123 |
-
application = Application.builder().token(
|
124 |
|
125 |
-
# Add
|
126 |
application.add_handler(CommandHandler("start", start))
|
127 |
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
|
128 |
|
129 |
logger.info("Starting bot in webhook mode...")
|
130 |
print("Starting bot in webhook mode...")
|
131 |
|
132 |
-
# Run the bot
|
133 |
-
# The bot will listen on all interfaces (0.0.0.0) at port 7860.
|
134 |
-
# Telegram will send updates to WEBHOOK_URL.
|
135 |
await application.run_webhook(
|
136 |
-
listen="0.0.0.0",
|
137 |
-
port=7860,
|
138 |
-
url_path=
|
139 |
-
webhook_url=WEBHOOK_URL
|
140 |
)
|
141 |
|
142 |
-
|
143 |
# -------------------------
|
144 |
-
# Run the main function
|
145 |
# -------------------------
|
146 |
if __name__ == "__main__":
|
147 |
-
# Apply nest_asyncio to
|
148 |
nest_asyncio.apply()
|
149 |
loop = asyncio.get_event_loop()
|
150 |
-
|
151 |
try:
|
152 |
loop.run_until_complete(main())
|
153 |
except Exception as e:
|
|
|
2 |
import logging
|
3 |
import asyncio
|
4 |
import nest_asyncio
|
5 |
+
import requests
|
6 |
+
from hugchat import hugchat
|
|
|
|
|
7 |
|
8 |
# Import Telegram bot components
|
9 |
from telegram import Update, Bot
|
10 |
from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext
|
11 |
|
12 |
+
# -------------------------
|
13 |
+
# Load environment variables
|
14 |
+
# -------------------------
|
15 |
+
# Expected environment variables:
|
16 |
+
# TELEGRAM_BOT_TOKEN - Telegram bot token
|
17 |
+
# WEBHOOK_DOMAIN - example: your-space.hf.space
|
18 |
+
# HF_EMAIL and HF_PASSWORD
|
19 |
+
|
20 |
+
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
|
21 |
+
if not TELEGRAM_BOT_TOKEN:
|
22 |
+
raise ValueError("Missing TELEGRAM_BOT_TOKEN environment variable.")
|
23 |
+
|
24 |
+
WEBHOOK_DOMAIN = os.getenv("WEBHOOK_DOMAIN")
|
25 |
+
if not WEBHOOK_DOMAIN:
|
26 |
+
raise ValueError("Missing WEBHOOK_DOMAIN environment variable.")
|
27 |
+
|
28 |
# -------------------------
|
29 |
# Configure logging
|
30 |
# -------------------------
|
31 |
+
logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s", level=logging.INFO)
|
|
|
|
|
32 |
logger = logging.getLogger(__name__)
|
33 |
|
34 |
# -------------------------
|
35 |
+
# Set up Hugging Chat integration
|
36 |
# -------------------------
|
37 |
+
# Logs into Hugging Face or uses a fallback to get cookies.
|
38 |
+
if os.getenv("HF_EMAIL") and os.getenv("HF_PASSWORD"):
|
39 |
+
from hugchat.login import Login
|
40 |
+
logger.info("Logging into Hugging Face using provided credentials.")
|
41 |
+
sign = Login(os.getenv("HF_EMAIL"), os.getenv("HF_PASSWORD"))
|
42 |
+
cookies = sign.login()
|
43 |
+
else:
|
44 |
+
logger.info("No HF_EMAIL/HF_PASSWORD provided. Using fallback method to get cookies.")
|
45 |
+
cookies = requests.get("https://huggingface.co/chat/").cookies
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
+
# Create a ChatBot instance from the hugchat library.
|
49 |
+
chatbot = hugchat.ChatBot(cookies=cookies.get_dict())
|
50 |
|
51 |
# -------------------------
|
52 |
+
# Helper Functions
|
53 |
# -------------------------
|
54 |
+
|
55 |
+
def detect_language(user_input: str) -> str:
|
56 |
+
"""
|
57 |
+
Detect language using langid.
|
58 |
+
Returns 'hebrew' if Hebrew, 'english' if English, otherwise 'unsupported'.
|
59 |
+
"""
|
60 |
try:
|
61 |
+
import langid
|
62 |
lang, _ = langid.classify(user_input)
|
63 |
if lang == "he":
|
64 |
return "hebrew"
|
|
|
70 |
logger.error(f"Language detection error: {e}")
|
71 |
return "unsupported"
|
72 |
|
73 |
+
|
74 |
+
def generate_response_sync(message: str) -> str:
|
75 |
+
"""
|
76 |
+
Generate a response using Hugging Chat in a synchronous manner.
|
77 |
+
This function is blocking; we'll run it in an executor.
|
78 |
+
"""
|
79 |
+
language = detect_language(message)
|
80 |
if language == "hebrew":
|
81 |
+
prompt = "תענה בקצרה אבל תשתף את תהליך קבלת ההחלטות שלך, " + message
|
|
|
|
|
82 |
elif language == "english":
|
83 |
+
prompt = "keep it short but tell your decision making process, " + message
|
|
|
|
|
84 |
else:
|
85 |
return "Sorry, I only support Hebrew and English."
|
86 |
|
87 |
+
response_queue = ""
|
88 |
+
full_response = ""
|
89 |
try:
|
90 |
+
# The huggingchat.ChatBot.chat() method returns a generator (streaming tokens)
|
91 |
+
for resp in chatbot.chat(prompt, _stream_yield_all=True):
|
92 |
+
if resp and "token" in resp:
|
93 |
+
response_queue += resp["token"]
|
94 |
+
# Flush the response if it's long (optional, here we accumulate)
|
95 |
+
full_response = response_queue
|
96 |
+
return full_response
|
|
|
|
|
97 |
except Exception as e:
|
98 |
+
logger.error(f"Error generating response via Hugging Chat: {e}")
|
99 |
return "Error: Could not generate response."
|
100 |
|
101 |
|
102 |
+
async def generate_response(message: str) -> str:
|
103 |
+
"""
|
104 |
+
Asynchronous wrapper around generate_response_sync using run_in_executor.
|
105 |
+
"""
|
106 |
+
loop = asyncio.get_event_loop()
|
107 |
+
response = await loop.run_in_executor(None, generate_response_sync, message)
|
108 |
+
return response
|
109 |
+
|
110 |
+
|
111 |
# -------------------------
|
112 |
# Telegram Bot Handlers
|
113 |
# -------------------------
|
114 |
async def start(update: Update, context: CallbackContext):
|
115 |
+
"""
|
116 |
+
Handler for the /start command.
|
117 |
+
"""
|
118 |
await update.message.reply_text("Hello! Tell me your decision-making issue, and I'll try to help.")
|
119 |
+
logger.info("Received /start command.")
|
120 |
|
121 |
|
122 |
async def handle_message(update: Update, context: CallbackContext):
|
123 |
+
"""
|
124 |
+
Handler for incoming text messages.
|
125 |
+
It generates a response using the Hugging Chat integration.
|
126 |
+
"""
|
127 |
user_text = update.message.text
|
128 |
+
logger.info(f"Received message: {user_text}")
|
129 |
+
response_text = await generate_response(user_text)
|
|
|
|
|
130 |
logger.info(f"Generated response: {response_text}")
|
|
|
131 |
await update.message.reply_text(response_text)
|
132 |
|
133 |
|
134 |
+
# -------------------------
|
135 |
+
# Webhook Configuration for Telegram
|
136 |
+
# -------------------------
|
137 |
+
# Construct the full webhook URL.
|
138 |
+
# We use the bot token as the URL path for uniqueness.
|
139 |
+
WEBHOOK_URL = f"https://{WEBHOOK_DOMAIN}/{TELEGRAM_BOT_TOKEN}"
|
140 |
+
|
141 |
# -------------------------
|
142 |
# Main function to run the Telegram Bot using Webhook mode
|
143 |
# -------------------------
|
144 |
async def main():
|
145 |
+
# Build the Telegram Application.
|
146 |
+
application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
|
147 |
|
148 |
+
# Add handlers.
|
149 |
application.add_handler(CommandHandler("start", start))
|
150 |
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
|
151 |
|
152 |
logger.info("Starting bot in webhook mode...")
|
153 |
print("Starting bot in webhook mode...")
|
154 |
|
155 |
+
# Run the bot using webhook mode.
|
|
|
|
|
156 |
await application.run_webhook(
|
157 |
+
listen="0.0.0.0", # Listen on all interfaces.
|
158 |
+
port=7860, # Port to listen on – must match the exposed port in Dockerfile.
|
159 |
+
url_path=TELEGRAM_BOT_TOKEN, # Use the bot token as the URL path.
|
160 |
+
webhook_url=WEBHOOK_URL # Full webhook URL that Telegram will call.
|
161 |
)
|
162 |
|
|
|
163 |
# -------------------------
|
164 |
+
# Run the main function (handling event loop issues)
|
165 |
# -------------------------
|
166 |
if __name__ == "__main__":
|
167 |
+
# Apply nest_asyncio to support nested event loops (useful in HF Spaces).
|
168 |
nest_asyncio.apply()
|
169 |
loop = asyncio.get_event_loop()
|
|
|
170 |
try:
|
171 |
loop.run_until_complete(main())
|
172 |
except Exception as e:
|