summaryrefslogblamecommitdiffstats
path: root/g4f/Provider/Nexra.py
blob: e2c3e197b63fc33df47b33ebd23f49f66fc152a3 (plain) (tree)
1
2
3
4
5
6
7
8
9


                                  
             
                                 
                                 


                                                                     
                                 

                                 

                                                        

                                                                         








                                   







                                                                                                                   

     


                                                 









































                                                  
                                                   

                                    














                                                                                                   










                                                             
                                                                                               



                                                


































































                                                                                                
from __future__ import annotations

import json
import base64
from aiohttp import ClientSession
from typing import AsyncGenerator

from ..typing import AsyncResult, Messages
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
from ..image import ImageResponse
from .helper import format_prompt

class Nexra(AsyncGeneratorProvider, ProviderModelMixin):
    url = "https://nexra.aryahcr.cc"
    api_endpoint_text = "https://nexra.aryahcr.cc/api/chat/gpt"
    api_endpoint_image = "https://nexra.aryahcr.cc/api/image/complements"
    working = True
    supports_gpt_35_turbo = True
    supports_gpt_4 = True
    supports_stream = True
    supports_system_message = True
    supports_message_history = True
    
    default_model = 'gpt-3.5-turbo'
    models = [
        # Text models
        'gpt-4', 'gpt-4-0613', 'gpt-4-32k', 'gpt-4-0314', 'gpt-4-32k-0314',
        'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-3.5-turbo-0613', 'gpt-3.5-turbo-16k-0613', 'gpt-3.5-turbo-0301',
        'gpt-3', 'text-davinci-003', 'text-davinci-002', 'code-davinci-002',
        'text-curie-001', 'text-babbage-001', 'text-ada-001',
        'davinci', 'curie', 'babbage', 'ada', 'babbage-002', 'davinci-002',
        # Image models
        'dalle', 'dalle-mini', 'emi'
    ]
    
    image_models = {"dalle", "dalle-mini", "emi"}
    text_models = set(models) - image_models
    
    model_aliases = {
        "gpt-4": "gpt-4-0613",
        "gpt-4": "gpt-4-32k",
        "gpt-4": "gpt-4-0314",
        "gpt-4": "gpt-4-32k-0314",
        
        "gpt-3.5-turbo": "gpt-3.5-turbo-16k",
        "gpt-3.5-turbo": "gpt-3.5-turbo-0613",
        "gpt-3.5-turbo": "gpt-3.5-turbo-16k-0613",
        "gpt-3.5-turbo": "gpt-3.5-turbo-0301",
        
        "gpt-3": "text-davinci-003",
        "gpt-3": "text-davinci-002",
        "gpt-3": "code-davinci-002",
        "gpt-3": "text-curie-001",
        "gpt-3": "text-babbage-001",
        "gpt-3": "text-ada-001",
        "gpt-3": "text-ada-001",
        "gpt-3": "davinci",
        "gpt-3": "curie",
        "gpt-3": "babbage",
        "gpt-3": "ada",
        "gpt-3": "babbage-002",
        "gpt-3": "davinci-002",
    }

    @classmethod
    def get_model(cls, model: str) -> str:
        if model in cls.models:
            return model
        elif model in cls.model_aliases:
            return cls.model_aliases[model]
        else:
            return cls.default_model

    @classmethod
    async def create_async_generator(
        cls,
        model: str,
        messages: Messages,
        proxy: str = None,
        **kwargs
    ) -> AsyncGenerator[str | ImageResponse, None]:
        model = cls.get_model(model)
        
        if model in cls.image_models:
            async for result in cls.create_image_async_generator(model, messages, proxy, **kwargs):
                yield result
        else:
            async for result in cls.create_text_async_generator(model, messages, proxy, **kwargs):
                yield result

    @classmethod
    async def create_text_async_generator(
        cls,
        model: str,
        messages: Messages,
        proxy: str = None,
        **kwargs
    ) -> AsyncGenerator[str, None]:
        headers = {
            "Content-Type": "application/json",
        }
        async with ClientSession(headers=headers) as session:
            data = {
                "messages": messages,
                "prompt": format_prompt(messages),
                "model": model,
                "markdown": False,
                "stream": False,
            }
            async with session.post(cls.api_endpoint_text, json=data, proxy=proxy) as response:
                response.raise_for_status()
                result = await response.text()
                json_result = json.loads(result)
                yield json_result["gpt"]

    @classmethod
    async def create_image_async_generator(
        cls,
        model: str,
        messages: Messages,
        proxy: str = None,
        **kwargs
    ) -> AsyncGenerator[ImageResponse | str, None]:
        headers = {
            "Content-Type": "application/json"
        }

        prompt = messages[-1]['content'] if messages else ""

        data = {
            "prompt": prompt,
            "model": model
        }

        async def process_response(response_text: str) -> ImageResponse | None:
            json_start = response_text.find('{')
            if json_start != -1:
                json_data = response_text[json_start:]
                try:
                    response_data = json.loads(json_data)
                    image_data = response_data.get('images', [])[0]
                    
                    if image_data.startswith('data:image/'):
                        return ImageResponse([image_data], "Generated image")
                    
                    try:
                        base64.b64decode(image_data)
                        data_uri = f"data:image/jpeg;base64,{image_data}"
                        return ImageResponse([data_uri], "Generated image")
                    except:
                        print("Invalid base64 data")
                        return None
                except json.JSONDecodeError:
                    print("Failed to parse JSON.")
            else:
                print("No JSON data found in the response.")
            return None

        async with ClientSession(headers=headers) as session:
            async with session.post(cls.api_endpoint_image, json=data, proxy=proxy) as response:
                response.raise_for_status()
                response_text = await response.text()
                
                image_response = await process_response(response_text)
                if image_response:
                    yield image_response
                else:
                    yield "Failed to process image data."

    @classmethod
    async def create_async(
        cls,
        model: str,
        messages: Messages,
        proxy: str = None,
        **kwargs
    ) -> str:
        async for response in cls.create_async_generator(model, messages, proxy, **kwargs):
            if isinstance(response, ImageResponse):
                return response.images[0]
            return response