Spaces:
Running
Running
Chandima Prabhath
commited on
Commit
·
b9724da
1
Parent(s):
29e070f
flux & audio reply
Browse files- .gitignore +6 -0
- FLUX.py +146 -0
- VoiceReply.py +67 -0
- app.py +58 -34
- requirements.txt +2 -1
.gitignore
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# directories
|
2 |
+
/images
|
3 |
+
/audio_replies
|
4 |
+
|
5 |
+
# env
|
6 |
+
.env
|
FLUX.py
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import time
|
3 |
+
import io
|
4 |
+
import os
|
5 |
+
import re
|
6 |
+
import json
|
7 |
+
from PIL import Image, UnidentifiedImageError
|
8 |
+
from dotenv import load_dotenv
|
9 |
+
|
10 |
+
load_dotenv()
|
11 |
+
|
12 |
+
# Load the ImgBB API key from the environment variables.
|
13 |
+
IMGBB_API_KEY = os.getenv("IMGBB_API_KEY")
|
14 |
+
|
15 |
+
def upload_to_imgbb(image_path, file_name):
|
16 |
+
"""
|
17 |
+
Uploads the image located at image_path to ImgBB.
|
18 |
+
Returns:
|
19 |
+
str: URL of the uploaded image on ImgBB or None if failed.
|
20 |
+
"""
|
21 |
+
try:
|
22 |
+
with open(image_path, 'rb') as f:
|
23 |
+
image_data = f.read()
|
24 |
+
response = requests.post(
|
25 |
+
"https://api.imgbb.com/1/upload",
|
26 |
+
params={"key": IMGBB_API_KEY},
|
27 |
+
files={"image": (file_name, image_data)}
|
28 |
+
)
|
29 |
+
response.raise_for_status()
|
30 |
+
result = response.json()
|
31 |
+
if result.get("data") and "url" in result["data"]:
|
32 |
+
return result["data"]["url"]
|
33 |
+
else:
|
34 |
+
print("Failed to upload image to ImgBB.")
|
35 |
+
return None
|
36 |
+
except requests.RequestException as e:
|
37 |
+
print(f"Error uploading image to ImgBB: {e}")
|
38 |
+
return None
|
39 |
+
except Exception as e:
|
40 |
+
print(f"Unexpected error uploading image to ImgBB: {e}")
|
41 |
+
return None
|
42 |
+
|
43 |
+
def generate_image(prompt, request_id, current_request_id, image_dir, attempt=0):
|
44 |
+
"""
|
45 |
+
Generate an image using the Pollinations API.
|
46 |
+
|
47 |
+
Parameters:
|
48 |
+
prompt (str): The prompt for image generation.
|
49 |
+
width (int): Desired image width.
|
50 |
+
height (int): Desired image height.
|
51 |
+
request_id (int): The request id for the current operation.
|
52 |
+
current_request_id (int): The current active request id.
|
53 |
+
image_dir (str): Directory where image will be saved.
|
54 |
+
attempt (int): Current attempt count (zero-indexed).
|
55 |
+
|
56 |
+
Returns:
|
57 |
+
tuple: (PIL.Image object, image_path (str), returned_prompt (str), image_url (str))
|
58 |
+
or None if image fetch fails or request id mismatches.
|
59 |
+
"""
|
60 |
+
model = "flux"
|
61 |
+
width = 1920
|
62 |
+
height = 1080
|
63 |
+
enhance_param = "true"
|
64 |
+
url = f"https://image.pollinations.ai/prompt/{prompt}?nologo=true&safe=false&private=true&model={model}&enhance={enhance_param}&width={width}&height={height}"
|
65 |
+
print(f"Attempt {attempt + 1}: Fetching image with URL: {url}")
|
66 |
+
|
67 |
+
try:
|
68 |
+
response = requests.get(url, timeout=45)
|
69 |
+
except Exception as e:
|
70 |
+
print(f"Error fetching image: {e}")
|
71 |
+
return None
|
72 |
+
|
73 |
+
if response.status_code != 200:
|
74 |
+
print(f"Failed to fetch image. Status code: {response.status_code}")
|
75 |
+
return None
|
76 |
+
|
77 |
+
if request_id != current_request_id:
|
78 |
+
print("Request ID mismatch. Operation cancelled.")
|
79 |
+
return None
|
80 |
+
|
81 |
+
print("Image fetched successfully.")
|
82 |
+
image_data = response.content
|
83 |
+
|
84 |
+
try:
|
85 |
+
image = Image.open(io.BytesIO(image_data))
|
86 |
+
actual_width, actual_height = image.size
|
87 |
+
print(f"Actual image dimensions: {actual_width}x{actual_height}")
|
88 |
+
|
89 |
+
# Extract metadata from EXIF if available
|
90 |
+
exif_data = image.info.get('exif', b'')
|
91 |
+
returned_prompt = prompt
|
92 |
+
if exif_data:
|
93 |
+
json_match = re.search(b'{"prompt":.*}', exif_data)
|
94 |
+
if json_match:
|
95 |
+
json_str = json_match.group(0).decode('utf-8')
|
96 |
+
try:
|
97 |
+
metadata_dict = json.loads(json_str)
|
98 |
+
returned_prompt = metadata_dict.get('prompt', prompt)
|
99 |
+
except json.JSONDecodeError as e:
|
100 |
+
print(f"Failed to parse JSON in metadata: {e}")
|
101 |
+
else:
|
102 |
+
print("No JSON data found in EXIF")
|
103 |
+
|
104 |
+
if (actual_width, actual_height) != (width, height):
|
105 |
+
print(f"Warning: Received image dimensions ({actual_width}x{actual_height}) do not match requested dimensions ({width}x{height})")
|
106 |
+
except UnidentifiedImageError:
|
107 |
+
print("Error: Received data is not a valid image.")
|
108 |
+
raise
|
109 |
+
|
110 |
+
timestamp = int(time.time())
|
111 |
+
image_filename = f"background_{timestamp}.png"
|
112 |
+
image_path = os.path.join(image_dir, image_filename)
|
113 |
+
|
114 |
+
# Ensure the image directory exists
|
115 |
+
os.makedirs(image_dir, exist_ok=True)
|
116 |
+
|
117 |
+
try:
|
118 |
+
image.save(image_path, 'PNG')
|
119 |
+
print(f"Image saved to {image_path}")
|
120 |
+
# Upload image to ImgBB
|
121 |
+
image_url = upload_to_imgbb(image_path, image_filename)
|
122 |
+
if image_url:
|
123 |
+
print(f"Image uploaded to ImgBB: {image_url}")
|
124 |
+
else:
|
125 |
+
print("Failed to upload image to ImgBB.")
|
126 |
+
except Exception as e:
|
127 |
+
print(f"Error saving image: {e}")
|
128 |
+
return None
|
129 |
+
|
130 |
+
return image, image_path, returned_prompt, image_url
|
131 |
+
|
132 |
+
if __name__ == "__main__":
|
133 |
+
# Example usage
|
134 |
+
prompt = "Beach party, anime style, vibrant colors"
|
135 |
+
request_id = 1
|
136 |
+
current_request_id = 1
|
137 |
+
image_dir = "./images"
|
138 |
+
|
139 |
+
image, image_path, returned_prompt, image_url = generate_image(prompt, request_id, current_request_id, image_dir)
|
140 |
+
|
141 |
+
if image:
|
142 |
+
print(f"Image generated and saved at {image_path}")
|
143 |
+
print(f"Returned prompt: {returned_prompt}")
|
144 |
+
print(f"Image URL: {image_url}")
|
145 |
+
else:
|
146 |
+
print("Failed to generate image.")
|
VoiceReply.py
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import os
|
3 |
+
import time
|
4 |
+
import urllib.parse
|
5 |
+
|
6 |
+
def generate_voice_reply(prompt, model="openai-audio", voice="coral", audio_dir="."):
|
7 |
+
"""
|
8 |
+
Generate an audio file (MP3) using the Pollinations text-to-speech API.
|
9 |
+
|
10 |
+
The prompt is appended with a system message explaining that this is Eve,
|
11 |
+
a WhatsApp bot that can generate images from Flux and help users generate images.
|
12 |
+
To generate an image, the user should send a message like: /imagine {prompt}
|
13 |
+
|
14 |
+
Parameters:
|
15 |
+
prompt (str): The text prompt for audio generation.
|
16 |
+
model (str): Model identifier (default: openai-audio).
|
17 |
+
voice (str): Voice parameter (default: coral).
|
18 |
+
audio_dir (str): Directory where the audio file will be saved.
|
19 |
+
|
20 |
+
Returns:
|
21 |
+
tuple: (audio_file_path (str), audio_data (bytes)) or None if failed.
|
22 |
+
"""
|
23 |
+
# Append system prompt to the user's prompt
|
24 |
+
system_prompt = ("Your name is Eve, a WhatsApp bot that can generate images from Flux and help users generate images. "
|
25 |
+
"To generate an image, send a message like: /imagine prompt. Rules: Don't say that you can't send whatsapp messages or generate images. Be friendly and helpful to users. help them with prompts. You can engage in general conversation. ")
|
26 |
+
full_prompt = f"{prompt}\n\n{system_prompt}"
|
27 |
+
encoded_prompt = urllib.parse.quote(full_prompt)
|
28 |
+
url = f"http://text.pollinations.ai/{encoded_prompt}?model={model}&voice={voice}"
|
29 |
+
print(f"Fetching audio with URL: {url}")
|
30 |
+
|
31 |
+
try:
|
32 |
+
response = requests.get(url, timeout=30)
|
33 |
+
except Exception as e:
|
34 |
+
print(f"Error fetching audio: {e}")
|
35 |
+
return None
|
36 |
+
|
37 |
+
if response.status_code != 200:
|
38 |
+
print(f"Failed to fetch audio. Status code: {response.status_code}")
|
39 |
+
return None
|
40 |
+
|
41 |
+
audio_data = response.content
|
42 |
+
timestamp = int(time.time())
|
43 |
+
file_name = f"voice_reply_{timestamp}.mp3"
|
44 |
+
audio_file_path = os.path.join(audio_dir, file_name)
|
45 |
+
|
46 |
+
try:
|
47 |
+
with open(audio_file_path, "wb") as f:
|
48 |
+
f.write(audio_data)
|
49 |
+
print(f"Audio saved to {audio_file_path}")
|
50 |
+
except Exception as e:
|
51 |
+
print(f"Error saving audio file: {e}")
|
52 |
+
return None
|
53 |
+
|
54 |
+
return audio_file_path, audio_data
|
55 |
+
|
56 |
+
|
57 |
+
if __name__ == "__main__":
|
58 |
+
# Example usage
|
59 |
+
prompt = "Hi. how are you."
|
60 |
+
audio_dir = "./audio_replies"
|
61 |
+
os.makedirs(audio_dir, exist_ok=True)
|
62 |
+
|
63 |
+
audio_file_path, audio_data = generate_voice_reply(prompt, audio_dir=audio_dir)
|
64 |
+
if audio_file_path:
|
65 |
+
print(f"Generated audio file: {audio_file_path}")
|
66 |
+
else:
|
67 |
+
print("Failed to generate audio file.")
|
app.py
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
import os
|
2 |
import threading
|
3 |
import requests
|
4 |
-
from
|
|
|
|
|
|
|
5 |
|
6 |
from llm import generate_llm
|
7 |
-
from sd import generate_sd
|
8 |
|
9 |
GREEN_API_URL = os.getenv("GREEN_API_URL")
|
10 |
GREEN_API_MEDIA_URL = os.getenv("GREEN_API_MEDIA_URL", "https://api.green-api.com")
|
@@ -12,16 +14,15 @@ GREEN_API_TOKEN = os.getenv("GREEN_API_TOKEN")
|
|
12 |
GREEN_API_ID_INSTANCE = os.getenv("GREEN_API_ID_INSTANCE")
|
13 |
WEBHOOK_AUTH_TOKEN = os.getenv("WEBHOOK_AUTH_TOKEN")
|
14 |
PORT = 7860
|
|
|
|
|
15 |
|
16 |
if not all([GREEN_API_URL, GREEN_API_TOKEN, GREEN_API_ID_INSTANCE, WEBHOOK_AUTH_TOKEN]):
|
17 |
raise ValueError("Environment variables are not set properly")
|
18 |
|
19 |
-
app =
|
20 |
|
21 |
def send_message(message_id, to_number, message, retries=3):
|
22 |
-
"""
|
23 |
-
Send a text message using Green API with retry logic.
|
24 |
-
"""
|
25 |
if to_number.endswith('@g.us'):
|
26 |
chat_id = to_number
|
27 |
else:
|
@@ -45,9 +46,6 @@ def send_message(message_id, to_number, message, retries=3):
|
|
45 |
return {"error": str(e)}
|
46 |
|
47 |
def send_image(message_id, to_number, image_path, retries=3):
|
48 |
-
"""
|
49 |
-
Send an image using Green API with retry logic.
|
50 |
-
"""
|
51 |
if to_number.endswith('@g.us'):
|
52 |
chat_id = to_number
|
53 |
else:
|
@@ -67,49 +65,75 @@ def send_image(message_id, to_number, image_path, retries=3):
|
|
67 |
continue
|
68 |
return {"error": str(e)}
|
69 |
|
70 |
-
def
|
71 |
"""
|
72 |
-
|
73 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
try:
|
75 |
msg = generate_llm(prompt)
|
76 |
send_message(message_id, chat_id, msg)
|
77 |
except Exception as e:
|
78 |
send_message(message_id, chat_id, "There was an error processing your request.")
|
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
def handle_image_generation(message_id, chat_id, prompt):
|
81 |
-
"""
|
82 |
-
Generate an image from the provided prompt and send it to the user.
|
83 |
-
"""
|
84 |
try:
|
85 |
-
|
86 |
-
if
|
87 |
send_image(message_id, chat_id, image_path)
|
|
|
88 |
else:
|
89 |
send_message(message_id, chat_id, "Failed to generate image. Please try again later.")
|
90 |
except Exception as e:
|
91 |
send_message(message_id, chat_id, "There was an error generating the image. Please try again later.")
|
92 |
|
93 |
-
@app.
|
94 |
def index():
|
95 |
-
"""
|
96 |
-
Basic endpoint to check if the script is running.
|
97 |
-
"""
|
98 |
return "Server is running!"
|
99 |
|
100 |
-
@app.
|
101 |
-
def whatsapp_webhook():
|
102 |
-
"""
|
103 |
-
Handle incoming WhatsApp messages.
|
104 |
-
"""
|
105 |
-
data = request.get_json()
|
106 |
auth_header = request.headers.get('Authorization', '').strip()
|
107 |
-
|
108 |
if auth_header != f"Bearer {WEBHOOK_AUTH_TOKEN}":
|
109 |
-
|
|
|
|
|
|
|
|
|
|
|
110 |
|
111 |
if data.get('typeWebhook') != 'incomingMessageReceived':
|
112 |
-
return
|
113 |
|
114 |
try:
|
115 |
chat_id = data['senderData']['chatId']
|
@@ -121,10 +145,9 @@ def whatsapp_webhook():
|
|
121 |
elif 'extendedTextMessageData' in message_data:
|
122 |
body = message_data['extendedTextMessageData']['text'].strip()
|
123 |
else:
|
124 |
-
return
|
125 |
-
|
126 |
except KeyError as e:
|
127 |
-
return
|
128 |
|
129 |
if body.lower().startswith('/imagine'):
|
130 |
prompt = body.replace('/imagine', '').strip()
|
@@ -136,7 +159,8 @@ def whatsapp_webhook():
|
|
136 |
else:
|
137 |
threading.Thread(target=response_text, args=(message_id, chat_id, body)).start()
|
138 |
|
139 |
-
return
|
140 |
|
141 |
if __name__ == '__main__':
|
142 |
-
|
|
|
|
1 |
import os
|
2 |
import threading
|
3 |
import requests
|
4 |
+
from fastapi import FastAPI, Request, HTTPException
|
5 |
+
from fastapi.responses import PlainTextResponse, JSONResponse
|
6 |
+
from FLUX import generate_image
|
7 |
+
from VoiceReply import generate_voice_reply
|
8 |
|
9 |
from llm import generate_llm
|
|
|
10 |
|
11 |
GREEN_API_URL = os.getenv("GREEN_API_URL")
|
12 |
GREEN_API_MEDIA_URL = os.getenv("GREEN_API_MEDIA_URL", "https://api.green-api.com")
|
|
|
14 |
GREEN_API_ID_INSTANCE = os.getenv("GREEN_API_ID_INSTANCE")
|
15 |
WEBHOOK_AUTH_TOKEN = os.getenv("WEBHOOK_AUTH_TOKEN")
|
16 |
PORT = 7860
|
17 |
+
image_dir = "/tmp/images"
|
18 |
+
audio_dir = "/tmp/audio"
|
19 |
|
20 |
if not all([GREEN_API_URL, GREEN_API_TOKEN, GREEN_API_ID_INSTANCE, WEBHOOK_AUTH_TOKEN]):
|
21 |
raise ValueError("Environment variables are not set properly")
|
22 |
|
23 |
+
app = FastAPI()
|
24 |
|
25 |
def send_message(message_id, to_number, message, retries=3):
|
|
|
|
|
|
|
26 |
if to_number.endswith('@g.us'):
|
27 |
chat_id = to_number
|
28 |
else:
|
|
|
46 |
return {"error": str(e)}
|
47 |
|
48 |
def send_image(message_id, to_number, image_path, retries=3):
|
|
|
|
|
|
|
49 |
if to_number.endswith('@g.us'):
|
50 |
chat_id = to_number
|
51 |
else:
|
|
|
65 |
continue
|
66 |
return {"error": str(e)}
|
67 |
|
68 |
+
def send_audio(message_id, to_number, audio_path, retries=3):
|
69 |
"""
|
70 |
+
Send an audio file using the Green API similar to send_image.
|
71 |
"""
|
72 |
+
if to_number.endswith('@g.us'):
|
73 |
+
chat_id = to_number
|
74 |
+
else:
|
75 |
+
chat_id = to_number
|
76 |
+
|
77 |
+
url = f"{GREEN_API_MEDIA_URL}/waInstance{GREEN_API_ID_INSTANCE}/sendFileByUpload/{GREEN_API_TOKEN}"
|
78 |
+
payload = {'chatId': chat_id, 'caption': 'Here is your voice reply!', 'quotedMessageId': message_id}
|
79 |
+
files = [('file', ('audio.mp3', open(audio_path, 'rb'), 'audio/mpeg'))]
|
80 |
+
|
81 |
+
for attempt in range(retries):
|
82 |
+
try:
|
83 |
+
response = requests.post(url, data=payload, files=files)
|
84 |
+
response.raise_for_status()
|
85 |
+
return response.json()
|
86 |
+
except requests.RequestException as e:
|
87 |
+
if attempt < retries - 1:
|
88 |
+
continue
|
89 |
+
return {"error": str(e)}
|
90 |
+
|
91 |
+
def response_text(message_id, chat_id, prompt):
|
92 |
try:
|
93 |
msg = generate_llm(prompt)
|
94 |
send_message(message_id, chat_id, msg)
|
95 |
except Exception as e:
|
96 |
send_message(message_id, chat_id, "There was an error processing your request.")
|
97 |
|
98 |
+
def response_audio(message_id, chat_id, prompt):
|
99 |
+
try:
|
100 |
+
audio_file_path, audio_data = generate_voice_reply(prompt, model="openai-audio", voice="coral", audio_dir=audio_dir)
|
101 |
+
if audio_file_path:
|
102 |
+
send_audio(message_id, chat_id, audio_file_path)
|
103 |
+
os.remove(audio_file_path) # Clean up the file after sending
|
104 |
+
else:
|
105 |
+
response_text(message_id, chat_id, prompt=prompt)
|
106 |
+
except Exception as e:
|
107 |
+
send_message(message_id, chat_id, "There was an error generating the audio. Please try again later.")
|
108 |
+
|
109 |
def handle_image_generation(message_id, chat_id, prompt):
|
|
|
|
|
|
|
110 |
try:
|
111 |
+
image, image_path, returned_prompt, image_url = generate_image(prompt, message_id, message_id, image_dir)
|
112 |
+
if image:
|
113 |
send_image(message_id, chat_id, image_path)
|
114 |
+
send_message(message_id, chat_id, f"Image generated successfully! You can view it here: {image_url}. \nPrompt: > _{returned_prompt}_")
|
115 |
else:
|
116 |
send_message(message_id, chat_id, "Failed to generate image. Please try again later.")
|
117 |
except Exception as e:
|
118 |
send_message(message_id, chat_id, "There was an error generating the image. Please try again later.")
|
119 |
|
120 |
+
@app.get("/", response_class=PlainTextResponse)
|
121 |
def index():
|
|
|
|
|
|
|
122 |
return "Server is running!"
|
123 |
|
124 |
+
@app.post("/whatsapp")
|
125 |
+
async def whatsapp_webhook(request: Request):
|
|
|
|
|
|
|
|
|
126 |
auth_header = request.headers.get('Authorization', '').strip()
|
|
|
127 |
if auth_header != f"Bearer {WEBHOOK_AUTH_TOKEN}":
|
128 |
+
raise HTTPException(status_code=403, detail="Unauthorized")
|
129 |
+
|
130 |
+
try:
|
131 |
+
data = await request.json()
|
132 |
+
except Exception:
|
133 |
+
return JSONResponse(content={"error": "Invalid JSON"}, status_code=400)
|
134 |
|
135 |
if data.get('typeWebhook') != 'incomingMessageReceived':
|
136 |
+
return {"success": True}
|
137 |
|
138 |
try:
|
139 |
chat_id = data['senderData']['chatId']
|
|
|
145 |
elif 'extendedTextMessageData' in message_data:
|
146 |
body = message_data['extendedTextMessageData']['text'].strip()
|
147 |
else:
|
148 |
+
return {"success": True}
|
|
|
149 |
except KeyError as e:
|
150 |
+
return JSONResponse(content={"error": f"Missing key in data: {e}"}, status_code=200)
|
151 |
|
152 |
if body.lower().startswith('/imagine'):
|
153 |
prompt = body.replace('/imagine', '').strip()
|
|
|
159 |
else:
|
160 |
threading.Thread(target=response_text, args=(message_id, chat_id, body)).start()
|
161 |
|
162 |
+
return {"success": True}
|
163 |
|
164 |
if __name__ == '__main__':
|
165 |
+
import uvicorn
|
166 |
+
uvicorn.run(app, host="0.0.0.0", port=PORT, debug=True)
|
requirements.txt
CHANGED
@@ -2,4 +2,5 @@ fastapi
|
|
2 |
uvicorn[standard]
|
3 |
openai
|
4 |
flask
|
5 |
-
pillow
|
|
|
|
2 |
uvicorn[standard]
|
3 |
openai
|
4 |
flask
|
5 |
+
pillow
|
6 |
+
requests
|