diff --git a/example.html b/example.html index 625d706..86e924c 100644 --- a/example.html +++ b/example.html @@ -21,7 +21,7 @@
- +
+
+ + +
+ +
+ + +
+
@@ -40,7 +56,9 @@

Parameters:

Important: Make sure function calling is enabled in SillyTavern's AI settings and the model you're using supports function calling.

@@ -51,16 +69,20 @@
  • The function appears in the function list
  • 🚨 REQUIRED SETUP: You MUST add the following to your system prompt or character card:

    -
    You have access to a function called generateChatBubbleImage(text, style) that creates chat bubbles with the given text.
    +                    
    You have access to a function called generateChatBubbleImage(text, character, bubble_type, style) that creates character-styled chat bubbles.
     
     The function parameters are:
     - text: The text to display in the chat bubble (required string)
    -- style: Visual style of the bubble (optional string: "default", "modern", "retro", or "minimal")
    +- character: The character to use for the bubble (optional string: "Example", "Bianca", etc.)
    +- bubble_type: The type of bubble to use (optional string: "speech" or "thought")
    +- style: Legacy parameter for visual style (optional string: "default", "modern", "retro", or "minimal")
     
     When you want to create a chat bubble, call this function with the text you want to display.
     Example usage:
     generateChatBubbleImage("Hello world!")
    -generateChatBubbleImage("Hello in retro style", "retro")
    +generateChatBubbleImage("Hello from Bianca", "Bianca") +generateChatBubbleImage("I'm thinking...", "Example", "thought") +generateChatBubbleImage("Hello in retro style", null, null, "retro")

    ALTERNATIVE: If the AI can't call the function directly, you can instruct it to respond with Markdown formatted like this:

    ![](image.php?q=Hello%20world)
    diff --git a/index.js b/index.js index ba8f392..146b90c 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,8 @@ const extensionFolderPath = `scripts/extensions/third-party/${extensionName}`; const defaultSettings = { image_service_url: "http://calista.the.sexiest.cat/image.php", // Use fully qualified URL by default default_style: "default", + default_character: "Example", + default_bubble_type: "speech", enabled: true, render_in_collapse: true // Setting to enable/disable rendering in collapsed tool calls }; @@ -33,13 +35,15 @@ if (extension_settings[extensionName].image_service_url && } // Function for AI to call - generates markdown image with URL-encoded text -function generateChatBubbleImage(text, style) { +function generateChatBubbleImage(text, style, character, bubble_type) { if (!extension_settings[extensionName].enabled) { return text; } - // Use default style if not specified + // Use default values if parameters not specified const bubbleStyle = style || extension_settings[extensionName].default_style; + const characterName = character || extension_settings[extensionName].default_character; + const bubbleType = bubble_type || extension_settings[extensionName].default_bubble_type; // URL encode the text parameter const encodedText = encodeURIComponent(text); @@ -52,17 +56,26 @@ function generateChatBubbleImage(text, style) { } // Construct the URL with the encoded text - const imageUrl = `${serviceUrl}?q=${encodedText}`; + let imageUrl = `${serviceUrl}?q=${encodedText}`; - // Add style parameter if specified - const fullUrl = bubbleStyle !== "default" - ? `${imageUrl}&style=${bubbleStyle}` - : imageUrl; + // Add parameters if they differ from defaults + if (characterName && characterName !== "Example") { + imageUrl += `&character=${characterName}`; + } - console.log(`[${extensionName}] Generated image URL: ${fullUrl}`); + if (bubbleType && bubbleType !== "speech") { + imageUrl += `&bubble_type=${bubbleType}`; + } + + // Add style parameter if specified (for backward compatibility) + if (bubbleStyle && bubbleStyle !== "default" && !characterName) { + imageUrl += `&style=${bubbleStyle}`; + } + + console.log(`[${extensionName}] Generated image URL: ${imageUrl}`); // Return markdown image format - return `![](${fullUrl})`; + return `![](${imageUrl})`; } // Load extension settings into UI @@ -71,6 +84,8 @@ function loadSettings() { $("#sillybubble_enabled").prop("checked", extension_settings[extensionName].enabled).trigger("input"); $("#sillybubble_image_url").val(extension_settings[extensionName].image_service_url).trigger("input"); $("#sillybubble_default_style").val(extension_settings[extensionName].default_style).trigger("input"); + $("#sillybubble_default_character").val(extension_settings[extensionName].default_character).trigger("input"); + $("#sillybubble_default_bubble_type").val(extension_settings[extensionName].default_bubble_type).trigger("input"); $("#sillybubble_render_in_collapse").prop("checked", extension_settings[extensionName].render_in_collapse).trigger("input"); } @@ -103,6 +118,20 @@ function onDefaultStyleInput(event) { saveSettingsDebounced(); } +// Handle default character changes +function onDefaultCharacterInput(event) { + const value = $(event.target).val(); + extension_settings[extensionName].default_character = value; + saveSettingsDebounced(); +} + +// Handle default bubble type changes +function onDefaultBubbleTypeInput(event) { + const value = $(event.target).val(); + extension_settings[extensionName].default_bubble_type = value; + saveSettingsDebounced(); +} + // Handle render in collapse toggle function onRenderInCollapseInput(event) { const value = Boolean($(event.target).prop("checked")); @@ -116,11 +145,15 @@ function onRenderInCollapseInput(event) { // Test function to visualize a bubble function onTestButtonClick() { const testText = "This is a test chat bubble generated by SillyBubble!"; - const markdown = generateChatBubbleImage(testText); + const character = extension_settings[extensionName].default_character; + const bubbleType = extension_settings[extensionName].default_bubble_type; + + const markdown = generateChatBubbleImage(testText, null, character, bubbleType); const testPopup = `

    Generated Markdown:

    ${markdown.replace(//g, '>')}
    +

    Using character: ${character}, bubble type: ${bubbleType}

    Preview (if connected to image service):

    ${markdown}
    @@ -151,7 +184,15 @@ function registerFunctionTool() { }, style: { type: 'string', - description: 'The visual style of the chat bubble (default, modern, retro, minimal)' + description: 'Legacy parameter: The visual style of the chat bubble (default, modern, retro, minimal). Prefer using character parameter instead.' + }, + character: { + type: 'string', + description: 'The character to display (Example, Bianca, etc.). Each character has its own bubble style.' + }, + bubble_type: { + type: 'string', + description: 'The type of bubble to use (speech, thought). Defaults to speech.' }, }, required: ['text'] @@ -161,11 +202,11 @@ function registerFunctionTool() { context.registerFunctionTool({ name: 'generateChatBubbleImage', displayName: 'Chat Bubble Image', - description: 'Creates a markdown image link with the text displayed as a styled chat bubble. Use when you want to visually style messages or display text in a speech bubble.', + description: 'Creates a markdown image link with the text displayed as a character-styled chat bubble. Use when you want to visually style messages or display text in a speech or thought bubble.', parameters: bubbleSchema, action: async (args) => { if (!args?.text) return ''; - return generateChatBubbleImage(args.text, args.style); + return generateChatBubbleImage(args.text, args.style, args.character, args.bubble_type); }, formatMessage: () => '', }); @@ -395,6 +436,8 @@ jQuery(async () => { $("#sillybubble_enabled").on("input", onEnabledInput); $("#sillybubble_image_url").on("input", onImageUrlInput); $("#sillybubble_default_style").on("input", onDefaultStyleInput); + $("#sillybubble_default_character").on("input", onDefaultCharacterInput); + $("#sillybubble_default_bubble_type").on("input", onDefaultBubbleTypeInput); $("#sillybubble_render_in_collapse").on("input", onRenderInCollapseInput); $("#sillybubble_test_button").on("click", onTestButtonClick);