Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import numpy as np | |
| import random | |
| import logging | |
| import sys | |
| import os | |
| import requests | |
| import io | |
| import json | |
| import base64 | |
| from PIL import Image as PILImage | |
| # 设置日志记录 | |
| logging.basicConfig(level=logging.INFO, | |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', | |
| stream=sys.stdout) | |
| logger = logging.getLogger(__name__) | |
| # 补丁修复 Gradio JSON Schema 错误 | |
| try: | |
| import gradio_client.utils | |
| # 保存原始函数 | |
| original_get_type = gradio_client.utils.get_type | |
| # 创建新的 get_type 函数,处理布尔值 | |
| def patched_get_type(schema): | |
| if schema is True or schema is False or schema is None: | |
| return "any" | |
| if not isinstance(schema, dict): | |
| return "any" | |
| return original_get_type(schema) | |
| # 替换原始函数 | |
| gradio_client.utils.get_type = patched_get_type | |
| logger.info("Successfully patched gradio_client.utils.get_type") | |
| # 同样修补 _json_schema_to_python_type 函数 | |
| original_json_schema_to_python_type = gradio_client.utils._json_schema_to_python_type | |
| def patched_json_schema_to_python_type(schema, defs=None): | |
| if schema is True or schema is False: | |
| return "bool" | |
| if schema is None: | |
| return "None" | |
| if not isinstance(schema, dict): | |
| return "any" | |
| try: | |
| return original_json_schema_to_python_type(schema, defs) | |
| except Exception as e: | |
| logger.warning(f"Error in json_schema_to_python_type: {e}") | |
| return "any" | |
| gradio_client.utils._json_schema_to_python_type = patched_json_schema_to_python_type | |
| logger.info("Successfully patched gradio_client.utils._json_schema_to_python_type") | |
| except Exception as e: | |
| logger.error(f"Failed to patch Gradio utils: {e}") | |
| # 创建一个备用图像 | |
| def create_backup_image(prompt=""): | |
| logger.info(f"Creating backup image for: {prompt}") | |
| img = PILImage.new('RGB', (512, 512), color=(240, 240, 250)) | |
| try: | |
| from PIL import ImageDraw, ImageFont | |
| draw = ImageDraw.Draw(img) | |
| font = ImageFont.load_default() | |
| # 使用英文消息避免编码问题 | |
| draw.text((20, 20), f"Prompt: {prompt}", fill=(0, 0, 0), font=font) | |
| draw.text((20, 60), "Model loading failed. Showing placeholder image.", fill=(255, 0, 0), font=font) | |
| except Exception as e: | |
| logger.error(f"Error creating backup image: {e}") | |
| return img | |
| # 预加载图像用于快速响应 | |
| PLACEHOLDER_IMAGE = create_backup_image("placeholder") | |
| # 使用 Hugging Face Inference API 生成图像 | |
| def generate_image_with_api(prompt, api_url=None, api_key=None): | |
| """ | |
| 使用 Hugging Face Inference API 生成图像 | |
| Parameters: | |
| - prompt: 文本提示 | |
| - api_url: API 端点 URL (可选) | |
| - api_key: API 密钥 (可选) | |
| Returns: | |
| - PIL Image | |
| """ | |
| logger.info(f"Generating image via API for: {prompt}") | |
| # 默认使用 Stable Diffusion API | |
| if api_url is None: | |
| api_url = "https://api-inference.huggingface.co/models/runwayml/stable-diffusion-v1-5" | |
| # 尝试从环境变量中获取 API 密钥 | |
| if api_key is None: | |
| api_key = os.environ.get("HF_API_KEY", "") | |
| # 如果没有 API 密钥,使用公共访问(可能会受到速率限制) | |
| headers = {} | |
| if api_key: | |
| headers["Authorization"] = f"Bearer {api_key}" | |
| try: | |
| # 设置请求参数 | |
| payload = { | |
| "inputs": prompt, | |
| "parameters": { | |
| "num_inference_steps": 10, # 减少推理步骤以加快速度 | |
| "guidance_scale": 7.5, | |
| "width": 512, | |
| "height": 512 | |
| } | |
| } | |
| # 发送请求 | |
| response = requests.post(api_url, headers=headers, json=payload) | |
| # 检查响应是否成功 | |
| if response.status_code == 200: | |
| # 从响应中获取图像 | |
| image = PILImage.open(io.BytesIO(response.content)) | |
| logger.info("Successfully generated image via API") | |
| return image | |
| else: | |
| # 如果遇到错误,记录响应并返回备用图像 | |
| error_text = response.text | |
| logger.error(f"API error: {response.status_code}, {error_text}") | |
| return None | |
| except Exception as e: | |
| logger.error(f"Failed to generate image via API: {e}") | |
| return None | |
| # 使用 Hugging Face Spaces 内置模型生成图像 | |
| def generate_image_with_spaces(prompt): | |
| """使用同一个 Hugging Face Space 内的其他公共空间来生成图像""" | |
| logger.info(f"Generating image via Spaces for: {prompt}") | |
| try: | |
| # 一些公共可用的 Stable Diffusion 空间 URLs | |
| space_urls = [ | |
| "https://huggingface-projects-stable-diffusion-demo.hf.space/api/predict", | |
| "https://huggingface-projects-text-to-image.hf.space/api/predict", | |
| "https://dataautogpt-playground.hf.space/api/predict" | |
| ] | |
| # 尝试每个 URL 直到成功 | |
| for url in space_urls: | |
| try: | |
| payload = { | |
| "data": [prompt, 7.5, 512, 512] | |
| } | |
| response = requests.post(url, json=payload, timeout=30) | |
| if response.status_code == 200: | |
| # 解析 JSON 响应 | |
| result = response.json() | |
| # 根据结果格式提取图像数据 | |
| if isinstance(result, dict) and 'data' in result: | |
| image_data = result['data'][0] | |
| # 检查图像数据格式 | |
| if image_data.startswith('data:image'): | |
| # 提取 base64 图像数据 | |
| image_b64 = image_data.split(',')[1] | |
| image_bytes = base64.b64decode(image_b64) | |
| image = PILImage.open(io.BytesIO(image_bytes)) | |
| logger.info(f"Successfully generated image via {url}") | |
| return image | |
| except Exception as e: | |
| logger.warning(f"Failed to generate with {url}: {e}") | |
| continue | |
| logger.error("All space URLs failed") | |
| return None | |
| except Exception as e: | |
| logger.error(f"Failed to generate image via Spaces: {e}") | |
| return None | |
| # 使用简单的规则生成图像作为备用方案 | |
| def generate_rule_based_image(prompt): | |
| """当AI模型不可用时使用规则生成图像""" | |
| logger.info(f"Using rule-based generator for: {prompt}") | |
| # 创建基础图像 | |
| img = PILImage.new('RGB', (512, 512), color=(240, 240, 250)) | |
| try: | |
| from PIL import ImageDraw, ImageFont | |
| draw = ImageDraw.Draw(img) | |
| # 提取关键词 | |
| prompt_lower = prompt.lower() | |
| # 设置默认颜色和形状 | |
| bg_color = (240, 240, 250) # 浅蓝背景 | |
| shape_color = (64, 64, 128) # 深蓝形状 | |
| # 基于关键词调整颜色 | |
| if "red" in prompt_lower: | |
| shape_color = (200, 50, 50) | |
| elif "blue" in prompt_lower: | |
| shape_color = (50, 50, 200) | |
| elif "green" in prompt_lower: | |
| shape_color = (50, 200, 50) | |
| elif "yellow" in prompt_lower: | |
| shape_color = (200, 200, 50) | |
| # 画一个基本形状 | |
| if "cat" in prompt_lower or "kitten" in prompt_lower: | |
| # 猫头 | |
| draw.ellipse((156, 156, 356, 356), fill=shape_color) | |
| # 猫眼睛 | |
| draw.ellipse((206, 206, 236, 236), fill=(255, 255, 255)) | |
| draw.ellipse((276, 206, 306, 236), fill=(255, 255, 255)) | |
| # 猫瞳孔 | |
| draw.ellipse((216, 216, 226, 226), fill=(0, 0, 0)) | |
| draw.ellipse((286, 216, 296, 226), fill=(0, 0, 0)) | |
| # 猫鼻子 | |
| draw.polygon([(256, 256), (246, 276), (266, 276)], fill=(255, 150, 150)) | |
| # 猫耳朵 | |
| draw.polygon([(156, 156), (176, 96), (216, 156)], fill=shape_color) | |
| draw.polygon([(356, 156), (336, 96), (296, 156)], fill=shape_color) | |
| elif "landscape" in prompt_lower or "mountain" in prompt_lower: | |
| # 天空 | |
| draw.rectangle([(0, 0), (512, 300)], fill=(100, 150, 250)) | |
| # 山脉 | |
| draw.polygon([(0, 300), (150, 100), (300, 300)], fill=(100, 100, 100)) | |
| draw.polygon([(200, 300), (400, 150), (512, 300)], fill=(80, 80, 80)) | |
| # 地面 | |
| draw.rectangle([(0, 300), (512, 512)], fill=(100, 200, 100)) | |
| elif "castle" in prompt_lower or "building" in prompt_lower: | |
| # 天空 | |
| draw.rectangle([(0, 0), (512, 200)], fill=(150, 200, 250)) | |
| # 主塔 | |
| draw.rectangle([(200, 200), (312, 400)], fill=shape_color) | |
| # 塔顶 | |
| draw.polygon([(180, 200), (256, 100), (332, 200)], fill=(180, 0, 0)) | |
| # 小塔 | |
| draw.rectangle([(150, 300), (200, 400)], fill=shape_color) | |
| draw.rectangle([(312, 300), (362, 400)], fill=shape_color) | |
| # 城墙 | |
| draw.rectangle([(100, 400), (412, 450)], fill=shape_color) | |
| # 地面 | |
| draw.rectangle([(0, 450), (512, 512)], fill=(100, 150, 100)) | |
| else: | |
| # 默认绘制几何形状 | |
| draw.rectangle([(100, 100), (412, 412)], outline=(0, 0, 0), width=2) | |
| draw.ellipse((150, 150, 362, 362), fill=shape_color) | |
| draw.polygon([(256, 100), (412, 412), (100, 412)], fill=(shape_color[0]//2, shape_color[1]//2, shape_color[2]//2)) | |
| # 添加提示词和说明 | |
| font = ImageFont.load_default() | |
| draw.text((10, 10), f"Prompt: {prompt}", fill=(0, 0, 0), font=font) | |
| draw.text((10, 30), "Generated with rules (AI model unavailable)", fill=(100, 100, 100), font=font) | |
| except Exception as e: | |
| logger.error(f"Error in rule-based image generation: {e}") | |
| return img | |
| # 入口点函数 - 处理请求并生成图像 | |
| def generate_image(prompt): | |
| # 处理空提示 | |
| if not prompt or prompt.strip() == "": | |
| prompt = "a beautiful landscape" | |
| logger.info(f"Empty prompt, using default: {prompt}") | |
| logger.info(f"Received prompt: {prompt}") | |
| # 尝试使用 Hugging Face API 生成 | |
| image = generate_image_with_api(prompt) | |
| if image is not None: | |
| return image | |
| # 如果 API 方法失败,尝试使用 Spaces | |
| logger.info("API method failed, trying Spaces method...") | |
| image = generate_image_with_spaces(prompt) | |
| if image is not None: | |
| return image | |
| # 如果所有 AI 方法都失败,使用规则生成 | |
| logger.warning("All AI methods failed, using rule-based image generation") | |
| return generate_rule_based_image(prompt) | |
| # 为旧版 gradio 创建界面 | |
| def create_demo(): | |
| # 使用 Interface 替代 Blocks (兼容3.19.1) | |
| demo = gr.Interface( | |
| fn=generate_image, | |
| inputs=gr.Textbox( | |
| label="Prompt", | |
| placeholder="Describe the image you want, e.g.: a cute cat, sunset over mountains...", | |
| lines=2 | |
| ), | |
| outputs=gr.Image(label="Generated Image", type="pil"), | |
| title="Text to Image Generator", | |
| description="Enter a text description to generate an image. This demo uses Hugging Face API for image generation.", | |
| examples=[ | |
| "a cute cat sitting on a windowsill", | |
| "beautiful sunset over mountains", | |
| "an astronaut riding a horse in space", | |
| "a fantasy castle on a floating island" | |
| ], | |
| flagging_mode="never", # 使用枚举值 'never' 而不是 False | |
| cache_examples=False | |
| ) | |
| return demo | |
| # 创建演示界面 | |
| demo = create_demo() | |
| # 启动应用 | |
| if __name__ == "__main__": | |
| try: | |
| logger.info("Starting Gradio interface...") | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| share=False | |
| ) | |
| except Exception as e: | |
| logger.error(f"Failed to launch: {e}") | |