dynstat commited on
Commit
ca65b3f
·
verified ·
1 Parent(s): 5cba54f

Upload 4 files

Browse files

added files related to my project

Files changed (4) hide show
  1. Dockerfile +26 -0
  2. app.py +64 -0
  3. async_ai_voice.py +60 -0
  4. async_tgvoicebot.py +44 -0
Dockerfile ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # Use the official Python 3.9 image as the base for the container, providing the Python runtime environment.
3
+ FROM python:3.9
4
+
5
+ # Set the working directory inside the container to /code where all subsequent commands will be executed.
6
+ WORKDIR /code
7
+
8
+ # Copy the requirements.txt file from the host to the /code directory in the container. This file lists all the Python dependencies needed for the application.
9
+ COPY ./requirements.txt /code/requirements.txt
10
+
11
+ # Install the Python dependencies specified in requirements.txt using pip.
12
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
13
+ # --no-cache-dir prevents pip from caching packages, reducing the image size.
14
+ # --upgrade ensures that the latest compatible versions of the dependencies are installed.
15
+ # Example: If requirements.txt contains "fastapi==0.70.0", this command will install FastAPI version 0.70.0.
16
+
17
+ # Copy all files from the current directory on the host machine into the /code directory inside the container.
18
+ COPY . /code
19
+ # This includes the application code, configuration files, and any other necessary resources.
20
+
21
+ # Define the default command to run when the container starts.
22
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
23
+ # This command launches the Uvicorn server to serve the FastAPI application defined in app.py.
24
+ # --host "0.0.0.0" makes the server accessible externally.
25
+ # --port "7860" sets the port on which the application will listen.
26
+ # Example: Running this command starts the web server, allowing users to access the Telegram Voice Transcription Bot via port 7860.
app.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, Request, Response # Import FastAPI classes for creating the web app and handling requests/responses
2
+ from async_tgvoicebot import handle_message # Import the asynchronous function to handle incoming Telegram messages
3
+ import aiohttp # Import aiohttp for making asynchronous HTTP requests
4
+ import os # Import os module to access environment variables
5
+
6
+ app = FastAPI() # Initialize a FastAPI application instance
7
+
8
+ # Retrieve the Telegram bot token from environment variables
9
+ TELEGRAM_BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
10
+ # Retrieve the secret token for webhook security from environment variables
11
+ SECRET_TOKEN = os.environ.get('SECRET_TOKEN')
12
+
13
+ @app.post("/webhook")
14
+ async def webhook(request: Request):
15
+ """
16
+ Endpoint to receive webhook updates from Telegram.
17
+ Only processes the update if the secret token matches (if provided).
18
+ """
19
+ # Check if a secret token is set for additional security
20
+ if SECRET_TOKEN:
21
+ # Compare the secret token in the request headers with the expected SECRET_TOKEN
22
+ if request.headers.get('X-Telegram-Bot-Api-Secret-Token') != SECRET_TOKEN:
23
+ # If tokens do not match, respond with 403 Forbidden status
24
+ return Response(status_code=403)
25
+
26
+ # Parse the incoming JSON payload from the request
27
+ update = await request.json()
28
+ # Create an asynchronous HTTP session
29
+ async with aiohttp.ClientSession() as session:
30
+ # Call the handle_message function with the current session and the message part of the update
31
+ await handle_message(session, update.get('message', {}))
32
+ # Respond to Telegram that the update was received and processed successfully
33
+ return {"status": "ok"}
34
+
35
+ @app.get("/")
36
+ async def root():
37
+ """
38
+ Root endpoint to confirm that the Telegram Bot is running.
39
+ """
40
+ # Return a simple JSON message indicating the bot's status
41
+ return {"message": "Telegram Bot is running"}
42
+
43
+ # Endpoint to set webhook
44
+ @app.get("/set_webhook")
45
+ async def set_webhook():
46
+ """
47
+ Endpoint to set the Telegram webhook to the specified URL.
48
+ This should be called after deploying the bot to ensure Telegram sends updates to the correct endpoint.
49
+ """
50
+ # Construct the webhook URL using the SPACE_ID environment variable
51
+ webhook_url = f"https://{os.environ.get('SPACE_ID')}.hf.space/webhook"
52
+ # Telegram API URL to set the webhook
53
+ set_webhook_url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/setWebhook"
54
+ # Payload containing the webhook URL and the secret token for security
55
+ payload = {
56
+ "url": webhook_url,
57
+ "secret_token": SECRET_TOKEN
58
+ }
59
+ # Create an asynchronous HTTP session
60
+ async with aiohttp.ClientSession() as session:
61
+ # Send a POST request to Telegram's setWebhook API with the payload
62
+ async with session.post(set_webhook_url, json=payload) as response:
63
+ # Await and return the JSON response from Telegram confirming the webhook setup
64
+ return await response.json()
async_ai_voice.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import aiohttp # Import aiohttp for making asynchronous HTTP requests
2
+ import os # Import os to access environment variables
3
+ import json # Import json to handle JSON data
4
+ from typing import Dict, Any # Import type hints for better code clarity
5
+
6
+ # Define the API endpoint URL for the Hugging Face Whisper model
7
+ API_URL = "https://api-inference.huggingface.co/models/distil-whisper/distil-large-v3"
8
+
9
+ # Set up the headers with the authorization token retrieved from environment variables
10
+ headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_API_KEY')}"}
11
+
12
+ async def send_to_voice_AI(audio_data: bytes) -> Dict[str, Any]:
13
+ """
14
+ Asynchronously sends audio data to the Hugging Face Whisper model for transcription.
15
+
16
+ Args:
17
+ audio_data (bytes): The raw audio data to be transcribed.
18
+
19
+ Returns:
20
+ Dict[str, Any]: A dictionary containing the transcription result or error message.
21
+ """
22
+ print("Sending to voice AI") # Log the action for debugging purposes
23
+
24
+ # Create an asynchronous HTTP session using aiohttp
25
+ async with aiohttp.ClientSession() as session:
26
+ try:
27
+ # Asynchronously send a POST request to the API_URL with headers and audio data
28
+ async with session.post(API_URL, headers=headers, data=audio_data) as response:
29
+ # Await the response to ensure the request completes before proceeding
30
+ if response.status == 200:
31
+ # If the response is successful, await and return the JSON content
32
+ return await response.json()
33
+ else:
34
+ # If the response status is not 200, await the text of the response
35
+ error_text = await response.text()
36
+ # Parse the error text into a JSON object
37
+ error_json = json.loads(error_text)
38
+ # Return a dictionary with an error message and estimated loading time
39
+ return {
40
+ "text": f"error: {error_json.get('error', 'Unknown error')}\n"
41
+ f"Estimated time to load: {error_json.get('estimated_time', 'unknown')} seconds"
42
+ }
43
+ except aiohttp.ClientError as e:
44
+ # Handle any client-related errors that occur during the request
45
+ return {"text": f"Network error: {str(e)}"}
46
+ except json.JSONDecodeError:
47
+ # Handle errors that occur if the response cannot be parsed as JSON
48
+ return {"text": "Error: Unable to parse API response"}
49
+
50
+ # Example usage:
51
+ # The following example demonstrates how to use the send_to_voice_AI function asynchronously.
52
+ # It reads an audio file, sends it to the voice AI, and prints the output.
53
+
54
+ # import asyncio # Import asyncio to run the asynchronous function
55
+ # async def example():
56
+ # with open("sample1.flac", "rb") as f: # Open the audio file in binary read mode
57
+ # audio_data = f.read() # Read the audio data from the file
58
+ # output = await send_to_voice_AI(audio_data) # Await the asynchronous transcription function
59
+ # print(output) # Print the transcription result
60
+ # asyncio.run(example()) # Run the asynchronous example function
async_tgvoicebot.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio # Imports the asyncio library for writing single-threaded concurrent code using coroutines
2
+ import aiohttp # Imports aiohttp for making asynchronous HTTP requests
3
+ import os # Imports the os module to interact with the operating system
4
+ from dotenv import load_dotenv # Imports load_dotenv to load environment variables from a .env file
5
+ load_dotenv() # Loads environment variables from the .env file into the program's environment
6
+ from async_ai_voice import send_to_voice_AI # Imports the send_to_voice_AI function from the async_ai_voice module
7
+
8
+ # Telegram Bot API setup
9
+ TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN') # Retrieves the Telegram bot token from environment variables
10
+ TELEGRAM_API_URL = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}" # Constructs the base Telegram API URL using the bot token
11
+
12
+ async def get_voice_file(session, file_id):
13
+ """
14
+ Asynchronous function to retrieve the voice file from Telegram using the file ID.
15
+ """
16
+ # Get file path
17
+ file_path_url = f"{TELEGRAM_API_URL}/getFile?file_id={file_id}" # Constructs the URL to get file information from Telegram
18
+ async with session.get(file_path_url) as response: # Asynchronously sends a GET request to the file_path_url
19
+ file_info = await response.json() # Awaits and parses the JSON response containing file information
20
+ file_path = file_info['result']['file_path'] # Extracts the file path from the response
21
+
22
+ # Download file
23
+ file_url = f"https://api.telegram.org/file/bot{TELEGRAM_BOT_TOKEN}/{file_path}" # Constructs the URL to download the actual voice file
24
+ async with session.get(file_url) as response: # Asynchronously sends a GET request to download the file
25
+ return await response.read() # Awaits and returns the raw bytes of the downloaded file
26
+
27
+ async def handle_message(session, message):
28
+ """
29
+ Asynchronous function to handle incoming Telegram messages.
30
+ """
31
+ if 'voice' in message: # Checks if the incoming message contains a voice message
32
+ file_id = message['voice']['file_id'] # Retrieves the file ID of the voice message
33
+ audio_data = await get_voice_file(session, file_id) # Awaits the retrieval of the audio data using the get_voice_file function
34
+ transcription = await send_to_voice_AI(audio_data) # Awaits the transcription of the audio data using the AI service
35
+
36
+ # Send transcription back to user
37
+ chat_id = message['chat']['id'] # Retrieves the chat ID to identify where to send the response
38
+ text = transcription.get('text', 'Sorry, could not transcribe the audio due to AI error.') # Gets the transcribed text or a default error message
39
+ send_message_url = f"{TELEGRAM_API_URL}/sendMessage" # Constructs the URL to send a message via the Telegram API
40
+ payload = {
41
+ 'chat_id': chat_id, # Specifies the chat ID where the message should be sent
42
+ 'text': text # The transcribed text to send back to the user
43
+ }
44
+ await session.post(send_message_url, json=payload) # Asynchronously sends a POST request to send the transcription back to the user