import os import time import argparse import requests from dotenv import load_dotenv from openai import OpenAI # 加载根目录或当前目录的 .env 文件 env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))), ".env") if os.path.exists(env_path): load_dotenv(env_path) else: load_dotenv() APIYI_KEY = os.getenv("APIYI_KEY") if APIYI_KEY and not APIYI_KEY.startswith("sk-"): APIYI_KEY = f"sk-{APIYI_KEY}" APIYI_BASE_URL = os.getenv("APIYI_BASE_URL", "https://api.apiyi.com/v1") if not APIYI_KEY: print("错误: 请在 .env 文件中设置 APIYI_KEY") exit(1) # 初始化客户端 client = OpenAI( api_key=APIYI_KEY, base_url=APIYI_BASE_URL ) import tempfile from urllib.parse import urlparse def download_image_from_url(url): """从 URL 下载图片到临时文件""" try: response = requests.get(url, timeout=30) response.raise_for_status() parsed_url = urlparse(url) extension = parsed_url.path.split('.')[-1] if '.' in parsed_url.path else 'jpg' temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=f'.{extension}') temp_file.write(response.content) temp_file.close() return temp_file.name except Exception as e: print(f"下载图片失败: {e}") return None def generate_flux_image(prompt, aspect_ratio="1:1", model="flux-kontext-pro", seed=None, safety_tolerance=2, output_format="jpeg", prompt_upsampling=False, image_url=None, mask_url=None): """ 生成或编辑 Flux 图像 """ mode = "编辑" if image_url else "生成" print(f"正在{mode}图像...") print(f" - 模型: {model}") print(f" - 比例: {aspect_ratio}") print(f" - 提示词: {prompt}") image_path = None mask_path = None image_file = None mask_file = None try: # 构建 extra_body 参数 extra_params = { "aspect_ratio": aspect_ratio, "safety_tolerance": safety_tolerance, "output_format": output_format } if seed is not None: extra_params["seed"] = seed if not image_url: # 纯生成特有参数 extra_params["prompt_upsampling"] = prompt_upsampling response = client.images.generate( model=model, prompt=prompt, extra_body=extra_params ) else: # 图生图编辑模式 print(f" - 参考图: {image_url}") image_path = download_image_from_url(image_url) if not image_path: raise ValueError("无法下载参考图") image_file = open(image_path, "rb") edit_kwargs = { "model": model, "image": image_file, "prompt": prompt, "extra_body": extra_params } if mask_url: print(f" - 蒙版图: {mask_url}") mask_path = download_image_from_url(mask_url) if mask_path: mask_file = open(mask_path, "rb") edit_kwargs["mask"] = mask_file response = client.images.edit(**edit_kwargs) image_out_url = response.data[0].url return image_out_url except Exception as e: print(f" 请求失败: {e}") return None finally: # 关闭文件并删除临时文件 if image_file: image_file.close() if mask_file: mask_file.close() for path in [image_path, mask_path]: if path and os.path.exists(path): try: os.unlink(path) except: pass def save_image_from_url(url, prompt, ratio): """从 URL 下载并保存图像""" if not url: return None try: print("正在下载临时链接中的图像...") response = requests.get(url, timeout=30) response.raise_for_status() # 生成文件名,替换掉可能导致问题的非法字符 timestamp = int(time.time()) safe_prompt = ''.join(c if c.isalnum() else '_' for c in prompt[:30]).strip('_') # 保存到当前目录下的 outputs 文件夹 output_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "outputs") os.makedirs(output_dir, exist_ok=True) filename = f"flux_{safe_prompt}_{ratio.replace(':', 'x')}_{timestamp}.png" filepath = os.path.join(output_dir, filename) with open(filepath, 'wb') as f: f.write(response.content) print(f"✅ 已成功保存至: {filepath}") return filepath except requests.exceptions.RequestException as e: print(f"❌ 下载失败: {e}") print("提示:Flux URL 仅 10 分钟有效,请确保及时手动下载!") return None if __name__ == "__main__": parser = argparse.ArgumentParser(description="Flux API 图像生成高级调试工具") parser.add_argument("--prompt", type=str, default="A futuristic city with flying cars and neon lights, high resolution, cyberpunk style", help="图像描述提示词") parser.add_argument("--ratio", type=str, default="16:9", help="宽高比 (如: 1:1, 16:9, 9:16, 2:3, 3:2)") parser.add_argument("--model", type=str, default="flux-kontext-pro", choices=["flux-kontext-pro", "flux-kontext-max"], help="模型名称") parser.add_argument("--seed", type=int, default=None, help="随机种子 (默认随机)") parser.add_argument("--format", type=str, default="png", choices=["jpeg", "png"], help="输出图片格式") parser.add_argument("--upsampling", action="store_true", help="开启提示词自动增强") args = parser.parse_args() image_url = generate_flux_image( prompt=args.prompt, aspect_ratio=args.ratio, model=args.model, seed=args.seed, output_format=args.format, prompt_upsampling=args.upsampling ) if image_url: print(f"\n✅ 生成成功!图像 URL (10分钟有效): \n{image_url}") save_image_from_url(image_url, args.prompt, args.ratio)