File size: 6,357 Bytes
5e0e3eb
 
 
 
12a002e
 
b2b218d
5e0e3eb
 
 
 
 
12a002e
 
 
 
 
b2b218d
12a002e
 
 
 
 
 
 
 
 
 
b2b218d
 
 
 
 
 
 
 
 
5e0e3eb
 
 
12a002e
5e0e3eb
 
ab7fa87
5e0e3eb
12a002e
5e0e3eb
12a002e
b2b218d
ddf7731
 
 
 
b2b218d
ddf7731
 
 
b2b218d
12a002e
 
5e0e3eb
b2b218d
5e0e3eb
12a002e
5e0e3eb
12a002e
 
 
 
 
5e0e3eb
12a002e
5e0e3eb
 
 
 
 
 
 
 
 
 
 
12a002e
 
 
 
 
 
 
5e0e3eb
12a002e
5e0e3eb
12a002e
5e0e3eb
 
 
12a002e
 
5e0e3eb
12a002e
 
 
 
 
 
 
5e0e3eb
12a002e
5e0e3eb
 
 
12a002e
 
 
 
 
 
 
 
 
5e0e3eb
 
 
 
12a002e
 
 
5e0e3eb
12a002e
5e0e3eb
 
 
12a002e
 
 
 
5e0e3eb
12a002e
 
5e0e3eb
 
 
 
12a002e
 
 
 
 
 
 
b2b218d
5e0e3eb
 
 
 
12a002e
 
5e0e3eb
12a002e
5e0e3eb
 
 
 
 
 
12a002e
5e0e3eb
12a002e
 
 
 
5e0e3eb
 
b2b218d
5e0e3eb
12a002e
5e0e3eb
 
12a002e
5e0e3eb
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import os
import logging
import asyncio
import nest_asyncio
import requests
from hugchat import hugchat
from hugchat.login import Login

# Import Telegram bot components
from telegram import Update, Bot
from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext

# -------------------------
# Load environment variables
# -------------------------
# Expected environment variables:
# TELEGRAM_BOT_TOKEN - Telegram bot token
# WEBHOOK_DOMAIN -  your-space.hf.space
# HF_EMAIL and HF_PASSWORD 

TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
if not TELEGRAM_BOT_TOKEN:
    raise ValueError("Missing TELEGRAM_BOT_TOKEN environment variable.")

WEBHOOK_DOMAIN = os.getenv("WEBHOOK_DOMAIN")
if not WEBHOOK_DOMAIN:
    raise ValueError("Missing WEBHOOK_DOMAIN environment variable.")

HF_EMAIL = os.getenv("HF_EMAIL")
if not HF_EMAIL:
    raise ValueError("Missing HF_EMAIL environment variable.")

HF_PASSWORD = os.getenv("HF_PASSWORD")
if not HF_PASSWORD:
    raise ValueError("Missing HF_PASSWORD environment variable.")


# -------------------------
# Configure logging
# -------------------------
logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s", level=logging.INFO)
logger = logging.getLogger(__name__)


# -------------------------
# Set up Hugging Chat integration
# -------------------------
# Logs into Hugging Face or uses a fallback to get cookies.
try:
    logger.info("Logging into Hugging Face using provided credentials.")
    sign = Login(HF_EMAIL, HF_PASSWORD)
    cookies = sign.login()
    print("cookies: ", cookies)
except Exception as e:
    logger.error(f"Error in Logging-into Hugging Chat: {e}")
    logger.info("Using fallback method to get cookies.")
    cookies = requests.get("https://huggingface.co/chat/").cookies
 
# Create a ChatBot instance from the hugchat library.
chatbot = hugchat.ChatBot(cookies=cookies.get_dict())


# -------------------------
# Helper Functions
# -------------------------
def detect_language(user_input: str) -> str:
    """
    Detect language using langid.
    Returns 'hebrew' if Hebrew, 'english' if English, otherwise 'unsupported'.
    """
    try:
        import langid
        lang, _ = langid.classify(user_input)
        if lang == "he":
            return "hebrew"
        elif lang == "en":
            return "english"
        else:
            return "unsupported"
    except Exception as e:
        logger.error(f"Language detection error: {e}")
        return "unsupported"

        
def generate_response_sync(message: str) -> str:
    """
    Generate a response using Hugging Chat in a synchronous manner.
    This function is blocking; we'll run it in an executor.
    """
    language = detect_language(message)
    if language == "hebrew":
        prompt = "תענה בקצרה אבל תשתף את תהליך קבלת ההחלטות שלך, " + message
    elif language == "english":
        prompt = "keep it short but tell your decision making process, " + message
    else:
        return "Sorry, I only support Hebrew and English."
    
    response_queue = ""
    full_response = ""
    try:
        # The huggingchat.ChatBot.chat() method returns a generator (streaming tokens)
        for resp in chatbot.chat(prompt, _stream_yield_all=True):
            if resp and "token" in resp:
                response_queue += resp["token"]
            # Flush the response if it's long (optional, here we accumulate)
        full_response = response_queue
        return full_response
    except Exception as e:
        logger.error(f"Error generating response via Hugging Chat: {e}")
        return "Error: Could not generate response."


async def generate_response(message: str) -> str:
    """
    Asynchronous wrapper around generate_response_sync using run_in_executor.
    """
    loop = asyncio.get_event_loop()
    response = await loop.run_in_executor(None, generate_response_sync, message)
    return response


# -------------------------
# Telegram Bot Handlers
# -------------------------
async def start(update: Update, context: CallbackContext):
    """
    Handler for the /start command.
    """
    await update.message.reply_text("Hello! Tell me your decision-making issue, and I'll try to help.")
    logger.info("Received /start command.")


async def handle_message(update: Update, context: CallbackContext):
    """
    Handler for incoming text messages.
    It generates a response using the Hugging Chat integration.
    """
    user_text = update.message.text
    logger.info(f"Received message: {user_text}")
    response_text = await generate_response(user_text)
    logger.info(f"Generated response: {response_text}")
    await update.message.reply_text(response_text)


# -------------------------
# Webhook Configuration for Telegram
# -------------------------
# Construct the full webhook URL.
# We use the bot token as the URL path for uniqueness.
WEBHOOK_URL = f"https://{WEBHOOK_DOMAIN}/{TELEGRAM_BOT_TOKEN}"

    
# -------------------------
# Main function to run the Telegram Bot using Webhook mode
# -------------------------
async def main():
    # Build the Telegram Application.
    application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()

    # Add handlers.
    application.add_handler(CommandHandler("start", start))
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))

    logger.info("Starting bot in webhook mode...")
    print("Starting bot in webhook mode...")

    # Run the bot using webhook mode.
    await application.run_webhook(
        listen="0.0.0.0",           # Listen on all interfaces.
        port=7860,                  # Port to listen on – must match the exposed port in Dockerfile.
        url_path=TELEGRAM_BOT_TOKEN,  # Use the bot token as the URL path.
        webhook_url=WEBHOOK_URL     # Full webhook URL that Telegram will call.
    )


# -------------------------
# Run the main function (handling event loop issues)
# -------------------------
if __name__ == "__main__":
    # Apply nest_asyncio to support nested event loops (useful in HF Spaces).
    nest_asyncio.apply()
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    except Exception as e:
        logger.error(f"Error in main loop: {e}")
        print(f"Error in main loop: {e}")