Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,399 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask, request, send_file
|
2 |
+
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
3 |
+
import textwrap
|
4 |
+
import io
|
5 |
+
import os
|
6 |
+
import math
|
7 |
+
from datetime import datetime
|
8 |
+
|
9 |
+
app = Flask(__name__)
|
10 |
+
|
11 |
+
class TelegramChatGenerator:
|
12 |
+
def __init__(self):
|
13 |
+
# Modern Telegram colors with gradients
|
14 |
+
self.bg_gradient_start = (15, 20, 28)
|
15 |
+
self.bg_gradient_end = (22, 32, 45)
|
16 |
+
self.bubble_color = (55, 125, 255) # Telegram blue
|
17 |
+
self.bubble_shadow = (35, 90, 200) # Darker shadow
|
18 |
+
self.reply_bubble_color = (45, 48, 55)
|
19 |
+
self.reply_line_color = (55, 125, 255) # Blue accent line
|
20 |
+
self.text_color = (255, 255, 255)
|
21 |
+
self.reply_text_color = (140, 150, 165)
|
22 |
+
self.username_color = (255, 255, 255)
|
23 |
+
self.time_color = (140, 150, 165)
|
24 |
+
|
25 |
+
# Load fonts with fallbacks
|
26 |
+
self.load_fonts()
|
27 |
+
|
28 |
+
# Standard square size
|
29 |
+
self.image_size = 800
|
30 |
+
|
31 |
+
def load_fonts(self):
|
32 |
+
"""Load fonts with multiple fallbacks"""
|
33 |
+
font_paths = [
|
34 |
+
"fonts/Roboto-Regular.ttf",
|
35 |
+
"fonts/Arial.ttf",
|
36 |
+
"/System/Library/Fonts/Arial.ttf",
|
37 |
+
"C:/Windows/Fonts/arial.ttf",
|
38 |
+
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
39 |
+
]
|
40 |
+
|
41 |
+
try:
|
42 |
+
# Try to load a modern font
|
43 |
+
for path in font_paths:
|
44 |
+
if os.path.exists(path):
|
45 |
+
self.font = ImageFont.truetype(path, 22)
|
46 |
+
self.username_font = ImageFont.truetype(path, 18)
|
47 |
+
self.reply_font = ImageFont.truetype(path, 16)
|
48 |
+
self.time_font = ImageFont.truetype(path, 14)
|
49 |
+
return
|
50 |
+
|
51 |
+
# Fallback to default
|
52 |
+
self.font = ImageFont.load_default()
|
53 |
+
self.username_font = ImageFont.load_default()
|
54 |
+
self.reply_font = ImageFont.load_default()
|
55 |
+
self.time_font = ImageFont.load_default()
|
56 |
+
except:
|
57 |
+
self.font = ImageFont.load_default()
|
58 |
+
self.username_font = ImageFont.load_default()
|
59 |
+
self.reply_font = ImageFont.load_default()
|
60 |
+
self.time_font = ImageFont.load_default()
|
61 |
+
|
62 |
+
def create_gradient_background(self, size):
|
63 |
+
"""Create a gradient background"""
|
64 |
+
img = Image.new('RGB', size, self.bg_gradient_start)
|
65 |
+
draw = ImageDraw.Draw(img)
|
66 |
+
|
67 |
+
# Create vertical gradient
|
68 |
+
for y in range(size[1]):
|
69 |
+
ratio = y / size[1]
|
70 |
+
r = int(self.bg_gradient_start[0] * (1 - ratio) + self.bg_gradient_end[0] * ratio)
|
71 |
+
g = int(self.bg_gradient_start[1] * (1 - ratio) + self.bg_gradient_end[1] * ratio)
|
72 |
+
b = int(self.bg_gradient_start[2] * (1 - ratio) + self.bg_gradient_end[2] * ratio)
|
73 |
+
|
74 |
+
draw.line([(0, y), (size[0], y)], fill=(r, g, b))
|
75 |
+
|
76 |
+
return img
|
77 |
+
|
78 |
+
def wrap_text(self, text, font, max_width):
|
79 |
+
"""Smart text wrapping based on pixel width"""
|
80 |
+
words = text.split()
|
81 |
+
lines = []
|
82 |
+
current_line = []
|
83 |
+
|
84 |
+
for word in words:
|
85 |
+
test_line = ' '.join(current_line + [word])
|
86 |
+
bbox = font.getbbox(test_line)
|
87 |
+
width = bbox[2] - bbox[0]
|
88 |
+
|
89 |
+
if width <= max_width:
|
90 |
+
current_line.append(word)
|
91 |
+
else:
|
92 |
+
if current_line:
|
93 |
+
lines.append(' '.join(current_line))
|
94 |
+
current_line = [word]
|
95 |
+
else:
|
96 |
+
# Word is too long, force break
|
97 |
+
lines.append(word)
|
98 |
+
|
99 |
+
if current_line:
|
100 |
+
lines.append(' '.join(current_line))
|
101 |
+
|
102 |
+
return '\n'.join(lines)
|
103 |
+
|
104 |
+
def draw_advanced_bubble(self, draw, coords, radius, fill, shadow_offset=3):
|
105 |
+
"""Draw bubble with shadow and gradient effect"""
|
106 |
+
x1, y1, x2, y2 = coords
|
107 |
+
|
108 |
+
# Draw shadow first
|
109 |
+
shadow_coords = (x1 + shadow_offset, y1 + shadow_offset,
|
110 |
+
x2 + shadow_offset, y2 + shadow_offset)
|
111 |
+
self.draw_rounded_rectangle(draw, shadow_coords, radius, (0, 0, 0, 30))
|
112 |
+
|
113 |
+
# Draw main bubble
|
114 |
+
self.draw_rounded_rectangle(draw, coords, radius, fill)
|
115 |
+
|
116 |
+
# Add subtle highlight
|
117 |
+
highlight_coords = (x1, y1, x2, y1 + 2)
|
118 |
+
lighter_fill = tuple(min(255, c + 20) for c in fill)
|
119 |
+
self.draw_rounded_rectangle(draw, highlight_coords, radius, lighter_fill)
|
120 |
+
|
121 |
+
def draw_rounded_rectangle(self, draw, coords, radius, fill):
|
122 |
+
"""Draw a perfect rounded rectangle"""
|
123 |
+
x1, y1, x2, y2 = coords
|
124 |
+
|
125 |
+
# Main rectangles
|
126 |
+
draw.rectangle([x1 + radius, y1, x2 - radius, y2], fill=fill)
|
127 |
+
draw.rectangle([x1, y1 + radius, x2, y2 - radius], fill=fill)
|
128 |
+
|
129 |
+
# Corner circles
|
130 |
+
draw.ellipse([x1, y1, x1 + 2 * radius, y1 + 2 * radius], fill=fill)
|
131 |
+
draw.ellipse([x2 - 2 * radius, y1, x2, y1 + 2 * radius], fill=fill)
|
132 |
+
draw.ellipse([x1, y2 - 2 * radius, x1 + 2 * radius, y2], fill=fill)
|
133 |
+
draw.ellipse([x2 - 2 * radius, y2 - 2 * radius, x2, y2], fill=fill)
|
134 |
+
|
135 |
+
def get_text_dimensions(self, text, font):
|
136 |
+
"""Get accurate text dimensions"""
|
137 |
+
lines = text.split('\n')
|
138 |
+
max_width = 0
|
139 |
+
total_height = 0
|
140 |
+
|
141 |
+
for i, line in enumerate(lines):
|
142 |
+
bbox = font.getbbox(line)
|
143 |
+
width = bbox[2] - bbox[0]
|
144 |
+
height = bbox[3] - bbox[1]
|
145 |
+
max_width = max(max_width, width)
|
146 |
+
total_height += height
|
147 |
+
|
148 |
+
# Add line spacing except for last line
|
149 |
+
if i < len(lines) - 1:
|
150 |
+
total_height += 6
|
151 |
+
|
152 |
+
return max_width, total_height
|
153 |
+
|
154 |
+
def add_subtle_pattern(self, img):
|
155 |
+
"""Add a subtle dot pattern to the background"""
|
156 |
+
draw = ImageDraw.Draw(img)
|
157 |
+
width, height = img.size
|
158 |
+
|
159 |
+
# Create subtle dot pattern
|
160 |
+
for x in range(0, width, 40):
|
161 |
+
for y in range(0, height, 40):
|
162 |
+
# Vary opacity based on position
|
163 |
+
opacity = max(5, min(15, abs(x - width//2) // 20 + abs(y - height//2) // 20))
|
164 |
+
color = (255, 255, 255, opacity)
|
165 |
+
draw.ellipse([x, y, x + 2, y + 2], fill=color)
|
166 |
+
|
167 |
+
def generate_chat_bubble(self, message, username, reply_to=None, replied_username=None):
|
168 |
+
# Create square canvas
|
169 |
+
img = self.create_gradient_background((self.image_size, self.image_size))
|
170 |
+
|
171 |
+
# Add subtle pattern
|
172 |
+
self.add_subtle_pattern(img)
|
173 |
+
|
174 |
+
draw = ImageDraw.Draw(img)
|
175 |
+
|
176 |
+
# Calculate bubble dimensions with proper spacing
|
177 |
+
padding = 50
|
178 |
+
max_bubble_width = self.image_size - (padding * 2) - 60
|
179 |
+
|
180 |
+
# Wrap text intelligently
|
181 |
+
wrapped_message = self.wrap_text(message, self.font, max_bubble_width - 60)
|
182 |
+
msg_width, msg_height = self.get_text_dimensions(wrapped_message, self.font)
|
183 |
+
|
184 |
+
username_width, username_height = self.get_text_dimensions(username, self.username_font)
|
185 |
+
|
186 |
+
# Handle reply if present
|
187 |
+
reply_height = 0
|
188 |
+
wrapped_reply = ""
|
189 |
+
if reply_to and replied_username:
|
190 |
+
# Truncate and wrap reply
|
191 |
+
truncated_reply = reply_to[:100] + "..." if len(reply_to) > 100 else reply_to
|
192 |
+
wrapped_reply = self.wrap_text(truncated_reply, self.reply_font, max_bubble_width - 80)
|
193 |
+
reply_username_w, reply_username_h = self.get_text_dimensions(replied_username, self.reply_font)
|
194 |
+
reply_msg_w, reply_msg_h = self.get_text_dimensions(wrapped_reply, self.reply_font)
|
195 |
+
reply_height = reply_username_h + reply_msg_h + 25
|
196 |
+
|
197 |
+
# Calculate total bubble dimensions
|
198 |
+
bubble_padding = 25
|
199 |
+
bubble_width = min(max_bubble_width, max(350, msg_width + bubble_padding * 2))
|
200 |
+
bubble_height = username_height + msg_height + bubble_padding * 2 + 30
|
201 |
+
|
202 |
+
if reply_to:
|
203 |
+
bubble_height += reply_height + 15
|
204 |
+
|
205 |
+
# Center the bubble vertically in the square
|
206 |
+
bubble_x = self.image_size - bubble_width - padding
|
207 |
+
bubble_y = (self.image_size - bubble_height) // 2
|
208 |
+
|
209 |
+
# Draw main bubble with shadow
|
210 |
+
self.draw_advanced_bubble(
|
211 |
+
draw,
|
212 |
+
[bubble_x, bubble_y, bubble_x + bubble_width, bubble_y + bubble_height],
|
213 |
+
radius=20,
|
214 |
+
fill=self.bubble_color,
|
215 |
+
shadow_offset=4
|
216 |
+
)
|
217 |
+
|
218 |
+
# Current position for content
|
219 |
+
content_y = bubble_y + bubble_padding
|
220 |
+
|
221 |
+
# Draw reply section if present
|
222 |
+
if reply_to and replied_username:
|
223 |
+
reply_y = content_y
|
224 |
+
reply_bubble_height = reply_height + 10
|
225 |
+
|
226 |
+
# Reply background
|
227 |
+
self.draw_rounded_rectangle(
|
228 |
+
draw,
|
229 |
+
[bubble_x + 15, reply_y, bubble_x + bubble_width - 15, reply_y + reply_bubble_height],
|
230 |
+
radius=12,
|
231 |
+
fill=self.reply_bubble_color
|
232 |
+
)
|
233 |
+
|
234 |
+
# Blue accent line
|
235 |
+
draw.rectangle([bubble_x + 20, reply_y + 5, bubble_x + 24, reply_y + reply_bubble_height - 5],
|
236 |
+
fill=self.reply_line_color)
|
237 |
+
|
238 |
+
# Reply content
|
239 |
+
reply_content_x = bubble_x + 35
|
240 |
+
reply_content_y = reply_y + 8
|
241 |
+
|
242 |
+
# Reply username
|
243 |
+
draw.text((reply_content_x, reply_content_y), replied_username,
|
244 |
+
fill=self.reply_line_color, font=self.reply_font)
|
245 |
+
reply_content_y += 20
|
246 |
+
|
247 |
+
# Reply message
|
248 |
+
for line in wrapped_reply.split('\n'):
|
249 |
+
draw.text((reply_content_x, reply_content_y), line,
|
250 |
+
fill=self.reply_text_color, font=self.reply_font)
|
251 |
+
reply_content_y += 20
|
252 |
+
|
253 |
+
content_y += reply_bubble_height + 15
|
254 |
+
|
255 |
+
# Main message username
|
256 |
+
draw.text((bubble_x + bubble_padding, content_y), username,
|
257 |
+
fill=self.username_color, font=self.username_font)
|
258 |
+
content_y += username_height + 10
|
259 |
+
|
260 |
+
# Main message text with better spacing
|
261 |
+
for line in wrapped_message.split('\n'):
|
262 |
+
draw.text((bubble_x + bubble_padding, content_y), line,
|
263 |
+
fill=self.text_color, font=self.font)
|
264 |
+
content_y += 28
|
265 |
+
|
266 |
+
# Add timestamp
|
267 |
+
current_time = datetime.now().strftime("%H:%M")
|
268 |
+
time_bbox = self.time_font.getbbox(current_time)
|
269 |
+
time_width = time_bbox[2] - time_bbox[0]
|
270 |
+
|
271 |
+
draw.text((bubble_x + bubble_width - time_width - bubble_padding,
|
272 |
+
bubble_y + bubble_height - 25),
|
273 |
+
current_time, fill=self.time_color, font=self.time_font)
|
274 |
+
|
275 |
+
# Add checkmark (delivered status)
|
276 |
+
check_x = bubble_x + bubble_width - 25
|
277 |
+
check_y = bubble_y + bubble_height - 22
|
278 |
+
self.draw_checkmarks(draw, check_x, check_y)
|
279 |
+
|
280 |
+
return img
|
281 |
+
|
282 |
+
def draw_checkmarks(self, draw, x, y):
|
283 |
+
"""Draw double checkmarks for message status"""
|
284 |
+
# First checkmark
|
285 |
+
points1 = [(x-8, y), (x-5, y+3), (x-2, y-2)]
|
286 |
+
self.draw_polyline(draw, points1, self.time_color, width=2)
|
287 |
+
|
288 |
+
# Second checkmark (overlapping)
|
289 |
+
points2 = [(x-5, y), (x-2, y+3), (x+2, y-2)]
|
290 |
+
self.draw_polyline(draw, points2, self.time_color, width=2)
|
291 |
+
|
292 |
+
def draw_polyline(self, draw, points, fill, width=1):
|
293 |
+
"""Draw a polyline (series of connected lines)"""
|
294 |
+
for i in range(len(points) - 1):
|
295 |
+
draw.line([points[i], points[i + 1]], fill=fill, width=width)
|
296 |
+
|
297 |
+
# Initialize generator
|
298 |
+
chat_gen = TelegramChatGenerator()
|
299 |
+
|
300 |
+
@app.route('/chat')
|
301 |
+
def generate_chat():
|
302 |
+
# Get parameters
|
303 |
+
message = request.args.get('message', 'Hello World! π')
|
304 |
+
username = request.args.get('username', 'User')
|
305 |
+
reply_to = request.args.get('replyto')
|
306 |
+
replied_username = request.args.get('repliedusername')
|
307 |
+
|
308 |
+
# Generate image
|
309 |
+
img = chat_gen.generate_chat_bubble(
|
310 |
+
message=message,
|
311 |
+
username=username,
|
312 |
+
reply_to=reply_to,
|
313 |
+
replied_username=replied_username
|
314 |
+
)
|
315 |
+
|
316 |
+
# Return as PNG
|
317 |
+
img_io = io.BytesIO()
|
318 |
+
img.save(img_io, 'PNG', quality=95, optimize=True)
|
319 |
+
img_io.seek(0)
|
320 |
+
|
321 |
+
return send_file(img_io, mimetype='image/png', as_attachment=False)
|
322 |
+
|
323 |
+
@app.route('/')
|
324 |
+
def index():
|
325 |
+
return '''
|
326 |
+
<!DOCTYPE html>
|
327 |
+
<html>
|
328 |
+
<head>
|
329 |
+
<title>Telegram Chat Generator</title>
|
330 |
+
<style>
|
331 |
+
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; background: #f5f5f5; }
|
332 |
+
.container { background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
333 |
+
h1 { color: #333; text-align: center; margin-bottom: 30px; }
|
334 |
+
.example { margin: 15px 0; }
|
335 |
+
.example img { max-width: 300px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.2); }
|
336 |
+
.params { background: #f8f9fa; padding: 20px; border-radius: 8px; margin: 20px 0; }
|
337 |
+
a { color: #007bff; text-decoration: none; }
|
338 |
+
a:hover { text-decoration: underline; }
|
339 |
+
</style>
|
340 |
+
</head>
|
341 |
+
<body>
|
342 |
+
<div class="container">
|
343 |
+
<h1>π¨ Premium Telegram Chat Generator</h1>
|
344 |
+
|
345 |
+
<div class="params">
|
346 |
+
<h3>β¨ Features:</h3>
|
347 |
+
<ul>
|
348 |
+
<li>π¨ Beautiful gradient backgrounds</li>
|
349 |
+
<li>π¬ Authentic Telegram bubble design</li>
|
350 |
+
<li>β©οΈ Reply message support</li>
|
351 |
+
<li>π Perfect square format (800x800)</li>
|
352 |
+
<li>π Automatic timestamps</li>
|
353 |
+
<li>β
Read status indicators</li>
|
354 |
+
<li>π± Smart text wrapping</li>
|
355 |
+
</ul>
|
356 |
+
</div>
|
357 |
+
|
358 |
+
<h3>π Try These Examples:</h3>
|
359 |
+
|
360 |
+
<div class="example">
|
361 |
+
<h4>Simple Message:</h4>
|
362 |
+
<a href="/chat?message=Hey! How are you doing today? π&username=Alice">
|
363 |
+
<img src="/chat?message=Hey! How are you doing today? π&username=Alice" alt="Simple message example">
|
364 |
+
</a>
|
365 |
+
</div>
|
366 |
+
|
367 |
+
<div class="example">
|
368 |
+
<h4>Long Message:</h4>
|
369 |
+
<a href="/chat?message=I just wanted to let you know that the meeting has been rescheduled to tomorrow at 3 PM. Please make sure to bring all the documents we discussed earlier. Thanks!&username=John">
|
370 |
+
<img src="/chat?message=I just wanted to let you know that the meeting has been rescheduled to tomorrow at 3 PM. Please make sure to bring all the documents we discussed earlier. Thanks!&username=John" alt="Long message example">
|
371 |
+
</a>
|
372 |
+
</div>
|
373 |
+
|
374 |
+
<div class="example">
|
375 |
+
<h4>Reply Message:</h4>
|
376 |
+
<a href="/chat?message=Sounds great! I'll be there π&username=Mike&replyto=Want to grab coffee tomorrow morning?&repliedusername=Sarah">
|
377 |
+
<img src="/chat?message=Sounds great! I'll be there π&username=Mike&replyto=Want to grab coffee tomorrow morning?&repliedusername=Sarah" alt="Reply message example">
|
378 |
+
</a>
|
379 |
+
</div>
|
380 |
+
|
381 |
+
<div class="params">
|
382 |
+
<h3>π§ API Parameters:</h3>
|
383 |
+
<ul>
|
384 |
+
<li><code>message</code> - Your message text (supports emojis!)</li>
|
385 |
+
<li><code>username</code> - Sender's display name</li>
|
386 |
+
<li><code>replyto</code> - (Optional) Message being replied to</li>
|
387 |
+
<li><code>repliedusername</code> - (Optional) Original sender's name</li>
|
388 |
+
</ul>
|
389 |
+
|
390 |
+
<h4>Example URL:</h4>
|
391 |
+
<code>/chat?message=Hello World!&username=YourName&replyto=How are you?&repliedusername=Friend</code>
|
392 |
+
</div>
|
393 |
+
</div>
|
394 |
+
</body>
|
395 |
+
</html>
|
396 |
+
'''
|
397 |
+
|
398 |
+
if __name__ == '__main__':
|
399 |
+
app.run(debug=True, host='0.0.0.0', port=7860)
|