🏖️ Summer Update: Retro cleanup, QOL, optimized JPEG output

This commit is contained in:
mrkmntal 2025-06-22 18:35:05 -04:00
commit cb3ccd80c0
6 changed files with 421 additions and 392 deletions

207
README.md
View file

@ -1,92 +1,179 @@
# Legacy Stable Diffusion WebUI # Legacy Stable Diffusion WebUI — Summer Update ☀️
![phpsd-logo-256](https://github.com/user-attachments/assets/9ca5934f-97e2-4885-bf06-a93dcfc393a6) ![phpsd-logo-256](https://github.com/user-attachments/assets/9ca5934f-97e2-4885-bf06-a93dcfc393a6)
A minimalistic, **JavaScript-free** web interface for Stable Diffusion, designed for compatibility with **legacy web browsers** like Internet Explorer 4, Netscape 4.x, and even Classilla on Mac OS 9.
Built for long-term access to AI image generation using the AUTOMATIC1111 API — from modern GPUs to vintage clients.
A minimalistic, JavaScript-free web interface, front-end and processing server for Stable Diffusion, designed specifically for being accessed by legacy systems and browsers as clients. This interface relies on the API from AUTOMATIC1111's Stable Diffusion WebUI. ---
## Features ## 🆕 Summer 2025 Update Highlights
- No JavaScript dependencies
- Lightweight and fast loading
- Support for LORA models using square bracket syntax
- Image optimization with automatic PNG to JPG conversion
- Prompt saving and loading functionality
- Full configurability of key generation parameters:
- Image dimensions
- Sampling steps
- CFG Scale
- Choice of sampling methods
- Negative prompt support (1-19-2025 Update)
- Optimized default parameters for better quality images by default (1-19-2025 Update)
## Browser Compatibility - 🗂 **File structure cleanup** Generation, prompt saving, and UI now fully separated for better maintainability.
- ⏳ **True loading screen** `loading.php` now displays a loading message before generation starts.
- 💾 **"Save Prompt" moved to result page** Save your prompt right after generation from `result.php`.
- 📉 **Improved compression** Lowered ImageMagick quality to 75 (from 85) for **9093% file size reduction**.
- ✅ **Default sampler set to `Euler a`**, which works especially well with **Illustrious XL** (the recommended model).
- 🧼 Overall code quality and parameter consistency improved.
- `index.php`: Tested working on IE4+, Netscape 4.x and above browsers (HTML 4 compliant) ---
## Requirements ## 🔧 Features
- Linux server with a suitable GPU; running a model in AUTOMATIC1111's Stable Diffusion WebUI https://github.com/AUTOMATIC1111/stable-diffusion-webui with API access (image generation back-end) - No JavaScript — 100% HTML 4.01 and PHP
- Externally accessible Linux server running PHP 8+ to run the PHP front-end (Tested on frankenphp running on Debian 12, should also run with traditional PHP setups with apache/nginx, can run on the same server as the back-end) - Ultra-lightweight for slow or vintage clients
- Web server (Apache, nginx, etc.) - LORA model support via `[name:weight]` syntax
- ImageMagick for image optimization - Prompt saving and loading via `saved-prompts.json`
- Curl - Server-side PNG ➜ JPG conversion with ImageMagick
- Client machine to access the front-end via web browser - Compatible with AUTOMATIC1111 Stable Diffusion WebUI
- Configurable generation settings:
- Image size
- CFG scale
- Steps
- Sampler method
- Negative prompt support
---
## Installation ## 🌐 Browser Compatibility
1. Ensure you have AUTOMATIC1111's Stable Diffusion WebUI running with the `--api` flag Tested on:
2. Install PHP and ImageMagick on your system
3. Copy both `index.php` to your web server directory
4. Ensure the directory is writable by the web server for saved prompts and generated images
5. Access through your web browser:
- Use `index.php` for HTML 4.01+ compatible browsers
## Usage - ✅ Internet Explorer 46 (Windows 952000)
- ✅ Netscape 4.x
- ✅ Classilla (Mac OS 9)
- ✅ Firefox ESR 102+ (modern systems)
1. Enter your prompt and negative prompt if applicable in the text area ---
2. Configure generation parameters as needed
3. Click "Generate Image" to create your image
4. Save frequently used prompts server-side using the "Save Prompt" feature
5. Load saved prompts from the dropdown menu
## LORA Usage ## 📦 Requirements
To use LORA models, include them in your prompt using square brackets: - **Back-end:**
```[lora-name:weight]``` AUTOMATIC1111 Stable Diffusion WebUI running with `--api`
https://github.com/AUTOMATIC1111/stable-diffusion-webui
- **Front-end Server:**
Linux server with:
- PHP 8+
- ImageMagick
- cURL
- Any web server (Apache, nginx, or FrankenPHP)
- **Client:**
Any browser capable of submitting forms and rendering HTML 4.01
(Yes, it really works on Windows NT 4.0)
---
## 🧪 Installation
1. Start AUTOMATIC1111's WebUI with `--api`
2. Install PHP and ImageMagick on your web server
3. Place `index.php`, `loading.php`, `generate.php`, and `result.php` in your web directory
4. Ensure write permissions for:
- `saved-prompts.json`
- Your web server's root directory containing the phpsd files, this is where images will be stored
5. Access `index.php` from a browser and start generating!
---
## 🧭 Usage Guide
1. Open `index.php`
2. Type your prompt and negative prompt (optional)
3. Adjust generation parameters
4. Submit ➜ loading screen ➜ image result
5. Save your favorite prompts directly from `result.php`
---
## 🧠 LORA Support
Use the syntax:
```text
[lora-name:weight]
````
Example: Example:
```a beautiful landscape by [my-artist-lora:0.8]```
## Notes ```text
a high-detail wizard portrait [wizard-style:0.8]
```
- Images are automatically optimized and converted from PNG to JPG for faster loading Weight values typically range from `0.1` to `1.0`
- The interface works without any client-side scripting
- All processing is done server-side
- Compatible with browsers from the late 1990s to now
## Screenshots ---
### Running on Windows NT 4.0 With IE 4 ## 📸 Image Processing Notes
![Screenshot 2024-12-14 142743](https://github.com/user-attachments/assets/838095cb-0af7-4c6e-a140-78e8f7c65691)
### Running on Debian 12 With Firefox ESR 115 * Generated PNGs are automatically converted to optimized JPGs
![Screenshot 2024-12-14 143036](https://github.com/user-attachments/assets/9745d00f-57cc-4788-a17d-43782d7e6fa3) * ImageMagick runs with:
```
-quality 75 -strip -interlace Plane -gaussian-blur 0.05 -sampling-factor 4:2:0
```
* Resulting file sizes reduced by \~9093%, ideal for slow connections and legacy hardware
---
## 🧭 System Architecture
Below is a flowchart diagram representing the separation of concerns between the legacy client and the backend server during prompt submission and image generation.
![Screenshot 2025-06-22 182155](https://github.com/user-attachments/assets/28e9aa66-42d8-4820-bfd9-6b4b23571188)
---
## 🖥️ Screenshots
### Running on Windows 2000 SP2 with IE 5 — Illustrious XL Output (June 22, 2025 Summer Update)
![Gura sample](https://github.com/user-attachments/assets/afa2366b-1760-47da-a7d6-12465b1ba076)
This image was generated using `Euler a` sampler and the Illustrious XL model, processed entirely through the `phpsd` legacy frontend. Displayed here in Internet Explorer 5 on Windows 2000 SP2.
### Running on Mac OS 9 + Classilla
### Running on Mac OS 9 With Classilla
![screenshot2](https://github.com/user-attachments/assets/5284613c-9060-49d4-aed6-5d7fa1d041d3) ![screenshot2](https://github.com/user-attachments/assets/5284613c-9060-49d4-aed6-5d7fa1d041d3)
### Firefox ESR 115 on Debian 12
## Contributing ![Screenshot 2024-12-14 143036](https://github.com/user-attachments/assets/9745d00f-57cc-4788-a17d-43782d7e6fa3)
Contributions are welcome! Please feel free to submit a Pull Request or fork. ---
## License ## 🖼️ Legacy Wallpaper Output
This project is MIT licensed. Dont just generate — **decorate**.
All generated images are:
- Optimized for ultra-low size (JPG @ quality 75)
- CRT-safe resolution options
- Perfect for Retro PC wallpapers
Whether youre browsing from Classilla or setting your ThinkPad T21s background, `phpsd` delivers.
## 🤝 Contributing
Pull requests, forks, and retro tweaks welcome!
Feel free to adapt the UI for even older setups or customize layouts per browser profile.
---
## 📜 License
MIT License
---
## 🧠 Credits
* Front-end & optimization by markmental
* Powered by [AUTOMATIC1111s Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui)
---
## Credits
Built to work with AUTOMATIC1111's Stable Diffusion WebUI API:
https://github.com/AUTOMATIC1111/stable-diffusion-webui

101
generate.php Normal file
View file

@ -0,0 +1,101 @@
<?php
// generate.php
session_start();
ini_set('max_execution_time', '300');
header('Content-Type: text/html; charset=iso-8859-1');
// Input values
$prompt = $_POST['prompt'] ?? '';
$negative_prompt = $_POST['negative_prompt'] ?? '';
$width = isset($_POST['width']) ? (int)$_POST['width'] : 512;
$height = isset($_POST['height']) ? (int)$_POST['height'] : 512;
$steps = isset($_POST['steps']) ? (int)$_POST['steps'] : 20;
$cfg_scale = isset($_POST['cfg_scale']) ? (float)$_POST['cfg_scale'] : 7.5;
$sampler = $_POST['sampler'] ?? 'Euler';
// Input validation
if (strpos($prompt, '<') !== false || strpos($prompt, '>') !== false) {
die("Error: Angle brackets are not allowed in prompts.");
}
// Convert LORA-style square bracket syntax
$processed_prompt = preg_replace('/\[([\w\s\-]+?):([\d\.]+)\]/', '<lora:$1:$2>', $prompt);
// Build request
$data = array(
'prompt' => $processed_prompt,
'negative_prompt' => $negative_prompt,
'steps' => $steps,
'width' => $width,
'height' => $height,
'cfg_scale' => $cfg_scale,
'sampler_name' => $sampler,
'override_settings' => new stdClass(),
'override_settings_restore_afterwards' => true
);
// Call Stable Diffusion API
$ch = curl_init('http://127.0.0.1:7860/sdapi/v1/txt2img');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$result = curl_exec($ch);
curl_close($ch);
if (!$result) {
die("Error: Failed to communicate with the image generation API.");
}
$decoded = json_decode($result, true);
if (!isset($decoded['images'][0])) {
die("Error: No image returned.");
}
// Decode base64 PNG
$image_data = base64_decode($decoded['images'][0]);
// Save original PNG temporarily
$temp_png = 'temp_' . time() . '_' . bin2hex(random_bytes(8)) . '.png';
file_put_contents($temp_png, $image_data);
// Convert PNG to JPG with ImageMagick
$generated_image = 'generated_' . time() . '_' . bin2hex(random_bytes(8)) . '.jpg';
$quality = 75;
$cmd = "convert \"$temp_png\" -strip -interlace Plane -gaussian-blur 0.05 -quality $quality -sampling-factor 4:2:0 \"$generated_image\" 2>&1";
exec($cmd, $output, $returnVar);
// Get image size info
if ($returnVar !== 0 || !file_exists($generated_image)) {
$generated_image = $temp_png;
$size_info = null;
} else {
$originalSize = filesize($temp_png);
$convertedSize = filesize($generated_image);
unlink($temp_png);
$size_info = array(
'original' => round($originalSize / 1024, 2),
'converted' => round($convertedSize / 1024, 2),
'reduction' => round((($originalSize - $convertedSize) / $originalSize) * 100, 2)
);
}
// Save result to session
$_SESSION['result'] = array(
'generated_image' => $generated_image,
'prompt' => $prompt,
'negative_prompt' => $negative_prompt,
'processed_prompt' => $processed_prompt,
'width' => $width,
'height' => $height,
'steps' => $steps,
'cfg_scale' => $cfg_scale,
'sampler' => $sampler,
'size_info' => $size_info
);
// Redirect to result page
header("Location: result.php");
exit;

386
index.php
View file

@ -2,22 +2,8 @@
ini_set('max_execution_time', '300'); ini_set('max_execution_time', '300');
header('Content-Type: text/html; charset=iso-8859-1'); header('Content-Type: text/html; charset=iso-8859-1');
$response = "";
$generated_image = "";
$prompt = "";
$negative_prompt = "";
$width = 768;
$height = 768;
$steps = 35;
$cfg_scale = 3;
$sampler = "DPM++ 3M SDE";
$error_message = "";
$success_message = "";
// File to store saved prompts
$saved_prompts_file = 'saved-prompts.json'; $saved_prompts_file = 'saved-prompts.json';
// Load saved prompts
function loadSavedPrompts() { function loadSavedPrompts() {
global $saved_prompts_file; global $saved_prompts_file;
if (file_exists($saved_prompts_file)) { if (file_exists($saved_prompts_file)) {
@ -27,366 +13,102 @@ function loadSavedPrompts() {
return array(); return array();
} }
// Save a new prompt
function savePrompt($prompt_text, $negative_prompt_text, $prompt_name) {
global $saved_prompts_file;
$prompts = loadSavedPrompts();
$prompts[$prompt_name] = array(
'prompt' => $prompt_text,
'negative_prompt' => $negative_prompt_text
);
file_put_contents($saved_prompts_file, json_encode($prompts, JSON_PRETTY_PRINT));
}
$saved_prompts = loadSavedPrompts(); $saved_prompts = loadSavedPrompts();
// List of available samplers $prompt = '';
$samplers = array( $negative_prompt = '';
"Euler", $width = 768;
"Euler a", $height = 768;
"Heun", $steps = 35;
"DPM2", $cfg_scale = 3;
"DPM2 a", $sampler = "Euler a";
"DPM++ 2S a",
"DPM++ 2M",
"DPM++ SDE",
"DPM++ 2M SDE",
"DPM++ 3M SDE",
"DPM fast",
"DPM adaptive",
"LMS",
"DPM++ SDE Karras",
"DPM++ 2M SDE Karras",
"DPM++ 3M SDE Karras",
"DDIM",
"PLMS"
);
if ($_SERVER["REQUEST_METHOD"] == "POST") { if ($_SERVER["REQUEST_METHOD"] == "GET" && isset($_GET['load_prompt'])) {
// All requests to the server to save or execute prompts will be POST requests to itself
// Handle prompt saving
if (isset($_POST['save_prompt']) && isset($_POST['prompt_name'])) {
$prompt_to_save = trim($_POST['prompt']);
$negative_prompt_to_save = trim($_POST['negative_prompt']);
$prompt_name = trim($_POST['prompt_name']);
if (!empty($prompt_to_save) && !empty($prompt_name)) {
savePrompt($prompt_to_save, $negative_prompt_to_save, $prompt_name);
$success_message = "Prompt saved successfully!";
$saved_prompts = loadSavedPrompts(); // Reload prompts
} else {
$error_message = "Both prompt and prompt name are required to save.";
}
}
// Handle image generation
else {
$prompt = isset($_POST['prompt']) ? $_POST['prompt'] : '';
$negative_prompt = isset($_POST['negative_prompt']) ? $_POST['negative_prompt'] : '';
$width = isset($_POST['width']) ? (int)$_POST['width'] : 512;
$height = isset($_POST['height']) ? (int)$_POST['height'] : 512;
$steps = isset($_POST['steps']) ? (int)$_POST['steps'] : 20;
$cfg_scale = isset($_POST['cfg_scale']) ? (float)$_POST['cfg_scale'] : 7.5;
$sampler = isset($_POST['sampler']) ? $_POST['sampler'] : 'Euler';
// Check for angle brackets in the prompt
if (strpos($prompt, '<') !== false || strpos($prompt, '>') !== false) {
$error_message = "Error: Angle brackets are not allowed in the prompt. Please use square brackets [lora-name:weight] for LORAs.";
}
// Only proceed if there's no error
elseif (!empty($prompt)) {
// Process the prompt to handle LORA syntax
$processed_prompt = preg_replace('/\[([\w\s\-]+?):([\d\.]+)\]/', '<lora:$1:$2>', $prompt);
$data = array(
'prompt' => $processed_prompt,
'negative_prompt' => $negative_prompt,
'steps' => $steps,
'width' => $width,
'height' => $height,
'cfg_scale' => $cfg_scale,
'sampler_name' => $sampler,
'override_settings' => new stdClass(),
'override_settings_restore_afterwards' => true
);
// Replace 127.0.0.1 with your Stable diffusion server's IP if running externally
$ch = curl_init('http://127.0.0.1:7860/sdapi/v1/txt2img');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$result = curl_exec($ch);
if (curl_errno($ch)) {
$response = 'Error: ' . curl_error($ch);
} else {
$decoded = json_decode($result, true);
if (isset($decoded['images'][0])) {
$image_data = base64_decode($decoded['images'][0]);
// Save original PNG temporarily
$temp_png = 'temp_' . time() . '_' . bin2hex(random_bytes(8)) . '.png';
file_put_contents($temp_png, $image_data);
// Create output JPG filename
$generated_image = 'generated_' . time() . '_' . bin2hex(random_bytes(8)) . '.jpg';
// Build ImageMagick convert command with optimization
$quality = 85; // Balanced quality setting
$cmd = "convert \"$temp_png\" -strip -interlace Plane -gaussian-blur 0.05 -quality $quality ";
$cmd .= "-sampling-factor 4:2:0 \"$generated_image\" 2>&1";
// Execute conversion
$output = [];
$returnVar = 0;
exec($cmd, $output, $returnVar);
if ($returnVar === 0 && file_exists($generated_image)) {
// Get file sizes for comparison
$originalSize = filesize($temp_png);
$convertedSize = filesize($generated_image);
// Clean up temporary PNG file
if (file_exists($temp_png)) {
unlink($temp_png);
}
// Clean up old generated files
foreach (glob("generated_*.png") as $file) {
if ($file != $generated_image && (time() - filemtime($file)) > 3600) {
unlink($file);
}
}
// Store size information for display
$size_info = array(
'original' => round($originalSize / 1024, 2),
'converted' => round($convertedSize / 1024, 2),
'reduction' => round((($originalSize - $convertedSize) / $originalSize) * 100, 2)
);
} else {
// If conversion fails, keep the original PNG
if (file_exists($temp_png)) {
$generated_image = $temp_png;
}
$error_message = "Image conversion failed. Using original PNG format.";
}
}
}
curl_close($ch);
}
}
} else if ($_SERVER["REQUEST_METHOD"] == "GET" && isset($_GET['load_prompt'])) {
// For loading prompts we use GET method to send the client's choice of prompt to load
// Load saved prompt into textarea
$saved_prompts = loadSavedPrompts();
if (isset($saved_prompts[$_GET['load_prompt']])) { if (isset($saved_prompts[$_GET['load_prompt']])) {
// Check if the saved prompt is in the new format (array) or old format (string)
if (is_array($saved_prompts[$_GET['load_prompt']])) { if (is_array($saved_prompts[$_GET['load_prompt']])) {
$prompt = $saved_prompts[$_GET['load_prompt']]['prompt']; $prompt = $saved_prompts[$_GET['load_prompt']]['prompt'];
$negative_prompt = $saved_prompts[$_GET['load_prompt']]['negative_prompt']; $negative_prompt = $saved_prompts[$_GET['load_prompt']]['negative_prompt'];
} else { } else {
// Handle old format
$prompt = $saved_prompts[$_GET['load_prompt']]; $prompt = $saved_prompts[$_GET['load_prompt']];
$negative_prompt = ''; $negative_prompt = '';
} }
} }
} }
$samplers = array(
"Euler", "Euler a", "Heun", "DPM2", "DPM2 a", "DPM++ 2S a", "DPM++ 2M",
"DPM++ SDE", "DPM++ 2M SDE", "DPM++ 3M SDE", "DPM fast", "DPM adaptive",
"LMS", "DPM++ SDE Karras", "DPM++ 2M SDE Karras", "DPM++ 3M SDE Karras",
"DDIM", "PLMS"
);
?> ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <!DOCTYPE HTML>
<html> <html>
<head> <head>
<title>Stable Diffusion Image Generator</title> <title>Stable Diffusion Image Generator</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css">
.lora-help {
background-color: #f8f8f8;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
}
.form-group {
margin-bottom: 15px;
}
textarea#prompt {
width: 100%;
height: 100px;
padding: 8px;
font-family: Arial, sans-serif;
font-size: 14px;
border: 1px solid #ddd;
}
textarea#negative_prompt {
width: 100%;
height: 100px;
padding: 8px;
font-family: Arial, sans-serif;
font-size: 14px;
border: 1px solid #ddd;
background-color: #fff3f3;
}
.error-message {
color: #dc3545;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
padding: 10px;
margin: 10px 0;
}
.success-message {
color: #28a745;
background-color: #d4edda;
border: 1px solid #c3e6cb;
padding: 10px;
margin: 10px 0;
}
.saved-prompts {
margin: 20px 0;
padding: 15px;
background-color: #f8f8f8;
border: 1px solid #ddd;
}
.save-prompt-form {
margin: 20px 0;
padding: 15px;
background-color: #f8f8f8;
border: 1px solid #ddd;
}
</style>
</head> </head>
<body> <body>
<?php if (isset($_GET['save_success'])): ?>
<div style="color:green;">Prompt saved successfully.</div>
<?php elseif (isset($_GET['save_error'])): ?>
<div style="color:red;">Error: Prompt and name are required.</div>
<?php endif; ?>
<h1>Stable Diffusion Image Generator</h1> <h1>Stable Diffusion Image Generator</h1>
<div class="lora-help"> <div style="border:1px solid #ccc;padding:10px;margin-bottom:10px;">
<h3>How to use LORAs:</h3> <strong>How to use LORAs:</strong>
<p>Include LORAs in your prompt using this syntax: <code>[lora-name:weight]</code></p> <p>Use square bracket format: <code>[lora-name:weight]</code></p>
<p>Example: <code>a beautiful landscape by [my-artist-lora:0.8]</code></p> <p>Example: <code>a detailed castle, [my-style-lora:0.7]</code></p>
<p>Weight values typically range from 0.1 to 1.0</p> <p><b>Note:</b> Angle brackets are not allowed.</p>
<p><strong>Note:</strong> Angle brackets (< >) are not allowed in prompts. Use square brackets instead.</p>
</div> </div>
<?php if (!empty($error_message)): ?> <div>
<div class="error-message"> <form method="get" action="index.php">
<?php echo htmlspecialchars($error_message); ?> <label for="load_prompt">Load Saved Prompt:</label>
</div> <select name="load_prompt" id="load_prompt">
<?php endif; ?> <option value="">-- Choose --</option>
<?php foreach ($saved_prompts as $name => $data): ?>
<?php if (!empty($success_message)): ?> <option value="<?php echo htmlspecialchars($name); ?>">
<div class="success-message">
<?php echo htmlspecialchars($success_message); ?>
</div>
<?php endif; ?>
<div class="saved-prompts">
<h3>Saved Prompts</h3>
<form method="get" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
<select name="load_prompt">
<option value="">Select a saved prompt</option>
<?php foreach ($saved_prompts as $name => $saved_prompt): ?>
<option value="<?php echo htmlspecialchars($name); ?>"
title="Prompt: <?php echo htmlspecialchars(is_array($saved_prompt) ? $saved_prompt['prompt'] : $saved_prompt); ?>&#13;Negative: <?php echo htmlspecialchars(is_array($saved_prompt) ? $saved_prompt['negative_prompt'] : ''); ?>">
<?php echo htmlspecialchars($name); ?> <?php echo htmlspecialchars($name); ?>
</option> </option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
<input type="submit" value="Load Prompt"> <input type="submit" value="Load">
</form> </form>
</div> </div>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>"> <form method="post" action="loading.php">
<div class="form-group"> <p><label for="prompt">Prompt:</label><br>
<label for="prompt">Enter your prompt (including LORA syntax if needed):</label><br> <textarea name="prompt" id="prompt" rows="5" cols="60"><?php echo htmlspecialchars($prompt); ?></textarea></p>
<textarea name="prompt" id="prompt"><?php echo htmlspecialchars($prompt); ?></textarea>
</div>
<div class="form-group"> <p><label for="negative_prompt">Negative Prompt:</label><br>
<label for="negative_prompt">Enter your negative prompt (things to avoid in the image):</label><br> <textarea name="negative_prompt" id="negative_prompt" rows="5" cols="60"><?php echo htmlspecialchars($negative_prompt); ?></textarea></p>
<textarea name="negative_prompt" id="negative_prompt"><?php echo htmlspecialchars($negative_prompt); ?></textarea>
</div>
<div class="form-group"> <p>
<label for="width">Width:</label> Width: <input type="number" name="width" value="<?php echo $width; ?>" min="64" max="2048" step="64">
<input type="number" name="width" id="width" value="<?php echo $width; ?>" min="64" max="2048" step="64"> Height: <input type="number" name="height" value="<?php echo $height; ?>" min="64" max="2048" step="64">
</div> </p>
<div class="form-group"> <p>
<label for="height">Height:</label> Steps: <input type="number" name="steps" value="<?php echo $steps; ?>" min="1" max="150">
<input type="number" name="height" id="height" value="<?php echo $height; ?>" min="64" max="2048" step="64"> CFG Scale: <input type="number" name="cfg_scale" value="<?php echo $cfg_scale; ?>" min="1" max="30" step="0.5">
</div> </p>
<div class="form-group"> <p>
<label for="steps">Steps:</label> Sampler:
<input type="number" name="steps" id="steps" value="<?php echo $steps; ?>" min="1" max="150"> <select name="sampler">
</div>
<div class="form-group">
<label for="cfg_scale">CFG Scale:</label>
<input type="number" name="cfg_scale" id="cfg_scale" value="<?php echo $cfg_scale; ?>" min="1" max="30" step="0.5">
</div>
<div class="form-group">
<label for="sampler">Sampler:</label>
<select name="sampler" id="sampler">
<?php foreach ($samplers as $s): ?> <?php foreach ($samplers as $s): ?>
<option value="<?php echo htmlspecialchars($s); ?>" <?php echo $s === $sampler ? 'selected' : ''; ?>> <option value="<?php echo htmlspecialchars($s); ?>" <?php echo $s === $sampler ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($s); ?> <?php echo htmlspecialchars($s); ?>
</option> </option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</div>
<div>
<input type="submit" value="Generate Image">
</div>
</form>
<div class="save-prompt-form">
<h3>Save Current Prompt</h3>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
<div class="form-group">
<label for="prompt_name">Prompt Name:</label>
<input type="text" name="prompt_name" id="prompt_name" required>
</div>
<input type="hidden" name="prompt" value="<?php echo htmlspecialchars($prompt); ?>">
<input type="hidden" name="negative_prompt" value="<?php echo htmlspecialchars($negative_prompt); ?>">
<input type="submit" name="save_prompt" value="Save Prompt">
</form>
</div>
<?php if (!empty($generated_image)): ?>
<div class="result">
<h2>Generated Image:</h2>
<img width="250px" src="<?php echo htmlspecialchars($generated_image); ?>" alt="Generated image"/>
<br/>
<a download href="<?php echo htmlspecialchars($generated_image); ?>">Download Generated Image</a>
<?php if (isset($size_info)): ?>
<div class="size-info">
<p>
Original size: <?php echo $size_info['original']; ?> KB<br>
Converted size: <?php echo $size_info['converted']; ?> KB<br>
Size reduction: <?php echo $size_info['reduction']; ?>%
</p> </p>
</div>
<?php endif; ?>
<div class="parameters">
<strong>Parameters used:</strong><br>
Prompt: <?php echo htmlspecialchars($prompt); ?><br>
Negative Prompt: <?php echo htmlspecialchars($negative_prompt); ?><br>
Processed Prompt: <?php echo htmlspecialchars($processed_prompt); ?><br>
Size: <?php echo $width; ?>x<?php echo $height; ?><br>
Steps: <?php echo $steps; ?><br>
CFG Scale: <?php echo $cfg_scale; ?><br>
Sampler: <?php echo htmlspecialchars($sampler); ?>
</div>
</div>
<?php endif; ?>
<?php if (!empty($response)): ?> <p><input type="submit" value="Generate Image"></p>
<div class="result"> </form>
<h2>Error:</h2>
<p><?php echo htmlspecialchars($response); ?></p>
</div>
<?php endif; ?>
</body> </body>
</html> </html>

28
loading.php Normal file
View file

@ -0,0 +1,28 @@
<?php
// loading.php
?>
<!DOCTYPE HTML>
<html>
<head>
<title>Generating Image...</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body onload="document.forms[0].submit();">
<h1>Generating Your Image...</h1>
<p>Please wait. This may take up to 30 seconds depending on prompt complexity.</p>
<form method="post" action="generate.php">
<?php
foreach ($_POST as $key => $value):
$safeKey = htmlspecialchars($key, ENT_QUOTES);
$safeValue = htmlspecialchars($value, ENT_QUOTES);
?>
<input type="hidden" name="<?php echo $safeKey; ?>" value="<?php echo $safeValue; ?>">
<?php endforeach; ?>
<noscript>
<p><input type="submit" value="Click here if not redirected."></p>
</noscript>
</form>
</body>
</html>

50
result.php Normal file
View file

@ -0,0 +1,50 @@
<?php
// result.php
session_start();
if (!isset($_SESSION['result'])) {
die("No image generated yet.");
}
$data = $_SESSION['result'];
unset($_SESSION['result']); // clear for next use
?>
<!DOCTYPE HTML>
<html>
<head>
<title>Stable Diffusion Result</title>
</head>
<body>
<h1>Generated Image</h1>
<img width="250px" src="<?php echo htmlspecialchars($data['generated_image']); ?>" alt="Generated image"/><br>
<a download href="<?php echo htmlspecialchars($data['generated_image']); ?>">Download Generated Image</a>
<div class="parameters">
<strong>Parameters used:</strong><br>
Prompt: <?php echo htmlspecialchars($data['prompt']); ?><br>
Negative Prompt: <?php echo htmlspecialchars($data['negative_prompt']); ?><br>
Processed Prompt: <?php echo htmlspecialchars($data['processed_prompt']); ?><br><br>
Size: <?php echo $data['width']; ?>x<?php echo $data['height']; ?><br>
Steps: <?php echo $data['steps']; ?><br>
CFG Scale: <?php echo $data['cfg_scale']; ?><br>
Sampler: <?php echo htmlspecialchars($data['sampler']); ?><br>
<?php if (!empty($data['size_info'])): ?>
<p>
Original size: <?php echo $data['size_info']['original']; ?> KB<br>
Converted size: <?php echo $data['size_info']['converted']; ?> KB<br>
Size reduction: <?php echo $data['size_info']['reduction']; ?>%
</p>
<?php endif; ?>
</div>
<div class="save-prompt-form" style="margin-top:20px;padding:10px;border:1px solid #ccc;">
<h3>Save This Prompt</h3>
<form method="post" action="save-prompt.php">
<label for="prompt_name">Prompt Name:</label><br>
<input type="text" name="prompt_name" id="prompt_name" required>
<input type="hidden" name="prompt" value="<?php echo htmlspecialchars($data['prompt']); ?>">
<input type="hidden" name="negative_prompt" value="<?php echo htmlspecialchars($data['negative_prompt']); ?>">
<input type="submit" value="Save Prompt">
</form>
</div>
<a href="/" >Return to Home</a>
</body>
</html>

41
save-prompt.php Normal file
View file

@ -0,0 +1,41 @@
<?php
// save-prompt.php
header('Content-Type: text/html; charset=iso-8859-1');
$saved_prompts_file = 'saved-prompts.json';
function loadSavedPrompts() {
global $saved_prompts_file;
if (file_exists($saved_prompts_file)) {
$json = file_get_contents($saved_prompts_file);
return json_decode($json, true) ?: array();
}
return array();
}
function savePrompt($prompt_text, $negative_prompt_text, $prompt_name) {
global $saved_prompts_file;
$prompts = loadSavedPrompts();
$prompts[$prompt_name] = array(
'prompt' => $prompt_text,
'negative_prompt' => $negative_prompt_text
);
file_put_contents($saved_prompts_file, json_encode($prompts, JSON_PRETTY_PRINT));
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$prompt = trim($_POST['prompt'] ?? '');
$negative_prompt = trim($_POST['negative_prompt'] ?? '');
$prompt_name = trim($_POST['prompt_name'] ?? '');
if (!empty($prompt) && !empty($prompt_name)) {
savePrompt($prompt, $negative_prompt, $prompt_name);
header("Location: index.php?save_success=1");
} else {
header("Location: index.php?save_error=1");
}
exit;
} else {
echo "Invalid request method.";
}