metaai-sdk 2.3.4__py3-none-any.whl → 2.3.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- metaai_api/main.py +154 -32
- metaai_api/video_generation.py +83 -33
- {metaai_sdk-2.3.4.dist-info → metaai_sdk-2.3.5.dist-info}/METADATA +45 -9
- {metaai_sdk-2.3.4.dist-info → metaai_sdk-2.3.5.dist-info}/RECORD +7 -7
- {metaai_sdk-2.3.4.dist-info → metaai_sdk-2.3.5.dist-info}/WHEEL +1 -1
- {metaai_sdk-2.3.4.dist-info → metaai_sdk-2.3.5.dist-info}/licenses/LICENSE +0 -0
- {metaai_sdk-2.3.4.dist-info → metaai_sdk-2.3.5.dist-info}/top_level.txt +0 -0
metaai_api/main.py
CHANGED
|
@@ -141,6 +141,7 @@ class MetaAI:
|
|
|
141
141
|
media_ids: Optional[list] = None,
|
|
142
142
|
attachment_metadata: Optional[Dict[str, Any]] = None,
|
|
143
143
|
is_image_generation: bool = False,
|
|
144
|
+
orientation: Optional[str] = None,
|
|
144
145
|
) -> Union[Dict, Generator[Dict, None, None]]:
|
|
145
146
|
"""
|
|
146
147
|
Sends a message to the Meta AI and returns the response.
|
|
@@ -154,6 +155,7 @@ class MetaAI:
|
|
|
154
155
|
media_ids (list): List of media IDs from uploaded images to include in the prompt. Defaults to None.
|
|
155
156
|
attachment_metadata (dict): Optional dict with 'file_size' (int) and 'mime_type' (str). Defaults to None.
|
|
156
157
|
is_image_generation (bool): Whether this is for image generation (vs chat). Defaults to False.
|
|
158
|
+
orientation (str): Image orientation for generation. Valid values: "LANDSCAPE", "VERTICAL", "SQUARE". Defaults to "VERTICAL".
|
|
157
159
|
|
|
158
160
|
Returns:
|
|
159
161
|
dict: A dictionary containing the response message and sources.
|
|
@@ -167,7 +169,10 @@ class MetaAI:
|
|
|
167
169
|
url = "https://graph.meta.ai/graphql?locale=user"
|
|
168
170
|
|
|
169
171
|
else:
|
|
170
|
-
auth_payload = {
|
|
172
|
+
auth_payload = {
|
|
173
|
+
"fb_dtsg": self.cookies["fb_dtsg"],
|
|
174
|
+
"lsd": self.cookies.get("lsd", ""),
|
|
175
|
+
}
|
|
171
176
|
url = "https://www.meta.ai/api/graphql/"
|
|
172
177
|
|
|
173
178
|
if not self.external_conversation_id or new_conversation:
|
|
@@ -186,13 +191,15 @@ class MetaAI:
|
|
|
186
191
|
|
|
187
192
|
# Generate offline threading IDs
|
|
188
193
|
offline_threading_id = generate_offline_threading_id()
|
|
194
|
+
bot_offline_threading_id = str(int(offline_threading_id) + 1)
|
|
195
|
+
thread_session_id = str(uuid.uuid4())
|
|
189
196
|
|
|
190
197
|
# Determine entrypoint based on context
|
|
191
198
|
if images:
|
|
192
199
|
# Video generation with images uses CHAT
|
|
193
200
|
entrypoint = "KADABRA__CHAT__UNIFIED_INPUT_BAR"
|
|
194
|
-
elif media_ids:
|
|
195
|
-
#
|
|
201
|
+
elif media_ids or orientation:
|
|
202
|
+
# Image generation with orientation OR uploaded images uses DISCOVER
|
|
196
203
|
entrypoint = "KADABRA__DISCOVER__UNIFIED_INPUT_BAR"
|
|
197
204
|
else:
|
|
198
205
|
entrypoint = "ABRA__CHAT__TEXT"
|
|
@@ -200,42 +207,154 @@ class MetaAI:
|
|
|
200
207
|
# Set friendly name based on entrypoint
|
|
201
208
|
friendly_name = "useKadabraSendMessageMutation" if entrypoint.startswith("KADABRA") else "useAbraSendMessageMutation"
|
|
202
209
|
|
|
210
|
+
# Build variables dictionary
|
|
211
|
+
is_kadabra = entrypoint.startswith("KADABRA")
|
|
212
|
+
|
|
213
|
+
if is_kadabra:
|
|
214
|
+
# Full Kadabra variables for image generation
|
|
215
|
+
variables = {
|
|
216
|
+
"message": {"sensitive_string_value": message},
|
|
217
|
+
"externalConversationId": self.external_conversation_id,
|
|
218
|
+
"offlineThreadingId": offline_threading_id,
|
|
219
|
+
"threadSessionId": thread_session_id,
|
|
220
|
+
"isNewConversation": new_conversation or not self.offline_threading_id,
|
|
221
|
+
"suggestedPromptIndex": None,
|
|
222
|
+
"promptPrefix": None,
|
|
223
|
+
"entrypoint": entrypoint,
|
|
224
|
+
"attachments": [],
|
|
225
|
+
"attachmentsV2": attachments_v2,
|
|
226
|
+
"activeMediaSets": [],
|
|
227
|
+
"activeCardVersions": [],
|
|
228
|
+
"activeArtifactVersion": None,
|
|
229
|
+
"userUploadEditModeInput": None,
|
|
230
|
+
"reelComposeInput": None,
|
|
231
|
+
"qplJoinId": uuid.uuid4().hex[:17],
|
|
232
|
+
"sourceRemixPostId": None,
|
|
233
|
+
"gkPlannerOrReasoningEnabled": True,
|
|
234
|
+
"selectedModel": "BASIC_OPTION",
|
|
235
|
+
"conversationMode": None,
|
|
236
|
+
"selectedAgentType": "PLANNER",
|
|
237
|
+
"agentSettings": None,
|
|
238
|
+
"conversationStarterId": None,
|
|
239
|
+
"promptType": None,
|
|
240
|
+
"artifactRewriteOptions": None,
|
|
241
|
+
"imagineOperationRequest": None,
|
|
242
|
+
"imagineClientOptions": {"orientation": orientation.upper() if orientation else "VERTICAL"},
|
|
243
|
+
"spaceId": None,
|
|
244
|
+
"sparkSnapshotId": None,
|
|
245
|
+
"topicPageId": None,
|
|
246
|
+
"includeSpace": False,
|
|
247
|
+
"storybookId": None,
|
|
248
|
+
"messagePersistentInput": {
|
|
249
|
+
"attachment_size": attachment_metadata.get('file_size') if attachment_metadata else None,
|
|
250
|
+
"attachment_type": attachment_metadata.get('mime_type') if attachment_metadata else None,
|
|
251
|
+
"bot_message_offline_threading_id": bot_offline_threading_id,
|
|
252
|
+
"conversation_mode": None,
|
|
253
|
+
"external_conversation_id": self.external_conversation_id,
|
|
254
|
+
"is_new_conversation": new_conversation or not self.offline_threading_id,
|
|
255
|
+
"meta_ai_entry_point": entrypoint,
|
|
256
|
+
"offline_threading_id": offline_threading_id,
|
|
257
|
+
"prompt_id": None,
|
|
258
|
+
"prompt_session_id": thread_session_id,
|
|
259
|
+
},
|
|
260
|
+
"alakazam_enabled": True,
|
|
261
|
+
"skipInFlightMessageWithParams": None,
|
|
262
|
+
"__relay_internal__pv__KadabraSocialSearchEnabledrelayprovider": False,
|
|
263
|
+
"__relay_internal__pv__KadabraZeitgeistEnabledrelayprovider": False,
|
|
264
|
+
"__relay_internal__pv__alakazam_enabledrelayprovider": True,
|
|
265
|
+
"__relay_internal__pv__sp_kadabra_survey_invitationrelayprovider": True,
|
|
266
|
+
"__relay_internal__pv__enable_kadabra_partial_resultsrelayprovider": False,
|
|
267
|
+
"__relay_internal__pv__AbraArtifactsEnabledrelayprovider": True,
|
|
268
|
+
"__relay_internal__pv__KadabraMemoryEnabledrelayprovider": False,
|
|
269
|
+
"__relay_internal__pv__AbraPlannerEnabledrelayprovider": True,
|
|
270
|
+
"__relay_internal__pv__AbraWidgetsEnabledrelayprovider": False,
|
|
271
|
+
"__relay_internal__pv__KadabraDeepResearchEnabledrelayprovider": False,
|
|
272
|
+
"__relay_internal__pv__KadabraThinkHarderEnabledrelayprovider": False,
|
|
273
|
+
"__relay_internal__pv__KadabraVergeEnabledrelayprovider": False,
|
|
274
|
+
"__relay_internal__pv__KadabraSpacesEnabledrelayprovider": False,
|
|
275
|
+
"__relay_internal__pv__KadabraProductSearchEnabledrelayprovider": False,
|
|
276
|
+
"__relay_internal__pv__KadabraAreServiceEnabledrelayprovider": False,
|
|
277
|
+
"__relay_internal__pv__kadabra_render_reasoning_response_statesrelayprovider": True,
|
|
278
|
+
"__relay_internal__pv__kadabra_reasoning_cotrelayprovider": False,
|
|
279
|
+
"__relay_internal__pv__AbraSearchInlineReferencesEnabledrelayprovider": True,
|
|
280
|
+
"__relay_internal__pv__AbraComposedTextWidgetsrelayprovider": True,
|
|
281
|
+
"__relay_internal__pv__KadabraNewCitationsEnabledrelayprovider": True,
|
|
282
|
+
"__relay_internal__pv__WebPixelRatiorelayprovider": 1,
|
|
283
|
+
"__relay_internal__pv__KadabraVideoDeliveryRequestrelayprovider": {
|
|
284
|
+
"dash_manifest_requests": [{}],
|
|
285
|
+
"progressive_url_requests": [{"quality": "HD"}, {"quality": "SD"}]
|
|
286
|
+
},
|
|
287
|
+
"__relay_internal__pv__KadabraWidgetsRedesignEnabledrelayprovider": False,
|
|
288
|
+
"__relay_internal__pv__kadabra_enable_send_message_retryrelayprovider": True,
|
|
289
|
+
"__relay_internal__pv__KadabraEmailCalendarIntegrationrelayprovider": False,
|
|
290
|
+
"__relay_internal__pv__ClippyUIrelayprovider": False,
|
|
291
|
+
"__relay_internal__pv__kadabra_reels_connect_featuresrelayprovider": False,
|
|
292
|
+
"__relay_internal__pv__AbraBugNubrelayprovider": False,
|
|
293
|
+
"__relay_internal__pv__AbraRedteamingrelayprovider": False,
|
|
294
|
+
"__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
|
|
295
|
+
"__relay_internal__pv__kadabra_enable_open_in_editor_message_actionrelayprovider": True,
|
|
296
|
+
"__relay_internal__pv__BloksDeviceContextrelayprovider": {"pixel_ratio": 1},
|
|
297
|
+
"__relay_internal__pv__AbraThreadsEnabledrelayprovider": False,
|
|
298
|
+
"__relay_internal__pv__kadabra_story_builder_enabledrelayprovider": False,
|
|
299
|
+
"__relay_internal__pv__kadabra_imagine_canvas_enable_dev_settingsrelayprovider": False,
|
|
300
|
+
"__relay_internal__pv__kadabra_create_media_deletionrelayprovider": False,
|
|
301
|
+
"__relay_internal__pv__kadabra_moodboardrelayprovider": False,
|
|
302
|
+
"__relay_internal__pv__AbraArtifactDragImagineFromConversationrelayprovider": True,
|
|
303
|
+
"__relay_internal__pv__kadabra_media_item_renderer_heightrelayprovider": 545,
|
|
304
|
+
"__relay_internal__pv__kadabra_media_item_renderer_widthrelayprovider": 620,
|
|
305
|
+
"__relay_internal__pv__AbraQPDocUploadNuxTriggerNamerelayprovider": "meta_dot_ai_abra_web_doc_upload_nux_tour",
|
|
306
|
+
"__relay_internal__pv__AbraSurfaceNuxIDrelayprovider": "12177",
|
|
307
|
+
"__relay_internal__pv__KadabraConversationRenamingrelayprovider": True,
|
|
308
|
+
"__relay_internal__pv__AbraIsLoggedOutrelayprovider": not self.is_authed,
|
|
309
|
+
"__relay_internal__pv__KadabraCanvasDisplayHeaderV2relayprovider": False,
|
|
310
|
+
"__relay_internal__pv__AbraArtifactEditorDebugModerelayprovider": False,
|
|
311
|
+
"__relay_internal__pv__AbraArtifactEditorDownloadHTMLEnabledrelayprovider": False,
|
|
312
|
+
"__relay_internal__pv__kadabra_create_row_hover_optionsrelayprovider": False,
|
|
313
|
+
"__relay_internal__pv__kadabra_media_info_pillsrelayprovider": True,
|
|
314
|
+
"__relay_internal__pv__KadabraConcordInternalProfileBadgeEnabledrelayprovider": False,
|
|
315
|
+
"__relay_internal__pv__KadabraSocialGraphrelayprovider": True,
|
|
316
|
+
}
|
|
317
|
+
else:
|
|
318
|
+
# Simpler Abra variables for chat
|
|
319
|
+
variables = {
|
|
320
|
+
"message": {"sensitive_string_value": message},
|
|
321
|
+
"externalConversationId": self.external_conversation_id,
|
|
322
|
+
"offlineThreadingId": offline_threading_id,
|
|
323
|
+
"suggestedPromptIndex": None,
|
|
324
|
+
"flashVideoRecapInput": flash_video_input,
|
|
325
|
+
"flashPreviewInput": None,
|
|
326
|
+
"promptPrefix": None,
|
|
327
|
+
"entrypoint": entrypoint,
|
|
328
|
+
"attachments": [],
|
|
329
|
+
"attachmentsV2": attachments_v2,
|
|
330
|
+
"messagePersistentInput": {
|
|
331
|
+
"attachment_size": attachment_metadata.get('file_size') if attachment_metadata else None,
|
|
332
|
+
"attachment_type": attachment_metadata.get('mime_type') if attachment_metadata else None,
|
|
333
|
+
"external_conversation_id": self.external_conversation_id,
|
|
334
|
+
"offline_threading_id": offline_threading_id,
|
|
335
|
+
"meta_ai_entry_point": entrypoint,
|
|
336
|
+
} if media_ids else None,
|
|
337
|
+
"icebreaker_type": "TEXT",
|
|
338
|
+
"__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
|
|
339
|
+
"__relay_internal__pv__WebPixelRatiorelayprovider": 1,
|
|
340
|
+
}
|
|
341
|
+
|
|
203
342
|
payload = {
|
|
204
343
|
**auth_payload,
|
|
205
344
|
"fb_api_caller_class": "RelayModern",
|
|
206
345
|
"fb_api_req_friendly_name": friendly_name,
|
|
207
|
-
"variables": json.dumps(
|
|
208
|
-
{
|
|
209
|
-
"message": {"sensitive_string_value": message},
|
|
210
|
-
"externalConversationId": self.external_conversation_id,
|
|
211
|
-
"offlineThreadingId": offline_threading_id,
|
|
212
|
-
"suggestedPromptIndex": None,
|
|
213
|
-
"flashVideoRecapInput": flash_video_input,
|
|
214
|
-
"flashPreviewInput": None,
|
|
215
|
-
"promptPrefix": None,
|
|
216
|
-
"entrypoint": entrypoint,
|
|
217
|
-
"attachments": [],
|
|
218
|
-
"attachmentsV2": attachments_v2,
|
|
219
|
-
"messagePersistentInput": {
|
|
220
|
-
"attachment_size": attachment_metadata.get('file_size') if attachment_metadata else None,
|
|
221
|
-
"attachment_type": attachment_metadata.get('mime_type') if attachment_metadata else None,
|
|
222
|
-
"external_conversation_id": self.external_conversation_id,
|
|
223
|
-
"offline_threading_id": offline_threading_id,
|
|
224
|
-
"meta_ai_entry_point": entrypoint,
|
|
225
|
-
} if media_ids else None,
|
|
226
|
-
"icebreaker_type": "TEXT",
|
|
227
|
-
"__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
|
|
228
|
-
"__relay_internal__pv__WebPixelRatiorelayprovider": 1,
|
|
229
|
-
}
|
|
230
|
-
),
|
|
346
|
+
"variables": json.dumps(variables),
|
|
231
347
|
"server_timestamps": "true",
|
|
232
|
-
"doc_id": "
|
|
348
|
+
"doc_id": "24895882500088854" if is_kadabra else "7783822248314888",
|
|
233
349
|
}
|
|
234
350
|
payload = urllib.parse.urlencode(payload) # noqa
|
|
235
351
|
headers = {
|
|
236
352
|
"content-type": "application/x-www-form-urlencoded",
|
|
237
353
|
"x-fb-friendly-name": friendly_name,
|
|
238
354
|
}
|
|
355
|
+
# Add lsd header for authenticated requests
|
|
356
|
+
if self.cookies.get("lsd"):
|
|
357
|
+
headers["x-fb-lsd"] = self.cookies["lsd"]
|
|
239
358
|
if self.is_authed:
|
|
240
359
|
headers["cookie"] = f'abra_sess={self.cookies["abra_sess"]}'
|
|
241
360
|
# Recreate the session to avoid cookie leakage when user is authenticated
|
|
@@ -248,7 +367,7 @@ class MetaAI:
|
|
|
248
367
|
raw_response = response.text
|
|
249
368
|
last_streamed_response = self.extract_last_response(raw_response)
|
|
250
369
|
if not last_streamed_response:
|
|
251
|
-
return self.retry(message, stream=stream, attempts=attempts, media_ids=media_ids, attachment_metadata=attachment_metadata, is_image_generation=is_image_generation)
|
|
370
|
+
return self.retry(message, stream=stream, attempts=attempts, new_conversation=new_conversation, images=images, media_ids=media_ids, attachment_metadata=attachment_metadata, is_image_generation=is_image_generation, orientation=orientation)
|
|
252
371
|
|
|
253
372
|
extracted_data = self.extract_data(last_streamed_response)
|
|
254
373
|
return extracted_data
|
|
@@ -257,10 +376,10 @@ class MetaAI:
|
|
|
257
376
|
lines = response.iter_lines()
|
|
258
377
|
is_error = json.loads(next(lines))
|
|
259
378
|
if len(is_error.get("errors", [])) > 0:
|
|
260
|
-
return self.retry(message, stream=stream, attempts=attempts, media_ids=media_ids, attachment_metadata=attachment_metadata, is_image_generation=is_image_generation)
|
|
379
|
+
return self.retry(message, stream=stream, attempts=attempts, new_conversation=new_conversation, images=images, media_ids=media_ids, attachment_metadata=attachment_metadata, is_image_generation=is_image_generation, orientation=orientation)
|
|
261
380
|
return self.stream_response(lines)
|
|
262
381
|
|
|
263
|
-
def retry(self, message: str, stream: bool = False, attempts: int = 0, media_ids: Optional[list] = None, attachment_metadata: Optional[Dict[str, Any]] = None, is_image_generation: bool = False):
|
|
382
|
+
def retry(self, message: str, stream: bool = False, attempts: int = 0, new_conversation: bool = False, images: Optional[list] = None, media_ids: Optional[list] = None, attachment_metadata: Optional[Dict[str, Any]] = None, is_image_generation: bool = False, orientation: Optional[str] = None):
|
|
264
383
|
"""
|
|
265
384
|
Retries the prompt function if an error occurs.
|
|
266
385
|
"""
|
|
@@ -269,7 +388,7 @@ class MetaAI:
|
|
|
269
388
|
f"Was unable to obtain a valid response from Meta AI. Retrying... Attempt {attempts + 1}/{MAX_RETRIES}."
|
|
270
389
|
)
|
|
271
390
|
time.sleep(3)
|
|
272
|
-
return self.prompt(message, stream=stream, attempts=attempts + 1, media_ids=media_ids, attachment_metadata=attachment_metadata, is_image_generation=is_image_generation)
|
|
391
|
+
return self.prompt(message, stream=stream, attempts=attempts + 1, new_conversation=new_conversation, images=images, media_ids=media_ids, attachment_metadata=attachment_metadata, is_image_generation=is_image_generation, orientation=orientation)
|
|
273
392
|
else:
|
|
274
393
|
raise Exception(
|
|
275
394
|
"Unable to obtain a valid response from Meta AI. Try again later."
|
|
@@ -587,6 +706,7 @@ class MetaAI:
|
|
|
587
706
|
prompt: str,
|
|
588
707
|
media_ids: Optional[list] = None,
|
|
589
708
|
attachment_metadata: Optional[Dict[str, Any]] = None,
|
|
709
|
+
orientation: Optional[str] = None,
|
|
590
710
|
wait_before_poll: int = 10,
|
|
591
711
|
max_attempts: int = 30,
|
|
592
712
|
wait_seconds: int = 5,
|
|
@@ -600,6 +720,7 @@ class MetaAI:
|
|
|
600
720
|
prompt: Text prompt for video generation
|
|
601
721
|
media_ids: Optional list of media IDs from uploaded images
|
|
602
722
|
attachment_metadata: Optional dict with 'file_size' (int) and 'mime_type' (str)
|
|
723
|
+
orientation: Video orientation. Valid values: "LANDSCAPE", "VERTICAL", "SQUARE". Defaults to None.
|
|
603
724
|
wait_before_poll: Seconds to wait before starting to poll (default: 10)
|
|
604
725
|
max_attempts: Maximum polling attempts (default: 30)
|
|
605
726
|
wait_seconds: Seconds between polling attempts (default: 5)
|
|
@@ -633,6 +754,7 @@ class MetaAI:
|
|
|
633
754
|
prompt=prompt,
|
|
634
755
|
media_ids=media_ids,
|
|
635
756
|
attachment_metadata=attachment_metadata,
|
|
757
|
+
orientation=orientation,
|
|
636
758
|
wait_before_poll=wait_before_poll,
|
|
637
759
|
max_attempts=max_attempts,
|
|
638
760
|
wait_seconds=wait_seconds,
|
metaai_api/video_generation.py
CHANGED
|
@@ -92,6 +92,7 @@ class VideoGenerator:
|
|
|
92
92
|
prompt: str,
|
|
93
93
|
media_ids: Optional[List[str]] = None,
|
|
94
94
|
attachment_metadata: Optional[Dict[str, Any]] = None,
|
|
95
|
+
orientation: Optional[str] = None,
|
|
95
96
|
verbose: bool = True
|
|
96
97
|
) -> Dict:
|
|
97
98
|
"""
|
|
@@ -103,6 +104,7 @@ class VideoGenerator:
|
|
|
103
104
|
prompt: Text prompt for video generation
|
|
104
105
|
media_ids: Optional list of media IDs from uploaded images
|
|
105
106
|
attachment_metadata: Optional dict with 'file_size' (int) and 'mime_type' (str)
|
|
107
|
+
orientation: Video orientation ("LANDSCAPE", "VERTICAL", "SQUARE"). Defaults to "VERTICAL".
|
|
106
108
|
verbose: Whether to print status messages
|
|
107
109
|
|
|
108
110
|
Returns:
|
|
@@ -113,11 +115,12 @@ class VideoGenerator:
|
|
|
113
115
|
cookies_str="datr=...; abra_sess=...",
|
|
114
116
|
prompt="Generate a video of a sunset",
|
|
115
117
|
media_ids=["1234567890"],
|
|
116
|
-
attachment_metadata={'file_size': 3310, 'mime_type': 'image/jpeg'}
|
|
118
|
+
attachment_metadata={'file_size': 3310, 'mime_type': 'image/jpeg'},
|
|
119
|
+
orientation="LANDSCAPE"
|
|
117
120
|
)
|
|
118
121
|
"""
|
|
119
122
|
generator = cls(cookies_str=cookies_str)
|
|
120
|
-
return generator.generate_video(prompt=prompt, media_ids=media_ids, attachment_metadata=attachment_metadata, verbose=verbose)
|
|
123
|
+
return generator.generate_video(prompt=prompt, media_ids=media_ids, attachment_metadata=attachment_metadata, orientation=orientation, verbose=verbose)
|
|
121
124
|
|
|
122
125
|
def build_headers(
|
|
123
126
|
self,
|
|
@@ -169,6 +172,7 @@ class VideoGenerator:
|
|
|
169
172
|
prompt_text: str,
|
|
170
173
|
media_ids: Optional[List[str]] = None,
|
|
171
174
|
attachment_metadata: Optional[Dict[str, Any]] = None,
|
|
175
|
+
orientation: Optional[str] = None,
|
|
172
176
|
verbose: bool = True
|
|
173
177
|
) -> Optional[str]:
|
|
174
178
|
"""
|
|
@@ -178,6 +182,7 @@ class VideoGenerator:
|
|
|
178
182
|
prompt_text: The text prompt for video generation
|
|
179
183
|
media_ids: Optional list of media IDs from uploaded images
|
|
180
184
|
attachment_metadata: Optional dict with 'file_size' (int) and 'mime_type' (str)
|
|
185
|
+
orientation: Video orientation ("LANDSCAPE", "VERTICAL", "SQUARE"). Defaults to "VERTICAL".
|
|
181
186
|
verbose: Whether to print status messages
|
|
182
187
|
|
|
183
188
|
Returns:
|
|
@@ -231,7 +236,7 @@ class VideoGenerator:
|
|
|
231
236
|
"promptType": None,
|
|
232
237
|
"artifactRewriteOptions": None,
|
|
233
238
|
"imagineOperationRequest": None,
|
|
234
|
-
"imagineClientOptions": {"orientation": "VERTICAL"},
|
|
239
|
+
"imagineClientOptions": {"orientation": orientation.upper() if orientation else "VERTICAL"},
|
|
235
240
|
"spaceId": None,
|
|
236
241
|
"sparkSnapshotId": None,
|
|
237
242
|
"topicPageId": None,
|
|
@@ -306,7 +311,7 @@ class VideoGenerator:
|
|
|
306
311
|
"__relay_internal__pv__KadabraSocialGraphrelayprovider": True
|
|
307
312
|
}, separators=(',', ':'))
|
|
308
313
|
|
|
309
|
-
print(variables)
|
|
314
|
+
# print(variables)
|
|
310
315
|
|
|
311
316
|
# Build raw multipart body (exactly as in working example)
|
|
312
317
|
spin_t = str(int(time.time()))
|
|
@@ -468,6 +473,9 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
468
473
|
Returns:
|
|
469
474
|
List of video URLs
|
|
470
475
|
"""
|
|
476
|
+
import logging
|
|
477
|
+
logger = logging.getLogger(__name__)
|
|
478
|
+
|
|
471
479
|
# Build headers with query-specific friendly name
|
|
472
480
|
headers = self.build_headers(
|
|
473
481
|
content_type='application/x-www-form-urlencoded',
|
|
@@ -566,6 +574,9 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
566
574
|
|
|
567
575
|
for attempt in range(1, max_attempts + 1):
|
|
568
576
|
try:
|
|
577
|
+
if verbose and attempt % 5 == 1: # Log every 5th attempt
|
|
578
|
+
logger.info(f"[VIDEO POLLING] Attempt {attempt}/{max_attempts} for conversation {conversation_id}")
|
|
579
|
+
|
|
569
580
|
response = requests.post(
|
|
570
581
|
self.GRAPHQL_URL,
|
|
571
582
|
cookies=self.cookies,
|
|
@@ -575,29 +586,44 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
575
586
|
)
|
|
576
587
|
|
|
577
588
|
if response.status_code == 200:
|
|
578
|
-
# Extract video URLs from response
|
|
579
|
-
|
|
589
|
+
# Extract video URLs from response, passing attempt info to reduce noise
|
|
590
|
+
is_final_attempt = (attempt == max_attempts)
|
|
591
|
+
video_urls = self._extract_video_urls_from_response(
|
|
592
|
+
response.text,
|
|
593
|
+
is_final_attempt=is_final_attempt
|
|
594
|
+
)
|
|
580
595
|
|
|
581
596
|
if video_urls:
|
|
597
|
+
if verbose:
|
|
598
|
+
logger.info(f"[VIDEO POLLING] ✓ Successfully extracted {len(video_urls)} video URL(s) on attempt {attempt}")
|
|
582
599
|
return video_urls
|
|
583
600
|
else:
|
|
601
|
+
if verbose and attempt % 5 == 0: # Log every 5th attempt
|
|
602
|
+
logger.debug(f"[VIDEO POLLING] No URLs yet on attempt {attempt}, continuing...")
|
|
584
603
|
time.sleep(wait_seconds)
|
|
585
604
|
else:
|
|
605
|
+
if verbose:
|
|
606
|
+
logger.warning(f"[VIDEO POLLING] HTTP {response.status_code} on attempt {attempt}")
|
|
586
607
|
time.sleep(wait_seconds)
|
|
587
608
|
|
|
588
609
|
except Exception as e:
|
|
610
|
+
if verbose:
|
|
611
|
+
logger.error(f"[VIDEO POLLING] Error on attempt {attempt}: {e}")
|
|
589
612
|
time.sleep(wait_seconds)
|
|
590
613
|
|
|
614
|
+
if verbose:
|
|
615
|
+
logger.error(f"[VIDEO POLLING] ⚠️ Failed to extract video URLs after {max_attempts} attempts")
|
|
591
616
|
return []
|
|
592
617
|
|
|
593
618
|
@staticmethod
|
|
594
|
-
def _extract_video_urls_from_response(response_text: str) -> List[str]:
|
|
619
|
+
def _extract_video_urls_from_response(response_text: str, is_final_attempt: bool = False) -> List[str]:
|
|
595
620
|
"""
|
|
596
621
|
Extract video URLs from Meta AI GraphQL response.
|
|
597
622
|
Uses the CORRECT structure from the original GitHub repo.
|
|
598
623
|
|
|
599
624
|
Args:
|
|
600
625
|
response_text: The response text to extract URLs from
|
|
626
|
+
is_final_attempt: Whether this is the final polling attempt (for logging)
|
|
601
627
|
|
|
602
628
|
Returns:
|
|
603
629
|
List of video URLs
|
|
@@ -605,15 +631,20 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
605
631
|
import logging
|
|
606
632
|
logger = logging.getLogger(__name__)
|
|
607
633
|
|
|
608
|
-
|
|
609
|
-
|
|
634
|
+
# Only log detailed extraction info on final attempt or when verbose debugging
|
|
635
|
+
log_details = is_final_attempt or logger.isEnabledFor(logging.DEBUG)
|
|
636
|
+
|
|
637
|
+
if log_details:
|
|
638
|
+
logger.debug("[VIDEO URL EXTRACTION] Starting extraction with proper structure...")
|
|
639
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Response length: {len(response_text)} characters")
|
|
610
640
|
|
|
611
641
|
urls: List[str] = []
|
|
612
642
|
|
|
613
643
|
try:
|
|
614
644
|
# Parse the response
|
|
615
645
|
data = json.loads(response_text)
|
|
616
|
-
|
|
646
|
+
if log_details:
|
|
647
|
+
logger.debug("[VIDEO URL EXTRACTION] Successfully parsed response as JSON")
|
|
617
648
|
|
|
618
649
|
# CORRECT STRUCTURE from original GitHub code:
|
|
619
650
|
# data -> xfb_genai_fetch_post (or xab_abra__xfb_genai_fetch_post)
|
|
@@ -622,13 +653,14 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
622
653
|
data_obj = data.get("data", {})
|
|
623
654
|
fetch_post = data_obj.get("xfb_genai_fetch_post") or data_obj.get("xab_abra__xfb_genai_fetch_post") or {}
|
|
624
655
|
|
|
625
|
-
if not fetch_post:
|
|
626
|
-
logger.
|
|
627
|
-
|
|
628
|
-
logger.
|
|
656
|
+
if not fetch_post and log_details:
|
|
657
|
+
logger.debug("[VIDEO URL EXTRACTION] No xfb_genai_fetch_post or xab_abra__xfb_genai_fetch_post found in response")
|
|
658
|
+
elif log_details:
|
|
659
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found fetch_post: {list(fetch_post.keys())}")
|
|
629
660
|
|
|
630
661
|
messages = fetch_post.get("messages", {}).get("edges", [])
|
|
631
|
-
|
|
662
|
+
if log_details:
|
|
663
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found {len(messages)} message edges")
|
|
632
664
|
|
|
633
665
|
for edge_idx, edge in enumerate(messages):
|
|
634
666
|
node = edge.get("node", {})
|
|
@@ -636,62 +668,75 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
636
668
|
imagine_video = content.get("imagine_video") or {}
|
|
637
669
|
|
|
638
670
|
if not imagine_video:
|
|
639
|
-
|
|
671
|
+
if log_details:
|
|
672
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Edge {edge_idx}: No imagine_video found")
|
|
640
673
|
continue
|
|
641
674
|
|
|
642
|
-
|
|
675
|
+
if log_details:
|
|
676
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Edge {edge_idx}: Found imagine_video with keys: {list(imagine_video.keys())}")
|
|
643
677
|
|
|
644
678
|
# Extract from videos.nodes[] array
|
|
645
679
|
videos = imagine_video.get("videos", {}).get("nodes", [])
|
|
646
|
-
|
|
680
|
+
if log_details:
|
|
681
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Edge {edge_idx}: Found {len(videos)} video nodes")
|
|
647
682
|
|
|
648
683
|
for video_idx, video in enumerate(videos):
|
|
649
684
|
# Try video_url or uri
|
|
650
685
|
uri = video.get("video_url") or video.get("uri")
|
|
651
686
|
if uri:
|
|
652
|
-
|
|
687
|
+
if log_details:
|
|
688
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found video_url/uri in videos.nodes[{video_idx}]: {uri[:100]}...")
|
|
653
689
|
urls.append(uri)
|
|
654
690
|
|
|
655
691
|
# Try videoDeliveryResponseResult.progressive_urls[]
|
|
656
692
|
delivery = video.get("videoDeliveryResponseResult") or {}
|
|
657
693
|
prog = delivery.get("progressive_urls", [])
|
|
658
|
-
|
|
694
|
+
if log_details and prog:
|
|
695
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found {len(prog)} progressive_urls in video {video_idx}")
|
|
659
696
|
|
|
660
697
|
for prog_idx, p in enumerate(prog):
|
|
661
698
|
pu = p.get("progressive_url")
|
|
662
699
|
if pu:
|
|
663
|
-
|
|
700
|
+
if log_details:
|
|
701
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found progressive_url[{prog_idx}]: {pu[:100]}...")
|
|
664
702
|
urls.append(pu)
|
|
665
703
|
|
|
666
704
|
# Extract from single video object
|
|
667
705
|
single_video = imagine_video.get("video") or {}
|
|
668
706
|
if isinstance(single_video, dict) and single_video:
|
|
669
|
-
|
|
707
|
+
if log_details:
|
|
708
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found single video object with keys: {list(single_video.keys())}")
|
|
670
709
|
|
|
671
710
|
uri = single_video.get("video_url") or single_video.get("uri")
|
|
672
711
|
if uri:
|
|
673
|
-
|
|
712
|
+
if log_details:
|
|
713
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found video_url/uri in single video: {uri[:100]}...")
|
|
674
714
|
urls.append(uri)
|
|
675
715
|
|
|
676
716
|
delivery = single_video.get("videoDeliveryResponseResult") or {}
|
|
677
717
|
prog = delivery.get("progressive_urls", [])
|
|
678
|
-
|
|
718
|
+
if log_details and prog:
|
|
719
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found {len(prog)} progressive_urls in single video")
|
|
679
720
|
|
|
680
721
|
for prog_idx, p in enumerate(prog):
|
|
681
722
|
pu = p.get("progressive_url")
|
|
682
723
|
if pu:
|
|
683
|
-
|
|
724
|
+
if log_details:
|
|
725
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Found progressive_url[{prog_idx}]: {pu[:100]}...")
|
|
684
726
|
urls.append(pu)
|
|
685
727
|
|
|
686
728
|
except json.JSONDecodeError as e:
|
|
687
|
-
|
|
688
|
-
|
|
729
|
+
if is_final_attempt:
|
|
730
|
+
logger.error(f"[VIDEO URL EXTRACTION] JSON decode failed: {e}")
|
|
731
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Response preview: {response_text[:500]}")
|
|
689
732
|
|
|
690
733
|
# Fallback to regex
|
|
691
|
-
|
|
734
|
+
if log_details:
|
|
735
|
+
logger.debug("[VIDEO URL EXTRACTION] Falling back to regex extraction...")
|
|
692
736
|
import re
|
|
693
737
|
urls = re.findall(r'https?://[^\s"\'<>]+fbcdn[^\s"\'<>]+\.mp4[^\s"\'<>]*', response_text)
|
|
694
|
-
|
|
738
|
+
if log_details:
|
|
739
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Regex found {len(urls)} .mp4 URLs")
|
|
695
740
|
|
|
696
741
|
# Deduplicate while preserving order
|
|
697
742
|
seen = set()
|
|
@@ -701,11 +746,13 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
701
746
|
seen.add(u)
|
|
702
747
|
unique_urls.append(u)
|
|
703
748
|
|
|
704
|
-
|
|
749
|
+
# Only log final result if we have URLs or if this is the final attempt
|
|
705
750
|
if unique_urls:
|
|
706
|
-
|
|
707
|
-
logger.
|
|
708
|
-
|
|
751
|
+
if log_details:
|
|
752
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Final result: {len(unique_urls)} unique video URLs")
|
|
753
|
+
for idx, url in enumerate(unique_urls, 1):
|
|
754
|
+
logger.debug(f"[VIDEO URL EXTRACTION] Final URL {idx}: {url[:150]}...")
|
|
755
|
+
elif is_final_attempt:
|
|
709
756
|
logger.warning("[VIDEO URL EXTRACTION] ⚠️ NO VIDEO URLs FOUND!")
|
|
710
757
|
logger.debug(f"[VIDEO URL EXTRACTION] Response preview (first 1000 chars): {response_text[:1000]}")
|
|
711
758
|
|
|
@@ -716,6 +763,7 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
716
763
|
prompt: str,
|
|
717
764
|
media_ids: Optional[List[str]] = None,
|
|
718
765
|
attachment_metadata: Optional[Dict[str, Any]] = None,
|
|
766
|
+
orientation: Optional[str] = None,
|
|
719
767
|
wait_before_poll: int = 10,
|
|
720
768
|
max_attempts: int = 30,
|
|
721
769
|
wait_seconds: int = 5,
|
|
@@ -728,6 +776,7 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
728
776
|
prompt: Text prompt for video generation
|
|
729
777
|
media_ids: Optional list of media IDs from uploaded images
|
|
730
778
|
attachment_metadata: Optional dict with 'file_size' (int) and 'mime_type' (str)
|
|
779
|
+
orientation: Video orientation ("LANDSCAPE", "VERTICAL", "SQUARE"). Defaults to "VERTICAL".
|
|
731
780
|
wait_before_poll: Seconds to wait before starting to poll
|
|
732
781
|
max_attempts: Maximum polling attempts
|
|
733
782
|
wait_seconds: Seconds between polling attempts
|
|
@@ -741,6 +790,7 @@ Content-Disposition: form-data; name="doc_id"\r
|
|
|
741
790
|
prompt_text=prompt,
|
|
742
791
|
media_ids=media_ids,
|
|
743
792
|
attachment_metadata=attachment_metadata,
|
|
793
|
+
orientation=orientation,
|
|
744
794
|
verbose=verbose
|
|
745
795
|
)
|
|
746
796
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metaai-sdk
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.5
|
|
4
4
|
Summary: Feature-rich Python SDK for Meta AI - Chat, Image & Video Generation powered by Llama 3
|
|
5
5
|
Author-email: Ashiq Hussain Mir <imseldrith@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -27,8 +27,8 @@ Requires-Dist: lxml-html-clean>=0.1.1
|
|
|
27
27
|
Requires-Dist: beautifulsoup4>=4.9.0
|
|
28
28
|
Requires-Dist: python-multipart>=0.0.21
|
|
29
29
|
Provides-Extra: api
|
|
30
|
-
Requires-Dist: fastapi
|
|
31
|
-
Requires-Dist: uvicorn[standard]
|
|
30
|
+
Requires-Dist: fastapi>=0.95.2; extra == "api"
|
|
31
|
+
Requires-Dist: uvicorn[standard]>=0.22.0; extra == "api"
|
|
32
32
|
Requires-Dist: python-multipart>=0.0.6; extra == "api"
|
|
33
33
|
Requires-Dist: python-dotenv>=1.0.0; extra == "api"
|
|
34
34
|
Provides-Extra: dev
|
|
@@ -487,22 +487,29 @@ print(f"\n🎉 Generated {len(videos)} videos successfully!")
|
|
|
487
487
|
🎉 Generated 3 videos successfully!
|
|
488
488
|
```
|
|
489
489
|
|
|
490
|
-
### Example 3: Advanced Video Generation
|
|
490
|
+
### Example 3: Advanced Video Generation with Orientation
|
|
491
491
|
|
|
492
492
|
```python
|
|
493
493
|
from metaai_api import MetaAI
|
|
494
494
|
|
|
495
495
|
ai = MetaAI(cookies=cookies)
|
|
496
496
|
|
|
497
|
-
#
|
|
497
|
+
# Generate video with specific orientation (default is VERTICAL)
|
|
498
498
|
result = ai.generate_video(
|
|
499
499
|
prompt="A time-lapse of a flower blooming",
|
|
500
|
+
orientation="VERTICAL", # Options: "LANDSCAPE", "VERTICAL", "SQUARE"
|
|
500
501
|
wait_before_poll=15, # Wait 15 seconds before checking
|
|
501
502
|
max_attempts=50, # Try up to 50 times
|
|
502
503
|
wait_seconds=3, # Wait 3 seconds between attempts
|
|
503
504
|
verbose=True # Show detailed progress
|
|
504
505
|
)
|
|
505
506
|
|
|
507
|
+
# Generate landscape video for widescreen
|
|
508
|
+
result_landscape = ai.generate_video(
|
|
509
|
+
prompt="Panoramic view of sunset over mountains",
|
|
510
|
+
orientation="LANDSCAPE" # Wide format (16:9)
|
|
511
|
+
)
|
|
512
|
+
|
|
506
513
|
if result["success"]:
|
|
507
514
|
print(f"\n🎬 Your videos are ready!")
|
|
508
515
|
print(f"🔗 Generated {len(result['video_urls'])} videos:")
|
|
@@ -511,6 +518,14 @@ if result["success"]:
|
|
|
511
518
|
print(f"⏱️ Generated at: {result['timestamp']}")
|
|
512
519
|
```
|
|
513
520
|
|
|
521
|
+
**Supported Video Orientations:**
|
|
522
|
+
|
|
523
|
+
- `"LANDSCAPE"` - Wide/horizontal (16:9) - ideal for widescreen, cinematic content
|
|
524
|
+
- `"VERTICAL"` - Tall/vertical (9:16) - ideal for mobile, stories, reels (default)
|
|
525
|
+
- `"SQUARE"` - Equal dimensions (1:1) - ideal for social posts
|
|
526
|
+
|
|
527
|
+
````
|
|
528
|
+
|
|
514
529
|
📖 **Full Video Guide:** See [VIDEO_GENERATION_README.md](https://github.com/mir-ashiq/metaai-api/blob/main/VIDEO_GENERATION_README.md) for complete documentation!
|
|
515
530
|
|
|
516
531
|
---
|
|
@@ -565,7 +580,7 @@ if result["success"]:
|
|
|
565
580
|
)
|
|
566
581
|
if video["success"]:
|
|
567
582
|
print(f"🎬 Video: {video['video_urls'][0]}")
|
|
568
|
-
|
|
583
|
+
````
|
|
569
584
|
|
|
570
585
|
**Output:**
|
|
571
586
|
|
|
@@ -583,7 +598,7 @@ if result["success"]:
|
|
|
583
598
|
|
|
584
599
|
## 🎨 Image Generation
|
|
585
600
|
|
|
586
|
-
Generate AI-powered images (requires Facebook authentication):
|
|
601
|
+
Generate AI-powered images with customizable orientations (requires Facebook authentication):
|
|
587
602
|
|
|
588
603
|
```python
|
|
589
604
|
from metaai_api import MetaAI
|
|
@@ -591,9 +606,25 @@ from metaai_api import MetaAI
|
|
|
591
606
|
# Initialize with Facebook credentials
|
|
592
607
|
ai = MetaAI(fb_email="your_email@example.com", fb_password="your_password")
|
|
593
608
|
|
|
594
|
-
# Generate images
|
|
609
|
+
# Generate images with default orientation (VERTICAL)
|
|
595
610
|
response = ai.prompt("Generate an image of a cyberpunk cityscape at night with neon lights")
|
|
596
611
|
|
|
612
|
+
# Or specify orientation explicitly
|
|
613
|
+
response_landscape = ai.prompt(
|
|
614
|
+
"Generate an image of a panoramic mountain landscape",
|
|
615
|
+
orientation="LANDSCAPE" # Options: "LANDSCAPE", "VERTICAL", "SQUARE"
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
response_vertical = ai.prompt(
|
|
619
|
+
"Generate an image of a tall waterfall",
|
|
620
|
+
orientation="VERTICAL" # Tall/portrait format (default)
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
response_square = ai.prompt(
|
|
624
|
+
"Generate an image of a centered mandala pattern",
|
|
625
|
+
orientation="SQUARE" # Square format (1:1)
|
|
626
|
+
)
|
|
627
|
+
|
|
597
628
|
# Display results (Meta AI generates 4 images by default)
|
|
598
629
|
print(f"🎨 Generated {len(response['media'])} images:")
|
|
599
630
|
for i, image in enumerate(response['media'], 1):
|
|
@@ -601,6 +632,12 @@ for i, image in enumerate(response['media'], 1):
|
|
|
601
632
|
print(f" Prompt: {image['prompt']}")
|
|
602
633
|
```
|
|
603
634
|
|
|
635
|
+
**Supported Orientations:**
|
|
636
|
+
|
|
637
|
+
- `"LANDSCAPE"` - Wide/horizontal format (16:9) - ideal for panoramas, landscapes
|
|
638
|
+
- `"VERTICAL"` - Tall/vertical format (9:16) - ideal for portraits, mobile content (default)
|
|
639
|
+
- `"SQUARE"` - Equal dimensions (1:1) - ideal for social media, profile images
|
|
640
|
+
|
|
604
641
|
**Output:**
|
|
605
642
|
|
|
606
643
|
```
|
|
@@ -680,7 +717,6 @@ class MetaAI:
|
|
|
680
717
|
**Methods:**
|
|
681
718
|
|
|
682
719
|
- **`prompt(message, stream=False, new_conversation=False)`**
|
|
683
|
-
|
|
684
720
|
- Send a chat message
|
|
685
721
|
- Returns: `dict` with `message`, `sources`, and `media`
|
|
686
722
|
|
|
@@ -3,11 +3,11 @@ metaai_api/api_server.py,sha256=hb1C3rEarPOHF6W-qqENaxrZWwn8A0qUrjSVlRtNV2s,1324
|
|
|
3
3
|
metaai_api/client.py,sha256=Th46qW1l8OS8Hu5pj0aGFn4iQNz62A3sbXko-LP-SAU,5263
|
|
4
4
|
metaai_api/exceptions.py,sha256=MRRAppZa0OFA0QLSvC0nABgZN_Ll1dUq9JfhECTqV-Q,114
|
|
5
5
|
metaai_api/image_upload.py,sha256=DQ2xqKdM1I_pF1rZBsB7-QTvXLzke2_0XiIOxFhpc70,6563
|
|
6
|
-
metaai_api/main.py,sha256=
|
|
6
|
+
metaai_api/main.py,sha256=bZrao6uZI-CdtHvdu64jUH72h0R7atN2PNrP5TaHpMM,36738
|
|
7
7
|
metaai_api/utils.py,sha256=qzfIO3WkRH-gSV99b8RiECnMOku8lZEY3Jka9lTLExA,11979
|
|
8
|
-
metaai_api/video_generation.py,sha256=
|
|
9
|
-
metaai_sdk-2.3.
|
|
10
|
-
metaai_sdk-2.3.
|
|
11
|
-
metaai_sdk-2.3.
|
|
12
|
-
metaai_sdk-2.3.
|
|
13
|
-
metaai_sdk-2.3.
|
|
8
|
+
metaai_api/video_generation.py,sha256=Kw0Hwqeai6EexPhJsN-0eLSmIL0zDp95EwAPk6UQ9Rs,37480
|
|
9
|
+
metaai_sdk-2.3.5.dist-info/licenses/LICENSE,sha256=hRLLSBixyX0tRh2k0iOGoF7nx-l-vBChNffFfVOIEtc,1290
|
|
10
|
+
metaai_sdk-2.3.5.dist-info/METADATA,sha256=adQytqJvLOkHunqgkZet0ImIU74pTSbZK2udaC0utN4,28998
|
|
11
|
+
metaai_sdk-2.3.5.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
12
|
+
metaai_sdk-2.3.5.dist-info/top_level.txt,sha256=R6YCiIQLYFKKaqhNZXDwXbpj1u01P_YhcMCVbJiDUJs,11
|
|
13
|
+
metaai_sdk-2.3.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|