返回提交历史
Added
etc/examples/audio.py
+28
-0
Modified
g4f/Provider/PollinationsAI.py
+1
-1
Modified
g4f/api/stubs.py
+1
-0
Modified
g4f/client/stubs.py
+14
-2
Modified
g4f/image/__init__.py
+2
-2
XFEstudio/gpt4free
Add audio example usage
705ad029
代码差异
5 个文件
+46
-5
@@ -0,0 +1,28 @@
1
import asyncio
2
from g4f.client import AsyncClient
3
import g4f.Provider
4
import g4f.models
5
6
async def main():
7
client = AsyncClient(provider=g4f.Provider.PollinationsAI)
8
9
# Generate audio with PollinationsAI
10
response = await client.chat.completions.create(
11
model="openai-audio",
12
messages=[{"role": "user", "content": "Say good day to the world"}],
13
audio={ "voice": "alloy", "format": "mp3" },
14
)
15
response.choices[0].message.save("alloy.mp3")
16
17
# Transcribe a audio file
18
with open("audio.wav", "rb") as audio_file:
19
response = await client.chat.completions.create(
20
messages="Transcribe this audio",
21
provider=g4f.Provider.Microsoft_Phi_4,
22
media=[[audio_file, "audio.wav"]],
23
modalities=["text"],
24
)
25
print(response.choices[0].message.content)
26
27
if __name__ == "__main__":
28
asyncio.run(main())
@@ -152,7 +152,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
152
152
top_p: float = 1,
153
153
frequency_penalty: float = None,
154
154
response_format: Optional[dict] = None,
155
extra_parameters: list[str] = ["tools", "parallel_tool_calls", "tool_choice", "reasoning_effort", "logit_bias", "voice", "modalities"],
155
extra_parameters: list[str] = ["tools", "parallel_tool_calls", "tool_choice", "reasoning_effort", "logit_bias", "voice", "modalities", "audio"],
156
156
**kwargs
157
157
) -> AsyncResult:
158
158
# Load model list
@@ -18,6 +18,7 @@ class ChatCompletionsConfig(BaseModel):
18
18
image_name: Optional[str] = None
19
19
images: Optional[list[tuple[str, str]]] = None
20
20
media: Optional[list[tuple[str, str]]] = None
21
modalities: Optional[list[str]] = ["text", "audio"]
21
22
temperature: Optional[float] = None
22
23
presence_penalty: Optional[float] = None
23
24
frequency_penalty: Optional[float] = None
@@ -1,8 +1,10 @@
1
1
from __future__ import annotations
2
2
3
from typing import Optional, List, Dict, Any
3
from typing import Optional, List
4
4
from time import time
5
5
6
from ..image import extract_data_uri
7
from ..client.helper import filter_markdown
6
8
from .helper import filter_none
7
9
8
10
try:
@@ -103,6 +105,16 @@ class ChatCompletionMessage(BaseModel):
103
105
def model_construct(cls, content: str, tool_calls: list = None):
104
106
return super().model_construct(role="assistant", content=content, **filter_none(tool_calls=tool_calls))
105
107
108
def save(self, filepath: str, allowd_types = None):
109
if self.content.startswith("data:"):
110
with open(filepath, "wb") as f:
111
f.write(extract_data_uri(self.content))
112
return
113
content = filter_markdown(self.content, allowd_types)
114
if content is not None:
115
with open(filepath, "w") as f:
116
f.write(content)
117
106
118
class ChatCompletionChoice(BaseModel):
107
119
index: int
108
120
message: ChatCompletionMessage
@@ -118,7 +130,7 @@ class ChatCompletion(BaseModel):
118
130
created: int
119
131
model: str
120
132
provider: Optional[str]
121
choices: List[ChatCompletionChoice]
133
choices: list[ChatCompletionChoice]
122
134
usage: UsageModel
123
135
124
136
@classmethod
@@ -248,14 +248,14 @@ def to_input_audio(audio: ImageType, filename: str = None) -> str:
248
248
if filename is not None and (filename.endswith(".wav") or filename.endswith(".mp3")):
249
249
return {
250
250
"data": base64.b64encode(to_bytes(audio)).decode(),
251
"format": "wav" if filename.endswith(".wav") else "mpeg"
251
"format": "wav" if filename.endswith(".wav") else "mp3"
252
252
}
253
253
raise ValueError("Invalid input audio")
254
254
audio = re.match(r'^data:audio/(\w+);base64,(.+?)', audio)
255
255
if audio:
256
256
return {
257
257
"data": audio.group(2),
258
"format": audio.group(1),
258
"format": audio.group(1).replace("mpeg", "mp3")
259
259
}
260
260
raise ValueError("Invalid input audio")
261
261