| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- 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)
|