user: necesito que me crees una api igual a este ejemplo "from __future__ import annotations from fastapi import FastAPI, HTTPException, Request from fastapi.responses import StreamingResponse from typing import AsyncGenerator, List, Dict, Any, Optional from aiohttp import ClientSession, ClientError from pydantic import BaseModel import json import logging import asyncio import random import string import re # Configurar logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) # Definiciones de tipos AsyncResult = AsyncGenerator[str, None] Messages = List[Dict[str, str]] ImageType = Any  # Reemplazar con el tipo correcto si es necesario class AsyncGeneratorProvider:     pass class ProviderModelMixin:     @classmethod     def get_model(cls, model: str) -> str:         return cls.model_aliases.get(model, model) def to_data_uri(image: ImageType) -> str:     # Implementar esta función según tus necesidades     return "data:image/png;base64," + image  # Ejemplo simplificado class BlackboxAPI(AsyncGeneratorProvider, ProviderModelMixin):     url = "https://www.blackbox.ai"     api_endpoint = "https://www.blackbox.ai/api/chat"     working = True     supports_stream = True     supports_system_message = True     supports_message_history = True     default_model = "blackboxai"     image_models = ["ImageGeneration"]     models = [         default_model,         "blackboxai-pro",         *image_models,         "llama-3.1-8b",         "llama-3.1-70b",         "llama-3.1-405b",         "gpt-4o",         "gemini-pro",         "gemini-1.5-flash",         "claude-sonnet-3.5",         "PythonAgent",         "JavaAgent",         "JavaScriptAgent",         "HTMLAgent",         "GoogleCloudAgent",         "AndroidDeveloper",         "SwiftDeveloper",         "Next.jsAgent",         "MongoDBAgent",         "PyTorchAgent",         "ReactAgent",         "XcodeAgent",         "AngularJSAgent",     ]     agentMode = {         "ImageGeneration": {             "mode": True,             "id": "ImageGenerationLV45LJp",             "name": "Image Generation",         },     }     trendingAgentMode = {         "blackboxai": {},         "gemini-1.5-flash": {"mode": True, "id": "Gemini"},         "llama-3.1-8b": {"mode": True, "id": "llama-3.1-8b"},         "llama-3.1-70b": {"mode": True, "id": "llama-3.1-70b"},         "llama-3.1-405b": {"mode": True, "id": "llama-3.1-405b"},         "blackboxai-pro": {"mode": True, "id": "BLACKBOXAI-PRO"},         "PythonAgent": {"mode": True, "id": "Python Agent"},         "JavaAgent": {"mode": True, "id": "Java Agent"},         "JavaScriptAgent": {"mode": True, "id": "JavaScript Agent"},         "HTMLAgent": {"mode": True, "id": "HTML Agent"},         "GoogleCloudAgent": {"mode": True, "id": "Google Cloud Agent"},         "AndroidDeveloper": {"mode": True, "id": "Android Developer"},         "SwiftDeveloper": {"mode": True, "id": "Swift Developer"},         "Next.jsAgent": {"mode": True, "id": "Next.js Agent"},         "MongoDBAgent": {"mode": True, "id": "MongoDB Agent"},         "PyTorchAgent": {"mode": True, "id": "PyTorch Agent"},         "ReactAgent": {"mode": True, "id": "React Agent"},         "XcodeAgent": {"mode": True, "id": "Xcode Agent"},         "AngularJSAgent": {"mode": True, "id": "AngularJS Agent"},     }     userSelectedModel = {         "gpt-4o": "gpt-4o",         "gemini-pro": "gemini-pro",         "claude-sonnet-3.5": "claude-sonnet-3.5",     }     model_aliases = {         "gemini-flash": "gemini-1.5-flash",         "claude-3.5-sonnet": "claude-sonnet-3.5",         "flux": "ImageGeneration",     }     headers = {         "accept": "*/*",         "accept-language": "en-US,en;q=0.9",         "cache-control": "no-cache",         "content-type": "application/json",         "origin": url,         "pragma": "no-cache",         "referer": f"{url}/",         "sec-ch-ua": '"Not;A=Brand";v="24", "Chromium";v="128"',         "sec-ch-ua-mobile": "?0",         "sec-ch-ua-platform": '"Linux"',         "sec-fetch-dest": "empty",         "sec-fetch-mode": "cors",         "sec-fetch-site": "same-origin",         "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",     }     @classmethod     def get_model(cls, model: str) -> str:         if model in cls.models:             return model         elif model in cls.userSelectedModel:             return model         elif model in cls.model_aliases:             return cls.model_aliases[model]         else:             return cls.default_model     @staticmethod     def generate_random_string(length: int = 7) -> str:         return "".join(random.choices(string.ascii_letters + string.digits, k=length))     @classmethod     async def create_async_generator(         cls,         model: str,         messages: Messages,         temperature: float = 0.7,         max_retries: int = 5,         proxy: str = None,         image: Optional[ImageType] = None,         image_name: Optional[str] = None,         **kwargs,     ) -> AsyncResult:         model = cls.get_model(model)         if model in cls.userSelectedModel:             prefix = f"@{cls.userSelectedModel[model]}"             if not messages[0]["content"].startswith(prefix):                 messages[0]["content"] = f"{prefix} {messages[0]['content']}"         random_id = cls.generate_random_string()         data = {             "messages": messages,             "id": random_id,             "previewToken": None,             "userId": None,             "codeModelMode": True,             "agentMode": cls.agentMode.get(model, {}),             "trendingAgentMode": cls.trendingAgentMode.get(model, {}),             "userSelectedModel": cls.userSelectedModel.get(model),             "userSystemPrompt": None,             "isMicMode": False,             "maxTokens": 8024,             "playgroundTopP": 0.9,             "playgroundTemperature": temperature,             "isChromeExt": False,             "githubToken": None,             "clickedAnswer2": False,             "clickedAnswer3": False,             "clickedForceWebSearch": False,             "visitFromDelta": False,             "mobileClient": False,             "webSearchMode": False,         }         if image is not None:             messages[-1]["data"] = {                 "fileText": image_name,                 "imageBase64": to_data_uri(image),             }         async with ClientSession(headers=cls.headers) as session:             for attempt in range(max_retries):                 try:                     logger.debug(                         f"Sending POST request to {cls.api_endpoint} (Attempt {attempt + 1})"                     )                     async with session.post(                         cls.api_endpoint, json=data, proxy=proxy                     ) as response:                         response.raise_for_status()                         if model == "ImageGeneration":                             response_text = await response.text()                             url_match = re.search(                                 r"https://storage\.googleapis\.com/[^\s\)]+",                                 response_text,                             )                             if url_match:                                 image_url = url_match.group(0)                                 yield f"Image generated: {image_url}"                             else:                                 raise Exception("Image URL not found in the response")                         else:                             async for chunk in response.content:                                 if chunk:                                     decoded_chunk = chunk.decode()                                     decoded_chunk = re.sub(                                         r"\$@\$v=[^$]+\$@\$", "", decoded_chunk                                     )                                     if decoded_chunk.strip():                                         yield decoded_chunk                     break  # Si llegamos aquí, la generación fue exitosa                 except ClientError as e:                     logger.error(f"Client error on attempt {attempt + 1}: {str(e)}")                     if attempt == max_retries - 1:                         yield f"Error: Blackbox API request failed after {max_retries} attempts. The service might be temporarily unavailable. Please try again later."                         return                     await asyncio.sleep(2**attempt)  # Espera exponencial                 except Exception as e:                     logger.error(f"Unexpected error on attempt {attempt + 1}: {str(e)}")                     if attempt == max_retries - 1:                         yield f"Error: An unexpected error occurred after {max_retries} attempts: {str(e)}. Please try again later or contact support if the issue persists."                         return                     await asyncio.sleep(2**attempt)  # Espera exponencial class Pipe:     class Valves(BaseModel):         NAME_PREFIX: str = ""     def __init__(self):         self.type = "manifold"         self.valves = self.Valves()         self.provider = BlackboxAPI()     def pipes(self):         return [             {                 "id": f"blackbox/{model}",                 "name": f"{self.valves.NAME_PREFIX}{model.replace('-', ' ').title()}",             }             for model in self.provider.models         ]     async def pipe(self, body: dict) -> AsyncResult:         model = body["model"].split("/")[-1]         messages = body["messages"]         temperature = body.get("temperature", 0.7)         image = body.get("image")         image_name = body.get("image_name")         try:             async for chunk in self.provider.create_async_generator(                 model, messages, temperature, image=image, image_name=image_name             ):                 yield chunk         except Exception as e:             logger.error(f"Error in pipe: {str(e)}")             yield f"Error: {str(e)}" # Instancia de Pipe para ser utilizada por OpenWebUI pipe = Pipe() app = FastAPI() @app.get("/v1/models") async def get_models():     """Devuelve la lista de modelos disponibles en el formato adecuado."""     models = [         {"id": f"blackbox/{model}", "name": model.replace('-', ' ').title()}          for model in pipe.provider.models     ]     return {"data": models} @app.post("/v1/chat/completions") async def chat_completions(request: Request):     body = await request.json()     if "model" not in body or "messages" not in body:         raise HTTPException(status_code=400, detail="Missing model or messages")     stream = body.get("stream", False)     async def generate():         async for chunk in pipe.pipe(body):             if stream:                 yield f"data: {json.dumps({'choices': [{'delta': {'content': chunk}}]})}\n\n"             else:                 # Yield the JSON response instead of returning                 yield json.dumps({                     "id": "chatcmpl-" + BlackboxAPI.generate_random_string(),                     "object": "chat.completion",                     "created": int(asyncio.get_event_loop().time()),                     "model": body["model"],                     "choices": [{                         "index": 0,                         "message": {                             "role": "assistant",                             "content": chunk                         },                         "finish_reason": "stop"                     }],                     "usage": {                         "prompt_tokens": sum(len(m["content"].split()) for m in body["messages"]),                         "completion_tokens": len(chunk.split()),                         "total_tokens": sum(len(m["content"].split()) for m in body["messages"]) + len(chunk.split())                     }                 })         if stream:             yield "data: [DONE]\n\n"     return StreamingResponse(generate(), media_type="text/event-stream" if stream else "application/json") if __name__ == "__main__":     import uvicorn     uvicorn.run(app, host="0.0.0.0", port=1333)" pero con este otro proveidor y el modelo que hay en este código "from __future__ import annotations
import json
import requests
from typing import List, Dict, Any, Union, Generator
from pydantic import BaseModel
import asyncio
# Definiciones de tipos
CreateResult = Union[str, Generator[str, None, None]]
Messages = List[Dict[str, Any]]
AsyncResult = Generator[str, None, None]

def format_prompt(messages: Messages) -> str:
    return "\n".join([f"{m['role']}: {m['content']}" for m in messages])

class AbstractProvider:
    pass

class ProviderModelMixin:
    @classmethod
    def get_model(cls, model: str) -> str:
        return (
            cls.model_aliases.get(model, model)
            if hasattr(cls, "model_aliases")
            else model
        )

class NexraChatGPT4o(AbstractProvider, ProviderModelMixin):
    label = "Nexra ChatGPT4o"
    url = "https://nexra.aryahcr.cc/documentation/chatgpt/en"
    api_endpoint = "https://nexra.aryahcr.cc/api/chat/complements"
    working = True
    supports_stream = True
    default_model = "gpt-4o"
    models = [default_model]
    model_aliases = {}
    @classmethod
    def get_model(cls, model: str) -> str:
        return cls.default_model
    @classmethod
    def create_completion(
        cls,
        model: str,
        messages: Messages,
        stream: bool,
        proxy: str = None,
        markdown: bool = False,
        **kwargs,
    ) -> CreateResult:
        model = cls.get_model(model)
        headers = {"Content-Type": "application/json"}
        data = {
            "messages": [{"role": "user", "content": format_prompt(messages)}],
            "stream": stream,
            "markdown": markdown,
            "model": model,
        }
        response = requests.post(
            cls.api_endpoint,
            headers=headers,
            json=data,
            stream=stream,
            proxies={"https": proxy} if proxy else None,
        )
        if stream:
            return cls.process_streaming_response(response)
        else:
            return cls.process_non_streaming_response(response)
    @classmethod
    def process_non_streaming_response(cls, response):
        if response.status_code == 200:
            try:
                content = response.text.lstrip("")
                data = json.loads(content)
                return data.get("message", "")
            except json.JSONDecodeError:
                return "Error: Unable to decode JSON response"
        else:
            return f"Error: {response.status_code}"
    @classmethod
    def process_streaming_response(cls, response):
        full_message = ""
        for line in response.iter_lines(decode_unicode=True):
            if line:
                try:
                    line = line.lstrip("")
                    data = json.loads(line)
                    if data.get("finish"):
                        break
                    message = data.get("message", "")
                    if message and message != full_message:
                        yield message[len(full_message) :]
                        full_message = message
                except json.JSONDecodeError:
                    pass

class Pipe:
    class Valves(BaseModel):
        NAME_PREFIX: str = ""
    def __init__(self):
        self.type = "manifold"
        self.valves = self.Valves()
        self.provider = NexraChatGPT4o()
    def pipes(self):
        return [
            {
                "id": f"nexrachatgpt4o/{model.lower().replace('-', '_')}",
                "name": f"{self.valves.NAME_PREFIX}{model.upper()}",
            }
            for model in self.provider.models
        ]
    async def pipe(self, body: dict) -> AsyncResult:
        model = body["model"].split("/")[-1].replace("_", "-")
        messages = body["messages"]
        stream = body.get("stream", True)
        proxy = body.get("proxy")
        markdown = body.get("markdown", False)
        loop = asyncio.get_event_loop()
        result = await loop.run_in_executor(
            None,
            self.provider.create_completion,
            model,
            messages,
            stream,
            proxy,
            markdown,
        )
        if stream:
            for chunk in result:
                yield chunk
        else:
            yield result

# Instancia de Pipe para ser utilizada por OpenWebUI
pipe = Pipe()
# Función de prueba
if __name__ == "__main__":
    import asyncio
    async def test():
        # Probar el método pipes
        models = pipe.pipes()
        print("Modelos disponibles:", models)
        # Probar el método pipe con un mensaje simple
        test_body = {
            "model": "nexrachatgpt4o/gpt_4o",
            "messages": [
                {"role": "system", "content": "Eres un asistente útil."},
                {"role": "user", "content": "Hola, ¿cómo estás?"},
            ],
            "stream": True,
            "markdown": False,
        }
        print("\nProbando con el modelo 'gpt-4o':")
        async for chunk in pipe.pipe(test_body):
            print(chunk, end="", flush=True)
        print("\nPrueba completada.")
    asyncio.run(test())