Spaces:
Running
Running
Rename index.html to app.py
Browse files- app.py +92 -0
- index.html +0 -19
app.py
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI
|
2 |
+
from fastapi.responses import StreamingResponse
|
3 |
+
from pydantic import BaseModel
|
4 |
+
from PIL import Image, ImageDraw, ImageFont
|
5 |
+
import requests
|
6 |
+
from io import BytesIO
|
7 |
+
import os
|
8 |
+
|
9 |
+
app = FastAPI()
|
10 |
+
|
11 |
+
class WelcomeRequest(BaseModel):
|
12 |
+
username: str
|
13 |
+
avatar_url: str | None = None
|
14 |
+
|
15 |
+
def load_font(size: int = 60) -> ImageFont.FreeTypeFont:
|
16 |
+
font_paths = [
|
17 |
+
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
|
18 |
+
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
|
19 |
+
"/usr/share/fonts/truetype/freefont/FreeSans.ttf",
|
20 |
+
"/System/Library/Fonts/Arial.ttf", # macOS
|
21 |
+
"C:/Windows/Fonts/arial.ttf", # Windows
|
22 |
+
"arial.ttf"
|
23 |
+
]
|
24 |
+
|
25 |
+
for path in font_paths:
|
26 |
+
try:
|
27 |
+
if os.path.exists(path):
|
28 |
+
return ImageFont.truetype(path, size)
|
29 |
+
except Exception as e:
|
30 |
+
print(f"Failed to load font {path}: {e}")
|
31 |
+
continue
|
32 |
+
|
33 |
+
# If no TrueType font found, try to use default but warn
|
34 |
+
print(f"Warning: Using default font, size may not scale properly")
|
35 |
+
try:
|
36 |
+
return ImageFont.load_default(size)
|
37 |
+
except:
|
38 |
+
return ImageFont.load_default()
|
39 |
+
|
40 |
+
@app.post("/generate-welcome")
|
41 |
+
async def generate_welcome(data: WelcomeRequest):
|
42 |
+
try:
|
43 |
+
base_image = Image.open("ChatGPT Image May 27, 2025, 05_24_11 AM.png").convert("RGBA")
|
44 |
+
except FileNotFoundError:
|
45 |
+
return {"error": "base_image.png not found"}
|
46 |
+
|
47 |
+
width, height = base_image.size
|
48 |
+
draw = ImageDraw.Draw(base_image)
|
49 |
+
|
50 |
+
# === Big, centered username font ===
|
51 |
+
username_font_size = 50
|
52 |
+
font = load_font(username_font_size)
|
53 |
+
|
54 |
+
# Debug: Check if font loaded properly
|
55 |
+
print(f"Font loaded: {type(font)}, size: {username_font_size}")
|
56 |
+
|
57 |
+
text_color = (148, 255, 255)
|
58 |
+
|
59 |
+
# === Position elements in lower center area ===
|
60 |
+
username_with_at = f"@{data.username}" # Add @ symbol
|
61 |
+
text_width = draw.textlength(username_with_at, font=font)
|
62 |
+
username_x = (width - text_width) // 2
|
63 |
+
|
64 |
+
# Position username in lower portion of image
|
65 |
+
username_y = height - 120 # 120px from bottom
|
66 |
+
|
67 |
+
# === Optional avatar ===
|
68 |
+
avatar_size = 120
|
69 |
+
if data.avatar_url:
|
70 |
+
try:
|
71 |
+
response = requests.get(data.avatar_url)
|
72 |
+
avatar = Image.open(BytesIO(response.content)).convert("RGBA").resize((avatar_size, avatar_size))
|
73 |
+
|
74 |
+
mask = Image.new("L", (avatar_size, avatar_size), 0)
|
75 |
+
draw_mask = ImageDraw.Draw(mask)
|
76 |
+
draw_mask.ellipse((0, 0, avatar_size, avatar_size), fill=255)
|
77 |
+
|
78 |
+
# Position avatar above the username in lower center
|
79 |
+
avatar_x = width // 2 - avatar_size // 2
|
80 |
+
avatar_y = username_y - avatar_size - 30 # 30px gap above username
|
81 |
+
|
82 |
+
base_image.paste(avatar, (avatar_x, avatar_y), mask)
|
83 |
+
except Exception as e:
|
84 |
+
print("Error loading avatar:", e)
|
85 |
+
|
86 |
+
# === Draw large centered username with @ symbol in lower area ===
|
87 |
+
draw.text((username_x, username_y), username_with_at, fill=text_color, font=font)
|
88 |
+
|
89 |
+
output = BytesIO()
|
90 |
+
base_image.save(output, format='PNG')
|
91 |
+
output.seek(0)
|
92 |
+
return StreamingResponse(output, media_type="image/png")
|
index.html
DELETED
@@ -1,19 +0,0 @@
|
|
1 |
-
<!doctype html>
|
2 |
-
<html>
|
3 |
-
<head>
|
4 |
-
<meta charset="utf-8" />
|
5 |
-
<meta name="viewport" content="width=device-width" />
|
6 |
-
<title>My static Space</title>
|
7 |
-
<link rel="stylesheet" href="style.css" />
|
8 |
-
</head>
|
9 |
-
<body>
|
10 |
-
<div class="card">
|
11 |
-
<h1>Welcome to your static Space!</h1>
|
12 |
-
<p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
|
13 |
-
<p>
|
14 |
-
Also don't forget to check the
|
15 |
-
<a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
|
16 |
-
</p>
|
17 |
-
</div>
|
18 |
-
</body>
|
19 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|