davidzhao66's picture
Upload 6 files
c76d407 verified
Raw
History Blame Contribute Delete
8.94 kB
import streamlit as st
import io
import requests
import random
import datetime
import qrcode
import json
from PIL import Image, ImageDraw, ImageFont
from huggingface_hub import hf_hub_download
from deep_translator import GoogleTranslator
import numpy as np
import os
import shutil
DATASET_ID = os.getenv("DATASET_ID")
HF_TOKEN = os.getenv("HF_TOKEN")
try:
from streamlit.runtime.scriptrunner import add_script_run_ctx
except ImportError:
def add_script_run_ctx(t): pass
OPENCV_AVAILABLE = False
try:
import cv2
from cv2 import dnn_superres
OPENCV_AVAILABLE = True
except ImportError:
pass
PSUTIL_AVAILABLE = False
try:
import psutil
PSUTIL_AVAILABLE = True
except ImportError:
pass
# [V30.12] 内存优化:使用上下文管理器确保图片句柄立即释放
def generate_thumbnail(image_bytes, size=(360, 360), quality=80):
try:
with Image.open(io.BytesIO(image_bytes)) as img:
if img.mode in ("RGBA", "P"):
img = img.convert("RGB")
# 使用低算力算法
img.thumbnail(size, Image.Resampling.BILINEAR)
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=quality, optimize=True)
return buf.getvalue()
except Exception:
return None
def get_disk_info(path):
try:
total_size = 0
if os.path.exists(path):
for dirpath, dirnames, filenames in os.walk(path):
for f in filenames:
fp = os.path.join(dirpath, f)
if not os.path.islink(fp):
total_size += os.path.getsize(fp)
used_gb = total_size / (1024**3)
total_host, used_host, free_host = shutil.disk_usage("/")
return used_gb, free_host / (1024**3), total_host / (1024**3), (used_host / total_host) * 100
except Exception:
return 0, 0, 0, 0
def _download_image_from_hf(repo_id, filename, token):
try:
# [V30.12] 移除 resume_download
path = hf_hub_download(repo_id=repo_id, filename=filename, repo_type="dataset", token=token, local_files_only=True)
with open(path, "rb") as f: return f.read()
except:
try:
path = hf_hub_download(repo_id=repo_id, filename=filename, repo_type="dataset", token=token)
with open(path, "rb") as f: return f.read()
except Exception:
return None
def ensure_png_bytes(image_data):
try:
with Image.open(io.BytesIO(image_data)) as img:
buf = io.BytesIO()
img.save(buf, format="PNG")
return buf.getvalue()
except Exception:
return image_data
def auto_translate(text):
if not text: return text, False
if any("\u4e00" <= char <= "\u9fff" for char in text):
try:
return GoogleTranslator(source='auto', target='en').translate(text), True
except Exception:
return text, False
return text, False
class PromptLoader:
def __init__(self):
self.config_file = "prompts_config.json"
self.data = self.load_data()
def load_data(self):
try:
path = hf_hub_download(repo_id=DATASET_ID, filename=self.config_file, repo_type="dataset", token=HF_TOKEN, local_files_only=True)
return json.load(open(path, "r"))
except:
try:
path = hf_hub_download(repo_id=DATASET_ID, filename=self.config_file, repo_type="dataset", token=HF_TOKEN)
return json.load(open(path, "r"))
except:
return {
"subjects": ["cyberpunk city", "magical forest", "robot cat"],
"environments": ["in rain", "under moonlight", "in space"],
"lighting": ["neon", "cinematic", "natural"]
}
def get_random_prompt(self):
s = random.choice(self.data.get("subjects", ["cat"]))
e = random.choice(self.data.get("environments", ["home"]))
l = random.choice(self.data.get("lighting", ["day"]))
return f"Illustration of {s} {e}, {l}."
class LocalUpscaler:
def __init__(self):
self.model_path = "FSRCNN_x2.pb"
def process(self, image_bytes):
if OPENCV_AVAILABLE and not os.path.exists(self.model_path):
try:
r = requests.get("https://github.com/Saafke/FSRCNN_Tensorflow/raw/master/models/FSRCNN_x2.pb", timeout=30)
if r.status_code == 200:
with open(self.model_path, "wb") as f: f.write(r.content)
except: pass
if OPENCV_AVAILABLE and os.path.exists(self.model_path):
try:
nparr = np.frombuffer(image_bytes, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
sr = cv2.dnn_superres.DnnSuperResImpl_create()
sr.readModel(self.model_path)
sr.setModel("fsrcnn", 2)
result = sr.upsample(img)
is_success, buffer = cv2.imencode(".png", result)
if is_success: return buffer.tobytes(), "AI FSRCNN"
except: pass
try:
with Image.open(io.BytesIO(image_bytes)) as img:
upscaled = img.resize((img.width * 2, img.height * 2), Image.Resampling.LANCZOS)
buf = io.BytesIO()
upscaled.save(buf, format="PNG")
return buf.getvalue(), "HQ Lanczos"
except Exception as e:
raise ValueError(f"Upscaling failed: {e}")
class SocialPosterGenerator:
def __init__(self):
self.font_path = "SimHei.ttf"
self._ensure_font()
def _ensure_font(self):
if not os.path.exists(self.font_path):
try:
r = requests.get("https://github.com/StellarCN/scp_zh/raw/master/fonts/SimHei.ttf", timeout=30)
with open(self.font_path, "wb") as f: f.write(r.content)
except: pass
def _get_text_width(self, text, font, draw):
return draw.textlength(text, font=font)
def create_card(self, image_bytes, prompt_text, qr_content, footer_text="AI 灵感绘图 PRO"):
try: base_img = Image.open(io.BytesIO(image_bytes)).convert("RGBA")
except: return None
padding = 50
text_area_height = 340
canvas_width = base_img.width
canvas_height = base_img.height + text_area_height
poster = Image.new("RGBA", (canvas_width, canvas_height), (255, 255, 255, 255))
poster.paste(base_img, (0, 0))
draw = ImageDraw.Draw(poster)
try:
font_title = ImageFont.truetype(self.font_path, 36)
font_text = ImageFont.truetype(self.font_path, 24)
font_footer = ImageFont.truetype(self.font_path, 20)
except:
font_title = font_text = font_footer = ImageFont.load_default()
draw.text((padding, base_img.height + 40), "🎨 AI 创意画作", font=font_title, fill="#222222")
qr_size = 150
try:
qr = qrcode.QRCode(box_size=4, border=1)
qr.add_data(qr_content or "https://huggingface.co/spaces")
qr.make(fit=True)
qr_img = qr.make_image(fill_color="black", back_color="white").convert("RGBA").resize((qr_size, qr_size))
poster.paste(qr_img, (canvas_width - qr_size - padding, base_img.height + (text_area_height - qr_size) // 2))
except: pass
text_width_limit = canvas_width - padding * 2 - qr_size - 20
lines = []
current_line = ""
clean_text = prompt_text.replace('\n', ' ').replace('\r', '')
for char in clean_text:
if self._get_text_width(current_line + char, font_text, draw) <= text_width_limit:
current_line += char
else:
lines.append(current_line)
current_line = char
if current_line: lines.append(current_line)
if len(lines) > 4: lines = lines[:4]; lines[-1] = lines[-1][:-3] + "..."
current_h = base_img.height + 100
for line in lines:
draw.text((padding, current_h), line, font=font_text, fill="#555555")
current_h += 36
date_str = datetime.datetime.now().strftime('%Y-%m-%d')
draw.text((padding, canvas_height - 50), f"{footer_text} · {date_str}", font=font_footer, fill="#999999")
buf = io.BytesIO()
poster.convert("RGB").save(buf, format="JPEG", quality=95)
# GC helper
base_img.close()
poster.close()
return buf.getvalue()