mirror of
https://github.com/xtekky/gpt4free.git
synced 2025-10-30 03:01:50 +08:00
Update video provider
This commit is contained in:
@@ -22,28 +22,38 @@ from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
||||
from ..helper import format_media_prompt
|
||||
from ... import debug
|
||||
|
||||
PUBLIC_URL = "https://home.g4f.dev"
|
||||
SEARCH_URL = f"{PUBLIC_URL}/search/video+"
|
||||
|
||||
class RequestConfig:
|
||||
urls: dict[str, list[str]] = {}
|
||||
headers: dict = {}
|
||||
|
||||
@classmethod
|
||||
def get_response(cls, prompt: str) -> VideoResponse | None:
|
||||
async def get_response(cls, prompt: str) -> VideoResponse | None:
|
||||
if prompt in cls.urls and cls.urls[prompt]:
|
||||
cls.urls[prompt] = list(set(cls.urls[prompt]))
|
||||
debug.log(f"Video URL: {len(cls.urls[prompt])}")
|
||||
return VideoResponse(cls.urls[prompt], prompt, {
|
||||
"headers": {"authorization": cls.headers.get("authorization")} if cls.headers.get("authorization") else {},
|
||||
"preview": [url.replace("md.mp4", "thumb.webp") for url in cls.urls[prompt]]
|
||||
})
|
||||
async with ClientSession() as session:
|
||||
found_urls = []
|
||||
for skip in range(0, 9):
|
||||
async with session.get(SEARCH_URL + quote_plus(prompt) + f"?skip={skip}", timeout=ClientTimeout(total=10)) as response:
|
||||
if response.ok:
|
||||
found_urls.append(str(response.url))
|
||||
else:
|
||||
break
|
||||
if found_urls:
|
||||
return VideoResponse(found_urls, prompt)
|
||||
|
||||
class Video(AsyncGeneratorProvider, ProviderModelMixin):
|
||||
urls = [
|
||||
"https://sora.chatgpt.com/explore",
|
||||
#"https://aistudio.google.com/generate-video"
|
||||
]
|
||||
pub_url = "https://home.g4f.dev"
|
||||
api_url = f"{pub_url}/backend-api/v2/create?provider=Video&cache=true&prompt="
|
||||
search_url = f"{pub_url}/search/video+"
|
||||
api_url = f"{PUBLIC_URL}/backend-api/v2/create?provider=Video&cache=true&prompt="
|
||||
drive_url = "https://www.googleapis.com/drive/v3/"
|
||||
|
||||
active_by_default = True
|
||||
@@ -67,27 +77,12 @@ class Video(AsyncGeneratorProvider, ProviderModelMixin):
|
||||
**kwargs
|
||||
) -> AsyncResult:
|
||||
yield ProviderInfo(**cls.get_dict(), model="sora")
|
||||
started = time.time()
|
||||
prompt = format_media_prompt(messages, prompt)
|
||||
if not prompt:
|
||||
raise ValueError("Prompt cannot be empty.")
|
||||
async with ClientSession() as session:
|
||||
yield Reasoning(label="Lookup")
|
||||
found_urls = []
|
||||
for skip in range(0, 9):
|
||||
async with session.get(cls.search_url + quote_plus(prompt) + f"?skip={skip}", timeout=ClientTimeout(total=10)) as response:
|
||||
if response.ok:
|
||||
yield Reasoning(label=f"Found {skip+1}", status="")
|
||||
found_urls.append(str(response.url))
|
||||
else:
|
||||
break
|
||||
if found_urls:
|
||||
yield Reasoning(label=f"Finished", status="")
|
||||
yield VideoResponse(found_urls, prompt)
|
||||
return
|
||||
response = RequestConfig.get_response(prompt)
|
||||
response = await RequestConfig.get_response(prompt)
|
||||
if response:
|
||||
yield Reasoning(label="Found cached Video", status="")
|
||||
yield Reasoning(label=f"Found {len(response.urls)} Video(s)", status="")
|
||||
yield response
|
||||
return
|
||||
try:
|
||||
@@ -104,16 +99,17 @@ class Video(AsyncGeneratorProvider, ProviderModelMixin):
|
||||
yield Reasoning(label="Finished", status="")
|
||||
if response.headers.get("content-type", "text/plain").startswith("text/plain"):
|
||||
data = (await response.text()).split("\n")
|
||||
yield VideoResponse([f"{cls.pub_url}{url}" if url.startswith("/") else url for url in data], prompt)
|
||||
yield VideoResponse([f"{PUBLIC_URL}{url}" if url.startswith("/") else url for url in data], prompt)
|
||||
return
|
||||
yield VideoResponse(str(response.url), prompt)
|
||||
return
|
||||
raise MissingRequirementsError("Video provider requires a browser to be installed.")
|
||||
try:
|
||||
yield ContinueResponse("Timeout waiting for Video URL")
|
||||
cls.page = await browser.get(random.choice(cls.urls))
|
||||
except Exception as e:
|
||||
debug.error(f"Error opening page:", e)
|
||||
response = RequestConfig.get_response(prompt)
|
||||
response = await RequestConfig.get_response(prompt)
|
||||
if response:
|
||||
yield Reasoning(label="Found", status="")
|
||||
yield response
|
||||
@@ -138,11 +134,12 @@ class Video(AsyncGeneratorProvider, ProviderModelMixin):
|
||||
debug.error(f"Error clicking button:", e)
|
||||
try:
|
||||
if aspect_ratio:
|
||||
button = await page.find("2:3")
|
||||
button = await page.find(":")
|
||||
if button:
|
||||
await button.click()
|
||||
else:
|
||||
debug.error("No '2:3' button found.")
|
||||
debug.error("No 'x:x' button found.")
|
||||
await asyncio.sleep(1)
|
||||
button = await page.find(aspect_ratio)
|
||||
if button:
|
||||
await button.click()
|
||||
@@ -200,13 +197,11 @@ class Video(AsyncGeneratorProvider, ProviderModelMixin):
|
||||
await page.send(nodriver.cdp.network.enable())
|
||||
page.add_handler(nodriver.cdp.network.RequestWillBeSent, on_request)
|
||||
for idx in range(600):
|
||||
yield Reasoning(label=f"Waiting for Video... {idx+1}/600")
|
||||
if time.time() - started > 30:
|
||||
yield ContinueResponse("Timeout waiting for Video URL")
|
||||
yield Reasoning(label="Waiting for Video...", status=f"{idx+1}/600")
|
||||
await asyncio.sleep(1)
|
||||
if RequestConfig.urls[prompt]:
|
||||
await asyncio.sleep(2)
|
||||
response = RequestConfig.get_response(prompt)
|
||||
response = await RequestConfig.get_response(prompt)
|
||||
if response:
|
||||
yield Reasoning(label="Finished", status="")
|
||||
yield response
|
||||
|
||||
@@ -94,6 +94,12 @@ async def lifespan(app: FastAPI):
|
||||
for browser in util.get_registered_instances():
|
||||
if browser.connection:
|
||||
browser.stop()
|
||||
lock_file = os.path.join(get_cookies_dir(), ".nodriver_is_open")
|
||||
if os.path.exists(lock_file):
|
||||
try:
|
||||
os.remove(lock_file)
|
||||
except Exception as e:
|
||||
debug.error(f"Failed to remove lock file {lock_file}:" ,e)
|
||||
|
||||
def create_app():
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
@@ -549,8 +549,10 @@ class Images:
|
||||
|
||||
async def async_create_variation(
|
||||
self,
|
||||
*,
|
||||
image: ImageType,
|
||||
image_name: str = None,
|
||||
prompt: str = "Create a variation of this image",
|
||||
model: Optional[str] = None,
|
||||
provider: Optional[ProviderType] = None,
|
||||
response_format: Optional[str] = None,
|
||||
@@ -561,7 +563,6 @@ class Images:
|
||||
provider_name = provider_handler.__name__ if hasattr(provider_handler, "__name__") else type(provider_handler).__name__
|
||||
if proxy is None:
|
||||
proxy = self.client.proxy
|
||||
prompt = "create a variation of this image"
|
||||
resolve_media(kwargs, image, image_name)
|
||||
error = None
|
||||
response = None
|
||||
@@ -618,7 +619,7 @@ class Images:
|
||||
images = await asyncio.gather(*[get_b64_from_url(image) for image in response.get_list()])
|
||||
else:
|
||||
# Save locally for None (default) case
|
||||
if download_media or response.get("cookies"):
|
||||
if download_media or response.get("cookies") or response.get("headers"):
|
||||
images = await copy_media(response.get_list(), response.get("cookies"), response.get("headers"), proxy, response.alt)
|
||||
images = [Image.model_construct(url=image, revised_prompt=response.alt) for image in images]
|
||||
|
||||
|
||||
@@ -435,14 +435,16 @@ class Backend_Api(Api):
|
||||
return jsonify({"error": {"message": "Not found"}}), 404
|
||||
if search not in self.match_files:
|
||||
self.match_files[search] = {}
|
||||
found_mime_type = False
|
||||
for root, _, files in os.walk(media_dir):
|
||||
for file in files:
|
||||
mime_type = is_allowed_extension(file)
|
||||
if mime_type is not None:
|
||||
mime_type = secure_filename(mime_type)
|
||||
if safe_search[0] in mime_type:
|
||||
found_mime_type = True
|
||||
self.match_files[search][file] = self.match_files[search].get(file, 0) + 1
|
||||
for tag in safe_search:
|
||||
for tag in safe_search[1:] if found_mime_type else safe_search:
|
||||
if tag in file.lower():
|
||||
self.match_files[search][file] = self.match_files[search].get(file, 0) + 1
|
||||
break
|
||||
|
||||
@@ -188,9 +188,8 @@ async def copy_media(
|
||||
target_path = f"{target_path}{media_extension}"
|
||||
except ValueError:
|
||||
pass
|
||||
# Build URL with safe encoding
|
||||
url_filename = quote(os.path.basename(target_path))
|
||||
return f"/media/{url_filename}" + ('?' + (add_url if isinstance(add_url, str) else '' + 'url=' + quote(image)) if add_url and not image.startswith('data:') else '')
|
||||
# Build URL relative to media directory
|
||||
return f"/media/{os.path.basename(target_path)}" + ('?' + (add_url if isinstance(add_url, str) else '' + 'url=' + quote(image)) if add_url and not image.startswith('data:') else '')
|
||||
|
||||
except (ClientError, IOError, OSError, ValueError) as e:
|
||||
debug.error(f"Image copying failed:", e)
|
||||
|
||||
Reference in New Issue
Block a user