Function
filter
Gif in response
Your model can use gif in response. Add fun in your conversation
Function ID
gif_in_response
Creator
@reise38
Downloads
52+

Function Content
python
"""
Giphy GIF Replacer Filter for Open WebUI

Author: Alban
GitHub: https://github.com/reise69
Installation instructions: https://github.com/reise69/open-webui-function-gif-replacer
Version: 1.0.0

Description:
Add some fun in your chat. A comprehensive filter that replaces /gif "query" commands with random GIFs from Giphy.


Features:
- Random GIF selection
- Configurable max results
- Debug mode

Requirements:
- Giphy API key


required_open_webui_version: 0.3.30

"""

import os
import re
import random
import requests
from pydantic import BaseModel, Field
from typing import Optional, Callable, Any, Awaitable

class Filter:
    """
    A filter to replace text commands with random GIFs from Giphy
    """
    class Valves(BaseModel):
        """
        Configuration settings for the filter
        """
        GIPHY_API_KEY: str = Field(
            default="", 
            description="Giphy API key for searching GIFs"
        )
        DEBUG_MODE: bool = Field(
            default=False, 
            description="Enable detailed debug logging"
        )
        PRIORITY: int = Field(
            default=5, 
            description="Filter processing priority"
        )
        MAX_GIF_RESULTS: int = Field(
            default=10, 
            description="Maximum number of GIFs to retrieve per search"
        )

    class UserValves(BaseModel):
        """
        User-configurable settings
        """
        ENABLE_GIF_REPLACE: bool = Field(
            default=True, 
            description="Enable GIF replacement functionality"
        )
        RANDOM_GIF: bool = Field(
            default=True, 
            description="Select a random GIF from search results"
        )

    def __init__(self):
        """
        Initialize filter with default configurations
        """
        self.valves = self.Valves(
            GIPHY_API_KEY=os.getenv("GIPHY_API_KEY", "")
        )
        self.user_valves = self.UserValves()
        self.gif_cache = {}  # Cache to store search results

    def _find_gif_commands(self, content: str) -> list:
        """
        Find all /gif "query" commands in the content
        
        Args:
            content (str): Text to search for GIF commands

        Returns:
            list: Found GIF query commands
        """
        pattern = r'/gif\s*"([^"]*)"'
        return re.findall(pattern, content)

    def _get_gif_url(self, query: str) -> str:
        """
        Retrieve a GIF URL from Giphy with randomization strategy
        
        Args:
            query (str): Search term for GIF

        Returns:
            str: URL of a selected GIF
        """
        if not self.valves.GIPHY_API_KEY:
            return f"Error: Giphy API key missing for query: {query}"

        # Use cache if available
        if query in self.gif_cache:
            gifs = self.gif_cache[query]
        else:
            params = {
                "api_key": self.valves.GIPHY_API_KEY,
                "q": query,
                "limit": self.valves.MAX_GIF_RESULTS,
                "rating": "g",
            }
            try:
                response = requests.get(
                    "https://api.giphy.com/v1/gifs/search", 
                    params=params
                )
                data = response.json()
                
                if data.get("data"):
                    gifs = [
                        gif["images"]["fixed_width"]["url"]
                        for gif in data["data"]
                        if gif.get("images", {}).get("fixed_width", {}).get("url")
                    ]
                    
                    self.gif_cache[query] = gifs
                else:
                    return f"No GIF found for: {query}"
            except Exception as e:
                return f"GIF search error: {e}"

        if not gifs:
            return f"No GIF found for: {query}"
        
        if self.user_valves.RANDOM_GIF:
            # Random selection
            return random.choice(gifs)
        else:
            # Sequential rotation
            gif_url = gifs[0]
            self.gif_cache[query] = gifs[1:] + [gif_url]
            return gif_url

    def inlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
        """
        Pre-processing method (currently a pass-through)
        
        Args:
            body (dict): Incoming message body
            __user__ (dict, optional): User information

        Returns:
            dict: Processed message body
        """
        if not self.user_valves.ENABLE_GIF_REPLACE:
            return body
        return body

    async def outlet(
        self,
        body: dict,
        __user__: Optional[dict] = None,
        __event_emitter__: Optional[Callable[[Any], Awaitable[None]]] = None,
    ) -> dict:
        """
        Post-processing method to replace GIF commands
        
        Args:
            body (dict): Message body
            __user__ (dict, optional): User information
            __event_emitter__ (Callable, optional): Event emission function

        Returns:
            dict: Processed message body
        """
        if not self.user_valves.ENABLE_GIF_REPLACE:
            return body

        messages = body.get("messages", [])
        if not messages:
            return body

        last_message = messages[-1]
        
        # Process text content
        if isinstance(last_message.get("content"), str):
            content = last_message["content"]
            gif_commands = self._find_gif_commands(content)
            
            for query in gif_commands:
                gif_url = self._get_gif_url(query)
                content = content.replace(f'/gif "{query}"', f"![GIF]({gif_url})")
            
            last_message["content"] = content

        # Process list content
        elif isinstance(last_message.get("content"), list):
            for item in last_message["content"]:
                if item.get("type") == "text":
                    text = item["text"]
                    gif_commands = self._find_gif_commands(text)
                    
                    for query in gif_commands:
                        gif_url = self._get_gif_url(query)
                        text = text.replace(f'/gif "{query}"', f"![GIF]({gif_url})")
                    
                    item["text"] = text

        # Emit debug status
        if self.valves.DEBUG_MODE and __event_emitter__:
            await __event_emitter__(
                {
                    "type": "status",
                    "data": {
                        "description": "GIF Filter: Commands processed",
                        "done": True,
                    },
                }
            )

        return body