DeMaking commited on
Commit
12a002e
·
verified ·
1 Parent(s): 3960dc2

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +94 -75
main.py CHANGED
@@ -2,53 +2,63 @@ import os
2
  import logging
3
  import asyncio
4
  import nest_asyncio
5
-
6
- # Import the Hugging Face Inference Client and login function
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
- # Environment variables and login to Hugging Face
24
  # -------------------------
25
- HF_HUB_TOKEN = os.getenv("HUGGINGFACEHUB_API_TOKEN")
26
- if not HF_HUB_TOKEN:
27
- raise ValueError("Missing Hugging Face API token. Please set HUGGINGFACEHUB_API_TOKEN.")
 
 
 
 
 
 
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
- # Function to detect language
49
  # -------------------------
50
- def detect_language(user_input: str):
 
 
 
 
 
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
- # Function to generate response using Hugging Face Chat models
66
- # -------------------------
67
- def generate_response(text: str) -> str:
68
- language = detect_language(text)
69
-
70
  if language == "hebrew":
71
- # For Hebrew, prompt the model accordingly.
72
- content = "תענה בקצרה אבל תשתף את תהליך קבלת ההחלטות שלך, " + text
73
- model = "microsoft/Phi-3.5-mini-instruct"
74
  elif language == "english":
75
- # For English, use a different prompt.
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
- messages = [{"role": "user", "content": content}]
82
-
83
  try:
84
- # Call the chat completion API
85
- completion = client.chat.completions.create(
86
- model=model,
87
- messages=messages,
88
- max_tokens=2048,
89
- temperature=0.5,
90
- top_p=0.7
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
- # Respond to the /start command.
 
 
103
  await update.message.reply_text("Hello! Tell me your decision-making issue, and I'll try to help.")
104
- logger.info("Start command received.")
105
 
106
 
107
  async def handle_message(update: Update, context: CallbackContext):
 
 
 
 
108
  user_text = update.message.text
109
- logger.info(f"User message: {user_text}")
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 Application with the Telegram Bot Token.
123
- application = Application.builder().token(TOKEN).build()
124
 
125
- # Add command and message handlers.
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 in webhook mode.
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", # Listen on all interfaces.
137
- port=7860, # Port to listen on.
138
- url_path=TOKEN, # Use the bot token as the URL path.
139
- webhook_url=WEBHOOK_URL # Full webhook URL.
140
  )
141
 
142
-
143
  # -------------------------
144
- # Run the main function without closing a running event loop
145
  # -------------------------
146
  if __name__ == "__main__":
147
- # Apply nest_asyncio to allow nested event loops (needed in some HF Space environments).
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: