mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-14 23:42:35 +08:00
feat: Add RunPod Hub configuration and storage access test
- Add .runpod/hub.json with serverless configuration - Add .runpod/tests.json with comprehensive test cases - Add storage access test to Dockerfile build process - Add RunPod badge to README.md - Include model download script for build-time optimization - Test storage accessibility during Docker build phase
This commit is contained in:
parent
cd8bb55239
commit
80848f3c54
66
.runpod/hub.json
Normal file
66
.runpod/hub.json
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"title": "ComfyUI - AI Image Generation",
|
||||||
|
"description": "ComfyUI serverless deployment with network storage support for models. Generate high-quality images using Stable Diffusion XL with custom workflows.",
|
||||||
|
"type": "serverless",
|
||||||
|
"category": "image",
|
||||||
|
"iconUrl": "https://raw.githubusercontent.com/comfyanonymous/ComfyUI/master/web/favicon.ico",
|
||||||
|
"config": {
|
||||||
|
"runsOn": "GPU",
|
||||||
|
"containerDiskInGb": 20,
|
||||||
|
"presets": [
|
||||||
|
{
|
||||||
|
"name": "SDXL Base",
|
||||||
|
"defaults": {
|
||||||
|
"MODEL_NAME": "sd_xl_base_1.0.safetensors",
|
||||||
|
"STEPS": "25",
|
||||||
|
"CFG": "8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "High Quality",
|
||||||
|
"defaults": {
|
||||||
|
"MODEL_NAME": "sd_xl_base_1.0.safetensors",
|
||||||
|
"STEPS": "50",
|
||||||
|
"CFG": "7.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"env": [
|
||||||
|
{
|
||||||
|
"key": "HF_HUB_DISABLE_TELEMETRY",
|
||||||
|
"value": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DO_NOT_TRACK",
|
||||||
|
"value": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "MODEL_NAME",
|
||||||
|
"input": {
|
||||||
|
"name": "Model Name",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Checkpoint model file name to use",
|
||||||
|
"default": "sd_xl_base_1.0.safetensors"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "STEPS",
|
||||||
|
"input": {
|
||||||
|
"name": "Generation Steps",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Number of denoising steps",
|
||||||
|
"default": "25"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "CFG",
|
||||||
|
"input": {
|
||||||
|
"name": "CFG Scale",
|
||||||
|
"type": "string",
|
||||||
|
"description": "Classifier-free guidance scale",
|
||||||
|
"default": "8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
94
.runpod/tests.json
Normal file
94
.runpod/tests.json
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"name": "basic_text_to_image",
|
||||||
|
"input": {
|
||||||
|
"workflow": {
|
||||||
|
"3": {
|
||||||
|
"inputs": {
|
||||||
|
"seed": 42,
|
||||||
|
"steps": 20,
|
||||||
|
"cfg": 8.0,
|
||||||
|
"sampler_name": "euler",
|
||||||
|
"scheduler": "normal",
|
||||||
|
"denoise": 1.0,
|
||||||
|
"model": ["4", 0],
|
||||||
|
"positive": ["6", 0],
|
||||||
|
"negative": ["7", 0],
|
||||||
|
"latent_image": ["5", 0]
|
||||||
|
},
|
||||||
|
"class_type": "KSampler"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"inputs": {
|
||||||
|
"ckpt_name": "sd_xl_base_1.0.safetensors"
|
||||||
|
},
|
||||||
|
"class_type": "CheckpointLoaderSimple"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"inputs": {
|
||||||
|
"width": 1024,
|
||||||
|
"height": 1024,
|
||||||
|
"batch_size": 1
|
||||||
|
},
|
||||||
|
"class_type": "EmptyLatentImage"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"inputs": {
|
||||||
|
"text": "a beautiful landscape, high quality, detailed",
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"inputs": {
|
||||||
|
"text": "blurry, low quality, distorted",
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"inputs": {
|
||||||
|
"samples": ["3", 0],
|
||||||
|
"vae": ["4", 2]
|
||||||
|
},
|
||||||
|
"class_type": "VAEDecode"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"inputs": {
|
||||||
|
"filename_prefix": "test_output",
|
||||||
|
"images": ["8", 0]
|
||||||
|
},
|
||||||
|
"class_type": "SaveImage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timeout": 120000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "simple_prompt_test",
|
||||||
|
"input": {
|
||||||
|
"prompt": "modern software interface, clean design"
|
||||||
|
},
|
||||||
|
"timeout": 60000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"config": {
|
||||||
|
"gpuTypeId": "NVIDIA RTX A4000",
|
||||||
|
"gpuCount": 1,
|
||||||
|
"env": [
|
||||||
|
{
|
||||||
|
"key": "HF_HUB_DISABLE_TELEMETRY",
|
||||||
|
"value": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DO_NOT_TRACK",
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"allowedCudaVersions": [
|
||||||
|
"12.1",
|
||||||
|
"11.8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Dockerfile
23
Dockerfile
@ -13,6 +13,29 @@ RUN apt-get update && apt-get install -y \
|
|||||||
# Tüm dosyaları kopyala
|
# Tüm dosyaları kopyala
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|
||||||
|
# Model klasörlerini oluştur
|
||||||
|
RUN mkdir -p /app/models/checkpoints /app/models/loras /app/models/vae \
|
||||||
|
/app/models/controlnet /app/models/upscale_models \
|
||||||
|
/app/models/text_encoders /app/models/clip \
|
||||||
|
/app/models/diffusion_models /app/models/unet \
|
||||||
|
/app/models/embeddings /app/models/clip_vision
|
||||||
|
|
||||||
|
# Storage erişim testi - Build sırasında storage erişimi kontrol et
|
||||||
|
RUN echo "🔍 RunPod Build Storage Access Test" && \
|
||||||
|
echo "=================================" && \
|
||||||
|
echo "📁 Testing storage paths:" && \
|
||||||
|
(ls -la /runpod-volume 2>/dev/null && echo "✅ /runpod-volume accessible" || echo "❌ /runpod-volume not accessible") && \
|
||||||
|
(ls -la /workspace 2>/dev/null && echo "✅ /workspace accessible" || echo "❌ /workspace not accessible") && \
|
||||||
|
(ls -la /content 2>/dev/null && echo "✅ /content accessible" || echo "❌ /content not accessible") && \
|
||||||
|
echo "🌐 Network test:" && \
|
||||||
|
(ping -c 1 google.com >/dev/null 2>&1 && echo "✅ Internet access available" || echo "❌ No internet access") && \
|
||||||
|
echo "================================="
|
||||||
|
|
||||||
|
# Temel modelleri Docker build sırasında indir
|
||||||
|
RUN pip install huggingface-hub && \
|
||||||
|
python download_models.py && \
|
||||||
|
rm -rf /tmp/hf_cache
|
||||||
|
|
||||||
# PyTorch CPU versiyonu ve bağımlılıklar
|
# PyTorch CPU versiyonu ve bağımlılıklar
|
||||||
RUN pip install --no-cache-dir \
|
RUN pip install --no-cache-dir \
|
||||||
torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu && \
|
torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu && \
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
[![Dynamic JSON Badge][discord-shield]][discord-url]
|
[![Dynamic JSON Badge][discord-shield]][discord-url]
|
||||||
[![Twitter][twitter-shield]][twitter-url]
|
[![Twitter][twitter-shield]][twitter-url]
|
||||||
[![Matrix][matrix-shield]][matrix-url]
|
[![Matrix][matrix-shield]][matrix-url]
|
||||||
|
[![Runpod][runpod-shield]][runpod-url]
|
||||||
<br>
|
<br>
|
||||||
[![][github-release-shield]][github-release-link]
|
[![][github-release-shield]][github-release-link]
|
||||||
[![][github-release-date-shield]][github-release-link]
|
[![][github-release-date-shield]][github-release-link]
|
||||||
@ -18,6 +19,8 @@
|
|||||||
[matrix-url]: https://app.element.io/#/room/%23comfyui_space%3Amatrix.org
|
[matrix-url]: https://app.element.io/#/room/%23comfyui_space%3Amatrix.org
|
||||||
[website-shield]: https://img.shields.io/badge/ComfyOrg-4285F4?style=flat
|
[website-shield]: https://img.shields.io/badge/ComfyOrg-4285F4?style=flat
|
||||||
[website-url]: https://www.comfy.org/
|
[website-url]: https://www.comfy.org/
|
||||||
|
[runpod-shield]: https://api.runpod.io/badge/bahadirciloglu/ComfyUI
|
||||||
|
[runpod-url]: https://console.runpod.io/hub/bahadirciloglu/ComfyUI
|
||||||
<!-- Workaround to display total user from https://github.com/badges/shields/issues/4500#issuecomment-2060079995 -->
|
<!-- Workaround to display total user from https://github.com/badges/shields/issues/4500#issuecomment-2060079995 -->
|
||||||
[discord-shield]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscord.com%2Fapi%2Finvites%2Fcomfyorg%3Fwith_counts%3Dtrue&query=%24.approximate_member_count&logo=discord&logoColor=white&label=Discord&color=green&suffix=%20total
|
[discord-shield]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscord.com%2Fapi%2Finvites%2Fcomfyorg%3Fwith_counts%3Dtrue&query=%24.approximate_member_count&logo=discord&logoColor=white&label=Discord&color=green&suffix=%20total
|
||||||
[discord-url]: https://www.comfy.org/discord
|
[discord-url]: https://www.comfy.org/discord
|
||||||
|
|||||||
17
debug_runpod.sh
Executable file
17
debug_runpod.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Debug RunPod API call
|
||||||
|
|
||||||
|
ENDPOINT_ID="sfkzjudvrj50yq"
|
||||||
|
API_KEY="${RUNPOD_API_KEY:-YOUR_API_KEY}"
|
||||||
|
BASE_URL="https://api.runpod.ai/v2"
|
||||||
|
|
||||||
|
echo "🔍 Debugging RunPod API..."
|
||||||
|
echo "📍 Endpoint: $ENDPOINT_ID"
|
||||||
|
echo "🔑 API Key: ${API_KEY:0:10}..." # Show only first 10 chars for security
|
||||||
|
|
||||||
|
# Simple test with minimal payload
|
||||||
|
echo "📤 Testing with simple payload..."
|
||||||
|
curl -v -X POST "$BASE_URL/$ENDPOINT_ID/run" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer $API_KEY" \
|
||||||
|
-d '{"input":{"prompt":"test prompt"}}'
|
||||||
90
download_models.py
Normal file
90
download_models.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Docker build sırasında temel modelleri indir
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from huggingface_hub import hf_hub_download
|
||||||
|
|
||||||
|
def download_model(repo_id, filename, target_dir):
|
||||||
|
"""Model indir ve hedef dizine kopyala"""
|
||||||
|
try:
|
||||||
|
print(f"📥 İndiriliyor: {repo_id}/{filename}")
|
||||||
|
|
||||||
|
# Model'i indir
|
||||||
|
model_path = hf_hub_download(
|
||||||
|
repo_id=repo_id,
|
||||||
|
filename=filename,
|
||||||
|
cache_dir="/tmp/hf_cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Hedef dizini oluştur
|
||||||
|
os.makedirs(target_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Dosyayı kopyala
|
||||||
|
target_path = os.path.join(target_dir, filename)
|
||||||
|
os.system(f"cp '{model_path}' '{target_path}'")
|
||||||
|
|
||||||
|
print(f"✅ Kaydedildi: {target_path}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Hata: {repo_id}/{filename} - {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Temel modelleri indir"""
|
||||||
|
print("🚀 Docker build - Model indirme başlatılıyor...")
|
||||||
|
|
||||||
|
models_base = "/app/models"
|
||||||
|
|
||||||
|
# İndirilecek modeller
|
||||||
|
models_to_download = [
|
||||||
|
# SDXL Base Model
|
||||||
|
{
|
||||||
|
"repo_id": "stabilityai/stable-diffusion-xl-base-1.0",
|
||||||
|
"filename": "sd_xl_base_1.0.safetensors",
|
||||||
|
"target_dir": f"{models_base}/checkpoints"
|
||||||
|
},
|
||||||
|
# SDXL VAE
|
||||||
|
{
|
||||||
|
"repo_id": "stabilityai/sdxl-vae",
|
||||||
|
"filename": "sdxl_vae.safetensors",
|
||||||
|
"target_dir": f"{models_base}/vae"
|
||||||
|
},
|
||||||
|
# CLIP Text Encoder
|
||||||
|
{
|
||||||
|
"repo_id": "openai/clip-vit-large-patch14",
|
||||||
|
"filename": "pytorch_model.bin",
|
||||||
|
"target_dir": f"{models_base}/clip"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
success_count = 0
|
||||||
|
|
||||||
|
for model in models_to_download:
|
||||||
|
if download_model(
|
||||||
|
model["repo_id"],
|
||||||
|
model["filename"],
|
||||||
|
model["target_dir"]
|
||||||
|
):
|
||||||
|
success_count += 1
|
||||||
|
|
||||||
|
print(f"\n🎉 Model indirme tamamlandı: {success_count}/{len(models_to_download)}")
|
||||||
|
|
||||||
|
# Model klasörlerini listele
|
||||||
|
print("\n📁 Model klasörleri:")
|
||||||
|
for root, dirs, files in os.walk(models_base):
|
||||||
|
level = root.replace(models_base, '').count(os.sep)
|
||||||
|
indent = ' ' * 2 * level
|
||||||
|
print(f"{indent}{os.path.basename(root)}/")
|
||||||
|
subindent = ' ' * 2 * (level + 1)
|
||||||
|
for file in files:
|
||||||
|
file_size = os.path.getsize(os.path.join(root, file))
|
||||||
|
size_mb = file_size / (1024 * 1024)
|
||||||
|
print(f"{subindent}{file} ({size_mb:.1f} MB)")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
0
runpod_template_config.md
Normal file
0
runpod_template_config.md
Normal file
91
runpod_test_commands.md
Normal file
91
runpod_test_commands.md
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# RunPod Container Test Komutları
|
||||||
|
|
||||||
|
## 1. Container'a Bağlan
|
||||||
|
RunPod dashboard'da "Connect" → "Start Web Terminal"
|
||||||
|
|
||||||
|
## 2. Test Scriptini Çalıştır
|
||||||
|
```bash
|
||||||
|
# Container içinde:
|
||||||
|
cd /app
|
||||||
|
python test_image_generation.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Manuel Test (Alternatif)
|
||||||
|
```bash
|
||||||
|
# ComfyUI durumunu kontrol et
|
||||||
|
curl http://127.0.0.1:8188/system_stats
|
||||||
|
|
||||||
|
# Model listesini al
|
||||||
|
curl http://127.0.0.1:8188/object_info | jq '.CheckpointLoaderSimple.input.required.ckpt_name'
|
||||||
|
|
||||||
|
# Basit workflow gönder
|
||||||
|
curl -X POST http://127.0.0.1:8188/prompt \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d @test_simple_workflow.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Network Storage Kontrolü
|
||||||
|
```bash
|
||||||
|
# Models klasörünü kontrol et
|
||||||
|
ls -la /app/models/
|
||||||
|
ls -la /runpod-volume/models/
|
||||||
|
|
||||||
|
# Symlink kontrolü
|
||||||
|
readlink /app/models
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Model Yükleme (Gerekirse)
|
||||||
|
```bash
|
||||||
|
# Network storage'a model yükle
|
||||||
|
cd /runpod-volume/models/checkpoints
|
||||||
|
wget https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_base_1.0.safetensors
|
||||||
|
|
||||||
|
# ComfyUI'yi yeniden başlat
|
||||||
|
pkill -f main.py
|
||||||
|
python main.py --listen 0.0.0.0 --port 8188 --cpu
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Beklenen Çıktılar
|
||||||
|
|
||||||
|
### Başarılı Durum:
|
||||||
|
```
|
||||||
|
✅ ComfyUI server çalışıyor
|
||||||
|
✅ Yüklü modeller (1 adet):
|
||||||
|
- sd_xl_base_1.0.safetensors
|
||||||
|
🎨 Resim üretiliyor...
|
||||||
|
Model: sd_xl_base_1.0.safetensors
|
||||||
|
Prompt: a modern user interface design...
|
||||||
|
📝 Prompt ID: abc123
|
||||||
|
⏳ Bekleniyor... (15s)
|
||||||
|
✅ Resim kaydedildi: test_output/test_ui_design_00001_.png
|
||||||
|
🎉 Test tamamlandı!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hata Durumu:
|
||||||
|
```
|
||||||
|
❌ ComfyUI server'a bağlanılamıyor
|
||||||
|
❌ Hiç model bulunamadı
|
||||||
|
❌ Network storage mount edilmedi
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Troubleshooting
|
||||||
|
|
||||||
|
### ComfyUI Başlamazsa:
|
||||||
|
```bash
|
||||||
|
# Logları kontrol et
|
||||||
|
tail -f /var/log/comfyui.log
|
||||||
|
|
||||||
|
# Manuel başlat
|
||||||
|
cd /app
|
||||||
|
python main.py --listen 0.0.0.0 --port 8188 --cpu
|
||||||
|
```
|
||||||
|
|
||||||
|
### Network Storage Sorunları:
|
||||||
|
```bash
|
||||||
|
# Mount durumunu kontrol et
|
||||||
|
mount | grep runpod-volume
|
||||||
|
|
||||||
|
# Manuel mount
|
||||||
|
mkdir -p /runpod-volume/models
|
||||||
|
ln -sf /runpod-volume/models /app/models
|
||||||
|
```
|
||||||
@ -161,11 +161,12 @@ def main():
|
|||||||
# Environment setup
|
# Environment setup
|
||||||
setup_environment()
|
setup_environment()
|
||||||
|
|
||||||
# Network storage'ı bekle
|
# Hızlı başlatma için network storage mount'u atla
|
||||||
wait_for_storage()
|
# Modeller zaten Docker image'da mevcut
|
||||||
|
logger.info("Hızlı başlatma modu - modeller image'da mevcut")
|
||||||
|
|
||||||
# Network storage mount
|
# Model klasörlerini kontrol et
|
||||||
mount_runpod_storage()
|
ensure_local_model_folders()
|
||||||
|
|
||||||
# Temel modelleri indir (opsiyonel)
|
# Temel modelleri indir (opsiyonel)
|
||||||
download_essential_models()
|
download_essential_models()
|
||||||
|
|||||||
40
test-storage-access.Dockerfile
Normal file
40
test-storage-access.Dockerfile
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
# RunPod build sırasında storage erişimi test et
|
||||||
|
RUN echo "🔍 RunPod Build Storage Access Test" && \
|
||||||
|
echo "=================================" && \
|
||||||
|
echo "" && \
|
||||||
|
echo "📁 Testing common RunPod storage paths:" && \
|
||||||
|
echo "" && \
|
||||||
|
echo "1. /workspace:" && \
|
||||||
|
(ls -la /workspace 2>/dev/null || echo "❌ /workspace not accessible") && \
|
||||||
|
echo "" && \
|
||||||
|
echo "2. /runpod-volume:" && \
|
||||||
|
(ls -la /runpod-volume 2>/dev/null || echo "❌ /runpod-volume not accessible") && \
|
||||||
|
echo "" && \
|
||||||
|
echo "3. /content:" && \
|
||||||
|
(ls -la /content 2>/dev/null || echo "❌ /content not accessible") && \
|
||||||
|
echo "" && \
|
||||||
|
echo "4. /storage:" && \
|
||||||
|
(ls -la /storage 2>/dev/null || echo "❌ /storage not accessible") && \
|
||||||
|
echo "" && \
|
||||||
|
echo "5. Environment variables:" && \
|
||||||
|
env | grep -i runpod || echo "❌ No RUNPOD env vars found" && \
|
||||||
|
echo "" && \
|
||||||
|
echo "6. Mount points:" && \
|
||||||
|
mount | grep -E "(workspace|runpod|storage)" || echo "❌ No storage mounts found" && \
|
||||||
|
echo "" && \
|
||||||
|
echo "7. Available disk space:" && \
|
||||||
|
df -h && \
|
||||||
|
echo "" && \
|
||||||
|
echo "8. Network connectivity test:" && \
|
||||||
|
(ping -c 1 google.com >/dev/null 2>&1 && echo "✅ Internet access available" || echo "❌ No internet access") && \
|
||||||
|
echo "" && \
|
||||||
|
echo "=================================" && \
|
||||||
|
echo "🏁 Test completed"
|
||||||
|
|
||||||
|
# Basit bir uygulama
|
||||||
|
WORKDIR /app
|
||||||
|
RUN echo 'print("Hello from RunPod build test!")' > app.py
|
||||||
|
|
||||||
|
CMD ["python", "app.py"]
|
||||||
21
test_build.sh
Executable file
21
test_build.sh
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# RunPod Build Test Script
|
||||||
|
|
||||||
|
echo "🔍 RunPod Storage Access Test"
|
||||||
|
echo "============================="
|
||||||
|
|
||||||
|
# Docker build ile test et (local)
|
||||||
|
echo "📦 Local Docker build test..."
|
||||||
|
docker build -f test-storage-access.Dockerfile -t runpod-storage-test . 2>&1 | grep -E "(Storage Access Test|accessible|not accessible)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🚀 Gerçek test için RunPod Dashboard'da bu Dockerfile'ı kullan:"
|
||||||
|
echo " 1. RunPod Dashboard → Templates → Create Template"
|
||||||
|
echo " 2. Container Image → Build from Dockerfile"
|
||||||
|
echo " 3. test-storage-access.Dockerfile içeriğini yapıştır"
|
||||||
|
echo " 4. Build loglarında storage erişim sonuçlarını kontrol et"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📋 Test sonuçlarına göre:"
|
||||||
|
echo " ✅ Storage erişimi VARSA → Build sırasında model kopyalama"
|
||||||
|
echo " ❌ Storage erişimi YOKSA → HuggingFace'den model indirme"
|
||||||
155
test_curl_runpod.sh
Executable file
155
test_curl_runpod.sh
Executable file
@ -0,0 +1,155 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# RunPod Serverless API Test with curl
|
||||||
|
# Usage: ./test_curl_runpod.sh "your prompt here"
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
ENDPOINT_ID="sfkzjudvrj50yq"
|
||||||
|
API_KEY="${RUNPOD_API_KEY:-YOUR_API_KEY}" # Set RUNPOD_API_KEY environment variable
|
||||||
|
BASE_URL="https://api.runpod.ai/v2"
|
||||||
|
|
||||||
|
# Check if API key is set
|
||||||
|
if [ "$API_KEY" = "YOUR_API_KEY" ]; then
|
||||||
|
echo "❌ API key not set!"
|
||||||
|
echo "💡 Set your API key: export RUNPOD_API_KEY='your_key_here'"
|
||||||
|
echo " Or edit this script and replace YOUR_API_KEY with your actual key"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get prompt from command line or use default
|
||||||
|
PROMPT="${1:-modern software interface, clean dashboard design, professional UI layout, high quality, detailed}"
|
||||||
|
|
||||||
|
echo "🚀 Testing RunPod Serverless API..."
|
||||||
|
echo "📍 Endpoint: $ENDPOINT_ID"
|
||||||
|
echo "💬 Prompt: $PROMPT"
|
||||||
|
|
||||||
|
# Create the JSON payload
|
||||||
|
JSON_PAYLOAD=$(cat <<EOF
|
||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"workflow": {
|
||||||
|
"3": {
|
||||||
|
"inputs": {
|
||||||
|
"seed": 42,
|
||||||
|
"steps": 25,
|
||||||
|
"cfg": 8.0,
|
||||||
|
"sampler_name": "euler",
|
||||||
|
"scheduler": "normal",
|
||||||
|
"denoise": 1.0,
|
||||||
|
"model": ["4", 0],
|
||||||
|
"positive": ["6", 0],
|
||||||
|
"negative": ["7", 0],
|
||||||
|
"latent_image": ["5", 0]
|
||||||
|
},
|
||||||
|
"class_type": "KSampler"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"inputs": {
|
||||||
|
"ckpt_name": "sd_xl_base_1.0.safetensors"
|
||||||
|
},
|
||||||
|
"class_type": "CheckpointLoaderSimple"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"inputs": {
|
||||||
|
"width": 1024,
|
||||||
|
"height": 1024,
|
||||||
|
"batch_size": 1
|
||||||
|
},
|
||||||
|
"class_type": "EmptyLatentImage"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"inputs": {
|
||||||
|
"text": "$PROMPT",
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"inputs": {
|
||||||
|
"text": "blurry, low quality, distorted, ugly, bad anatomy, worst quality",
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"inputs": {
|
||||||
|
"samples": ["3", 0],
|
||||||
|
"vae": ["4", 2]
|
||||||
|
},
|
||||||
|
"class_type": "VAEDecode"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"inputs": {
|
||||||
|
"filename_prefix": "curl_test",
|
||||||
|
"images": ["8", 0]
|
||||||
|
},
|
||||||
|
"class_type": "SaveImage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
# Submit the job
|
||||||
|
echo "📤 Submitting job..."
|
||||||
|
RESPONSE=$(curl -s -X POST "$BASE_URL/$ENDPOINT_ID/run" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer $API_KEY" \
|
||||||
|
-d "$JSON_PAYLOAD")
|
||||||
|
|
||||||
|
# Check if curl succeeded
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "❌ Curl command failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse job ID
|
||||||
|
JOB_ID=$(echo "$RESPONSE" | grep -o '"id":"[^"]*"' | cut -d'"' -f4)
|
||||||
|
|
||||||
|
if [ -z "$JOB_ID" ]; then
|
||||||
|
echo "❌ Failed to get job ID"
|
||||||
|
echo "Response: $RESPONSE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Job submitted: $JOB_ID"
|
||||||
|
|
||||||
|
# Monitor job status
|
||||||
|
echo "⏳ Monitoring job status..."
|
||||||
|
MAX_WAIT=300 # 5 minutes
|
||||||
|
WAIT_TIME=0
|
||||||
|
|
||||||
|
while [ $WAIT_TIME -lt $MAX_WAIT ]; do
|
||||||
|
STATUS_RESPONSE=$(curl -s -X GET "$BASE_URL/$ENDPOINT_ID/status/$JOB_ID" \
|
||||||
|
-H "Authorization: Bearer $API_KEY")
|
||||||
|
|
||||||
|
STATUS=$(echo "$STATUS_RESPONSE" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
|
||||||
|
|
||||||
|
case "$STATUS" in
|
||||||
|
"COMPLETED")
|
||||||
|
echo "✅ Job completed!"
|
||||||
|
echo "📄 Full response:"
|
||||||
|
echo "$STATUS_RESPONSE" | jq '.' 2>/dev/null || echo "$STATUS_RESPONSE"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
"FAILED")
|
||||||
|
echo "❌ Job failed!"
|
||||||
|
echo "📄 Error response:"
|
||||||
|
echo "$STATUS_RESPONSE" | jq '.' 2>/dev/null || echo "$STATUS_RESPONSE"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
"IN_QUEUE"|"IN_PROGRESS")
|
||||||
|
echo "⏳ Job status: $STATUS (${WAIT_TIME}s elapsed)"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "❓ Unknown status: $STATUS"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
WAIT_TIME=$((WAIT_TIME + 5))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "⏰ Timeout after ${MAX_WAIT} seconds"
|
||||||
|
echo "📄 Last status response:"
|
||||||
|
echo "$STATUS_RESPONSE" | jq '.' 2>/dev/null || echo "$STATUS_RESPONSE"
|
||||||
274
test_image_generation.py
Normal file
274
test_image_generation.py
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
ComfyUI Test Script - pars klasöründeki resimlere benzer resim üretimi
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import base64
|
||||||
|
import requests
|
||||||
|
from pathlib import Path
|
||||||
|
import time
|
||||||
|
|
||||||
|
class ComfyUITester:
|
||||||
|
def __init__(self, comfyui_url="http://127.0.0.1:8188"):
|
||||||
|
self.comfyui_url = comfyui_url
|
||||||
|
self.client_id = "test_client"
|
||||||
|
|
||||||
|
def check_server(self):
|
||||||
|
"""ComfyUI server'ın çalışıp çalışmadığını kontrol et"""
|
||||||
|
try:
|
||||||
|
response = requests.get(f"{self.comfyui_url}/system_stats", timeout=5)
|
||||||
|
if response.status_code == 200:
|
||||||
|
print("✅ ComfyUI server çalışıyor")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"❌ ComfyUI server yanıt vermiyor: {response.status_code}")
|
||||||
|
return False
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"❌ ComfyUI server'a bağlanılamıyor: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_models(self):
|
||||||
|
"""Yüklü modelleri listele"""
|
||||||
|
try:
|
||||||
|
response = requests.get(f"{self.comfyui_url}/object_info")
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
checkpoints = data.get("CheckpointLoaderSimple", {}).get("input", {}).get("required", {}).get("ckpt_name", [])
|
||||||
|
if isinstance(checkpoints, list) and len(checkpoints) > 1:
|
||||||
|
models = checkpoints[0] # İlk element model listesi
|
||||||
|
print(f"✅ Yüklü modeller ({len(models)} adet):")
|
||||||
|
for model in models[:5]: # İlk 5 modeli göster
|
||||||
|
print(f" - {model}")
|
||||||
|
return models
|
||||||
|
else:
|
||||||
|
print("❌ Model listesi alınamadı")
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Model listesi alınamadı: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def create_basic_workflow(self, model_name="sd_xl_base_1.0.safetensors", prompt="a beautiful landscape"):
|
||||||
|
"""Temel SDXL workflow oluştur"""
|
||||||
|
workflow = {
|
||||||
|
"3": {
|
||||||
|
"inputs": {
|
||||||
|
"seed": 42,
|
||||||
|
"steps": 20,
|
||||||
|
"cfg": 8.0,
|
||||||
|
"sampler_name": "euler",
|
||||||
|
"scheduler": "normal",
|
||||||
|
"denoise": 1.0,
|
||||||
|
"model": ["4", 0],
|
||||||
|
"positive": ["6", 0],
|
||||||
|
"negative": ["7", 0],
|
||||||
|
"latent_image": ["5", 0]
|
||||||
|
},
|
||||||
|
"class_type": "KSampler"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"inputs": {
|
||||||
|
"ckpt_name": model_name
|
||||||
|
},
|
||||||
|
"class_type": "CheckpointLoaderSimple"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"inputs": {
|
||||||
|
"width": 1024,
|
||||||
|
"height": 1024,
|
||||||
|
"batch_size": 1
|
||||||
|
},
|
||||||
|
"class_type": "EmptyLatentImage"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"inputs": {
|
||||||
|
"text": prompt,
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"inputs": {
|
||||||
|
"text": "blurry, low quality, distorted",
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"inputs": {
|
||||||
|
"samples": ["3", 0],
|
||||||
|
"vae": ["4", 2]
|
||||||
|
},
|
||||||
|
"class_type": "VAEDecode"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"inputs": {
|
||||||
|
"filename_prefix": "test_output",
|
||||||
|
"images": ["8", 0]
|
||||||
|
},
|
||||||
|
"class_type": "SaveImage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return workflow
|
||||||
|
|
||||||
|
def generate_image(self, prompt, model_name=None):
|
||||||
|
"""Resim üret"""
|
||||||
|
try:
|
||||||
|
# Model seç
|
||||||
|
if not model_name:
|
||||||
|
models = self.get_models()
|
||||||
|
if not models:
|
||||||
|
print("❌ Hiç model bulunamadı")
|
||||||
|
return None
|
||||||
|
model_name = models[0] # İlk modeli kullan
|
||||||
|
|
||||||
|
print(f"🎨 Resim üretiliyor...")
|
||||||
|
print(f" Model: {model_name}")
|
||||||
|
print(f" Prompt: {prompt}")
|
||||||
|
|
||||||
|
# Workflow oluştur
|
||||||
|
workflow = self.create_basic_workflow(model_name, prompt)
|
||||||
|
|
||||||
|
# İsteği gönder
|
||||||
|
response = requests.post(
|
||||||
|
f"{self.comfyui_url}/prompt",
|
||||||
|
json={
|
||||||
|
"prompt": workflow,
|
||||||
|
"client_id": self.client_id
|
||||||
|
},
|
||||||
|
timeout=30
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
prompt_id = response.json()["prompt_id"]
|
||||||
|
print(f"📝 Prompt ID: {prompt_id}")
|
||||||
|
|
||||||
|
# Tamamlanmasını bekle
|
||||||
|
return self.wait_for_completion(prompt_id)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Resim üretimi başarısız: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def wait_for_completion(self, prompt_id, timeout=300):
|
||||||
|
"""İşlemin tamamlanmasını bekle"""
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
while time.time() - start_time < timeout:
|
||||||
|
try:
|
||||||
|
# Queue durumunu kontrol et
|
||||||
|
queue_response = requests.get(f"{self.comfyui_url}/queue")
|
||||||
|
queue_data = queue_response.json()
|
||||||
|
|
||||||
|
# İşlem hala çalışıyor mu?
|
||||||
|
running = any(item[1]["prompt_id"] == prompt_id for item in queue_data.get("queue_running", []))
|
||||||
|
pending = any(item[1]["prompt_id"] == prompt_id for item in queue_data.get("queue_pending", []))
|
||||||
|
|
||||||
|
if not running and not pending:
|
||||||
|
# İşlem tamamlandı, sonuçları al
|
||||||
|
history_response = requests.get(f"{self.comfyui_url}/history/{prompt_id}")
|
||||||
|
if history_response.status_code == 200:
|
||||||
|
history_data = history_response.json()
|
||||||
|
if prompt_id in history_data:
|
||||||
|
return self.download_results(history_data[prompt_id])
|
||||||
|
|
||||||
|
print(f"⏳ Bekleniyor... ({int(time.time() - start_time)}s)")
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Durum kontrolü hatası: {e}")
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
print(f"⏰ Timeout: {timeout} saniye")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def download_results(self, history_data):
|
||||||
|
"""Sonuçları indir"""
|
||||||
|
results = []
|
||||||
|
|
||||||
|
if "outputs" in history_data:
|
||||||
|
for node_id, node_output in history_data["outputs"].items():
|
||||||
|
if "images" in node_output:
|
||||||
|
for image_info in node_output["images"]:
|
||||||
|
try:
|
||||||
|
# Resmi indir
|
||||||
|
image_url = f"{self.comfyui_url}/view"
|
||||||
|
params = {
|
||||||
|
"filename": image_info["filename"],
|
||||||
|
"subfolder": image_info.get("subfolder", ""),
|
||||||
|
"type": image_info.get("type", "output")
|
||||||
|
}
|
||||||
|
|
||||||
|
image_response = requests.get(image_url, params=params)
|
||||||
|
image_response.raise_for_status()
|
||||||
|
|
||||||
|
# Test output klasörüne kaydet
|
||||||
|
os.makedirs("test_output", exist_ok=True)
|
||||||
|
output_path = f"test_output/{image_info['filename']}"
|
||||||
|
|
||||||
|
with open(output_path, "wb") as f:
|
||||||
|
f.write(image_response.content)
|
||||||
|
|
||||||
|
results.append({
|
||||||
|
"filename": image_info["filename"],
|
||||||
|
"path": output_path,
|
||||||
|
"node_id": node_id
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"✅ Resim kaydedildi: {output_path}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Resim indirme hatası: {e}")
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Ana test fonksiyonu"""
|
||||||
|
print("🚀 ComfyUI Test Başlatılıyor...")
|
||||||
|
|
||||||
|
tester = ComfyUITester()
|
||||||
|
|
||||||
|
# Server kontrolü
|
||||||
|
if not tester.check_server():
|
||||||
|
print("\n💡 ComfyUI'yi başlatmak için:")
|
||||||
|
print(" python main.py --listen 0.0.0.0 --port 8188")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Model kontrolü
|
||||||
|
models = tester.get_models()
|
||||||
|
if not models:
|
||||||
|
print("\n💡 Model yüklemek için:")
|
||||||
|
print(" 1. models/checkpoints/ klasörüne .safetensors dosyası ekleyin")
|
||||||
|
print(" 2. ComfyUI'yi yeniden başlatın")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Test prompt'ları (pars klasöründeki screenshot'lara benzer)
|
||||||
|
test_prompts = [
|
||||||
|
"a modern user interface design, clean layout, professional software interface",
|
||||||
|
"screenshot of a web application, dashboard design, modern UI elements",
|
||||||
|
"software interface mockup, clean design, professional layout",
|
||||||
|
"application screenshot, user interface design, modern web app",
|
||||||
|
"dashboard interface, clean UI design, professional software layout"
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"\n🎨 {len(test_prompts)} adet test resmi üretiliyor...")
|
||||||
|
|
||||||
|
# Her prompt için resim üret
|
||||||
|
for i, prompt in enumerate(test_prompts, 1):
|
||||||
|
print(f"\n--- Test {i}/{len(test_prompts)} ---")
|
||||||
|
result = tester.generate_image(prompt, models[0])
|
||||||
|
|
||||||
|
if result:
|
||||||
|
print(f"✅ Test {i} başarılı: {len(result)} resim üretildi")
|
||||||
|
else:
|
||||||
|
print(f"❌ Test {i} başarısız")
|
||||||
|
|
||||||
|
# Kısa bekleme
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
print("\n🎉 Test tamamlandı!")
|
||||||
|
print("📁 Üretilen resimler: test_output/ klasöründe")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
257
test_runpod_api.py
Normal file
257
test_runpod_api.py
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
RunPod Serverless API Test - pars klasöründeki resimlere benzer resim üretimi
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import base64
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
class RunPodTester:
|
||||||
|
def __init__(self):
|
||||||
|
# RunPod API bilgileri (.env.example'dan alın)
|
||||||
|
self.api_key = os.getenv("RUNPOD_API_KEY", "YOUR_RUNPOD_API_KEY") # .env dosyasından alın
|
||||||
|
self.endpoint_id = "sfkzjudvrj50yq" # Dashboard'dan aldığınız ID
|
||||||
|
self.base_url = "https://api.runpod.ai/v2"
|
||||||
|
|
||||||
|
def create_test_workflow(self, prompt):
|
||||||
|
"""Test workflow'u oluştur"""
|
||||||
|
return {
|
||||||
|
"input": {
|
||||||
|
"workflow": {
|
||||||
|
"3": {
|
||||||
|
"inputs": {
|
||||||
|
"seed": 42,
|
||||||
|
"steps": 25,
|
||||||
|
"cfg": 8.0,
|
||||||
|
"sampler_name": "euler",
|
||||||
|
"scheduler": "normal",
|
||||||
|
"denoise": 1.0,
|
||||||
|
"model": ["4", 0],
|
||||||
|
"positive": ["6", 0],
|
||||||
|
"negative": ["7", 0],
|
||||||
|
"latent_image": ["5", 0]
|
||||||
|
},
|
||||||
|
"class_type": "KSampler"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"inputs": {
|
||||||
|
"ckpt_name": "sd_xl_base_1.0.safetensors"
|
||||||
|
},
|
||||||
|
"class_type": "CheckpointLoaderSimple"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"inputs": {
|
||||||
|
"width": 1024,
|
||||||
|
"height": 1024,
|
||||||
|
"batch_size": 1
|
||||||
|
},
|
||||||
|
"class_type": "EmptyLatentImage"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"inputs": {
|
||||||
|
"text": prompt,
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"inputs": {
|
||||||
|
"text": "blurry, low quality, distorted, ugly, bad anatomy, worst quality",
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"inputs": {
|
||||||
|
"samples": ["3", 0],
|
||||||
|
"vae": ["4", 2]
|
||||||
|
},
|
||||||
|
"class_type": "VAEDecode"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"inputs": {
|
||||||
|
"filename_prefix": "runpod_test",
|
||||||
|
"images": ["8", 0]
|
||||||
|
},
|
||||||
|
"class_type": "SaveImage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def submit_job(self, prompt):
|
||||||
|
"""RunPod'a job gönder"""
|
||||||
|
try:
|
||||||
|
workflow_data = self.create_test_workflow(prompt)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {self.api_key}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
url = f"{self.base_url}/{self.endpoint_id}/run"
|
||||||
|
|
||||||
|
print(f"🚀 Job gönderiliyor...")
|
||||||
|
print(f" Endpoint: {self.endpoint_id}")
|
||||||
|
print(f" Prompt: {prompt[:50]}...")
|
||||||
|
|
||||||
|
response = requests.post(url, json=workflow_data, headers=headers, timeout=30)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
job_data = response.json()
|
||||||
|
job_id = job_data.get("id")
|
||||||
|
|
||||||
|
print(f"✅ Job gönderildi: {job_id}")
|
||||||
|
return job_id
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Job gönderme hatası: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_job_status(self, job_id):
|
||||||
|
"""Job durumunu kontrol et"""
|
||||||
|
try:
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {self.api_key}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
url = f"{self.base_url}/{self.endpoint_id}/status/{job_id}"
|
||||||
|
response = requests.get(url, headers=headers, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Durum kontrolü hatası: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def wait_for_completion(self, job_id, timeout=300):
|
||||||
|
"""Job'ın tamamlanmasını bekle"""
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
while time.time() - start_time < timeout:
|
||||||
|
status_data = self.check_job_status(job_id)
|
||||||
|
|
||||||
|
if not status_data:
|
||||||
|
time.sleep(5)
|
||||||
|
continue
|
||||||
|
|
||||||
|
status = status_data.get("status")
|
||||||
|
|
||||||
|
if status == "COMPLETED":
|
||||||
|
print("✅ Job tamamlandı!")
|
||||||
|
return status_data.get("output")
|
||||||
|
elif status == "FAILED":
|
||||||
|
print("❌ Job başarısız!")
|
||||||
|
print(f" Hata: {status_data.get('error', 'Bilinmeyen hata')}")
|
||||||
|
return None
|
||||||
|
elif status in ["IN_QUEUE", "IN_PROGRESS"]:
|
||||||
|
elapsed = int(time.time() - start_time)
|
||||||
|
print(f"⏳ Job çalışıyor... ({status}) - {elapsed}s")
|
||||||
|
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
print(f"⏰ Timeout: {timeout} saniye")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def save_results(self, output_data, test_name):
|
||||||
|
"""Sonuçları kaydet"""
|
||||||
|
if not output_data:
|
||||||
|
return []
|
||||||
|
|
||||||
|
os.makedirs("test_output", exist_ok=True)
|
||||||
|
saved_files = []
|
||||||
|
|
||||||
|
outputs = output_data.get("outputs", [])
|
||||||
|
for i, output in enumerate(outputs):
|
||||||
|
if "data" in output:
|
||||||
|
try:
|
||||||
|
# Base64 decode
|
||||||
|
image_data = base64.b64decode(output["data"])
|
||||||
|
|
||||||
|
# Dosya adı
|
||||||
|
filename = f"{test_name}_{i+1:02d}.png"
|
||||||
|
filepath = f"test_output/{filename}"
|
||||||
|
|
||||||
|
# Kaydet
|
||||||
|
with open(filepath, "wb") as f:
|
||||||
|
f.write(image_data)
|
||||||
|
|
||||||
|
saved_files.append(filepath)
|
||||||
|
print(f"💾 Resim kaydedildi: {filepath}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Resim kaydetme hatası: {e}")
|
||||||
|
|
||||||
|
return saved_files
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Ana test fonksiyonu"""
|
||||||
|
print("🚀 RunPod Serverless Test Başlatılıyor...")
|
||||||
|
|
||||||
|
tester = RunPodTester()
|
||||||
|
|
||||||
|
# API key kontrolü
|
||||||
|
if tester.api_key == "YOUR_RUNPOD_API_KEY":
|
||||||
|
print("❌ API key ayarlanmamış!")
|
||||||
|
print("💡 test_runpod_api.py dosyasında API key'inizi güncelleyin")
|
||||||
|
print(" API key'i RunPod dashboard → Settings → API Keys'den alabilirsiniz")
|
||||||
|
return
|
||||||
|
|
||||||
|
# pars klasöründeki screenshot'lara benzer prompt'lar
|
||||||
|
test_prompts = [
|
||||||
|
"modern software interface, clean dashboard design, professional UI layout, high quality, detailed",
|
||||||
|
"web application screenshot, user interface mockup, modern design system, clean layout",
|
||||||
|
"software dashboard, data visualization interface, professional web app design, modern UI",
|
||||||
|
"application interface design, clean user experience, professional software layout, modern style",
|
||||||
|
"digital interface mockup, clean web design, professional dashboard layout, modern UI elements"
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"\n🎨 {len(test_prompts)} adet test resmi üretiliyor...")
|
||||||
|
print(f"📍 Endpoint: {tester.endpoint_id}")
|
||||||
|
|
||||||
|
all_results = []
|
||||||
|
|
||||||
|
# Her prompt için test
|
||||||
|
for i, prompt in enumerate(test_prompts, 1):
|
||||||
|
print(f"\n--- Test {i}/{len(test_prompts)} ---")
|
||||||
|
|
||||||
|
# Job gönder
|
||||||
|
job_id = tester.submit_job(prompt)
|
||||||
|
if not job_id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Tamamlanmasını bekle
|
||||||
|
output = tester.wait_for_completion(job_id)
|
||||||
|
|
||||||
|
# Sonuçları kaydet
|
||||||
|
if output:
|
||||||
|
saved_files = tester.save_results(output, f"ui_design_test_{i}")
|
||||||
|
all_results.extend(saved_files)
|
||||||
|
print(f"✅ Test {i} başarılı: {len(saved_files)} resim")
|
||||||
|
else:
|
||||||
|
print(f"❌ Test {i} başarısız")
|
||||||
|
|
||||||
|
# Rate limiting için bekleme
|
||||||
|
if i < len(test_prompts):
|
||||||
|
print("⏸️ Rate limiting için 10 saniye bekleniyor...")
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
# Özet
|
||||||
|
print(f"\n🎉 Test tamamlandı!")
|
||||||
|
print(f"📊 Toplam üretilen resim: {len(all_results)}")
|
||||||
|
print(f"📁 Kaydedilen dosyalar:")
|
||||||
|
for file in all_results:
|
||||||
|
print(f" - {file}")
|
||||||
|
|
||||||
|
if all_results:
|
||||||
|
print(f"\n💡 Resimleri görüntülemek için:")
|
||||||
|
print(f" open test_output/")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
59
test_simple_workflow.json
Normal file
59
test_simple_workflow.json
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"3": {
|
||||||
|
"inputs": {
|
||||||
|
"seed": 42,
|
||||||
|
"steps": 20,
|
||||||
|
"cfg": 8.0,
|
||||||
|
"sampler_name": "euler",
|
||||||
|
"scheduler": "normal",
|
||||||
|
"denoise": 1.0,
|
||||||
|
"model": ["4", 0],
|
||||||
|
"positive": ["6", 0],
|
||||||
|
"negative": ["7", 0],
|
||||||
|
"latent_image": ["5", 0]
|
||||||
|
},
|
||||||
|
"class_type": "KSampler"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"inputs": {
|
||||||
|
"ckpt_name": "sd_xl_base_1.0.safetensors"
|
||||||
|
},
|
||||||
|
"class_type": "CheckpointLoaderSimple"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"inputs": {
|
||||||
|
"width": 1024,
|
||||||
|
"height": 1024,
|
||||||
|
"batch_size": 1
|
||||||
|
},
|
||||||
|
"class_type": "EmptyLatentImage"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"inputs": {
|
||||||
|
"text": "a modern user interface design, clean layout, professional software interface, high quality, detailed",
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"inputs": {
|
||||||
|
"text": "blurry, low quality, distorted, ugly, bad anatomy",
|
||||||
|
"clip": ["4", 1]
|
||||||
|
},
|
||||||
|
"class_type": "CLIPTextEncode"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"inputs": {
|
||||||
|
"samples": ["3", 0],
|
||||||
|
"vae": ["4", 2]
|
||||||
|
},
|
||||||
|
"class_type": "VAEDecode"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"inputs": {
|
||||||
|
"filename_prefix": "test_ui_design",
|
||||||
|
"images": ["8", 0]
|
||||||
|
},
|
||||||
|
"class_type": "SaveImage"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user