返回提交历史
Deleted
g4f/Provider/WeWordle.py
+0
-82
Modified
g4f/Provider/__init__.py
+0
-6
Modified
g4f/Provider/needs_auth/Video.py
+78
-209
Modified
g4f/Provider/needs_auth/__init__.py
+0
-1
Modified
g4f/models.py
+1
-2
Modified
g4f/providers/any_model_map.py
+0
-6
Modified
g4f/tools/run_tools.py
+2
-2
XFEstudio/gpt4free
Remove Video and WeWordle provider
23fe8664
代码差异
7 个文件
+81
-308
@@ -1,82 +0,0 @@
1
from __future__ import annotations
2
3
import json
4
from typing import Any
5
6
from ..typing import AsyncResult, Messages
7
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
8
from .helper import format_prompt
9
from ..requests import StreamSession
10
from ..providers.response import Reasoning
11
12
class WeWordle(AsyncGeneratorProvider, ProviderModelMixin):
13
label = "WeWordle"
14
url = "https://chat-gpt.com"
15
api_endpoint = "https://llmproxy.org/api/chat.php"
16
17
working = True
18
needs_auth = False
19
supports_stream = True
20
supports_system_message = True
21
supports_message_history = True
22
23
default_model = 'v3'
24
models = [default_model, 'gpt-4', 'gpt-4o', 'gpt-4o-mini', 'deepseek', 'deepseek-reasoner', 'deepseek-r1']
25
26
model_aliases = {
27
"deepseek": "v3",
28
"deepseek-reasoner": "v3",
29
"deepseek-r1": "v3"
30
}
31
32
@classmethod
33
async def create_async_generator(
34
cls,
35
model: str,
36
messages: Messages,
37
proxy: str | None = None,
38
**kwargs: Any
39
) -> AsyncResult:
40
headers = {
41
"accept": "*/*",
42
"accept-language": "en-US,en;q=0.9",
43
"cache-control": "no-cache",
44
"content-type": "application/json",
45
"origin": "https://chat-gpt.com",
46
"referer": "https://chat-gpt.com/"
47
}
48
49
web_search = kwargs.get("web_search", False)
50
51
data_payload = {
52
"messages": messages,
53
"model": cls.get_model(model),
54
"cost": 1,
55
"stream": True,
56
"web_search": web_search
57
}
58
59
async with StreamSession(headers=headers, impersonate="chrome") as session:
60
async with session.post(cls.api_endpoint, json=data_payload, proxy=proxy) as response:
61
response.raise_for_status()
62
63
async for chunk in response.iter_lines():
64
if not chunk:
65
continue
66
chunk = chunk.decode("utf-8")
67
if chunk.startswith("data: "):
68
chunk = chunk[6:]
69
if chunk == "[DONE]":
70
break
71
try:
72
json_data = json.loads(chunk)
73
if "choices" in json_data and isinstance(json_data["choices"], list) and json_data["choices"]:
74
delta = json_data["choices"][0].get("delta", {})
75
76
if "reasoning" in delta and delta["reasoning"]:
77
yield Reasoning(status=delta["reasoning"])
78
79
if "content" in delta and delta["content"]:
80
yield delta["content"]
81
except json.JSONDecodeError:
82
pass
@@ -158,10 +158,6 @@ def _resolve_provider(name: str) -> ProviderType:
158
158
from g4f.Provider.needs_auth.ThebApi import ThebApi; return ThebApi
159
159
elif name == "Together":
160
160
from g4f.Provider.needs_auth.Together import Together; return Together
161
elif name == "Video":
162
from g4f.Provider.needs_auth.Video import Video; return Video
163
elif name == "WeWordle":
164
from g4f.Provider.WeWordle import WeWordle; return WeWordle
165
161
elif name == "WhiteRabbitNeo":
166
162
from g4f.Provider.needs_auth.WhiteRabbitNeo import WhiteRabbitNeo; return WhiteRabbitNeo
167
163
elif name == "You":
@@ -254,8 +250,6 @@ _provider_names = [
254
250
"TeachAnything",
255
251
"ThebApi",
256
252
"Together",
257
"Video",
258
"WeWordle",
259
253
"WhiteRabbitNeo",
260
254
"You",
261
255
"YouTube",
@@ -1,259 +1,128 @@
1
1
from __future__ import annotations
2
2
3
import os
4
import asyncio
3
import json
5
4
from typing import Optional
6
5
from aiohttp import ClientSession, ClientTimeout
7
8
from urllib.parse import quote, quote_plus
9
from aiohttp import ClientSession
10
11
try:
12
import zendriver as nodriver
13
from zendriver.core.connection import ProtocolException
14
has_nodriver = True
15
except Exception:
16
has_nodriver = False
6
from urllib.parse import quote
7
from urllib.parse import quote
17
8
18
9
from ...typing import Messages, AsyncResult
19
from ...providers.response import VideoResponse, Reasoning, ContinueResponse, ProviderInfo
20
from ...requests import get_nodriver
10
from ...providers.response import VideoResponse, Reasoning, ProviderInfo
21
11
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
22
12
from ..helper import format_media_prompt
23
13
from ... import debug
24
14
25
PUBLIC_URL = "https://g4f.space"
26
SEARCH_URL = f"{PUBLIC_URL}/search/video+"
15
FLIM_SEARCH_URL = "https://api.flim.ai/2.0.0/search"
16
TRANSLATE_URL = "https://g4f.space/ai/auto/Translate%20the%20given%20prompt%20into%20English%20and%20reply%20with%20only%20the%20translated%20text%E2%80%94no%20explanations,%20introductions,%20or%20additional%20content:%20{prompt}"
17
FLIM_HEADERS = {
18
"accept": "application/json",
19
"content-type": "application/json",
20
"origin": "https://app.flim.ai",
21
"referer": "https://app.flim.ai/",
22
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
23
}
27
24
28
25
class RequestConfig:
29
26
urls: dict[str, list[str]] = {}
30
headers: dict = {}
31
27
32
28
@classmethod
33
29
async def get_response(cls, prompt: str, search: bool = False) -> Optional[VideoResponse]:
34
30
if prompt in cls.urls and cls.urls[prompt]:
35
31
unique_list = list(set(cls.urls[prompt]))[:10]
36
return VideoResponse(unique_list, prompt, {
37
"headers": {"authorization": cls.headers.get("authorization")} if cls.headers.get("authorization") else {},
38
})
32
return VideoResponse(unique_list, prompt)
39
33
if search:
34
found_urls = await cls.search_flim(prompt)
35
if found_urls:
36
return VideoResponse(found_urls, prompt)
37
38
@classmethod
39
async def translate_prompt(cls, prompt: str) -> str:
40
"""Translate the prompt into English via the g4f.space auto endpoint."""
41
try:
42
url = TRANSLATE_URL.format(prompt=quote(prompt, safe=""))
40
43
async with ClientSession() as session:
41
found_urls = []
42
for skip in range(0, 9):
43
try:
44
async with session.get(SEARCH_URL + quote_plus(prompt) + f"?skip={skip}", timeout=ClientTimeout(total=10)) as response:
45
if response.ok:
46
found_urls.append(str(response.url))
47
else:
48
break
49
except Exception as e:
50
debug.error(f"Error fetching video URLs:", e)
51
break
52
if found_urls:
53
return VideoResponse(found_urls, prompt)
44
async with session.get(url, timeout=ClientTimeout(total=15)) as response:
45
if not response.ok:
46
debug.error(f"Translate prompt failed: {response.status}")
47
return prompt
48
text = (await response.text()).strip()
49
return text[:100] if text else prompt
50
except Exception as e:
51
debug.error(f"Error translating prompt:", e)
52
return prompt
53
54
@classmethod
55
async def search_flim(cls, prompt: str) -> list[str]:
56
payload = {
57
"search": {
58
"saved_images": False, "full_text": prompt,
59
"similar_picture_id": "", "movie_id": "", "dop": "", "director": "",
60
"brand": "", "agency": "", "production_company": "", "actor": "",
61
"creator": "", "artist": "", "collection_id": "", "board_id": "",
62
"filters": {
63
"genres": [], "colors": [], "number_of_persons": [], "years": [],
64
"shot_types": [], "movie_types": [], "aspect_ratio": [],
65
"safety_content": [], "has_video_cuts": True, "camera_motions": []
66
},
67
"negative_filters": {
68
"aspect_ratio": [], "genres": ["ANIMATION"], "movie_types": [],
69
"colors": [], "shot_types": [], "number_of_persons": [],
70
"years": [], "safety_content": ["nudity", "violence"]
71
}
72
},
73
"page": 0, "sort_by": "", "order_by": "", "number_per_pages": 100
74
}
75
urls = []
76
try:
77
async with ClientSession(headers=FLIM_HEADERS) as session:
78
async with session.post(FLIM_SEARCH_URL, json=payload, timeout=ClientTimeout(total=15)) as response:
79
if not response.ok:
80
debug.error(f"Flim search failed: {response.status}")
81
return urls
82
data = await response.json()
83
for img in data.get("query_response", {}).get("images", []):
84
if img.get("has_video_urls"):
85
video_urls = img.get("video_urls", {})
86
url = video_urls.get("url_thumbnail") or video_urls.get("url")
87
if url and url not in urls:
88
urls.append(url)
89
except Exception as e:
90
debug.error(f"Error fetching flim video URLs:", e)
91
return urls[:10]
54
92
55
93
class Video(AsyncGeneratorProvider, ProviderModelMixin):
56
94
urls = {
57
"search": "https://sora.chatgpt.com/explore?query={0}",
58
"sora": "https://sora.chatgpt.com/explore",
59
#"veo": "https://aistudio.google.com/generate-video"
95
"search": "https://app.flim.ai/?ft={0}",
60
96
}
61
api_path = f"?provider=Video&cache=true&prompt="
62
drive_url = "https://www.googleapis.com/drive/v3/"
63
97
64
98
active_by_default = True
65
99
default_model = "search"
66
100
models = list(urls.keys())
67
101
video_models = models
68
102
69
needs_auth = True
70
working = has_nodriver
71
72
browser = None
73
stop_browser = None
74
share_url: Optional[str] = None
103
needs_auth = False
104
working = True
75
105
76
106
@classmethod
77
107
async def create_async_generator(
78
108
cls,
79
109
model: str,
80
110
messages: Messages,
81
proxy: str = None,
82
111
prompt: str = None,
83
aspect_ratio: str = None,
84
112
**kwargs
85
113
) -> AsyncResult:
86
if cls.share_url is None:
87
cls.share_url = os.getenv("G4F_SHARE_URL")
88
114
if not model:
89
115
model = cls.default_model
90
116
if model not in cls.video_models:
91
117
raise ValueError(f"Model '{model}' is not supported by {cls.__name__}. Supported models: {cls.models}")
92
yield ProviderInfo(**cls.get_dict(), model="sora")
118
yield ProviderInfo(**cls.get_dict(), model=model)
93
119
prompt = format_media_prompt(messages, prompt).encode()[:100].decode("utf-8", "ignore").strip()
94
120
if not prompt:
95
121
raise ValueError("Prompt cannot be empty.")
96
response = await RequestConfig.get_response(prompt, model=="search")
122
prompt = await RequestConfig.translate_prompt(prompt)
123
response = await RequestConfig.get_response(prompt, model == "search")
97
124
if response:
98
125
yield Reasoning(label=f"Found {len(response.urls)} Video(s)", status="")
99
126
yield response
100
127
return
101
try:
102
yield Reasoning(label="Open browser")
103
browser, stop_browser = await get_nodriver(proxy=proxy)
104
except Exception as e:
105
if cls.share_url is None:
106
raise
107
debug.error(f"Error getting nodriver:", e)
108
async with ClientSession() as session:
109
yield Reasoning(label="Generating")
110
async with session.get(f"{cls.share_url}{cls.api_path + quote(prompt)}") as response:
111
if not response.ok:
112
debug.error(f"Failed to generate Video: {response.status}")
113
else:
114
yield Reasoning(label="Finished", status="")
115
if response.headers.get("content-type", "text/plain").startswith("text/plain"):
116
data = (await response.text()).split("\n")
117
yield VideoResponse([f"{PUBLIC_URL}{url}" if url.startswith("/") else url for url in data], prompt)
118
return
119
yield VideoResponse(str(response.url), prompt)
120
return
121
raise
122
page = None
123
try:
124
yield ContinueResponse("Timeout waiting for Video URL")
125
page = await browser.get(cls.urls[model].format(quote(prompt)))
126
except Exception as e:
127
await stop_browser()
128
debug.error(f"Error opening page:", e)
129
if prompt not in RequestConfig.urls:
130
RequestConfig.urls[prompt] = []
131
def on_request(event: nodriver.cdp.network.RequestWillBeSent, page=None):
132
if not hasattr(event, "request"):
133
return
134
if event.request.url.startswith(cls.drive_url) or ".mp4" in event.request.url:
135
RequestConfig.headers = {}
136
for key, value in event.request.headers.items():
137
RequestConfig.headers[key.lower()] = value
138
for urls in RequestConfig.urls.values():
139
if event.request.url in urls:
140
return
141
debug.log(f"Adding URL: {event.request.url}")
142
RequestConfig.urls[prompt].append(event.request.url)
143
if not page:
144
raise RuntimeError("Failed to open page.")
145
for idx in range(300):
146
button = await page.find("User menu")
147
if button:
148
break
149
if idx == 299:
150
await stop_browser()
151
raise RuntimeError("Failed to wait for user menu.")
152
if model == "search" and page is not None:
153
await page.send(nodriver.cdp.network.enable())
154
page.add_handler(nodriver.cdp.network.RequestWillBeSent, on_request)
155
for _ in range(5):
156
await page.scroll_down(5)
157
await asyncio.sleep(1)
158
response = await RequestConfig.get_response(prompt, True)
159
if response:
160
await stop_browser()
161
yield Reasoning(label="Found", status="")
162
yield response
163
return
164
if page is None:
165
raise RuntimeError("Failed to open page or get response.")
166
try:
167
await asyncio.sleep(3)
168
await page.select("textarea", 240)
169
try:
170
button = await page.find("Image")
171
if button:
172
await button.click()
173
else:
174
debug.error("No 'Image' button found.")
175
button = await page.find("Video")
176
if button:
177
await button.click()
178
yield Reasoning(label=f"Clicked 'Video' button")
179
else:
180
debug.error("No 'Video' button found.")
181
except Exception as e:
182
debug.error(f"Error clicking button:", e)
183
try:
184
if aspect_ratio:
185
button = await page.find(":")
186
if button:
187
await button.click()
188
else:
189
debug.error("No 'x:x' button found.")
190
await asyncio.sleep(1)
191
button = await page.find(aspect_ratio)
192
if button:
193
await button.click()
194
yield Reasoning(label=f"Clicked '{aspect_ratio}' button")
195
else:
196
debug.error(f"No '{aspect_ratio}' button found.")
197
except Exception as e:
198
debug.error(f"Error clicking button:", e)
199
debug.log(f"Using prompt: {prompt}")
200
textarea = await page.select("textarea", 180)
201
await textarea.click()
202
await textarea.clear_input()
203
await textarea.send_keys(prompt)
204
await asyncio.sleep(1)
205
yield Reasoning(label=f"Sending prompt", token=prompt)
206
try:
207
button = await page.select('button[type="submit"]', 5)
208
if button:
209
await button.click()
210
except Exception as e:
211
debug.error(f"Error clicking submit button:", e)
212
try:
213
button = await page.find("Create video")
214
if button:
215
await button.click()
216
yield Reasoning(label=f"Clicked 'Create video' button")
217
except Exception as e:
218
debug.error(f"Error clicking 'Create video' button:", e)
219
try:
220
button = await page.find("Activity")
221
if button:
222
await button.click()
223
yield Reasoning(label=f"Clicked 'Activity' button")
224
except Exception as e:
225
debug.error(f"Error clicking 'Activity' button:", e)
226
for idx in range(60):
227
await asyncio.sleep(1)
228
try:
229
button = await page.find("New Video")
230
if button:
231
await button.click()
232
yield Reasoning(label=f"Clicked 'New Video' button")
233
break
234
except ProtocolException as e:
235
if idx == 59:
236
debug.error(e)
237
if idx == 59:
238
await stop_browser()
239
raise RuntimeError("Failed to click 'New Video' button")
240
await asyncio.sleep(3)
241
if model != "search" and page is not None:
242
await page.send(nodriver.cdp.network.enable())
243
page.add_handler(nodriver.cdp.network.RequestWillBeSent, on_request)
244
for idx in range(300):
245
yield Reasoning(label="Waiting for Video...", status=f"{idx+1}/300")
246
await asyncio.sleep(1)
247
if RequestConfig.urls[prompt]:
248
await asyncio.sleep(2)
249
response = await RequestConfig.get_response(prompt, model=="search")
250
if response:
251
await stop_browser()
252
yield Reasoning(label="Finished", status="")
253
yield response
254
return
255
if idx == 299:
256
await stop_browser()
257
raise RuntimeError("Failed to get Video URL")
258
finally:
259
await stop_browser()
128
raise RuntimeError("Failed to find any videos for the prompt.")
@@ -41,6 +41,5 @@ from .Replicate import Replicate
41
41
from .ThebApi import ThebApi
42
42
from .WhiteRabbitNeo import WhiteRabbitNeo
43
43
from .Together import Together
44
from .Video import Video
45
44
from .xAI import xAI
46
45
from .You import You
@@ -116,7 +116,6 @@ default = Model(
116
116
"Pollinations",
117
117
"Qwen",
118
118
"Together",
119
"WeWordle",
120
119
"TeachAnything",
121
120
"OpenaiChat",
122
121
])
@@ -142,7 +141,7 @@ default_vision = VisionModel(
142
141
gpt_4 = Model(
143
142
name = 'gpt-4',
144
143
base_provider = 'OpenAI',
145
best_provider = IterListProvider(["CopilotApp", "Yqcloud", "WeWordle", "OpenaiChat"])
144
best_provider = IterListProvider(["CopilotApp", "Yqcloud", "OpenaiChat"])
146
145
)
147
146
148
147
# gpt-4o
@@ -14,12 +14,10 @@ model_map = {
14
14
"GLM": "",
15
15
"Pollinations": "",
16
16
"TeachAnything": "",
17
"WeWordle": ""
18
17
},
19
18
"gpt-4": {
20
19
"CopilotApp": "chat",
21
20
"Yqcloud": "gpt-4",
22
"WeWordle": "gpt-4",
23
21
"OpenaiChat": "gpt-4",
24
22
"Airforce": "gpt-4",
25
23
"Copilot": "Copilot",
@@ -38,7 +36,6 @@ model_map = {
38
36
"GithubCopilot": "gpt-4o",
39
37
"OpenRouter": "openai/gpt-4o-2024-05-13",
40
38
"Puter": "openrouter:openai/gpt-4o-2024-11-20",
41
"WeWordle": "gpt-4o"
42
39
},
43
40
"gpt-4o-mini": {
44
41
"OpenaiChat": "gpt-4o-mini",
@@ -46,7 +43,6 @@ model_map = {
46
43
"GithubCopilot": "gpt-4o-mini",
47
44
"OpenRouter": "openai/gpt-4o-mini-2024-07-18",
48
45
"Puter": "openrouter:openai/gpt-4o-mini-2024-07-18",
49
"WeWordle": "gpt-4o-mini"
50
46
},
51
47
"gpt-4o-mini-tts": {
52
48
"OpenAIFM": "coral",
@@ -422,7 +418,6 @@ model_map = {
422
418
"openrouter:deepseek/deepseek-r1:free",
423
419
"openrouter:deepseek/deepseek-r1"
424
420
],
425
"WeWordle": "v3"
426
421
},
427
422
"deepseek-r1-distill-llama-70b": {
428
423
"Together": "deepseek-r1-distill-llama-70b",
@@ -1171,7 +1166,6 @@ model_map = {
1171
1166
"HuggingChat": "deepseek-ai/DeepSeek-V3",
1172
1167
"PhindAi": "deepseek",
1173
1168
"Pollinations": "deepseek",
1174
"WeWordle": "v3"
1175
1169
},
1176
1170
"glm-4.5": {
1177
1171
"HuggingFace": "zai-org/GLM-4.5",
@@ -414,10 +414,10 @@ async def async_iter_run_tools(
414
414
usage_dict["saved_tokens"] = saved_tokens
415
415
prompt_tokens += saved_tokens
416
416
saved_percent = round(saved_tokens / prompt_tokens * 100) if prompt_tokens > 0 and saved_tokens > 0 else 0
417
debug.log(f"Token savings:", (f"{int(saved_tokens/1000)}k" if saved_tokens >= 1000 else str(saved_tokens)) + f"/{prompt_tokens} tokens ({saved_percent}%)")
417
debug.log(f"Saved tokens:", (f"{int(saved_tokens/1000)}k" if saved_tokens >= 1000 else str(saved_tokens)) + f"/{prompt_tokens} tokens ({saved_percent}%)")
418
418
cached_tokens = usage_dict.get("prompt_tokens_details", usage_dict).get("cached_tokens", 0)
419
419
if cached_tokens > 0:
420
debug.log(f"Cached tokens:", (f"{int(cached_tokens/1000)}k" if cached_tokens >= 1000 else str(cached_tokens)) + f"/{usage_dict.get('prompt_tokens', 0)} tokens ({round(cached_tokens / usage_dict.get('prompt_tokens', 1) * 100)}%)")
420
debug.log(f"Cached tokens:", (f"{int(cached_tokens/1000)}k" if cached_tokens >= 1000 else str(cached_tokens)) + f"/{prompt_tokens} tokens ({round(cached_tokens / prompt_tokens * 100)}%)")
421
421
usage = usage_dict
422
422
usage_dir = Path(get_cookies_dir()) / ".usage"
423
423
usage_file = usage_dir / f"{datetime.date.today()}.jsonl"