Function
filter
Auto tool Sémantique
Auto tool sémantique, choose tools from your list below addcustomtools by semantic interpretation of llm need.
Function ID
auto_tool_semantic
Creator
@nnaoycurt
Downloads
37+

Function Content
python
from pydantic import BaseModel, Field
from typing import Callable, Awaitable, Any, Optional, List
import re
from difflib import get_close_matches

from open_webui.apps.webui.models.users import Users
from open_webui.apps.webui.models.tools import Tools

from open_webui.utils.misc import get_last_user_message


class Filter:
    class Valves(BaseModel):
        status: bool = Field(default=False)
        match_threshold: int = Field(
            default=1
        )  # Seuil par défaut pour le nombre de mots correspondants
        symbols: list = Field(default=["?"])  # Liste par défaut des symboles
        fuzzy_match_threshold: float = Field(
            default=0.6
        )  # Seuil pour la correspondance floue

    def __init__(self):
        self.valves = self.Valves()
        self.custom_tools = []  # Liste pour stocker les outils personnalisés
        # Ajout manuel d'outils
        self.add_custom_tools()

    def add_custom_tools(self):
        # Ajouter manuellement des outils
        self.custom_tools.append(
            {
                "id": "youtube_video_transcript",
                "description": "Outil de transcription de lien youtube à l'aide de liens url.",
            }
        )
        self.custom_tools.append(
            {
                "id": "web_search",
                "description": "Web Search qui utilise SearXNG et Scrap les premières pages trouvées.",
            }
        )

    async def evaluate_needs(self, user_message: str) -> List[str]:
        # Évaluer les besoins et intentions de l'utilisateur
        user_message_lower = user_message.lower()
        needs = []

        if "data" in user_message_lower:
            needs.append("analyser")
            needs.append("visualiser")
        if "image" in user_message_lower:
            needs.append("modifier")
            needs.append("créer")
        if "recherche" in user_message_lower or "chercher" in user_message_lower:
            needs.append("recherche web")
        if "transcription" in user_message_lower or "youtube" in user_message_lower:
            needs.append("transcription youtube")

        if not needs:
            needs.append("aider")  # Besoin générique

        return needs

    async def inlet(
        self,
        body: dict,
        __event_emitter__: Callable[[Any], Awaitable[None]],
        __user__: Optional[dict] = None,
        __model__: Optional[dict] = None,
    ) -> dict:
        messages = body["messages"]
        user_message = get_last_user_message(messages)

        if self.valves.status:
            await __event_emitter__(
                {
                    "type": "status",
                    "data": {
                        "description": "Finding the right tools...",
                        "done": False,
                    },
                }
            )

        # Combiner les outils personnalisés et les outils disponibles
        all_tools = self.custom_tools + [
            {"id": tool.id, "description": tool.meta.description}
            for tool in Tools.get_tools()
        ]
        available_tool_ids = (
            __model__.get("info", {}).get("meta", {}).get("toolIds", [])
        )
        available_tools = [
            tool for tool in all_tools if tool["id"] in available_tool_ids
        ]

        # Évaluer les besoins de l'utilisateur à l'aide du LLM
        user_needs = await self.evaluate_needs(user_message)

        # Check each word and symbol in user_message against tool descriptions
        user_words = re.findall(r"\w+", user_message.lower())
        user_symbols = [char for char in user_message if char in self.valves.symbols]
        matched_tool_ids = []

        for tool in available_tools:
            description_words = re.findall(r"\w+", tool["description"].lower())
            description_symbols = [
                char for char in tool["description"] if char in self.valves.symbols
            ]

            # Compter les correspondances
            match_count = sum(
                1 for word in user_words if word in description_words
            ) + sum(1 for symbol in user_symbols if symbol in description_symbols)

            # Correspondance floue : trouver des correspondances proches pour la description
            for word in user_words:
                close_matches = get_close_matches(
                    word,
                    description_words,
                    n=1,
                    cutoff=self.valves.fuzzy_match_threshold,
                )
                match_count += len(close_matches)

            # Évaluer la pertinence de l'outil en fonction des besoins
            relevance_score = sum(1 for need in user_needs if need in description_words)

            # Si l'outil correspond aux besoins ou dépasse le seuil de correspondance
            if match_count >= self.valves.match_threshold or relevance_score > 0:
                matched_tool_ids.append(tool["id"])

        # Lancer automatiquement des outils basés sur les besoins
        if "recherche web" in user_needs:
            matched_tool_ids.append("web_search")
        if "transcription youtube" in user_needs:
            matched_tool_ids.append("youtube_video_transcript")

        if matched_tool_ids:
            body["tool_ids"] = matched_tool_ids
            if self.valves.status:
                await __event_emitter__(
                    {
                        "type": "status",
                        "data": {
                            "description": f"Found matching tools: {', '.join(matched_tool_ids)}",
                            "done": True,
                        },
                    }
                )
            if __event_emitter__:
                await __event_emitter__(
                    {
                        "type": "status",
                        "data": {
                            "description": f"List of tools chosen: {', '.join(matched_tool_ids)}",
                            "done": True,
                        },
                    }
                )
        else:
            if self.valves.status:
                await __event_emitter__(
                    {
                        "type": "status",
                        "data": {
                            "description": "No matching tools found.",
                            "done": True,
                        },
                    }
                )

        return body