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}")