返回提交历史
Modified
g4f/Provider/needs_auth/Video.py
+42
-25
Modified
g4f/image/copy_images.py
+13
-3
Modified
g4f/providers/response.py
+5
-0
Modified
g4f/requests/__init__.py
+2
-1
XFEstudio/gpt4free
Update copy_image
a354a2e8
代码差异
4 个文件
+62
-29
@@ -1,5 +1,6 @@
1
1
from __future__ import annotations
2
2
3
import time
3
4
import asyncio
4
5
import random
5
6
from aiohttp import ClientSession, ClientTimeout
@@ -13,7 +14,7 @@ except:
13
14
pass
14
15
15
16
from ...typing import Messages, AsyncResult
16
from ...providers.response import VideoResponse, Reasoning
17
from ...providers.response import VideoResponse, Reasoning, ContinueResponse
17
18
from ...requests import get_nodriver
18
19
from ...errors import MissingRequirementsError
19
20
from ..base_provider import AsyncGeneratorProvider
@@ -49,24 +50,34 @@ class Video(AsyncGeneratorProvider):
49
50
prompt: str = None,
50
51
**kwargs
51
52
) -> AsyncResult:
53
started = time.time()
52
54
prompt = format_media_prompt(messages, prompt)
53
55
if not prompt:
54
56
raise ValueError("Prompt cannot be empty.")
57
async with ClientSession() as session:
58
yield Reasoning(label="Lookup")
59
has_video = False
60
for skip in range(0, 9):
61
async with session.get(cls.search_url + quote_plus(prompt) + f"?skip={skip}", timeout=ClientTimeout(total=10)) as response:
62
if response.ok:
63
yield Reasoning(label=f"Found {skip+1}", status="")
64
yield VideoResponse(str(response.url), prompt)
65
has_video = True
66
else:
67
break
68
if has_video:
69
yield Reasoning(label=f"Finished", status="")
70
return
55
71
try:
72
yield Reasoning(label="Open browser")
56
73
browser, stop_browser = await get_nodriver(proxy=proxy, user_data_dir="gemini")
57
74
except Exception as e:
58
75
debug.error(f"Error getting nodriver:", e)
59
76
async with ClientSession() as session:
60
yield Reasoning(label="Lookup")
61
async with session.get(cls.search_url + quote_plus(prompt) + f"&min={prompt.count(' ') + 1}", timeout=ClientTimeout(total=10)) as response:
62
if response.status == 200:
63
yield Reasoning(label="Found", status="")
64
yield VideoResponse(str(response.url), prompt)
65
return
66
77
yield Reasoning(label="Generating")
67
78
async with session.post(cls.api_url + quote(prompt)) as response:
68
79
if not response.ok:
69
debug.error(f"Failed to lookup Video: {response.status}")
80
debug.error(f"Failed to generate Video: {response.status}")
70
81
else:
71
82
yield Reasoning(label="Finished", status="")
72
83
if response.headers.get("content-type", "text/plain").startswith("text/plain"):
@@ -92,20 +103,6 @@ class Video(AsyncGeneratorProvider):
92
103
page = cls.page
93
104
await asyncio.sleep(3)
94
105
await page.select("textarea", 240)
95
def on_request(event: nodriver.cdp.network.RequestWillBeSent, page=None):
96
if "mp4" in event.request.url:
97
RequestConfig.headers = {}
98
for key, value in event.request.headers.items():
99
RequestConfig.headers[key.lower()] = value
100
RequestConfig.urls.append(event.request.url)
101
elif event.request.url.startswith(cls.drive_url):
102
RequestConfig.headers = {}
103
for key, value in event.request.headers.items():
104
RequestConfig.headers[key.lower()] = value
105
RequestConfig.urls.append(event.request.url)
106
await page.send(nodriver.cdp.network.enable())
107
page.add_handler(nodriver.cdp.network.RequestWillBeSent, on_request)
108
109
106
try:
110
107
button = await page.find("Image")
111
108
if button:
@@ -115,6 +112,7 @@ class Video(AsyncGeneratorProvider):
115
112
button = await page.find("Video")
116
113
if button:
117
114
await button.click()
115
yield Reasoning(label=f"Clicked 'Video' button")
118
116
else:
119
117
debug.error("No 'Video' button found.")
120
118
except Exception as e:
@@ -122,6 +120,7 @@ class Video(AsyncGeneratorProvider):
122
120
debug.log(f"Using prompt: {prompt}")
123
121
textarea = await page.select("textarea", 180)
124
122
await textarea.send_keys(prompt)
123
yield Reasoning(label=f"Sending prompt", token=prompt)
125
124
# try:
126
125
# button = await page.select('button[type="submit"]', 5)
127
126
# if button:
@@ -131,12 +130,14 @@ class Video(AsyncGeneratorProvider):
131
130
button = await page.find("Create")
132
131
if button:
133
132
await button.click()
133
yield Reasoning(label=f"Clicked 'Create' button")
134
134
except Exception as e:
135
135
debug.error(f"Error clicking 'Create' button:", e)
136
136
try:
137
137
button = await page.find("Activity")
138
138
if button:
139
139
await button.click()
140
yield Reasoning(label=f"Clicked 'Activity' button")
140
141
except Exception as e:
141
142
debug.error(f"Error clicking 'Activity' button:", e)
142
143
for idx in range(60):
@@ -145,12 +146,27 @@ class Video(AsyncGeneratorProvider):
145
146
button = await page.find("Queued")
146
147
if button:
147
148
await button.click()
148
debug.log(f"Clicked 'Queued' button")
149
yield Reasoning(label=f"Clicked 'Queued' button")
149
150
break
150
except:
151
except Exception as e:
151
152
debug.error(f"Error clicking 'Queued' button:", e)
152
debug.log(f"Waiting for Video URL...")
153
yield Reasoning(label=f"Waiting for Video URL...")
154
def on_request(event: nodriver.cdp.network.RequestWillBeSent, page=None):
155
if "mp4" in event.request.url:
156
RequestConfig.headers = {}
157
for key, value in event.request.headers.items():
158
RequestConfig.headers[key.lower()] = value
159
RequestConfig.urls.append(event.request.url)
160
elif event.request.url.startswith(cls.drive_url):
161
RequestConfig.headers = {}
162
for key, value in event.request.headers.items():
163
RequestConfig.headers[key.lower()] = value
164
RequestConfig.urls.append(event.request.url)
165
await page.send(nodriver.cdp.network.enable())
166
page.add_handler(nodriver.cdp.network.RequestWillBeSent, on_request)
153
167
for idx in range(600):
168
if time.time() - started > 30:
169
yield ContinueResponse("Timeout waiting for Video URL")
154
170
await asyncio.sleep(1)
155
171
if RequestConfig.urls:
156
172
await asyncio.sleep(2)
@@ -159,6 +175,7 @@ class Video(AsyncGeneratorProvider):
159
175
yield VideoResponse(RequestConfig.urls, prompt, {
160
176
"headers": {"authorization": RequestConfig.headers.get("authorization")} if RequestConfig.headers.get("authorization") else {}
161
177
})
178
yield Reasoning(label=f"Finished", status="")
162
179
break
163
180
if idx == 599:
164
181
raise RuntimeError("Failed to get Video URL")
@@ -5,6 +5,7 @@ import time
5
5
import asyncio
6
6
import hashlib
7
7
import base64
8
from datetime import datetime
8
9
from typing import AsyncIterator
9
10
from urllib.parse import quote, unquote
10
11
from aiohttp import ClientSession, ClientError
@@ -135,14 +136,18 @@ async def copy_media(
135
136
if target_path is None:
136
137
# Build safe filename with full Unicode support
137
138
media_extension = get_media_extension(image)
138
filename = get_filename(tags, alt, media_extension, image)
139
path = urlparse(image).path
140
if path.startswith("/media/"):
141
filename = secure_filename(path[len("/media/"):])
142
else:
143
filename = get_filename(tags, alt, media_extension, image)
139
144
target_path = os.path.join(get_media_dir(), filename)
140
145
try:
141
146
# Handle different image types
142
147
if image.startswith("data:"):
143
148
with open(target_path, "wb") as f:
144
149
f.write(extract_data_uri(image))
145
else:
150
elif not os.path.exists(target_path) or os.lstat(target_path).st_size <= 0:
146
151
# Apply BackendApi settings if needed
147
152
if BackendApi.working and image.startswith(BackendApi.url):
148
153
request_headers = BackendApi.headers if headers is None else headers
@@ -151,9 +156,14 @@ async def copy_media(
151
156
request_headers = headers
152
157
request_ssl = ssl
153
158
# Use aiohttp to fetch the image
154
debug.log(f"Copying image: {image} to {target_path}")
155
159
async with session.get(image, ssl=request_ssl, headers=request_headers) as response:
156
160
response.raise_for_status()
161
date = response.headers.get("date")
162
if date and target_path != target:
163
timestamp = datetime.strptime(date, '%a, %d %b %Y %H:%M:%S %Z').timestamp()
164
filename = str(int(timestamp)) + "_" + filename.split("_", maxsplit=1)[-1]
165
target_path = os.path.join(get_media_dir(), filename)
166
debug.log(f"Copying image: {image} to {target_path}")
157
167
media_type = response.headers.get("content-type", "application/octet-stream")
158
168
if media_type not in ("application/octet-stream", "binary/octet-stream"):
159
169
if media_type not in MEDIA_TYPE_MAP:
@@ -192,6 +192,11 @@ class DebugResponse(HiddenResponse):
192
192
"""Initialize with a log message."""
193
193
self.log = log
194
194
195
class ContinueResponse(HiddenResponse):
196
def __init__(self, log: str) -> None:
197
"""Initialize with a log message."""
198
self.log = log
199
195
200
class Reasoning(ResponseType):
196
201
def __init__(
197
202
self,
@@ -146,7 +146,7 @@ def set_browser_executable_path(browser_executable_path: str):
146
146
async def get_nodriver(
147
147
proxy: str = None,
148
148
user_data_dir = "nodriver",
149
timeout: int = 120,
149
timeout: int = 300,
150
150
browser_executable_path: str = None,
151
151
**kwargs
152
152
) -> tuple[Browser, callable]:
@@ -172,6 +172,7 @@ async def get_nodriver(
172
172
time_open = time.time() - opend_at
173
173
if timeout * 2 > time_open:
174
174
debug.log(f"Nodriver: Browser is already in use since {time_open} secs.")
175
debug.log("Lock file:", lock_file)
175
176
for _ in range(timeout):
176
177
if lock_file.exists():
177
178
await asyncio.sleep(1)