summaryrefslogtreecommitdiffstats
path: root/g4f/gui/server
diff options
context:
space:
mode:
Diffstat (limited to 'g4f/gui/server')
-rw-r--r--g4f/gui/server/api.py4
-rw-r--r--g4f/gui/server/backend.py51
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: