feature: init proj

This commit is contained in:
贺海国
2026-04-15 18:43:55 +08:00
parent 580dbb8d25
commit 9bfa47804f
9 changed files with 2552 additions and 2 deletions

50
.gitignore vendored Normal file
View 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
View File

@@ -0,0 +1 @@
3.12

38
Dockerfile Normal file
View 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"]

View File

@@ -1,3 +1,87 @@
# image-gen # Z-Image-Turbo
AI 图像生成 🎨 **极速 AI 图像生成应用** — 基于 [Z-Image-Turbo](https://huggingface.co/openai/z-image-turbo) 模型,仅需 8 步即可生成精美图像。
[![Gradio](https://img.shields.io/badge/Gradio-6.0+-yellow)](https://gradio.app/)
[![Python](https://img.shields.io/badge/Python-3.12+-blue)](https://www.python.org/)
[![uv](https://img.shields.io/badge/uv-managed-purple)](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
View 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
View File

@@ -0,0 +1,6 @@
def main():
print("Hello from z-image-turbo!")
if __name__ == "__main__":
main()

15
pyproject.toml Normal file
View 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
View File

@@ -0,0 +1,3 @@
gradio
requests
Pillow

2067
uv.lock generated Normal file

File diff suppressed because it is too large Load Diff