feature: init proj
This commit is contained in:
50
.gitignore
vendored
Normal file
50
.gitignore
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env/
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
38
Dockerfile
Normal file
38
Dockerfile
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# 使用官方Python运行时作为基础镜像
|
||||||
|
FROM 172.16.102.3:30648/library/python:3.13-slim
|
||||||
|
|
||||||
|
# 设置工作目录
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 设置环境变量
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# 配置uv使用阿里云源
|
||||||
|
ENV UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
|
||||||
|
ENV UV_EXTRA_INDEX_URL=https://pypi.org/simple/
|
||||||
|
|
||||||
|
RUN python -m pip install --upgrade pip setuptools wheel --index-url https://mirrors.aliyun.com/pypi/simple/
|
||||||
|
|
||||||
|
# 安装uv
|
||||||
|
RUN pip install uv --index-url https://mirrors.aliyun.com/pypi/simple/
|
||||||
|
|
||||||
|
# 复制依赖文件
|
||||||
|
COPY pyproject.toml ./
|
||||||
|
|
||||||
|
# 安装依赖
|
||||||
|
RUN uv sync
|
||||||
|
|
||||||
|
# 复制应用代码
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# 创建非root用户
|
||||||
|
RUN adduser --disabled-password --gecos '' appuser
|
||||||
|
RUN chown -R appuser:appuser /app
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# 暴露端口
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# 启动命令
|
||||||
|
CMD ["uv", "run","python", "app.py"]
|
||||||
88
README.md
88
README.md
@@ -1,3 +1,87 @@
|
|||||||
# image-gen
|
# Z-Image-Turbo
|
||||||
|
|
||||||
AI 图像生成
|
🎨 **极速 AI 图像生成应用** — 基于 [Z-Image-Turbo](https://huggingface.co/openai/z-image-turbo) 模型,仅需 8 步即可生成精美图像。
|
||||||
|
|
||||||
|
[](https://gradio.app/)
|
||||||
|
[](https://www.python.org/)
|
||||||
|
[](https://docs.astral.sh/uv/)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- ⚡ **极速生成** — 8 步 DiT 前向传播即可生成高质量图像
|
||||||
|
- 🖼️ **自定义尺寸** — 支持 512~2048 像素范围的图像尺寸
|
||||||
|
- 🎲 **种子控制** — 支持固定种子或随机种子,便于复现结果
|
||||||
|
- 💡 **示例提示词** — 内置丰富的中文示例提示词
|
||||||
|
- 🌐 **远程 API 调用** — 通过 OpenAI 兼容 API 调用图像生成服务
|
||||||
|
- 🎨 **现代 UI** — 基于 Gradio 6 的现代化界面,支持响应式布局
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 环境要求
|
||||||
|
|
||||||
|
- Python >= 3.12
|
||||||
|
- [uv](https://docs.astral.sh/uv/) 包管理器
|
||||||
|
|
||||||
|
### 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv sync
|
||||||
|
```
|
||||||
|
|
||||||
|
### 配置环境变量
|
||||||
|
|
||||||
|
创建 `.env` 文件:
|
||||||
|
|
||||||
|
```env
|
||||||
|
IMAGE_API_URL=https://llm.dev.maimaiag.com/v1/images/generations
|
||||||
|
IMAGE_API_KEY=your-api-key-here
|
||||||
|
```
|
||||||
|
|
||||||
|
### 启动应用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
应用启动后,默认在本地 `http://127.0.0.1:7860` 运行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── app.py # Gradio 应用主入口
|
||||||
|
├── pyproject.toml # uv 项目配置与依赖
|
||||||
|
├── requirements.txt # 备用依赖列表(Gradio Space 兼容)
|
||||||
|
├── .env # 环境变量(需自行创建,不提交到仓库)
|
||||||
|
└── README.md # 本文件
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- **前端/UI**: [Gradio 6](https://gradio.app/)
|
||||||
|
- **后端**: Python 3.12+
|
||||||
|
- **包管理**: [uv](https://docs.astral.sh/uv/)
|
||||||
|
- **图像处理**: Pillow
|
||||||
|
- **API 协议**: OpenAI 兼容的 Images Generations API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 部署
|
||||||
|
|
||||||
|
本项目可直接部署到 [Hugging Face Spaces](https://huggingface.co/spaces) 或其他支持 Gradio 的平台。
|
||||||
|
|
||||||
|
Space 配置参考 `README.md` 顶部的 YAML Front Matter(保留在原始文件中用于 Hugging Face 识别)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|||||||
286
app.py
Normal file
286
app.py
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
import os
|
||||||
|
import base64
|
||||||
|
import io
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import requests
|
||||||
|
import gradio as gr
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
API_URL = os.getenv("IMAGE_API_URL", "https://llm.dev.maimaiag.com/v1/images/generations")
|
||||||
|
API_KEY = os.getenv("IMAGE_API_KEY", "")
|
||||||
|
|
||||||
|
|
||||||
|
def _call_remote_api(prompt: str, size: str, seed: int, num_inference_steps: int) -> Image.Image:
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
if API_KEY:
|
||||||
|
headers["Authorization"] = f"Bearer {API_KEY}"
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"model": "openai/z-image-turbo",
|
||||||
|
"prompt": prompt,
|
||||||
|
"size": size,
|
||||||
|
"seed": seed,
|
||||||
|
"num_inference_steps": num_inference_steps,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(API_URL, headers=headers, json=payload, timeout=300)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
b64_image = data["data"][0]["b64_json"]
|
||||||
|
image_bytes = base64.b64decode(b64_image)
|
||||||
|
return Image.open(io.BytesIO(image_bytes))
|
||||||
|
|
||||||
|
|
||||||
|
def generate_image(prompt, height, width, num_inference_steps, seed, randomize_seed, progress=gr.Progress(track_tqdm=True)):
|
||||||
|
"""Generate an image from the given prompt via remote API."""
|
||||||
|
if randomize_seed:
|
||||||
|
import random
|
||||||
|
seed = random.randint(0, 2**32 - 1)
|
||||||
|
|
||||||
|
size = f"{int(width)}x{int(height)}"
|
||||||
|
image = _call_remote_api(
|
||||||
|
prompt=prompt,
|
||||||
|
size=size,
|
||||||
|
seed=int(seed),
|
||||||
|
num_inference_steps=int(num_inference_steps),
|
||||||
|
)
|
||||||
|
return image, seed
|
||||||
|
|
||||||
|
# 示例提示词
|
||||||
|
examples = [
|
||||||
|
["一张黑白照片(约1950年代),捕捉了一场欢乐的跨代家庭感恩节或节日晚餐。中心人物是一位身穿白衬衫、系深色领带的微笑男子,他正在餐桌主位上兴致勃勃地切割一只大烤火鸡。他被一大群各年龄段的家庭成员包围,所有人都迫不及待地伸出盘子来接食物。许多不同年龄的孩子围在周围,眼睛睁得大大的,充满期待,有的站着,有的坐着。还有几位女性和青少年,有的在帮忙上菜,有的抱着婴儿。整个场景充满了自然的互动、笑声和热闹温馨的氛围。餐桌上摆满了传统的节日菜肴。背景是一面简单的、可能贴着壁纸的墙壁,反映了真实家庭住宅的质朴感。"],
|
||||||
|
["一幅全景场景,背景从石器时代过渡到未来(洞穴→金字塔→城堡→工厂→摩天大楼→漂浮城市),主体是前景中同一张面孔/同一个人,从左到右佩戴着符合时代特征的头盔:骨/兽皮头饰、青铜古代头盔、中世纪板甲头盔、一战钢盔、现代太空头盔,以及未来能量/全息头盔。"],
|
||||||
|
["一张现代会议室里的商务团队照片。在会议桌的首席位置,一位自信的老板站着,充满热情地介绍一个雄心勃勃的新产品创意。围坐在桌旁的雇员们反应各异,有的好奇、有的挑眉、有的若有所思,有的在记笔记,有的在提问。他们身后的大窗外可以看到摩天大楼和城市灯火。氛围专业但充满紧张和引人入胜的气息。"],
|
||||||
|
["一幅文艺复兴风格的绘画,描绘了一座现代城市景观。"],
|
||||||
|
["节日期间繁忙的城市街道,彩旗飘扬,人群熙攘,街头艺人在表演。"],
|
||||||
|
["科幻电影的电影海报,宇航员站在火星上凝望地球,戏剧性的灯光,黑暗的氛围,顶部有大号金属质感字体标题\"THE VOYAGE\""],
|
||||||
|
["兴奋的年轻内容创作者指着漂浮的机器人全息图,充满活力的紫色和蓝色霓虹背景,高对比度,YouTube缩略图风格,粗体黄色文字\"AI UPDATE\""],
|
||||||
|
["现代工作空间,木质桌面上放着笔记本电脑和咖啡,晨光透过窗户洒入,温馨的氛围,照片级真实感,高质量,便利贴上写着\"Productivity\""],
|
||||||
|
]
|
||||||
|
|
||||||
|
# 自定义主题,深色科技感 (Gradio 6)
|
||||||
|
custom_theme = gr.themes.Soft(
|
||||||
|
primary_hue="cyan",
|
||||||
|
secondary_hue="violet",
|
||||||
|
neutral_hue="zinc",
|
||||||
|
font=gr.themes.GoogleFont("Inter"),
|
||||||
|
text_size="lg",
|
||||||
|
spacing_size="md",
|
||||||
|
radius_size="lg"
|
||||||
|
).set(
|
||||||
|
button_primary_background_fill="*primary_500",
|
||||||
|
button_primary_background_fill_hover="*primary_400",
|
||||||
|
button_primary_text_color="*neutral_950",
|
||||||
|
block_title_text_weight="600",
|
||||||
|
block_background_fill="*neutral_900",
|
||||||
|
body_background_fill="*neutral_950",
|
||||||
|
body_text_color="*neutral_200",
|
||||||
|
block_label_text_color="*neutral_300",
|
||||||
|
input_background_fill="*neutral_800",
|
||||||
|
border_color_primary="*neutral_700",
|
||||||
|
)
|
||||||
|
|
||||||
|
# 构建 Gradio 界面
|
||||||
|
with gr.Blocks(fill_height=True) as demo:
|
||||||
|
# 页眉
|
||||||
|
gr.Markdown(
|
||||||
|
"""
|
||||||
|
# Z-Image-Turbo
|
||||||
|
极速 AI 图像生成 • 仅需 8 步即可生成精美图像
|
||||||
|
""",
|
||||||
|
elem_classes="header-text"
|
||||||
|
)
|
||||||
|
|
||||||
|
with gr.Row(equal_height=False):
|
||||||
|
# 左栏 - 输入控制
|
||||||
|
with gr.Column(scale=1, min_width=320):
|
||||||
|
prompt = gr.Textbox(
|
||||||
|
label="提示词",
|
||||||
|
placeholder="描述你想要生成的图像...",
|
||||||
|
lines=5,
|
||||||
|
max_lines=10,
|
||||||
|
autofocus=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
with gr.Accordion("高级设置", open=False):
|
||||||
|
with gr.Row():
|
||||||
|
height = gr.Slider(
|
||||||
|
minimum=512,
|
||||||
|
maximum=2048,
|
||||||
|
value=1024,
|
||||||
|
step=64,
|
||||||
|
label="高度",
|
||||||
|
info="图像高度(像素)"
|
||||||
|
)
|
||||||
|
width = gr.Slider(
|
||||||
|
minimum=512,
|
||||||
|
maximum=2048,
|
||||||
|
value=1024,
|
||||||
|
step=64,
|
||||||
|
label="宽度",
|
||||||
|
info="图像宽度(像素)"
|
||||||
|
)
|
||||||
|
|
||||||
|
num_inference_steps = gr.Slider(
|
||||||
|
minimum=1,
|
||||||
|
maximum=20,
|
||||||
|
value=9,
|
||||||
|
step=1,
|
||||||
|
label="推理步数",
|
||||||
|
info="9 步 = 8 次 DiT 前向传播(推荐)"
|
||||||
|
)
|
||||||
|
|
||||||
|
with gr.Row():
|
||||||
|
randomize_seed = gr.Checkbox(
|
||||||
|
label="随机种子",
|
||||||
|
value=True,
|
||||||
|
)
|
||||||
|
seed = gr.Number(
|
||||||
|
label="种子",
|
||||||
|
value=42,
|
||||||
|
precision=0,
|
||||||
|
visible=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
def toggle_seed(randomize):
|
||||||
|
return gr.Number(visible=not randomize)
|
||||||
|
|
||||||
|
randomize_seed.change(
|
||||||
|
toggle_seed,
|
||||||
|
inputs=[randomize_seed],
|
||||||
|
outputs=[seed]
|
||||||
|
)
|
||||||
|
|
||||||
|
generate_btn = gr.Button(
|
||||||
|
"生成图像",
|
||||||
|
variant="primary",
|
||||||
|
size="lg",
|
||||||
|
scale=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# 示例提示词
|
||||||
|
gr.Examples(
|
||||||
|
examples=examples,
|
||||||
|
inputs=[prompt],
|
||||||
|
label="试试这些提示词",
|
||||||
|
examples_per_page=5,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 右栏 - 输出
|
||||||
|
with gr.Column(scale=1, min_width=320):
|
||||||
|
output_image = gr.Image(
|
||||||
|
label="生成的图像",
|
||||||
|
type="pil",
|
||||||
|
format="png",
|
||||||
|
show_label=False,
|
||||||
|
height=600,
|
||||||
|
buttons=["download", "share"],
|
||||||
|
)
|
||||||
|
|
||||||
|
used_seed = gr.Number(
|
||||||
|
label="使用的种子",
|
||||||
|
interactive=False,
|
||||||
|
container=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 连接生成按钮
|
||||||
|
generate_btn.click(
|
||||||
|
fn=generate_image,
|
||||||
|
inputs=[prompt, height, width, num_inference_steps, seed, randomize_seed],
|
||||||
|
outputs=[output_image, used_seed],
|
||||||
|
)
|
||||||
|
|
||||||
|
# 也支持在提示词框中按回车键生成
|
||||||
|
prompt.submit(
|
||||||
|
fn=generate_image,
|
||||||
|
inputs=[prompt, height, width, num_inference_steps, seed, randomize_seed],
|
||||||
|
outputs=[output_image, used_seed],
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
demo.launch(
|
||||||
|
theme=custom_theme,
|
||||||
|
css="""
|
||||||
|
.header-text h1 {
|
||||||
|
font-size: 2.5rem !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
margin-bottom: 0.5rem !important;
|
||||||
|
background: linear-gradient(135deg, #22d3ee 0%, #a78bfa 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-text p {
|
||||||
|
font-size: 1.1rem !important;
|
||||||
|
color: #94a3b8 !important;
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-text {
|
||||||
|
padding: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-text a {
|
||||||
|
color: #22d3ee !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-text a:hover {
|
||||||
|
text-decoration: underline !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile optimizations */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.header-text h1 {
|
||||||
|
font-size: 1.8rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-text p {
|
||||||
|
font-size: 1rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smooth transitions */
|
||||||
|
button, .gr-button {
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover, .gr-button:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 0 20px rgba(34, 211, 238, 0.35) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Better spacing */
|
||||||
|
.gradio-container {
|
||||||
|
max-width: 1400px !important;
|
||||||
|
margin: 0 auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Glassmorphism panels */
|
||||||
|
.gradio-container .gr-block,
|
||||||
|
.gradio-container .gr-form,
|
||||||
|
.gradio-container .gr-box {
|
||||||
|
backdrop-filter: blur(8px) !important;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.12) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input focus glow */
|
||||||
|
input:focus, textarea:focus {
|
||||||
|
box-shadow: 0 0 0 2px rgba(34, 211, 238, 0.25) !important;
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
footer_links=[
|
||||||
|
"api",
|
||||||
|
"gradio"
|
||||||
|
],
|
||||||
|
mcp_server=True
|
||||||
|
)
|
||||||
6
main.py
Normal file
6
main.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
def main():
|
||||||
|
print("Hello from z-image-turbo!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
15
pyproject.toml
Normal file
15
pyproject.toml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[project]
|
||||||
|
name = "z-image-turbo"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Z-Image-Turbo AI image generation web app"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = [
|
||||||
|
"torch",
|
||||||
|
"gradio",
|
||||||
|
"gradio[mcp]",
|
||||||
|
"transformers",
|
||||||
|
"kernels",
|
||||||
|
"modelscope",
|
||||||
|
"diffusers",
|
||||||
|
"python-dotenv>=1.2.2",
|
||||||
|
]
|
||||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
gradio
|
||||||
|
requests
|
||||||
|
Pillow
|
||||||
Reference in New Issue
Block a user