欢迎光临
我们一直在努力

无偿分享ChatGPT Image 2画图网页与并发绘图python程序【Ai绘图】

目录

1、免费资源 

2、0.04超低价付费资源


1、免费资源 

无偿分享每日免费10+次画图网页分享,该网页非本人开发

https://clotheschange.ai/zh

ChatGPT Image 2 可用于营销广告素材的快速生成(海报、电商主图)、出版与内容创作支持(漫画分镜、书籍插图、人物设计),以及教育与科研中的可视化(课件、信息图表、实验示意图)。此外,也能应用于课堂上的学习材料制作(如学习指南)、帮助激发创意灵感和原型设计。

请严格遵守法律法规。

2、0.04超低价付费资源

代码无偿分析,搭配专有画图网页与API使用。

ChatGPT Image 2—0.04/张 附带画图网页与并发绘图python程序【Ai绘图】

画图网页:https://api.zmoapi.cn/image/

资源稳定不涨价

# -*- coding: utf-8 -*-
import os
import time
import random
import requests
import base64
import tempfile
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
from PIL import Image

# ================= 配置区域 =================
API_BASE_URL = "https://api.zmi"
API_KEY = "sk-hK8_KMnpJ-vaEHfgkCfWjr5"
KEY_ID = "367c2ba9914c"
KEY_NAME = "BetaCat."
MODEL = "gpt-image-2"
GENERATION_ENDPOINT = "/v1/images/generations"

folders = [
(r"E:\\AiPhoto\\photo\\1", 9),
(r"E:\\AiPhoto\\photo\\4", 9),
(r"E:\\AiPhoto\\photo\\11", 9),
(r"E:\\AiPhoto\\photo\\12", 9),
(r"E:\\AiPhoto\\photo\\13", 9),
]

loop_count = 0
round_interval = 90
output_dir = r"E:\\AiPhoto\\output8"
temp_dir = r"E:\\AiPhoto\\Atemp"
os.makedirs(output_dir, exist_ok=True)
os.makedirs(temp_dir, exist_ok=True)

max_workers = 2
rate_per_minute = 2
CONSOLE_CLEAR_INTERVAL = 180 # 每3分钟清空控制台

# ========== 子图布局描述 ==========
LAYOUTS = {
"collage": "子图排列为错落叠压/杂志拼贴风格:子图大小不一,部分重叠(半透明或边缘交错),不严格对齐。时尚、前卫、层次丰富,类似平面设计排版。不同子图的人可以跨越边界互动"
}

# ========== 简化后的提示词模板 ==========
PROMPT_TEMPLATE = (

"""

)

# ========== 控制台清屏功能 ==========
def clear_console():
"""清空控制台内容(兼容 Windows / Linux / macOS)"""
command = 'cls' if os.name == 'nt' else 'clear'
os.system(command)

def clear_loop():
"""后台线程:每隔 CONSOLE_CLEAR_INTERVAL 秒清屏一次"""
while True:
time.sleep(CONSOLE_CLEAR_INTERVAL)
clear_console()

# ========== 限流器(滑动窗口) ==========
class RateLimiter:
def __init__(self, max_per_minute):
self.max_per_minute = max_per_minute
self.timestamps = []
self.lock = threading.Lock()

def acquire(self):
with self.lock:
now = time.time()
self.timestamps = [t for t in self.timestamps if now – t < 60]
if len(self.timestamps) >= self.max_per_minute:
wait_time = 60 – (now – self.timestamps[0]) + 0.1
print(f"⏳ 达到速率限制 ({self.max_per_minute}次/分钟),等待 {wait_time:.1f} 秒…")
time.sleep(wait_time)
now = time.time()
self.timestamps = [t for t in self.timestamps if now – t < 60]
self.timestamps.append(now)

limiter = RateLimiter(rate_per_minute)

# ========== 延迟删除辅助函数 ==========
def delete_later(file_path, delay=180):
"""在 delay 秒后删除文件(默认3分钟)"""

def remove_file():
try:
if os.path.exists(file_path):
os.remove(file_path)
print(f"🗑️ 已删除临时文件: {file_path}")
except Exception as e:
print(f"⚠️ 删除临时文件失败 {file_path}: {e}")

timer = threading.Timer(delay, remove_file)
timer.daemon = True
timer.start()

# ========== 图片尺寸规范化(保持宽高比) ==========
def resize_image_to_bounds(img, min_size=1024, max_size=2048):
"""将图片缩放,使其满足:
– 若最大边长 > max_size,则缩小至最大边长为 max_size
– 否则若最小边长 < min_size,则放大至最小边长为 min_size
保持宽高比不变。
"""
width, height = img.width, img.height
max_dim = max(width, height)
min_dim = min(width, height)

if max_dim > max_size:
scale = max_size / max_dim
new_w = int(width * scale)
new_h = int(height * scale)
img = img.resize((new_w, new_h), Image.Resampling.LANCZOS)
return img

if min_dim < min_size:
scale = min_size / min_dim
new_w = int(width * scale)
new_h = int(height * scale)
img = img.resize((new_w, new_h), Image.Resampling.LANCZOS)
return img

return img

# ========== 图片拼接函数(保持每个子图宽高比) ==========
def merge_images(image_paths, output_path=None, max_size=2048):
"""
将多张图片拼合成网格。
每张子图先进行边界缩放(保持比例),然后统一放入相同大小的格子中(居中放置,留白填充)。
若合并后的画布最大边长超过 max_size,则整体等比例缩小。
"""
if not image_paths:
return None

images = []
for path in image_paths:
img = Image.open(path).convert("RGB")
img = resize_image_to_bounds(img)
images.append(img)

n = len(images)
cols = int(n ** 0.5)
rows = (n + cols – 1) // cols
if cols * rows < n:
cols += 1

cell_w = max(img.width for img in images)
cell_h = max(img.height for img in images)

merged_width = cell_w * cols
merged_height = cell_h * rows
merged_img = Image.new("RGB", (merged_width, merged_height), (255, 255, 255))

for idx, img in enumerate(images):
row = idx // cols
col = idx % cols
x0 = col * cell_w
y0 = row * cell_h

scale = min(cell_w / img.width, cell_h / img.height)
new_w = int(img.width * scale)
new_h = int(img.height * scale)
if new_w <= 0 or new_h <= 0:
continue
img_resized = img.resize((new_w, new_h), Image.Resampling.LANCZOS)

x_offset = (cell_w – new_w) // 2
y_offset = (cell_h – new_h) // 2
merged_img.paste(img_resized, (x0 + x_offset, y0 + y_offset))

max_dim = max(merged_width, merged_height)
if max_dim > max_size:
scale = max_size / max_dim
new_w = int(merged_width * scale)
new_h = int(merged_height * scale)
merged_img = merged_img.resize((new_w, new_h), Image.Resampling.LANCZOS)

if output_path is None:
os.makedirs(temp_dir, exist_ok=True)
timestamp = int(time.time() * 1000)
rand = random.randint(1000, 9999)
output_path = os.path.join(temp_dir, f"merged_{timestamp}_{rand}.jpg")
merged_img.save(output_path, quality=95)
return output_path

# ========== 按文件夹选取图片 ==========
def pick_images_by_folder(folder_configs):
result = []
for folder, num in folder_configs:
if num <= 0:
continue
if not os.path.exists(folder):
print(f"⚠️ 文件夹不存在: {folder}")
return []
images = [f for f in os.listdir(folder) if f.lower().endswith((".png", ".jpg", ".jpeg"))]
if len(images) < num:
print(f"⚠️ 文件夹 {folder} 中图片不足 {num} 张(实际 {len(images)} 张),跳过本轮")
return []
chosen = random.sample(images, num)
chosen_paths = [os.path.join(folder, img) for img in chosen]
result.append((folder, chosen_paths))
return result

# ========== API调用 ==========
def call_generation_api(prompt, reference_image_paths, max_retries=3):
print(f"📤 准备上传参考图 {len(reference_image_paths)} 张:")
for idx, path in enumerate(reference_image_paths, 1):
print(f" {idx}. {path}")

print("🔄 正在编码参考图为 Base64…")
image_data_list = []
for img_path in reference_image_paths:
try:
with open(img_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")
image_data_list.append(b64)
except Exception as e:
print(f"❌ 编码失败 {os.path.basename(img_path)}: {e}")
return []
if len(image_data_list) != len(reference_image_paths):
print(f"❌ 实际编码图片数量({len(image_data_list)})与输入数量({len(reference_image_paths)})不一致")
return []
print("✅ 编码完成")

headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
payload = {
"key_id": KEY_ID,
"key_name": KEY_NAME,
"model": MODEL,
"prompt": prompt,
"reference_images": image_data_list,
"num_images": 1,
"safety_filter": False
}

for attempt in range(max_retries):
try:
print(f"📡 第 {attempt + 1} 次尝试请求 API…")
response = requests.post(
API_BASE_URL + GENERATION_ENDPOINT,
headers=headers,
json=payload,
timeout=(10, 300)
)
print(f"📨 响应状态码: {response.status_code}")

if response.status_code == 400:
try:
error_json = response.json()
error_code = error_json.get("error", {}).get("code")
error_msg = error_json.get("error", {}).get("message", "无详细消息")
print(f"❌ API 拒绝请求 (400)")
print(f" 错误代码: {error_code}")
print(f" 错误信息: {error_msg}")
if error_code == "content_policy_violation":
print("⚠️ 内容策略违规!可能由于参考图中包含敏感内容或提示词触发策略。")
print("📋 本次上传的所有参考图如下(请检查是否可能包含不当内容):")
for path in reference_image_paths:
print(f" – {path}")
print("📝 提示词前5000字符:")
print(prompt[:5000] + "……")
else:
print(f" 完整响应: {error_json}")
return []
except:
print(f"❌ API 返回400但无法解析JSON: {response.text[:300]}")
return []

elif response.status_code == 200:
data = response.json()
if "urls" in data and data["urls"]:
print(f"✅ API 接受所有参考图,成功生成 {len(data['urls'])} 张图片")
return data["urls"]
elif "url" in data and data["url"]:
print("✅ API 接受所有参考图,成功生成1张图片")
return [data["url"]]
elif "data" in data and isinstance(data["data"], list):
urls = [item.get("url") for item in data["data"] if item.get("url")]
if urls:
print(f"✅ API 接受所有参考图,成功生成 {len(urls)} 张图片")
return urls
print(f"❌ API 返回200但格式异常,未找到图片URL: {data}")
return []
else:
print(f"❌ API 请求失败,状态码: {response.status_code}")
print(f" 响应内容: {response.text[:500]}")
return []

except requests.exceptions.Timeout:
print(f"⏱️ 请求超时 (尝试 {attempt + 1}/{max_retries}),等待后重试…")
time.sleep(10 * (attempt + 1))
except Exception as e:
print(f"❌ 请求异常 (尝试 {attempt + 1}/{max_retries}): {e}")
time.sleep(5)
return []

def download_image(url, save_path):
try:
resp = requests.get(url, timeout=60)
resp.raise_for_status()
with open(save_path, "wb") as f:
f.write(resp.content)
print(f"✅ 图片已下载: {save_path}")
except Exception as e:
print(f"❌ 保存图片失败: {e}")

def process_one_round(round_id):
print(f"\\n[任务 {round_id}] 开始")
folder_images = pick_images_by_folder(folders)
if not folder_images:
print(f"[任务 {round_id}] 素材不足,跳过")
return

merged_paths = []
temp_files = []
for folder_name, img_paths in folder_images:
print(f"[任务 {round_id}] 拼接文件夹 {folder_name} 中的 {len(img_paths)} 张图片…")
merged = merge_images(img_paths)
if merged:
merged_paths.append(merged)
temp_files.append(merged)
else:
print(f"[任务 {round_id}] 文件夹 {folder_name} 拼接失败,跳过本轮")
for f in temp_files:
delete_later(f)
return

print(f"[任务 {round_id}] 共生成 {len(merged_paths)} 张拼接图")
limiter.acquire()

layout_key = random.choice(list(LAYOUTS.keys()))
layout_desc = LAYOUTS[layout_key]
print(f"[任务 {round_id}] 选择布局: {layout_key}")

num_refs = len(merged_paths)
placeholders = ", ".join([f"image{i + 1}" for i in range(num_refs)])

prompt = PROMPT_TEMPLATE.format(
placeholders=placeholders,
layout_description=layout_desc
)

print(f"[任务 {round_id}] 调用 API…")
generated_urls = call_generation_api(prompt, merged_paths)

for f in temp_files:
delete_later(f, delay=180)

if not generated_urls:
print(f"[任务 {round_id}] 生成失败")
return

timestamp = time.strftime("%Y%m%d_%H%M%S")
for idx, url in enumerate(generated_urls):
filename = f"gen_{timestamp}_{round_id}_{idx + 1}.png"
save_path = os.path.join(output_dir, filename)
download_image(url, save_path)
print(f"[任务 {round_id}] 完成")

# ========== 主流程 ==========
def main():
# 启动后台清屏线程
threading.Thread(target=clear_loop, daemon=True).start()

round_number = 0
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = []
try:
while True:
round_number += 1
if loop_count > 0 and round_number > loop_count:
for f in as_completed(futures):
f.result()
break
future = executor.submit(process_one_round, round_number)
futures.append(future)
futures = [f for f in futures if not f.done()]
time.sleep(1)
except KeyboardInterrupt:
print("\\n用户中断,等待剩余任务完成…")
for f in as_completed(futures):
f.result()
print("所有任务已终止")

if __name__ == "__main__":
main()

赞(0)
未经允许不得转载:171主机测评 » 无偿分享ChatGPT Image 2画图网页与并发绘图python程序【Ai绘图】
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址