XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 1
返回提交历史

XFEstudio/gpt4free

Delete buckets with the conversation Fix lightbox for uploaded images Fix save media content Fix TypeGPT and Cloudflare provider

fa17ce1b
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

22 个文件 +425 -110
Added docs/media.md +244 -0
@@ -0,0 +1,244 @@
1 ### G4F - Media Documentation
2
3 This document outlines how to use the G4F (Generative Framework) library to generate and process various media types, including audio, images, and videos.
4
5 ---
6
7 ### 1. **Audio Generation and Transcription**
8
9 G4F supports audio generation through providers like PollinationsAI and audio transcription using providers like Microsoft_Phi_4.
10
11 #### **Generate Audio with PollinationsAI:**
12
13 ```python
14 import asyncio
15 from g4f.client import AsyncClient
16 import g4f.Provider
17
18 async def main():
19 client = AsyncClient(provider=g4f.Provider.PollinationsAI)
20
21 response = await client.chat.completions.create(
22 model="openai-audio",
23 messages=[{"role": "user", "content": "Say good day to the world"}],
24 audio={"voice": "alloy", "format": "mp3"},
25 )
26 response.choices[0].message.save("alloy.mp3")
27
28 asyncio.run(main())
29 ```
30
31 #### **Transcribe an Audio File:**
32
33 ```python
34 import asyncio
35 from g4f.client import AsyncClient
36 import g4f.Provider
37
38 async def main():
39 client = AsyncClient(provider=g4f.Provider.Microsoft_Phi_4)
40
41 with open("audio.wav", "rb") as audio_file:
42 response = await client.chat.completions.create(
43 messages="Transcribe this audio",
44 provider=g4f.Provider.Microsoft_Phi_4,
45 media=[[audio_file, "audio.wav"]],
46 modalities=["text"],
47 )
48 print(response.choices[0].message.content)
49
50 asyncio.run(main())
51 ```
52
53 ---
54
55 ### 2. **Image Generation**
56
57 G4F can generate images from text prompts and provides options to retrieve images as URLs or base64-encoded strings.
58
59 #### **Generate an Image:**
60
61 ```python
62 import asyncio
63 from g4f.client import AsyncClient
64
65 async def main():
66 client = AsyncClient()
67
68 response = await client.images.generate(
69 prompt="a white siamese cat",
70 model="flux",
71 response_format="url",
72 )
73
74 image_url = response.data[0].url
75 print(f"Generated image URL: {image_url}")
76
77 asyncio.run(main())
78 ```
79
80 #### **Base64 Response Format:**
81
82 ```python
83 import asyncio
84 from g4f.client import AsyncClient
85
86 async def main():
87 client = AsyncClient()
88
89 response = await client.images.generate(
90 prompt="a white siamese cat",
91 model="flux",
92 response_format="b64_json",
93 )
94
95 base64_text = response.data[0].b64_json
96 print(base64_text)
97
98 asyncio.run(main())
99 ```
100
101 #### **Image Parameters:**
102 - **`width`**: Defines the width of the generated image.
103 - **`height`**: Defines the height of the generated image.
104 - **`n`**: Specifies the number of images to generate.
105 - **`response_format`**: Specifies the format of the response:
106 - `"url"`: Returns the URL of the image.
107 - `"b64_json"`: Returns the image as a base64-encoded JSON string.
108 - (Default): Saves the image locally and returns a local url.
109
110 #### **Example with Image Parameters:**
111
112 ```python
113 import asyncio
114 from g4f.client import AsyncClient
115
116 async def main():
117 client = AsyncClient()
118
119 response = await client.images.generate(
120 prompt="a white siamese cat",
121 model="flux",
122 response_format="url",
123 width=512,
124 height=512,
125 n=2,
126 )
127
128 for image in response.data:
129 print(f"Generated image URL: {image.url}")
130
131 asyncio.run(main())
132 ```
133
134 ---
135
136 ### 3. **Creating Image Variations**
137
138 You can generate variations of an existing image using G4F.
139
140 #### **Create Image Variations:**
141
142 ```python
143 import asyncio
144 from g4f.client import AsyncClient
145 from g4f.Provider import OpenaiChat
146
147 async def main():
148 client = AsyncClient(image_provider=OpenaiChat)
149
150 response = await client.images.create_variation(
151 prompt="a white siamese cat",
152 image=open("docs/images/cat.jpg", "rb"),
153 model="dall-e-3",
154 )
155
156 image_url = response.data[0].url
157 print(f"Generated image URL: {image_url}")
158
159 asyncio.run(main())
160 ```
161
162 ---
163
164 ### 4. **Video Generation**
165
166 G4F supports video generation through providers like HuggingFaceMedia.
167
168 #### **Generate a Video:**
169
170 ```python
171 import asyncio
172 from g4f.client import AsyncClient
173 from g4f.Provider import HuggingFaceMedia
174
175 async def main():
176 client = AsyncClient(
177 provider=HuggingFaceMedia,
178 api_key="hf_***" # Your API key here
179 )
180
181 video_models = client.models.get_video()
182 print("Available Video Models:", video_models)
183
184 result = await client.media.generate(
185 model=video_models[0],
186 prompt="G4F AI technology is the best in the world.",
187 response_format="url",
188 )
189
190 print("Generated Video URL:", result.data[0].url)
191
192 asyncio.run(main())
193 ```
194
195 #### **Video Parameters:**
196 - **`resolution`**: Specifies the resolution of the generated video. Options include:
197 - `"480p"` (default)
198 - `"720p"`
199 - **`aspect_ratio`**: Defines the width-to-height ratio (e.g., `"16:9"`).
200 - **`n`**: Specifies the number of videos to generate.
201 - **`response_format`**: Specifies the format of the response:
202 - `"url"`: Returns the URL of the video.
203 - `"b64_json"`: Returns the video as a base64-encoded JSON string.
204 - (Default): Saves the video locally and returns a local url.
205
206 #### **Example with Video Parameters:**
207
208 ```python
209 import os
210 import asyncio
211 from g4f.client import AsyncClient
212 from g4f.Provider import HuggingFaceMedia
213
214 async def main():
215 client = AsyncClient(
216 provider=HuggingFaceMedia,
217 api_key=os.getenv("HUGGINGFACE_API_KEY") # Your API key here
218 )
219
220 video_models = client.models.get_video()
221 print("Available Video Models:", video_models)
222
223 result = await client.media.generate(
224 model=video_models[0],
225 prompt="G4F AI technology is the best in the world.",
226 resolution="720p",
227 aspect_ratio="16:9",
228 n=1,
229 response_format="url",
230 )
231
232 print("Generated Video URL:", result.data[0].url)
233
234 asyncio.run(main())
235 ```
236
237 ---
238
239 **Key Points:**
240
241 - **Provider Selection**: Ensure the selected provider supports the desired media generation or processing task.
242 - **API Keys**: Some providers require API keys for authentication.
243 - **Response Formats**: Use `response_format` to control the output format (URL, base64, local file).
244 - **Parameter Usage**: Use parameters like `width`, `height`, `resolution`, `aspect_ratio`, and `n` to customize the generated media.
Modified g4f/Provider/Cloudflare.py +14 -20
@@ -2,14 +2,12 @@ from __future__ import annotations
2 2
3 3 import asyncio
4 4 import json
5 from pathlib import Path
6 5
7 6 from ..typing import AsyncResult, Messages, Cookies
8 7 from .base_provider import AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin, get_running_loop
9 8 from ..requests import Session, StreamSession, get_args_from_nodriver, raise_for_status, merge_cookies
10 9 from ..requests import DEFAULT_HEADERS, has_nodriver, has_curl_cffi
11 from ..providers.response import FinishReason
12 from ..cookies import get_cookies_dir
10 from ..providers.response import FinishReason, Usage
13 11 from ..errors import ResponseStatusError, ModelNotFoundError
14 12
15 13 class Cloudflare(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
@@ -84,11 +82,16 @@ class Cloudflare(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
84 82 except ModelNotFoundError:
85 83 pass
86 84 data = {
87 "messages": messages,
85 "messages": [{
86 "role":"user",
87 "content": message["content"] if isinstance(message["content"], str) else "",
88 "parts": [{"type":"text", "text":message["content"]}] if isinstance(message["content"], str) else message["content"]} for message in messages],
88 89 "lora": None,
89 90 "model": model,
90 91 "max_tokens": max_tokens,
91 "stream": True
92 "stream": True,
93 "system_message":"You are a helpful assistant",
94 "tools":[]
92 95 }
93 96 async with StreamSession(**cls._args) as session:
94 97 async with session.post(
@@ -103,22 +106,13 @@ class Cloudflare(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
103 106 if cache_file.exists():
104 107 cache_file.unlink()
105 108 raise
106 reason = None
107 109 async for line in response.iter_lines():
108 if line.startswith(b'data: '):
109 if line == b'data: [DONE]':
110 break
111 try:
112 content = json.loads(line[6:].decode())
113 if content.get("response") and content.get("response") != '</s>':
114 yield content['response']
115 reason = "max_tokens"
116 elif content.get("response") == '':
117 reason = "stop"
118 except Exception:
119 continue
120 if reason is not None:
121 yield FinishReason(reason)
110 if line.startswith(b'0:'):
111 yield json.loads(line[2:])
112 elif line.startswith(b'e:'):
113 finish = json.loads(line[2:])
114 yield Usage(**finish.get("usage"))
115 yield FinishReason(finish.get("finishReason"))
122 116
123 117 with cache_file.open("w") as f:
124 118 json.dump(cls._args, f)
Modified g4f/Provider/PerplexityLabs.py +1 -1
@@ -68,7 +68,7 @@ class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin):
68 68 "version": "2.18",
69 69 "source": "default",
70 70 "model": model,
71 "messages": messages,
71 "messages": [message for message in messages if isinstance(message["content"], str)],
72 72 }
73 73 await ws.send_str("42" + json.dumps(["perplexity_labs", message_data]))
74 74 last_message = 0
Modified g4f/Provider/PollinationsAI.py +1 -1
@@ -155,7 +155,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
155 155 media: MediaListType = None,
156 156 temperature: float = None,
157 157 presence_penalty: float = None,
158 top_p: float = 1,
158 top_p: float = None,
159 159 frequency_penalty: float = None,
160 160 response_format: Optional[dict] = None,
161 161 extra_parameters: list[str] = ["tools", "parallel_tool_calls", "tool_choice", "reasoning_effort", "logit_bias", "voice", "modalities", "audio"],
Modified g4f/Provider/TypeGPT.py +25 -2
@@ -1,18 +1,41 @@
1 1 from __future__ import annotations
2 2
3 import requests
4
3 5 from .template import OpenaiTemplate
4 6
5 7 class TypeGPT(OpenaiTemplate):
6 8 label = "TypeGpt"
7 9 url = "https://chat.typegpt.net"
8 api_base = "https://chat.typegpt.net/api/openai/typegpt/v1"
10 api_base = "https://chat.typegpt.net/api/openai/v1"
9 11 working = True
12 headers = {
13 "accept": "application/json, text/event-stream",
14 "accept-language": "de,en-US;q=0.9,en;q=0.8",
15 "content-type": "application/json",
16 "priority": "u=1, i",
17 "sec-ch-ua": "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
18 "sec-ch-ua-mobile": "?0",
19 "sec-ch-ua-platform": "\"Linux\"",
20 "sec-fetch-dest": "empty",
21 "sec-fetch-mode": "cors",
22 "sec-fetch-site": "same-origin",
23 "referer": "https://chat.typegpt.net/",
24 }
10 25
11 26 default_model = 'gpt-4o-mini-2024-07-18'
12 27 default_vision_model = default_model
13 28 vision_models = ['gpt-3.5-turbo', 'gpt-3.5-turbo-202201', default_vision_model, "o3-mini"]
14 models = vision_models + ["deepseek-r1", "deepseek-v3", "evil", "o1"]
29 fallback_models = vision_models + ["deepseek-r1", "deepseek-v3", "evil", "o1"]
30 image_models = ["Image-Generator"]
15 31 model_aliases = {
16 32 "gpt-3.5-turbo": "gpt-3.5-turbo-202201",
17 33 "gpt-4o-mini": "gpt-4o-mini-2024-07-18",
18 34 }
35
36 @classmethod
37 def get_models(cls, **kwargs):
38 if not cls.models:
39 cls.models = requests.get(f"{cls.url}/api/config").json()["customModels"].split(",")
40 cls.models = [model.split("@")[0][1:] for model in cls.models if model.startswith("+") and model not in cls.image_models]
41 return cls.models
Modified g4f/Provider/hf/HuggingFaceAPI.py +11 -6
@@ -5,11 +5,10 @@ import requests
5 5 from ...providers.types import Messages
6 6 from ...typing import MediaListType
7 7 from ...requests import StreamSession, raise_for_status
8 from ...errors import ModelNotSupportedError
8 from ...errors import ModelNotSupportedError, PaymentRequiredError
9 9 from ...providers.response import ProviderInfo
10 10 from ..template.OpenaiTemplate import OpenaiTemplate
11 11 from .models import model_aliases, vision_models, default_llama_model, default_vision_model, text_models
12 from ... import debug
13 12
14 13 class HuggingFaceAPI(OpenaiTemplate):
15 14 label = "HuggingFace (Text Generation)"
@@ -89,6 +88,7 @@ class HuggingFaceAPI(OpenaiTemplate):
89 88 provider_mapping = await cls.get_mapping(model, api_key)
90 89 if not provider_mapping:
91 90 raise ModelNotSupportedError(f"Model is not supported: {model} in: {cls.__name__}")
91 error = None
92 92 for provider_key in provider_mapping:
93 93 api_path = provider_key if provider_key == "novita" else f"{provider_key}/v1"
94 94 api_base = f"https://router.huggingface.co/{api_path}"
@@ -97,7 +97,6 @@ class HuggingFaceAPI(OpenaiTemplate):
97 97 raise ModelNotSupportedError(f"Model is not supported: {model} in: {cls.__name__} task: {task}")
98 98 model = provider_mapping[provider_key]["providerId"]
99 99 yield ProviderInfo(**{**cls.get_dict(), "label": f"HuggingFace ({provider_key})"})
100 break
101 100 # start = calculate_lenght(messages)
102 101 # if start > max_inputs_lenght:
103 102 # if len(messages) > 6:
@@ -109,8 +108,14 @@ class HuggingFaceAPI(OpenaiTemplate):
109 108 # if len(messages) > 1 and calculate_lenght(messages) > max_inputs_lenght:
110 109 # messages = last_user_message
111 110 # debug.log(f"Messages trimmed from: {start} to: {calculate_lenght(messages)}")
112 async for chunk in super().create_async_generator(model, messages, api_base=api_base, api_key=api_key, max_tokens=max_tokens, media=media, **kwargs):
113 yield chunk
114
111 try:
112 async for chunk in super().create_async_generator(model, messages, api_base=api_base, api_key=api_key, max_tokens=max_tokens, media=media, **kwargs):
113 yield chunk
114 return
115 except PaymentRequiredError as e:
116 error = e
117 continue
118 if error is not None:
119 raise error
115 120 def calculate_lenght(messages: Messages) -> int:
116 121 return sum([len(message["content"]) + 16 for message in messages])
Modified g4f/Provider/hf/HuggingFaceMedia.py +29 -21
@@ -101,7 +101,14 @@ class HuggingFaceMedia(AsyncGeneratorProvider, ProviderModelMixin):
101 101 prompt: str = None,
102 102 proxy: str = None,
103 103 timeout: int = 0,
104 # Video & Image Generation
105 n: int = 1,
104 106 aspect_ratio: str = None,
107 # Only for Image Generation
108 height: int = None,
109 width: int = None,
110 # Video Generation
111 resolution: str = "480p",
105 112 **kwargs
106 113 ):
107 114 selected_provider = None
@@ -109,6 +116,7 @@ class HuggingFaceMedia(AsyncGeneratorProvider, ProviderModelMixin):
109 116 model, selected_provider = model.split(":", 1)
110 117 elif not model:
111 118 model = cls.get_models()[0]
119 prompt = format_image_prompt(messages, prompt)
112 120 provider_mapping = await cls.get_mapping(model, api_key)
113 121 headers = {
114 122 'Accept-Encoding': 'gzip, deflate',
@@ -119,7 +127,7 @@ class HuggingFaceMedia(AsyncGeneratorProvider, ProviderModelMixin):
119 127 if key in ["replicate", "together", "hf-inference"]
120 128 }
121 129 provider_mapping = {**new_mapping, **provider_mapping}
122 async def generate(extra_data: dict, prompt: str, aspect_ratio: str = None):
130 async def generate(extra_data: dict, aspect_ratio: str = None):
123 131 last_response = None
124 132 for provider_key, provider in provider_mapping.items():
125 133 if selected_provider is not None and selected_provider != provider_key:
@@ -132,34 +140,29 @@ class HuggingFaceMedia(AsyncGeneratorProvider, ProviderModelMixin):
132 140 if task not in cls.tasks:
133 141 raise ModelNotSupportedError(f"Model is not supported: {model} in: {cls.__name__} task: {task}")
134 142
135 prompt = format_image_prompt(messages, prompt)
136 143 if aspect_ratio is None:
137 144 aspect_ratio = "1:1" if task == "text-to-image" else "16:9"
138 145 if task == "text-to-video" and provider_key != "novita":
139 146 extra_data = {
140 147 "num_inference_steps": 20,
141 "resolution": "480p",
148 "resolution": resolution,
142 149 "aspect_ratio": aspect_ratio,
143 150 **extra_data
144 151 }
145 152 else:
146 extra_data = use_aspect_ratio(extra_data, aspect_ratio)
153 extra_data = use_aspect_ratio({
154 **extra_data,
155 "height": height,
156 "width": width,
157 }, aspect_ratio)
147 158 url = f"{api_base}/{provider_id}"
148 159 data = {
149 160 "prompt": prompt,
150 161 **extra_data
151 162 }
152 163 if provider_key == "fal-ai" and task == "text-to-image":
153 if aspect_ratio is None or aspect_ratio == "1:1":
154 image_size = "square_hd",
155 elif aspect_ratio == "16:9":
156 image_size = "landscape_hd",
157 elif aspect_ratio == "9:16":
158 image_size = "portrait_16_9"
159 else:
160 image_size = extra_data # width, height
161 164 data = {
162 "image_size": image_size,
165 "image_size": extra_data,
163 166 **data
164 167 }
165 168 elif provider_key == "novita":
@@ -212,16 +215,21 @@ class HuggingFaceMedia(AsyncGeneratorProvider, ProviderModelMixin):
212 215 await raise_for_status(last_response)
213 216
214 217 background_tasks = set()
218 running_tasks = set()
215 219 started = time.time()
216 task = asyncio.create_task(generate(extra_data, prompt, aspect_ratio))
217 background_tasks.add(task)
218 task.add_done_callback(background_tasks.discard)
219 while background_tasks:
220 while n > 0:
221 n -= 1
222 task = asyncio.create_task(generate(extra_data, aspect_ratio))
223 background_tasks.add(task)
224 running_tasks.add(task)
225 task.add_done_callback(running_tasks.discard)
226 while running_tasks:
220 227 diff = time.time() - started
221 228 if diff > 1:
222 229 yield Reasoning(label="Generating", status=f"{diff:.2f}s")
223 230 await asyncio.sleep(0.2)
224 provider_info, media_response = await task
225 yield Reasoning(label="Finished", status=f"{time.time() - started:.2f}s")
226 yield provider_info
227 yield media_response
231 for task in background_tasks:
232 provider_info, media_response = await task
233 yield Reasoning(label="Finished", status=f"{time.time() - started:.2f}s")
234 yield provider_info
235 yield media_response
Modified g4f/Provider/needs_auth/OpenaiChat.py +1 -0
@@ -142,6 +142,7 @@ class OpenaiChat(AsyncAuthedProvider, ProviderModelMixin):
142 142 An ImageRequest object that contains the download URL, file name, and other data
143 143 """
144 144 async def upload_image(image, image_name):
145 debug.log(f"Uploading image: {image_name}")
145 146 # Convert the image to a PIL Image object and get the extension
146 147 data_bytes = to_bytes(image)
147 148 image = to_image(data_bytes)
Modified g4f/client/__init__.py +12 -6
@@ -429,7 +429,7 @@ class Images:
429 429 **kwargs
430 430 ) -> MediaResponse:
431 431 messages = [{"role": "user", "content": f"{prompt_prefix}{prompt}"}]
432 response = None
432 items: list[MediaResponse] = []
433 433 if hasattr(provider_handler, "create_async_generator"):
434 434 async for item in provider_handler.create_async_generator(
435 435 model,
@@ -439,8 +439,7 @@ class Images:
439 439 **kwargs
440 440 ):
441 441 if isinstance(item, MediaResponse):
442 response = item
443 break
442 items.append(item)
444 443 elif hasattr(provider_handler, "create_completion"):
445 444 for item in provider_handler.create_completion(
446 445 model,
@@ -450,11 +449,18 @@ class Images:
450 449 **kwargs
451 450 ):
452 451 if isinstance(item, MediaResponse):
453 response = item
454 break
452 items.append(item)
455 453 else:
456 454 raise ValueError(f"Provider {provider_name} does not support image generation")
457 return response
455 urls = []
456 for item in items:
457 if isinstance(item.urls, str):
458 urls.append(item.urls)
459 elif isinstance(item.urls, list):
460 urls.extend(item.urls)
461 if not urls:
462 return None
463 return MediaResponse(urls, items[0].alt)
458 464
459 465 def create_variation(
460 466 self,
Modified g4f/errors.py +3 -0
@@ -34,6 +34,9 @@ class NestAsyncioError(MissingRequirementsError):
34 34 class MissingAuthError(Exception):
35 35 ...
36 36
37 class PaymentRequiredError(Exception):
38 ...
39
37 40 class NoMediaResponseError(Exception):
38 41 ...
39 42
Modified g4f/gui/client/background.html +3 -3
@@ -174,8 +174,8 @@
174 174 skipImage++;
175 175 return;
176 176 }
177 if (skipRefresh) {
178 skipRefresh = 0;
177 if (skipRefresh > 0) {
178 skipRefresh -= 1;
179 179 return;
180 180 }
181 181 if (images.length > 0) {
@@ -197,7 +197,7 @@
197 197 };
198 198 imageFeed.onclick = () => {
199 199 imageFeed.src = "/search/image?random=" + Math.random();
200 skipRefresh = 1;
200 skipRefresh = 2;
201 201 };
202 202 })();
203 203 </script>
Modified g4f/gui/client/index.html +5 -0
@@ -150,6 +150,11 @@
150 150 <input type="checkbox" id="countTokens" checked/>
151 151 <label for="countTokens" class="toogle" title=""></label>
152 152 </div>
153 <div class="field">
154 <span class="label">Automatic Orientation (16:9 or 9:16)</span>
155 <input type="checkbox" id="automaticOrientation" checked/>
156 <label for="automaticOrientation" class="toogle" title=""></label>
157 </div>
153 158 <div class="field box">
154 159 <label for="systemPrompt" class="label">System prompt</label>
155 160 <textarea id="systemPrompt" placeholder="You are a helpful assistant." data-example="If you need to generate images, you can use the following format: ![keywords](/generate/filename.jpg). This will enable the use of an image generation tool."></textarea>
Modified g4f/gui/client/static/css/style.css +2 -10
Modified g4f/gui/client/static/js/chat.v1.js +49 -25
Modified g4f/gui/client/static/js/photoswipe.js +1 -0
Modified g4f/image/__init__.py +3 -0
Modified g4f/image/copy_images.py +5 -5
Modified g4f/providers/base_provider.py +5 -1
Modified g4f/providers/response.py +6 -5
Modified g4f/requests/__init__.py +1 -0
Modified g4f/tools/files.py +2 -2
Modified g4f/tools/media.py +2 -2