From 5986b4598d3f6bd0138dc2dfb651f48892b9dedc Mon Sep 17 00:00:00 2001 From: bowtiedbluefin <95500901+bowtiedbluefin@users.noreply.github.com> Date: Sat, 8 Nov 2025 02:34:08 -0500 Subject: [PATCH] Fix: OpenAI video API expects JSON, not multipart/form-data The error 'failed to parse JSON value' revealed that despite curl examples using -F flags, OpenAI's video API actually expects JSON POST requests. - Changed back to JSON format using _request() method - Simplified code by removing multipart/form-data handling - Kept debug logging for troubleshooting - Updated documentation to remove multipart/form-data mention This should resolve the 400 Bad Request error. --- QUICKSTART.md | 1 - utils/api_client.py | 56 ++++++++++++--------------------------------- 2 files changed, 15 insertions(+), 42 deletions(-) diff --git a/QUICKSTART.md b/QUICKSTART.md index 991c8e4..aa47b4e 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -124,7 +124,6 @@ models: - `duration` (integer) → `seconds` (e.g., 5) - `fps` is filtered out (not supported by OpenAI) - For image-to-video, connect an image input → `image` parameter -- OpenAI uses multipart/form-data (not JSON) - handled automatically ### 💾 Saving Video Locally diff --git a/utils/api_client.py b/utils/api_client.py index d8833bb..d292a24 100644 --- a/utils/api_client.py +++ b/utils/api_client.py @@ -205,8 +205,6 @@ class OpenAIAPIClient: """ Generate videos (OpenAI Video API) - OpenAI uses multipart/form-data, not JSON for video generation. - Args: model: Model identifier (required) prompt: Video description (required) @@ -226,52 +224,28 @@ class OpenAIAPIClient: Returns: Video generation response object """ - url = f"{self.base_url}/videos" - - # OpenAI uses multipart/form-data for video generation - # Build form fields - form_data = { - "model": (None, model), - "prompt": (None, prompt), + # OpenAI video API uses JSON, not multipart/form-data + data = { + "model": model, + "prompt": prompt, + **params } - # Add optional parameters as form fields - for key, value in params.items(): - if value is not None and value != "": - # Don't convert integers - keep them as is for proper form encoding - if isinstance(value, int): - form_data[key] = (None, str(value)) - else: - form_data[key] = (None, value) - - # Remove Content-Type header to let requests set it with boundary - headers = {k: v for k, v in self.session.headers.items() if k.lower() != 'content-type'} - # Debug logging print(f"[DEBUG] Video API Request:") - print(f" URL: {url}") - print(f" Model: {model}") - print(f" Prompt: {prompt}") - print(f" Additional params: {list(params.keys())}") + print(f" URL: {self.base_url}/videos") + print(f" Data: {json.dumps(data, indent=2)}") try: - response = self.session.post( - url, - files=form_data, - headers=headers, - timeout=self.timeout, - ) - response.raise_for_status() - return response.json() - except requests.exceptions.HTTPError as e: - error_details = "" - try: - error_details = e.response.text - except: - pass - raise Exception(f"Video generation failed: {str(e)}\nResponse: {error_details}") + response = self._request("POST", "/videos", json=data) + return response except Exception as e: - raise Exception(f"Video generation failed: {str(e)}") + # Extract error details if available + error_msg = str(e) + if "Response:" in error_msg: + raise Exception(f"Video generation failed: {error_msg}") + else: + raise Exception(f"Video generation failed: {str(e)}") def generate_speech( self,