From 53db325bb24debb4644d59f843ad42bee5afab25 Mon Sep 17 00:00:00 2001 From: Sven Olderaan Date: Sun, 16 Mar 2025 12:05:12 +0100 Subject: [PATCH] Add PHP image generator and documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create image.php script for generating bubble images - Add example usage HTML page for testing - Update README with documentation - Support multiple bubble styles - Gracefully handle missing fonts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- README.md | 86 ++++++++++++------ example-usage.html | 152 +++++++++++++++++++++++++++++++ image.php | 221 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 433 insertions(+), 26 deletions(-) create mode 100644 example-usage.html create mode 100644 image.php diff --git a/README.md b/README.md index 1de842c..d02628e 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,76 @@ -# SillyBubble - Dynamic Chat Bubble Extension for SillyTavern +# SillyBubble Chat Bubble Generator -SillyBubble is a SillyTavern extension that enables AI models to generate dynamic chat bubble images with text. The extension provides a function that AI models can call to create properly formatted markdown image links with URL-encoded text parameters. +SillyBubble is a package that includes both a SillyTavern extension for generating chat bubble images from AI responses and a PHP script for rendering those bubbles. -## Features +## Components -- Provides a function for AI to generate markdown image links -- Properly URL-encodes text parameters for image generation -- Supports different bubble styles through style parameters -- Configurable image service URL -- Simple testing interface to preview bubble generation +1. **SillyTavern Extension**: JavaScript extension that registers a function tool for AIs to generate bubble images +2. **PHP Image Generator**: Server-side script that creates the actual images -## Installation and Usage +## Chat Bubble Image Generator (image.php) -### Installation +The `image.php` script is a standalone PHP application that generates chat bubble images from text. It uses the GD library to create PNG images dynamically. -1. Install the extension using SillyTavern's built-in extension installer -2. Configure the image service URL in the extension settings +### Requirements + +- PHP 7.0+ with GD extension enabled +- Web server (Apache, Nginx, etc.) ### Usage -1. The extension registers a custom function `generateChatBubbleImage` that AI models can call -2. When called, it returns a properly formatted markdown image link: - ```markdown - ![](image.php?q=Hello%20world) - ``` -3. The function accepts two parameters: - - `text`: The text to display in the bubble (required) - - `style`: The visual style of the bubble (optional) +The script accepts the following GET parameters: -## Prerequisites +- `q`: The text to display (URL-encoded) +- `style`: (Optional) The bubble style: `default`, `modern`, `retro`, or `minimal` -- SillyTavern with custom function support -- A properly configured image generation service that accepts text parameters +Example URLs: +``` +image.php?q=Hello%20World +image.php?q=Hello%20World&style=modern +``` -## Support and Contributions +### Styles -For support or to contribute to this project, please visit the [GitHub repository](https://github.com/crystal/SillyBubble) or open an issue. +The image generator comes with several built-in styles: + +- **default**: Light gray background with dark text +- **modern**: Blue background with white text +- **retro**: Yellow background with dark text +- **minimal**: White background with black text and no rounded corners + +### Integrating with SillyBubble Extension + +1. Place the `image.php` script on your web server +2. Configure the SillyBubble extension to use the correct URL to your image.php script +3. In the extension settings, set the "Image Service URL" to the path to your image.php script + +### Customizing + +You can customize the styles by editing the `$styles` array in the PHP script. Each style has parameters for: + +- `bg_color`: Background color [R, G, B] +- `text_color`: Text color [R, G, B] +- `border_color`: Border color [R, G, B] +- `padding`: Padding around the text +- `rounded`: Corner radius (0 for square corners) +- `font_size`: Text size +- `max_width`: Maximum bubble width +- `line_height`: Spacing between lines +- `font`: Path to a TTF font file + +### Fonts + +The script will look for TTF fonts in the `fonts` directory. If no fonts are found, it will fall back to using the built-in GD fonts. + +To add custom fonts: +1. Create a `fonts` directory in the same location as the script +2. Add `.ttf` font files to this directory +3. Update the font paths in the `$styles` array if needed + +## Example/Demo Page + +The included `example-usage.html` file provides a simple interface for testing the image generator with different styles and messages. ## License -MIT License +This project is licensed under the MIT License. \ No newline at end of file diff --git a/example-usage.html b/example-usage.html new file mode 100644 index 0000000..8aa51e0 --- /dev/null +++ b/example-usage.html @@ -0,0 +1,152 @@ + + + + + + SillyBubble Example + + + +

SillyBubble Image Generator Examples

+ +
+

Try It Yourself

+
+ + +
+ + + + +
+ + + +
+ Preview will appear here +
+ +
+ Markdown for this image: +
+
+
+
+ +
+

Examples of Different Styles

+
+
+

Default:

+ Default style +
+
+

Modern:

+ Modern style +
+
+

Retro:

+ Retro style +
+
+

Minimal:

+ Minimal style +
+
+
+ +
+

Usage in SillyBubble Extension

+

To use this image generator with the SillyBubble extension, make sure your extension settings point to this script:

+
// In SillyBubble settings
+"image_service_url": "image.php"
+ +

The extension will automatically generate URLs like:

+
![](image.php?q=Your%20message%20here&style=modern)
+ +

When the AI uses the function, it will create these markdown images that browsers will render as chat bubbles.

+
+ + + + \ No newline at end of file diff --git a/image.php b/image.php new file mode 100644 index 0000000..5a5cdf4 --- /dev/null +++ b/image.php @@ -0,0 +1,221 @@ + [ + 'bg_color' => [245, 245, 245], + 'text_color' => [50, 50, 50], + 'border_color' => [200, 200, 200], + 'padding' => 20, + 'rounded' => 15, + 'font_size' => 14, + 'max_width' => 600, + 'line_height' => 20, + 'font' => __DIR__ . '/fonts/arial.ttf', // Adjust path as needed + ], + 'modern' => [ + 'bg_color' => [66, 133, 244], + 'text_color' => [255, 255, 255], + 'border_color' => [59, 120, 220], + 'padding' => 20, + 'rounded' => 20, + 'font_size' => 14, + 'max_width' => 600, + 'line_height' => 20, + 'font' => __DIR__ . '/fonts/arial.ttf', // Adjust path as needed + ], + 'retro' => [ + 'bg_color' => [255, 204, 102], + 'text_color' => [51, 51, 51], + 'border_color' => [204, 153, 0], + 'padding' => 20, + 'rounded' => 5, + 'font_size' => 14, + 'max_width' => 600, + 'line_height' => 20, + 'font' => __DIR__ . '/fonts/arial.ttf', // Adjust path as needed + ], + 'minimal' => [ + 'bg_color' => [255, 255, 255], + 'text_color' => [0, 0, 0], + 'border_color' => [220, 220, 220], + 'padding' => 15, + 'rounded' => 0, + 'font_size' => 14, + 'max_width' => 600, + 'line_height' => 20, + 'font' => __DIR__ . '/fonts/arial.ttf', // Adjust path as needed + ], +]; + +// Use default style if specified style doesn't exist +if (!isset($styles[$style])) { + $style = 'default'; +} + +// Get style settings +$config = $styles[$style]; + +// Check for fonts directory and create if it doesn't exist +$fontsDir = __DIR__ . '/fonts'; +if (!is_dir($fontsDir)) { + mkdir($fontsDir, 0755, true); +} + +// Fallback to a built-in font if the specified font file doesn't exist +if (!file_exists($config['font'])) { + // Try to find any TTF font in the fonts directory + $foundFont = false; + if (is_dir($fontsDir)) { + $fontFiles = glob($fontsDir . '/*.ttf'); + if (!empty($fontFiles)) { + $config['font'] = $fontFiles[0]; + $foundFont = true; + } + } + + // If no TTF font found, use built-in font + if (!$foundFont) { + $config['use_builtin_font'] = true; + } +} + +// Create a temporary image to calculate text dimensions +$tempImage = imagecreatetruecolor(100, 100); +$textColor = imagecolorallocate($tempImage, $config['text_color'][0], $config['text_color'][1], $config['text_color'][2]); + +// Word wrap the text +$words = explode(' ', $text); +$lines = []; +$currentLine = ''; +$maxWidth = $config['max_width'] - (2 * $config['padding']); + +foreach ($words as $word) { + $testLine = $currentLine . ' ' . $word; + $testLine = ltrim($testLine); // Remove leading space + + // Calculate width using built-in or TTF font + if (isset($config['use_builtin_font'])) { + $textWidth = imagefontwidth(5) * strlen($testLine); + } else { + $bbox = imagettfbbox($config['font_size'], 0, $config['font'], $testLine); + $textWidth = $bbox[2] - $bbox[0]; + } + + if ($textWidth > $maxWidth && $currentLine !== '') { + $lines[] = $currentLine; + $currentLine = $word; + } else { + $currentLine = $testLine; + } +} +if ($currentLine !== '') { + $lines[] = $currentLine; +} + +// Calculate image dimensions +$lineCount = count($lines); +if (isset($config['use_builtin_font'])) { + $lineHeight = imagefontheight(5); + $textHeight = $lineHeight * $lineCount; + + // Find the longest line to determine width + $textWidth = 0; + foreach ($lines as $line) { + $lineWidth = imagefontwidth(5) * strlen($line); + $textWidth = max($textWidth, $lineWidth); + } +} else { + $lineHeight = $config['line_height']; + $textHeight = $lineHeight * $lineCount; + + // Find the longest line to determine width + $textWidth = 0; + foreach ($lines as $line) { + $bbox = imagettfbbox($config['font_size'], 0, $config['font'], $line); + $lineWidth = $bbox[2] - $bbox[0]; + $textWidth = max($textWidth, $lineWidth); + } +} + +// Add padding to dimensions +$imgWidth = min($config['max_width'], $textWidth + (2 * $config['padding'])); +$imgHeight = $textHeight + (2 * $config['padding']); + +// Create the bubble image +$image = imagecreatetruecolor($imgWidth, $imgHeight); + +// Allocate colors +$bgColor = imagecolorallocate($image, $config['bg_color'][0], $config['bg_color'][1], $config['bg_color'][2]); +$borderColor = imagecolorallocate($image, $config['border_color'][0], $config['border_color'][1], $config['border_color'][2]); +$textColor = imagecolorallocate($image, $config['text_color'][0], $config['text_color'][1], $config['text_color'][2]); + +// Fill background +imagefill($image, 0, 0, $bgColor); + +// Draw rounded rectangle (if rounded corners are requested) +if ($config['rounded'] > 0) { + // Draw filled rectangle + imagefilledrectangle($image, 0, 0, $imgWidth - 1, $imgHeight - 1, $bgColor); + + // Draw rounded corners - basic simulation for rounded corners + // This could be improved with proper arc drawing + $r = $config['rounded']; + + // Top left corner + imagefilledarc($image, $r, $r, $r * 2, $r * 2, 180, 270, $bgColor, IMG_ARC_PIE); + + // Top right corner + imagefilledarc($image, $imgWidth - $r - 1, $r, $r * 2, $r * 2, 270, 360, $bgColor, IMG_ARC_PIE); + + // Bottom left corner + imagefilledarc($image, $r, $imgHeight - $r - 1, $r * 2, $r * 2, 90, 180, $bgColor, IMG_ARC_PIE); + + // Bottom right corner + imagefilledarc($image, $imgWidth - $r - 1, $imgHeight - $r - 1, $r * 2, $r * 2, 0, 90, $bgColor, IMG_ARC_PIE); + + // Draw border + imagerectangle($image, 0, 0, $imgWidth - 1, $imgHeight - 1, $borderColor); +} else { + // Draw simple rectangle + imagefilledrectangle($image, 0, 0, $imgWidth - 1, $imgHeight - 1, $bgColor); + imagerectangle($image, 0, 0, $imgWidth - 1, $imgHeight - 1, $borderColor); +} + +// Draw text +$y = $config['padding']; +foreach ($lines as $line) { + if (isset($config['use_builtin_font'])) { + // Use built-in font (less nice but always available) + imagestring($image, 5, $config['padding'], $y, $line, $textColor); + $y += imagefontheight(5); + } else { + // Use TrueType font (nicer but requires font file) + imagettftext($image, $config['font_size'], 0, $config['padding'], $y + $config['font_size'], $textColor, $config['font'], $line); + $y += $lineHeight; + } +} + +// Output the image +imagepng($image); + +// Clean up +imagedestroy($image); +imagedestroy($tempImage); \ No newline at end of file