diff options
Diffstat (limited to 'g4f/gui/server')
-rw-r--r-- | g4f/gui/server/api.py | 4 | ||||
-rw-r--r-- | g4f/gui/server/backend.py | 51 |
2 files changed, 53 insertions, 2 deletions
diff --git a/g4f/gui/server/api.py b/g4f/gui/server/api.py index 00eb7182..0c32bea5 100644 --- a/g4f/gui/server/api.py +++ b/g4f/gui/server/api.py @@ -13,7 +13,7 @@ from g4f.errors import VersionNotFoundError from g4f.image import ImagePreview, ImageResponse, copy_images, ensure_images_dir, images_dir from g4f.Provider import ProviderType, __providers__, __map__ from g4f.providers.base_provider import ProviderModelMixin -from g4f.providers.response import BaseConversation, FinishReason +from g4f.providers.response import BaseConversation, FinishReason, SynthesizeData from g4f.client.service import convert_to_provider from g4f import debug @@ -177,6 +177,8 @@ class Api: images = asyncio.run(copy_images(chunk.get_list(), chunk.options.get("cookies"))) images = ImageResponse(images, chunk.alt) yield self._format_json("content", str(images)) + elif isinstance(chunk, SynthesizeData): + yield self._format_json("synthesize", chunk.to_json()) elif not isinstance(chunk, FinishReason): yield self._format_json("content", str(chunk)) if debug.logs: diff --git a/g4f/gui/server/backend.py b/g4f/gui/server/backend.py index 917d779e..87da49e1 100644 --- a/g4f/gui/server/backend.py +++ b/g4f/gui/server/backend.py @@ -1,8 +1,36 @@ import json +import asyncio +import flask from flask import request, Flask +from typing import AsyncGenerator, Generator + from g4f.image import is_allowed_extension, to_image +from g4f.client.service import convert_to_provider +from g4f.errors import ProviderNotFoundError from .api import Api +def safe_iter_generator(generator: Generator) -> Generator: + start = next(generator) + def iter_generator(): + yield start + yield from generator + return iter_generator() + +def to_sync_generator(gen: AsyncGenerator) -> Generator: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + gen = gen.__aiter__() + async def get_next(): + try: + obj = await gen.__anext__() + return False, obj + except StopAsyncIteration: return True, None + while True: + done, obj = loop.run_until_complete(get_next()) + if done: + break + yield obj + class Backend_Api(Api): """ Handles various endpoints in a Flask application for backend operations. @@ -47,6 +75,10 @@ class Backend_Api(Api): 'function': self.handle_conversation, 'methods': ['POST'] }, + '/backend-api/v2/synthesize/<provider>': { + 'function': self.handle_synthesize, + 'methods': ['GET'] + }, '/backend-api/v2/error': { 'function': self.handle_error, 'methods': ['POST'] @@ -98,11 +130,28 @@ class Backend_Api(Api): mimetype='text/event-stream' ) + def handle_synthesize(self, provider: str): + try: + provider_handler = convert_to_provider(provider) + except ProviderNotFoundError: + return "Provider not found", 404 + if not hasattr(provider_handler, "synthesize"): + return "Provider doesn't support synthesize", 500 + try: + response_generator = provider_handler.synthesize({**request.args}) + if hasattr(response_generator, "__aiter__"): + response_generator = to_sync_generator(response_generator) + response = flask.Response(safe_iter_generator(response_generator), content_type="audio/mpeg") + response.headers['Cache-Control'] = "max-age=604800" + return response + except Exception as e: + return f"{e.__class__.__name__}: {e}", 500 + def get_provider_models(self, provider: str): api_key = None if request.authorization is None else request.authorization.token models = super().get_provider_models(provider, api_key) if models is None: - return 404, "Provider not found" + return "Provider not found", 404 return models def _format_json(self, response_type: str, content) -> str: |