用Nano Banana API编辑图像

如果我们把最好的免费 API AI 提供商和最新的 Google 图像生成模型结合起来会怎样?

用Nano Banana API编辑图像

如果我们把最好的免费 API AI 提供商和最新的 Google 图像生成模型结合起来会怎样?

这篇文章讲述了这样一个成功的配对故事。

我一直都是 OpenRouter 的超级粉丝。

OpenRouter 是一个平台,它让你可以免费(甚至付费)访问顶级的 AI 生成模型。

最近,他们添加了免费层级的图像生成功能……这意味着你可以使用一些模型为你生成图像且零成本。

这是一个相当重要的公告:事实上,即使你可以在自己的电脑上运行任何现有的 LLM,确实不需要专用 GPU(只要你有足够的 RAM),但同样的原则并不适用于图像。

准确地说,100% 你可以,但你可能需要等待大约 30 分钟才能得到结果(而且可能根本不是你想要的……)。

1、Nano-Banana 模型的最新公告

因此,我决定与 Google 的新“Nano Banana”AI 模型进行一些实验——是的,这是它的真名——说实话,这有点重要。我知道你在想什么:“香蕉?就像……水果?”我也一样。但嘿,如果它能帮助我无需打开 Photoshop 就编辑照片,我会接受的。

有趣的部分是:我上传了一张我的狗 Pepe(显然,我的好狗狗)的照片,并告诉 AI 给他戴一顶小帽子。然后是一条超级英雄披风。然后想象他成为 90 年代的情景喜剧父亲。猜猜看?

他仍然看起来像我的狗,还是原来的 Pepe。

没有奇怪的外星变异或额外的眼睛。这是因为 Nano Banana — 正式称为 Gemini 2.5 Flash Image — 实际上 记得 原始图像的样子。它不会像我用过的其他一些 AI 模型那样掷骰子并希望最好。

我在我的 PC 上使用 OpenRouter API 运行了它(几分钟内就会有,别担心),它像魔法一样工作。

哦,每张图片都会有一个小小的“AI”水印——因为 Google 不想欺骗任何人。公平合理。

所以,如果你喜欢用文本提示来调整照片,给你的宠物一个幻想升级,或者只是想看看一个以香蕉命名的 AI 如何在不破坏它们的情况下改变你的照片——试试 Nano Banana 吧。只是不要期待真正的水果。

再次坦白地说:我们只谈论创意任务,而不是真正意义上的世界性变革。但是……如果你是一个作家或内容编辑者,它可能会对你的话和一张好图搭配起来很有用。

最后,一张图片胜过一千个字,对吧?

2、模型路由是王者!

我实际上在中国工作,所以我有一些困难访问基本工具,比如 GitHub 或甚至 Google。所以我第一个发现的是 Mistral 网络应用和 API 端点在这里的远东地区也正常工作。

在我寻找免费 API 提供商的过程中,我偶然发现了 openrouter.ai。这个网站声称:

一个统一的 LLM 接口 - 更好的价格,更好的停机时间,无需订阅。发现并使用最新的 LLM。300 多个模型,可探索的数据,私密聊天,以及统一的 API。

最酷的是:你可以自动设置 3 个模型,以确保你的调用总是会被回复。

有时流量太大,或者也许某些端点暂时不可用(毕竟这是一个免费服务……):但 OpenRouter 会提供一个路由故障转移机制,在第一个端点无法回复时将 API 调用发送到备用端点!

from openai import OpenAI  
openai_client = OpenAI(  
  base_url="https://openrouter.ai/api/v1",  
  api_key=<OPENROUTER_API_KEY>,  
)  
completion = openai_client.chat.completions.create(  
    model="openai/gpt-oss-20b:free",  
    extra_body={  
        "models": ["z-ai/glm-4.5-air:free", "qwen/qwen3-30b-a3b:free"],  
    },  
    messages=[  
        {  
            "role": "user",  
            "content": "What is the meaning of life?"  
        }  
    ]  
)  
print(completion.choices[0].message.content)

这个功能被称为 模型路由

3、如何操作?

我在之前的文章中涵盖了关于 OpenRouter 的所有基础知识,但在这里我会给你一个简短的故事。

现在有 58 个免费模型——来源

浏览可用的模型会让你印象深刻:你可以找到高性能的模型,如 Google Gemini 2.5 Flash、Qwen3-coder、OpenAI ogpt-oss-20b、Qwen3–30b-a3b、Moonshot.ai Kimi-k2……还有许多其他模型。

还有一个应用展示,其中完全工作的在线产品按照对 openrouter 统一端点的 API 调用次数进行排名。

1️⃣ 你可以免费注册/登录。

在首页的右上角,你可以找到登录/注册选项。你可以使用 Google 或直接使用你的电子邮件地址。

2️⃣ 设置密码并确认发送到你邮箱的链接。你已经准备好开始!

电子邮件验证过程

3️⃣ 现在你有一个选项来创建你的 API 密钥。API 完全免费,如果你没有信用额度,你将无权调用付费 API 端点。

4️⃣ 现在,注意……你必须将你的 API 密钥复制到安全的地方。事实上,它只会显示一次:

⚠️ 如果你忘记了它,就无法恢复
创建你的第一个 API 

按 Enter 键或点击以全尺寸查看图片!

现在你的第一个 API 密钥已创建并准备好了

有什么陷阱吗?

除了你不可能每秒有 200 亿次免费请求之外,没有其他陷阱。顺便说一句,我没有预料到这一点。

因此,对于某些类型的请求,无论账户状态如何,都有一定的速率限制:

免费限制:如果你使用的是免费模型变体(ID 以 :free 结尾),那么你每分钟最多只能有 20 个请求

  • 如果你购买的信用不足 10 个,你每天最多只能有 50 个 :free 模型请求。
  • 如果你至少购买了 10 个信用,你的每日限制增加到每天 1000 个 :free 模型请求。

对于 免费模型,速率限制 是根据你购买的信用来确定的。如果你至少购买了 10 个信用,你的免费模型速率限制将是每天 1000 次请求。否则,你将被限制为每天 50 次免费模型 API 请求。

DDoS 防护:Cloudflare 的 DDoS 防护将阻止明显超出合理使用的请求。

现在,如果我们做数学计算,假设你至少有 10 个信用,每天 1000 次请求,针对 58 个可用的免费模型,相当于每天约 60000 次请求

我认为,对于一个免费的服务来说,这不算太差,对吧?

4、如何使用 Gemini Nano Banana 生成图像?

你可以直接在终端或 ipython(交互式 Python)控制台中运行这个小型 Python 应用程序。我们需要安装少量的包:

pip install Pillow requests

Pillow 用于处理图像,requests 用于向 OpenRouter 端点发送 API 调用。

基础代码直接取自 OpenRouter 文档,除了显示图像的方式。

在第一部分中,我们将我们的提示发送到 Nano-Banana(gemini-2.5-flash-image-preview:free)的 API 端点,并提取 url

实际上它根本不是一个 url

APIK = 'sk-or-v1-xxxxxxxxx' #YOUR OPENROUTER API KEY  
import requests  
import json  

prompt = "Generate a beautiful sunset over mountains"  
url = "https://openrouter.ai/api/v1/chat/completions"  
headers = {  
    "Authorization": f"Bearer {APIK}",  
    "Content-Type": "application/json"  
}  
payload = {  
    "model": "google/gemini-2.5-flash-image-preview:free",  
    "messages": [  
        {  
            "role": "user",  
            "content": prompt  
        }  
    ],  
    "modalities": ["image", "text"]  
}  
response = requests.post(url, headers=headers, json=payload)  
result = response.json()  
# The generated image will be in the assistant message  
if result.get("choices"):  
    message = result["choices"][0]["message"]  
    if message.get("images"):  
        for image in message["images"]:  
            image_url = image["image_url"]["url"]  # Base64 data URL  

如果我们打印我们的结果,我们会得到我们的… 哦 no!没有图片!

print(image_url[:250])

好吧,图片确实在那里……你可以在下面看到,但我们无法读取它。然而……

生成美丽的山间日落

但怎么得到它呢?

5、为什么我们收到 base64 字符串?

好问题!在网页开发和 API 中接收图像作为 base64 字符串是很常见的,并且有几个实际原因为什么使用这种格式而不是直接发送原始二进制图像数据。

什么是 base64?

Base64 是一种编码方法,它将二进制数据(如图像)转换成由 ASCII 字符组成的文本字符串。这允许二进制数据在基于文本的系统(如 JSON、HTML 或 URL)中安全传输,而不会出现损坏或兼容性问题。

为什么使用 base64 来表示图像?

从我们的角度来看,让我们简单一点:我们不能在 JSON 对象中发送二进制数据!这个格式在互联网上到处使用,只接受文本。因此,base64 是图像文件二进制数据的编码(转换)成字符串。仅此而已。

大多数 API 使用 JSON 来交换数据。JSON 只支持文本,不支持原始二进制数据。

因此,为了在 JSON 负载中发送图像(例如,从前端到后端),您必须将其编码为文本——base64 是标准解决方案。

从开发人员/技术的角度来看,有几个原因:

1. 它可以通过 HTTP 表单或 API 发送

当通过 JavaScript 上传图像(例如,从画布或文件读取器)时,将图像转换为 base64 字符串并将其包含在 POST 请求体中通常更容易。

2. 直接嵌入 HTML/CSS(数据 URL)

Base64 允许您直接在 HTML 或 CSS 中嵌入图像:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…" />

不需要单独的图像文件或服务器请求——这对小图标或电子邮件很有用。

3. 避免文件上传的复杂性

使用 base64 意味着您不必处理:

  • multipart/form-data 解析
  • 临时文件存储
  • 处理不同编码的文件上传

相反,您获得一个干净的 JSON 字段,其中包含图像作为字符串。

所以,简而言之:

我们收到 base64 字符串的原因是:
- 它们可以在基于文本的格式(如 JSON)中安全发送。
- 它简化了从前端到后端的图像传输。
- 它允许直接在代码或标记中嵌入图像。
- 它避免了复杂的文件上传处理。
但请记住:base64 是编码,而不是压缩——它会使数据变大,因此要明智地使用!

✅ 从字符串到图像

所以我们的任务现在非常直接:

  • 使用 base64.b64decode() 解码 base64
  • 使用 PIL.Imageio.BytesIO 转换为图像
  • 使用 .save() 保存
  • 使用 .show() 显示

让我们看看代码…

import base64  
from PIL import Image  
import io  
# Example Base64 string (replace this with your actual data)  
base64_string = image_url  
# Remove the prefix if present (e.g., "data:image/png;base64,")  
if base64_string.startswith("data:image"):  
    base64_data = base64_string.split(",")[1]  # Get data after comma  
else:  
    base64_data = base64_string  

# Decode base64  
image_bytes = base64.b64decode(base64_data)  

# Convert to PIL Image  
image = Image.open(io.BytesIO(image_bytes))  

# Save image to file  
image.save("output_image.png", "PNG")  # or "JPEG", etc.  
print("Image saved as 'output_image.png'")  
image.show()

在第一个条件中,我们将检查我们是否已经有 base64 字符串,或者 HTML base64 格式 base64_string.startswith(“data:image”)

当我们解码 base64 字符串时,我们会得到一个字节流(每个文件都是由 1 和 0 构成的……)。幸运的是,Python 有所有必要的工具,我们可以使用 BytesIO 类型用 Pillow 读取图像。

就这么简单!如果一切正确,你会看到图像用你的默认图像查看器应用程序打开。

按 Enter 键或点击以全尺寸查看图片!

现在我们有了真实的图像

6、结束语

为了增添一些趣味性……让我们创建一些函数:这样我们就可以在其他应用程序中重复使用它们。

第一个函数将创建 API 请求(带有你的提示)并获取 base64 字符串。

import requests  
import json  
import base64  
from PIL import Image  
import io  

def genImage(prompt):  
    """  
    Generate an Image with gemini-2.5-flash-image-preview  
    starting from a prompt  
    return a base64 string  
    """  
    import requests  
    import json  
    APIK = 'sk-or-v1-xxxxxxx' #your openRouter API key here  
    url = "https://openrouter.ai/api/v1/chat/completions"  

    headers = {  
        "Authorization": f"Bearer {APIK}",  
        "Content-Type": "application/json"  
    }  
    payload = {  
        "model": "google/gemini-2.5-flash-image-preview:free",  
        "messages": [  
            {  
                "role": "user",  
                "content": prompt  
            }  
        ],  
        "modalities": ["image", "text"]  
    }  
    response = requests.post(url, headers=headers, json=payload)  
    result = response.json()  
    # The generated image will be in the assistant message  
    if result.get("choices"):  
        message = result["choices"][0]["message"]  
        if message.get("images"):  
            for image in message["images"]:  
                image_url = image["image_url"]["url"]  # Base64 data URL  
                #print(f"Generated image: {image_url[:50]}...")  
                return image_url

第二个函数将要求你给文件命名,并保存和显示图像。

def saveImage(image_url):  
    """  
    starting from base64 string ask for a filename and  
    save the image as PNG  
    """  
    #image base64 encoded is in variable image_url  
    import base64  
    from PIL import Image  
    import io  
    # Example Base64 string (replace this with your actual data)  
    base64_string = image_url  
    # Remove the prefix if present (e.g., "data:image/png;base64,")  
    if base64_string.startswith("data:image"):  
        base64_data = base64_string.split(",")[1]  # Get data after comma  
    else:  
        base64_data = base64_string  

    # Decode base64  
    image_bytes = base64.b64decode(base64_data)  

    # Convert to PIL Image  
    image = Image.open(io.BytesIO(image_bytes))  
    image.show()  
    filename = input('Give a name (no extension required): ')  
    # Save image to file  
    image_filename = filename+'.png'  
    image.save(image_filename, "PNG")  # or "JPEG", etc.  
    print(f"Image saved as {image_filename}")

现在我们可以甚至创建一个循环(你的任务),包括以下内容:

prompt = input('/IMAGINE: ')  # your creativity here  
yourImage = genImage(prompt)  # get the base64 image  
saveImage(yourImage)          # transform into PNG and save it

顺便说一下,我还不知道如何更改图像的宽高比。目前 OpenRouter 只能获得 1024x1024 像素的图像


原文链接:Free image generation with OpenRouter and Gemini Nano-banana

汇智网翻译整理,转载请标明出处