查看原文
其他

Flux 1.0:使用Streamlit和Replicate API批量生成AI图像 | 附完整代码

思辨view kate人不错
2024-08-22

引言

Flux 1.0 是由 Black Forest Labs 开发的文本到图像合成模型,利用 AI 技术从文本生成高质量图像。它包含三个针对不同用途优化的模型:

  • FLUX.1 [pro]:旗舰模型,提供卓越的图像质量、细节和多样性,适合专业应用。
  • FLUX.1 [dev]:pro 模型的蒸馏变体,适合研究和开发,非商业用途,权重可在 HuggingFace 获取。
  • FLUX.1 [schnell]:速度优化模型,适合本地开发和个人项目,支持高效本地部署。

Flux dev 8月初发布,现在是最强开源模型。

Flux模型示例

以下是我用Flux dev和schnell生成的图片

在不同平台上使用Flux

我在Poe、Replicate、Fal、Grok、本地应用Draw things APP 都试过Flux,效果很不错,但也有些问题。本地跑 FLUX.1 [dev] 8bit版本,电脑(32G内存)风扇呜呜响,生成时间也比较长。

使用Streamlit和Replicate API批量生成图片

今天,介绍如何通过Streamlit调用Replicate API来批量生成图片。

Replicate积分活动

Replicate有一个10美元积分活动,点击即可领取

https://replicate.com/invites/572ae3c6-1385-41b3-afdc-1e99e11836b8

Replicate图片生成效率

用Replicate生成的单张图片大小约1.5M。(100%png,schnell和dev模型)

1美元可以生成333张schnell图片或33张dev图片。

使用FLUX.1 [schnell]批量生成图片

非常推荐用FLUX.1 [schnell]来批量生成图片

Streamlit应用实例

我编写了Streamlit应用眨眼之间就能生成图片。

我设定的逻辑是上传txt,txt里每一段就是一个提示词,可以批量生成图片。

上面小猫找妈妈风格一致的图片是这样制作的:

和Claude沟通AI绘图提示词

对应的中文如下:

"超写实高分辨率图像。一只小橘猫,绿色的大眼睛,粉红色的鼻子和白色的爪子,独自坐在一个舒适的藤篮里。小猫看起来困惑且担忧,毛发的细节清晰可见。柔和的晨光从附近的窗户洒进来,营造出逼真的阴影,照亮空气中的灰尘颗粒。场景捕捉到了篮子的纹理、小猫毛发的柔软感,以及光影交错的摄影般的准确性。"

"超写实高分辨率图像。同一只绿色眼睛、粉红色鼻子和白色爪子的小橘猫小心翼翼地探索着阳光充足的客厅。小猫偷偷瞥向家具下方和窗帘后面,它的胡须和单根毛发清晰可见。阳光在柔软的地毯上形成了图案,每一根纤维都清晰分明。这种仿照片的画质展现了表面的反光效果和类似专业摄影的景深。"

"超写实高分辨率图像。勇敢的小橘猫,有着显眼的绿色眼睛和白色的爪子,进入了一个郁郁葱葱的后院花园。高耸的花朵和草围绕着这个小小的生灵,每一片花瓣和草叶都以清晰的细节呈现。附近有蝴蝶翩翩起舞,它们脆弱的翅膀被捕捉到在飞行的瞬间。高分辨率风格展现了小猫每一根胡须和它毛色的细微变化。"

"超写实高分辨率图像。雨开始下了,小橘猫带着绿色眼睛,找到了一个木质门廊下的庇护所。它的白色爪子上沾着一点泥,质感真实。水滴在附近的小水坑里激起了涟漪,逼真地反映出小猫的脸。场景捕捉了小猫湿润的毛发、门廊木纹的细节,以及雨滴折射光线的效果。"

"超写实高分辨率图像。这只坚定的小橘猫,绿色的眼睛充满警觉,白色的爪子略显疲惫,继续在安静的郊区人行道上寻找。随着黄昏的来临,街灯发出温暖的光芒,在小猫的毛发上创造出逼真的光效。高分辨率风格显示了水泥人行道的质地,边缘草叶的细节,以及光影的微妙渐变。"

"超写实高分辨率图像。最终,小橘猫带着绿色的眼睛和白色的爪子,与同样毛色的母猫喜悦地团聚了。他们在家门前亲密地互相蹭着。超写实风格捕捉到了每一个细节:它们毛发的柔软,眼中的光泽,鼻子的纹理,和每一根胡须。场景的灯光突出了重逢时的情感温暖,猫咪们被锐利地聚焦,背景略显模糊。"

运行程序时,在高级设置里固定种子。

因为Replicate里3个模型参数稍有差别,我设定的Streamlit应用可选schnell和dev来批量生成图片。

完整代码

import streamlit as st
import replicate
import io
import base64
from zipfile import ZipFile
import requests
import asyncio
from PIL import Image
import logging

# 设置日志记录
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 设置页面标题
st.set_page_config(page_title="Flux 图像生成器", layout="wide")

# 标题
st.title("Flux 图像生成器")

# 选择模型
model = st.selectbox(
    "选择模型",
    ["black-forest-labs/flux-schnell""black-forest-labs/flux-dev"],
    help="选择要使用的Flux模型"
)

# 输入提示词
prompt = st.text_area("输入提示词"help="描述您想生成的图像")

# 上传txt文件
uploaded_file = st.file_uploader("上传提示词文件 (每行一个提示词)"type="txt")

# 设置参数
with st.expander("高级设置"):
    seed = st.number_input("随机种子", min_value=0, help="设置随机种子以获得可重复的生成结果")
    num_outputs = st.slider("每个提示词的输出数量", min_value=1, max_value=4, value=1, help="每个提示词生成的图像数量")
    aspect_ratio = st.selectbox(
        "宽高比",
        ["16:9""1:1""21:9""2:3""3:2""4:5""5:4""9:16""9:21"],
        index=0,
        help="生成图像的宽高比"
    )
    output_format = st.selectbox("输出格式", ["png""webp""jpg"], index=0, help="输出图像的格式")
    output_quality = st.slider("输出质量", min_value=0, max_value=100, value=100, help="输出图像的质量,从0到100。100是最佳质量,0是最低质量。对于.png输出不相关")
    disable_safety_checker = st.checkbox("禁用安全检查器"help="禁用生成图像的安全检查器。此功能仅通过API可用。")

async def generate_image_async(prompt, model, input_data, timeout=45):
    try:
        prediction = await replicate.predictions.async_create(
            model=model,
            input=input_data
        )
        start_time = asyncio.get_event_loop().time()
        while prediction.status != "succeeded":
            if asyncio.get_event_loop().time() - start_time > timeout:
                raise asyncio.TimeoutError(f"生成图像超时({timeout}秒)")
            await asyncio.sleep(1)
            prediction = await replicate.predictions.async_get(prediction.id)
        
        logger.info(f"API 响应: {prediction.output}")
        logger.info(f"完整的 API 响应: {prediction}")

        if prediction.output:
            if isinstance(prediction.output, list):
                return prediction.output[0] if prediction.output else None
            elif isinstance(prediction.output, str):
                return prediction.output
            else:
                logger.error(f"未知的 API 响应格式: {type(prediction.output)}")
                return None
        else:
            logger.error("API 响应为空")
            return None
    except asyncio.TimeoutError as e:
        logger.error(str(e))
        return None
    except Exception as e:
        logger.error(f"生成图像时发生错误: {str(e)}")
        return None

def get_image_download_link(img_url, filename):
    response = requests.get(img_url)
    response.raise_for_status()
    img_data = response.content
    b64 = base64.b64encode(img_data).decode()
    file_size = len(img_data)
    logger.info(f"下载的图像大小: {file_size} 字节")
    return f'<a href="data:image/png;base64,{b64}" download="{filename}">下载图片 ({file_size/1024:.2f} KB)</a>'

# 生成按钮
if st.button("生成图像"):
    prompts = []
    if uploaded_file:
        prompts = [line.decode("utf-8").strip() for line in uploaded_file]
    elif prompt:
        prompts = [prompt]
    
    if not prompts:
        st.error("请输入提示词或上传提示词文件")
    else:
        with st.spinner(f"正在生成 {len(prompts) * num_outputs} 张图像..."):
            async def generate_all_images():
                tasks = []
                for current_prompt in prompts:
                    for _ in range(num_outputs):
                        input_data = {
                            "prompt": current_prompt,
                            "seed": seed if seed else None,
                            "aspect_ratio": aspect_ratio,
                            "output_format": output_format,
                            "output_quality": output_quality,
                            "disable_safety_checker": disable_safety_checker
                        }
                        input_data = {k: v for k, v in input_data.items() if v is not None}
                        tasks.append(generate_image_async(current_prompt, model, input_data, timeout=45))
                return await asyncio.gather(*tasks)

            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            generated_images = loop.run_until_complete(generate_all_images())
            
            # 显示生成的图像
            for i, image_url in enumerate(generated_images):
                if image_url:
                    logger.info(f"处理图像 URL: {image_url}")
                    col1, col2 = st.columns([3, 1])
                    with col1:
                        try:
                            if not image_url.startswith(('http://''https://')):
                                raise ValueError(f"无效的 URL: {image_url}")
                            
                            response = requests.get(image_url)
                            response.raise_for_status()
                            
                            image = Image.open(io.BytesIO(response.content))
                            logger.info(f"图像 {i+1} 尺寸: {image.size}")
                            st.image(image, caption=f"生成的图像 {i+1}", use_column_width=True)
                            logger.info(f"成功显示图像 {i+1}")
                        except requests.RequestException as e:
                            logger.error(f"下载图像时发生错误: {str(e)}")
                            st.error(f"无法加载图像 {i+1}: {str(e)}")
                        except ValueError as e:
                            logger.error(str(e))
                            st.error(f"无效的图像 URL {i+1}: {str(e)}")
                        except Exception as e:
                            logger.error(f"处理图像时发生未知错误: {str(e)}")
                            st.error(f"处理图像 {i+1} 时发生错误: {str(e)}")
                    with col2:
                        st.markdown(get_image_download_link(image_url, f"generated_image_{i+1}.{output_format}"), unsafe_allow_html=True)
                        st.text_area("提示词", prompts[i // num_outputs], height=100)
                else:
                    logger.warning(f"图像 {i+1} 的 URL 为空")
        
        # 批量下载
        if len(generated_images) > 1:
            zip_buffer = io.BytesIO()
            with ZipFile(zip_buffer, 'w') as zip_file:
                for i, image_url in enumerate(generated_images):
                    if image_url:
                        response = requests.get(image_url)
                        zip_file.writestr(f"generated_image_{i+1}.{output_format}", response.content)
            
            zip_buffer.seek(0)
            b64 = base64.b64encode(zip_buffer.getvalue()).decode()
            href = f'<a href="data:application/zip;base64,{b64}" download="generated_images.zip">下载所有图片</a>'
            st.markdown(href, unsafe_allow_html=True)

# 添加说明
st.markdown("""
## 使用说明
- 选择要使用的Flux模型。
- 在文本框中输入描述您想要生成的图像的提示词,或上传包含多个提示词的txt文件(每行一个提示词)。
- 如果需要,可以展开“高级设置”调整其他参数。
- 点击“生成图像”按钮开始生成过程。
- 生成的图像将显示在页面上,您可以单独下载每张图片或批量下载所有图片。

注意:确保您已经设置了REPLICATE_API_TOKEN环境变量,否则API调用将失败。
"
"")

运行说明

  1. 环境准备:

  • 确保您的系统已安装Python(建议使用Python 3.9或更高版本)。
  • 安装依赖:

    • 打开命令行终端。

    • 安装必要的库。您可以使用以下命令:

      pip install streamlit replicate pillow requests
  • 设置API令牌:

    • 在Windows上:set REPLICATE_API_TOKEN=your_token_here
    • 在Mac或Linux上:export REPLICATE_API_TOKEN=your_token_here
    • 您需要一个Replicate API令牌。如果没有,请在Replicate网站上注册并获取令牌。
    • 设置环境变量REPLICATE_API_TOKEN。在终端中运行:
  • 保存代码:

    • 将提供的代码保存为一个Python文件,例如flux_image_generator.py
  • 运行应用:

    • 在终端中,导航到保存代码的目录。

    • 运行以下命令启动Streamlit应用:

      streamlit run flux_image_generator.py
  • 使用应用:

    • Streamlit会自动在您的默认web浏览器中打开应用。
    • 如果没有自动打开,您可以在浏览器中访问终端显示的URL(通常是 http://localhost:8501)。
  • 在应用中:

    • 选择Flux模型。
    • 输入提示词或上传包含提示词的txt文件。
    • 调整高级设置(如果需要)。
    • 点击"生成图像"按钮。
  • 查看结果:

    • 生成的图像将显示在页面上。
    • 您可以下载单个图像或所有图像的压缩包。

    注意事项:

    • 确保您的网络连接良好,因为程序需要与Replicate API进行通信。
    • 如果遇到任何错误,请检查终端输出以获取更多信息。

    结语

    通过结合Streamlit和Replicate API,我们可以轻松实现批量图像生成,大大提高了效率。

    希望本文的介绍和代码示例能够激发您的创意,帮助您在AI图像生成领域展开探索。

    广告

    过去我已写了170+篇AI主题原创长文,我对继续写作充满信心,因为这是我的爱好,我非常热爱这件事。

    最近我开通了知识星球,你加入后可以访问公众号收费文章,向我提问,第一时间获取AI资讯。

    精选历史文章,请看这里:

    推荐一款编程辅助工具:AI驱动的3倍效率提升

    效率提升N倍!分享我正在使用的AI编程新工具

    打造更可靠的 AI :解析 7 种减少幻觉的高效策略

    解锁 Claude 3.5 Sonnet 创意潜能:10+ 个 Web 应用实战

    Poe x Claude:零代码创建交互式 Web 应用,完整操作带你轻松上手

    AI 驱动的网页开发:用 Claude 3.5 Sonnet 打造趣味互动应用并轻松部署


    继续滑动看下一个
    kate人不错
    向上滑动看下一个

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存