metaai-sdk 2.0.0__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.
@@ -0,0 +1,679 @@
1
+ """
2
+ Meta AI Video Generation Module
3
+ Advanced video generation and retrieval using Meta AI's GraphQL API
4
+ """
5
+
6
+ import requests
7
+ import json
8
+ import time
9
+ import uuid
10
+ from typing import Dict, List, Optional
11
+ from requests_html import HTMLSession
12
+ from metaai_api.utils import extract_value
13
+
14
+
15
+ class VideoGenerator:
16
+ """
17
+ A class to handle video generation requests to Meta AI's GraphQL API.
18
+ Supports creating videos from text prompts and retrieving video URLs.
19
+ """
20
+
21
+ GRAPHQL_URL = 'https://www.meta.ai/api/graphql/'
22
+
23
+ def __init__(
24
+ self,
25
+ cookies_str: Optional[str] = None,
26
+ cookies_dict: Optional[Dict[str, str]] = None
27
+ ):
28
+ """
29
+ Initialize the VideoGenerator.
30
+ Automatically fetches lsd and fb_dtsg tokens from Meta AI.
31
+
32
+ Args:
33
+ cookies_str: Cookie string in format "key=value; key=value"
34
+ cookies_dict: Pre-parsed cookies dictionary
35
+ """
36
+ if cookies_dict:
37
+ self.cookies = cookies_dict
38
+ self.cookies_str = "; ".join([f"{k}={v}" for k, v in cookies_dict.items()])
39
+ elif cookies_str:
40
+ self.cookies = self._parse_cookies(cookies_str)
41
+ self.cookies_str = cookies_str
42
+ else:
43
+ raise ValueError("Either cookies_str or cookies_dict must be provided")
44
+
45
+ # Always auto-fetch tokens
46
+ try:
47
+ tokens = self.get_lsd_and_dtsg(self.cookies_str)
48
+ self.lsd = tokens['lsd']
49
+ self.fb_dtsg = tokens['fb_dtsg']
50
+ except Exception as e:
51
+ raise ValueError(f"Failed to auto-fetch tokens: {e}")
52
+
53
+ @staticmethod
54
+ def _parse_cookies(cookie_str: str) -> Dict[str, str]:
55
+ """Parse cookie string into dictionary"""
56
+ cookies = {}
57
+ for item in cookie_str.split('; '):
58
+ if '=' in item:
59
+ key, value = item.split('=', 1)
60
+ cookies[key] = value
61
+ return cookies
62
+
63
+ @staticmethod
64
+ def get_lsd_and_dtsg(cookies_str: str) -> Dict[str, str]:
65
+ """
66
+ Extract lsd and fb_dtsg from Meta AI page using provided cookies.
67
+
68
+ Args:
69
+ cookies_str: Cookie string in format "key1=value1; key2=value2; ..."
70
+
71
+ Returns:
72
+ Dictionary with 'lsd' and 'fb_dtsg' keys
73
+ """
74
+ # Fetch Meta AI page with cookies
75
+ session = HTMLSession()
76
+ headers = {"cookie": cookies_str}
77
+ response = session.get("https://www.meta.ai/", headers=headers)
78
+
79
+ # Extract lsd and fb_dtsg
80
+ lsd = extract_value(response.text, start_str='"LSD",[],{"token":"', end_str='"')
81
+ fb_dtsg = extract_value(response.text, start_str='DTSGInitData",[],{"token":"', end_str='"')
82
+
83
+ return {
84
+ "lsd": lsd,
85
+ "fb_dtsg": fb_dtsg
86
+ }
87
+
88
+ @classmethod
89
+ def quick_generate(
90
+ cls,
91
+ cookies_str: str,
92
+ prompt: str,
93
+ verbose: bool = True
94
+ ) -> Dict:
95
+ """
96
+ Convenience method to generate a video with minimal setup.
97
+ Automatically fetches tokens and generates video in one call.
98
+
99
+ Args:
100
+ cookies_str: Cookie string in format "key1=value1; key2=value2; ..."
101
+ prompt: Text prompt for video generation
102
+ verbose: Whether to print status messages
103
+
104
+ Returns:
105
+ Dictionary with success status, conversation_id, prompt, video_urls, and timestamp
106
+
107
+ Example:
108
+ result = VideoGenerator.quick_generate(
109
+ cookies_str="datr=...; abra_sess=...",
110
+ prompt="Generate a video of a sunset"
111
+ )
112
+ """
113
+ generator = cls(cookies_str=cookies_str)
114
+ return generator.generate_video(prompt=prompt, verbose=verbose)
115
+
116
+ def build_headers(
117
+ self,
118
+ content_type: str = 'application/x-www-form-urlencoded',
119
+ friendly_name: Optional[str] = None,
120
+ additional_headers: Optional[Dict[str, str]] = None
121
+ ) -> Dict[str, str]:
122
+ """
123
+ Build dynamic headers for Meta AI API requests.
124
+
125
+ Args:
126
+ content_type: Content-Type header value
127
+ friendly_name: Optional X-FB-Friendly-Name for the request
128
+ additional_headers: Optional dict of additional headers to merge
129
+
130
+ Returns:
131
+ Complete headers dictionary
132
+ """
133
+ # Base headers common to all requests
134
+ headers = {
135
+ 'accept': '*/*',
136
+ 'accept-language': 'en-US,en;q=0.5',
137
+ 'content-type': content_type,
138
+ 'origin': 'https://www.meta.ai',
139
+ 'referer': 'https://www.meta.ai/',
140
+ 'sec-ch-ua': '"Brave";v="141", "Not?A_Brand";v="8", "Chromium";v="141"',
141
+ 'sec-ch-ua-mobile': '?0',
142
+ 'sec-ch-ua-platform': '"Windows"',
143
+ 'sec-fetch-dest': 'empty',
144
+ 'sec-fetch-mode': 'cors',
145
+ 'sec-fetch-site': 'same-origin',
146
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36',
147
+ 'x-asbd-id': '359341',
148
+ 'x-fb-lsd': self.lsd,
149
+ }
150
+
151
+ # Add optional friendly name
152
+ if friendly_name:
153
+ headers['x-fb-friendly-name'] = friendly_name
154
+
155
+ # Add additional headers specific to request type
156
+ if additional_headers:
157
+ headers.update(additional_headers)
158
+
159
+ return headers
160
+
161
+ def create_video_generation_request(
162
+ self,
163
+ prompt_text: str,
164
+ verbose: bool = True
165
+ ) -> Optional[str]:
166
+ """
167
+ Send video generation request to Meta AI using raw multipart body.
168
+
169
+ Args:
170
+ prompt_text: The text prompt for video generation
171
+ verbose: Whether to print status messages
172
+
173
+ Returns:
174
+ external_conversation_id if successful, None otherwise
175
+ """
176
+ # Generate unique IDs
177
+ external_conversation_id = str(uuid.uuid4())
178
+ offline_threading_id = str(int(time.time() * 1000000000))[:19]
179
+ thread_session_id = str(uuid.uuid4())
180
+ bot_offline_threading_id = str(int(time.time() * 1000000000) + 1)[:19]
181
+ qpl_join_id = str(uuid.uuid4()).replace('-', '')
182
+
183
+ # Build headers with multipart-specific additions
184
+ multipart_headers = {
185
+ 'priority': 'u=1, i',
186
+ 'sec-ch-ua-full-version-list': '"Brave";v="141.0.0.0", "Not?A_Brand";v="8.0.0.0", "Chromium";v="141.0.0.0"',
187
+ 'sec-ch-ua-model': '""',
188
+ 'sec-ch-ua-platform-version': '"19.0.0"',
189
+ 'sec-gpc': '1',
190
+ }
191
+
192
+ headers = self.build_headers(
193
+ content_type='multipart/form-data; boundary=----WebKitFormBoundaryu59CeaZS4ag939lz',
194
+ additional_headers=multipart_headers
195
+ )
196
+
197
+ # Build variables JSON (compact, no extra spaces)
198
+ variables = json.dumps({
199
+ "message": {"sensitive_string_value": prompt_text},
200
+ "externalConversationId": external_conversation_id,
201
+ "offlineThreadingId": offline_threading_id,
202
+ "threadSessionId": thread_session_id,
203
+ "isNewConversation": True,
204
+ "suggestedPromptIndex": None,
205
+ "promptPrefix": None,
206
+ "entrypoint": "KADABRA__CHAT__UNIFIED_INPUT_BAR",
207
+ "attachments": [],
208
+ "attachmentsV2": [],
209
+ "activeMediaSets": [],
210
+ "activeCardVersions": [],
211
+ "activeArtifactVersion": None,
212
+ "userUploadEditModeInput": None,
213
+ "reelComposeInput": None,
214
+ "qplJoinId": qpl_join_id,
215
+ "sourceRemixPostId": None,
216
+ "gkPlannerOrReasoningEnabled": True,
217
+ "selectedModel": "BASIC_OPTION",
218
+ "conversationMode": None,
219
+ "selectedAgentType": "PLANNER",
220
+ "conversationStarterId": None,
221
+ "promptType": None,
222
+ "artifactRewriteOptions": None,
223
+ "imagineOperationRequest": None,
224
+ "imagineClientOptions": {"orientation": "VERTICAL"},
225
+ "spaceId": None,
226
+ "sparkSnapshotId": None,
227
+ "topicPageId": None,
228
+ "includeSpace": False,
229
+ "storybookId": None,
230
+ "messagePersistentInput": {
231
+ "attachment_size": None,
232
+ "attachment_type": None,
233
+ "bot_message_offline_threading_id": bot_offline_threading_id,
234
+ "conversation_mode": None,
235
+ "external_conversation_id": external_conversation_id,
236
+ "is_new_conversation": True,
237
+ "meta_ai_entry_point": "KADABRA__CHAT__UNIFIED_INPUT_BAR",
238
+ "offline_threading_id": offline_threading_id,
239
+ "prompt_id": None,
240
+ "prompt_session_id": thread_session_id
241
+ },
242
+ "alakazam_enabled": True,
243
+ "skipInFlightMessageWithParams": None,
244
+ "__relay_internal__pv__KadabraSocialSearchEnabledrelayprovider": False,
245
+ "__relay_internal__pv__KadabraZeitgeistEnabledrelayprovider": False,
246
+ "__relay_internal__pv__alakazam_enabledrelayprovider": True,
247
+ "__relay_internal__pv__sp_kadabra_survey_invitationrelayprovider": True,
248
+ "__relay_internal__pv__KadabraAINativeUXrelayprovider": False,
249
+ "__relay_internal__pv__enable_kadabra_partial_resultsrelayprovider": False,
250
+ "__relay_internal__pv__AbraArtifactsEnabledrelayprovider": True,
251
+ "__relay_internal__pv__KadabraMemoryEnabledrelayprovider": False,
252
+ "__relay_internal__pv__AbraPlannerEnabledrelayprovider": True,
253
+ "__relay_internal__pv__AbraWidgetsEnabledrelayprovider": False,
254
+ "__relay_internal__pv__KadabraDeepResearchEnabledrelayprovider": False,
255
+ "__relay_internal__pv__KadabraThinkHarderEnabledrelayprovider": False,
256
+ "__relay_internal__pv__KadabraVergeEnabledrelayprovider": False,
257
+ "__relay_internal__pv__KadabraSpacesEnabledrelayprovider": False,
258
+ "__relay_internal__pv__KadabraProductSearchEnabledrelayprovider": False,
259
+ "__relay_internal__pv__KadabraAreServiceEnabledrelayprovider": False,
260
+ "__relay_internal__pv__kadabra_render_reasoning_response_statesrelayprovider": True,
261
+ "__relay_internal__pv__kadabra_reasoning_cotrelayprovider": False,
262
+ "__relay_internal__pv__AbraSearchInlineReferencesEnabledrelayprovider": True,
263
+ "__relay_internal__pv__AbraComposedTextWidgetsrelayprovider": True,
264
+ "__relay_internal__pv__KadabraNewCitationsEnabledrelayprovider": True,
265
+ "__relay_internal__pv__WebPixelRatiorelayprovider": 1,
266
+ "__relay_internal__pv__KadabraVideoDeliveryRequestrelayprovider": {
267
+ "dash_manifest_requests": [{}],
268
+ "progressive_url_requests": [{"quality": "HD"}, {"quality": "SD"}]
269
+ },
270
+ "__relay_internal__pv__KadabraWidgetsRedesignEnabledrelayprovider": False,
271
+ "__relay_internal__pv__kadabra_enable_send_message_retryrelayprovider": True,
272
+ "__relay_internal__pv__KadabraEmailCalendarIntegrationrelayprovider": False,
273
+ "__relay_internal__pv__kadabra_reels_connect_featuresrelayprovider": False,
274
+ "__relay_internal__pv__AbraBugNubrelayprovider": False,
275
+ "__relay_internal__pv__AbraRedteamingrelayprovider": False,
276
+ "__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
277
+ "__relay_internal__pv__kadabra_enable_open_in_editor_message_actionrelayprovider": True,
278
+ "__relay_internal__pv__AbraThreadsEnabledrelayprovider": False,
279
+ "__relay_internal__pv__kadabra_story_builder_enabledrelayprovider": False,
280
+ "__relay_internal__pv__kadabra_imagine_canvas_enable_dev_settingsrelayprovider": False,
281
+ "__relay_internal__pv__kadabra_create_media_deletionrelayprovider": False,
282
+ "__relay_internal__pv__kadabra_moodboardrelayprovider": False,
283
+ "__relay_internal__pv__AbraArtifactDragImagineFromConversationrelayprovider": True,
284
+ "__relay_internal__pv__kadabra_media_item_renderer_heightrelayprovider": 545,
285
+ "__relay_internal__pv__kadabra_media_item_renderer_widthrelayprovider": 620,
286
+ "__relay_internal__pv__AbraQPDocUploadNuxTriggerNamerelayprovider": "meta_dot_ai_abra_web_doc_upload_nux_tour",
287
+ "__relay_internal__pv__AbraSurfaceNuxIDrelayprovider": "12177",
288
+ "__relay_internal__pv__KadabraConversationRenamingrelayprovider": True,
289
+ "__relay_internal__pv__AbraIsLoggedOutrelayprovider": False,
290
+ "__relay_internal__pv__KadabraCanvasDisplayHeaderV2relayprovider": False,
291
+ "__relay_internal__pv__AbraArtifactEditorDebugModerelayprovider": False,
292
+ "__relay_internal__pv__AbraArtifactEditorDownloadHTMLEnabledrelayprovider": False,
293
+ "__relay_internal__pv__kadabra_create_row_hover_optionsrelayprovider": False,
294
+ "__relay_internal__pv__kadabra_media_info_pillsrelayprovider": True,
295
+ "__relay_internal__pv__KadabraConcordInternalProfileBadgeEnabledrelayprovider": False,
296
+ "__relay_internal__pv__KadabraSocialGraphrelayprovider": True
297
+ }, separators=(',', ':'))
298
+
299
+ # Build raw multipart body (exactly as in working example)
300
+ spin_t = str(int(time.time()))
301
+ body = f"""------WebKitFormBoundaryu59CeaZS4ag939lz\r
302
+ Content-Disposition: form-data; name="av"\r
303
+ \r
304
+ 813590375178585\r
305
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
306
+ Content-Disposition: form-data; name="__user"\r
307
+ \r
308
+ 0\r
309
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
310
+ Content-Disposition: form-data; name="__a"\r
311
+ \r
312
+ 1\r
313
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
314
+ Content-Disposition: form-data; name="__req"\r
315
+ \r
316
+ q\r
317
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
318
+ Content-Disposition: form-data; name="__hs"\r
319
+ \r
320
+ 20413.HYP:kadabra_pkg.2.1...0\r
321
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
322
+ Content-Disposition: form-data; name="dpr"\r
323
+ \r
324
+ 1\r
325
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
326
+ Content-Disposition: form-data; name="__ccg"\r
327
+ \r
328
+ GOOD\r
329
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
330
+ Content-Disposition: form-data; name="__rev"\r
331
+ \r
332
+ 1030219547\r
333
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
334
+ Content-Disposition: form-data; name="__s"\r
335
+ \r
336
+ q59jx4:9bnqdw:3ats33\r
337
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
338
+ Content-Disposition: form-data; name="__hsi"\r
339
+ \r
340
+ 7575127759957881428\r
341
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
342
+ Content-Disposition: form-data; name="__dyn"\r
343
+ \r
344
+ 7xeUjG1mxu1syUqxemh0no6u5U4e2C1vzEdE98K360CEbo1nEhw2nVEtwMw6ywaq221FwpUO0n24oaEnxO0Bo7O2l0Fwqo31w9O1lwlE-U2zxe2GewbS361qw82dUlwhE-15wmo423-0j52oS0Io5d0bS1LBwNwKG0WE8oC1IwGw-wlUcE2-G2O7E5y1rwa211wo84y1iwfe1aw\r
345
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
346
+ Content-Disposition: form-data; name="__csr"\r
347
+ \r
348
+ gaJNBjWsAJvliQPqlWFFknAiUB2bBjWLmhyblepaGyVFGy8y2i5pEW68mwwwPwxgtNgv2AMEu6PAgrCwc7F212xxe5YyVC1pAg01sq99uQ1zK0dp75gKzAy8y0EjcgQ8Ek0yMJC6G1og5KrXD4GexS8wdasU8U1e4075UeEuwfCA8K0hWiU2tAyE5m0gm0Jo0xUGxh1veU0gGyWfe0iK1xo32yXhoKkw56pwMw1e25onU4i0TA0xaxu00B1Q2ha2K3V0eqCmawnEgg2Gw\r
349
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
350
+ Content-Disposition: form-data; name="__hsdp"\r
351
+ \r
352
+ gdDdNhMlJ8bNG7i42aHgWzckH57ylAt8NkkOGCVQ8Ay8myETxW1vh48gHx-UC9Bgpy87G0BUfU7i0JFUeo7Cm12wlo5OawRwDwzxW1zg33wgodU\r
353
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
354
+ Content-Disposition: form-data; name="__hblp"\r
355
+ \r
356
+ 08W5EWt0BzUWp5Q4vz4HOk5kVogDGqmHgyi8xq9gNrxG1vh8B2K6pry4mVk8x28wuE5a1DxO1Qwr84Cu3C1VBwCxK2W2qi2y1LwDwzyK445Gwi63-0wUkxa9AyEjgogy3-\r
357
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
358
+ Content-Disposition: form-data; name="__sjsp"\r
359
+ \r
360
+ gdDtsAFMlJ8bNG7i47AG5lxmUmDiFQca9U\r
361
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
362
+ Content-Disposition: form-data; name="__comet_req"\r
363
+ \r
364
+ 72\r
365
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
366
+ Content-Disposition: form-data; name="fb_dtsg"\r
367
+ \r
368
+ {self.fb_dtsg}\r
369
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
370
+ Content-Disposition: form-data; name="jazoest"\r
371
+ \r
372
+ 25499\r
373
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
374
+ Content-Disposition: form-data; name="lsd"\r
375
+ \r
376
+ {self.lsd}\r
377
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
378
+ Content-Disposition: form-data; name="__spin_r"\r
379
+ \r
380
+ 1030219547\r
381
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
382
+ Content-Disposition: form-data; name="__spin_b"\r
383
+ \r
384
+ trunk\r
385
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
386
+ Content-Disposition: form-data; name="__spin_t"\r
387
+ \r
388
+ {spin_t}\r
389
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
390
+ Content-Disposition: form-data; name="__jssesw"\r
391
+ \r
392
+ 1\r
393
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
394
+ Content-Disposition: form-data; name="__crn"\r
395
+ \r
396
+ comet.kadabra.KadabraAssistantRoute\r
397
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
398
+ Content-Disposition: form-data; name="fb_api_caller_class"\r
399
+ \r
400
+ RelayModern\r
401
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
402
+ Content-Disposition: form-data; name="fb_api_req_friendly_name"\r
403
+ \r
404
+ useKadabraSendMessageMutation\r
405
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
406
+ Content-Disposition: form-data; name="server_timestamps"\r
407
+ \r
408
+ true\r
409
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
410
+ Content-Disposition: form-data; name="variables"\r
411
+ \r
412
+ {variables}\r
413
+ ------WebKitFormBoundaryu59CeaZS4ag939lz\r
414
+ Content-Disposition: form-data; name="doc_id"\r
415
+ \r
416
+ 25290947477183545\r
417
+ ------WebKitFormBoundaryu59CeaZS4ag939lz--\r
418
+ """
419
+
420
+ # URL with query parameters
421
+ url = f"{self.GRAPHQL_URL}?fb_dtsg={self.fb_dtsg}&jazoest=25499&lsd={self.lsd}"
422
+
423
+ try:
424
+ response = requests.post(
425
+ url,
426
+ cookies=self.cookies,
427
+ headers=headers,
428
+ data=body.encode('utf-8'),
429
+ timeout=30
430
+ )
431
+
432
+ if response.status_code == 200:
433
+ return external_conversation_id
434
+ else:
435
+ return None
436
+
437
+ except Exception as e:
438
+ return None
439
+
440
+ def fetch_video_urls(
441
+ self,
442
+ conversation_id: str,
443
+ max_attempts: int = 30,
444
+ wait_seconds: int = 5,
445
+ verbose: bool = True
446
+ ) -> List[str]:
447
+ """
448
+ Poll for video URLs from a conversation.
449
+
450
+ Args:
451
+ conversation_id: The conversation ID to fetch videos from
452
+ max_attempts: Maximum number of polling attempts
453
+ wait_seconds: Seconds to wait between attempts
454
+ verbose: Whether to print status messages
455
+
456
+ Returns:
457
+ List of video URLs
458
+ """
459
+ # Build headers with query-specific friendly name
460
+ headers = self.build_headers(
461
+ content_type='application/x-www-form-urlencoded',
462
+ friendly_name='KadabraPromptRootQuery'
463
+ )
464
+
465
+ # Build variables
466
+ variables = {
467
+ "prompt_id": conversation_id,
468
+ "__relay_internal__pv__kadabra_voice_consumptionrelayprovider": False,
469
+ "__relay_internal__pv__AbraIsLoggedOutrelayprovider": False,
470
+ "__relay_internal__pv__KadabraConversationRenamingrelayprovider": True,
471
+ "__relay_internal__pv__KadabraSpacesEnabledrelayprovider": False,
472
+ "__relay_internal__pv__KadabraRecipesEnabledrelayprovider": False,
473
+ "__relay_internal__pv__KadabraFOASharingEnabledrelayprovider": True,
474
+ "__relay_internal__pv__KadabraFeedImageDimensionrelayprovider": 800,
475
+ "__relay_internal__pv__kadabra_story_builder_enabledrelayprovider": False,
476
+ "__relay_internal__pv__kadabra_imagine_canvas_enable_dev_settingsrelayprovider": False,
477
+ "__relay_internal__pv__enable_kadabra_partial_resultsrelayprovider": False,
478
+ "__relay_internal__pv__kadabra_create_media_deletionrelayprovider": False,
479
+ "__relay_internal__pv__kadabra_moodboardrelayprovider": False,
480
+ "__relay_internal__pv__KadabraVideoDeliveryRequestrelayprovider": {
481
+ "dash_manifest_requests": [{}],
482
+ "progressive_url_requests": [{"quality": "HD"}, {"quality": "SD"}]
483
+ },
484
+ "__relay_internal__pv__AbraSearchInlineReferencesEnabledrelayprovider": True,
485
+ "__relay_internal__pv__AbraComposedTextWidgetsrelayprovider": True,
486
+ "__relay_internal__pv__KadabraNewCitationsEnabledrelayprovider": True,
487
+ "__relay_internal__pv__WebPixelRatiorelayprovider": 1,
488
+ "__relay_internal__pv__KadabraWidgetsRedesignEnabledrelayprovider": False,
489
+ "__relay_internal__pv__AbraArtifactDragImagineFromConversationrelayprovider": True,
490
+ "__relay_internal__pv__kadabra_media_item_renderer_heightrelayprovider": 545,
491
+ "__relay_internal__pv__kadabra_media_item_renderer_widthrelayprovider": 620,
492
+ "__relay_internal__pv__AbraBugNubrelayprovider": False,
493
+ "__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
494
+ "__relay_internal__pv__abra_silverstone_enable_hidden_commentsrelayprovider": True,
495
+ "__relay_internal__pv__kadabra_voicerelayprovider": True,
496
+ "__relay_internal__pv__KadabraSocialSearchEnabledrelayprovider": False,
497
+ "__relay_internal__pv__KadabraZeitgeistEnabledrelayprovider": False,
498
+ "__relay_internal__pv__alakazam_enabledrelayprovider": True,
499
+ "__relay_internal__pv__sp_kadabra_survey_invitationrelayprovider": True,
500
+ "__relay_internal__pv__KadabraAINativeUXrelayprovider": False,
501
+ "__relay_internal__pv__AbraArtifactsEnabledrelayprovider": True,
502
+ "__relay_internal__pv__KadabraMemoryEnabledrelayprovider": False,
503
+ "__relay_internal__pv__AbraPlannerEnabledrelayprovider": True,
504
+ "__relay_internal__pv__AbraWidgetsEnabledrelayprovider": False,
505
+ "__relay_internal__pv__KadabraDeepResearchEnabledrelayprovider": False,
506
+ "__relay_internal__pv__KadabraThinkHarderEnabledrelayprovider": False,
507
+ "__relay_internal__pv__KadabraVergeEnabledrelayprovider": False,
508
+ "__relay_internal__pv__KadabraProductSearchEnabledrelayprovider": False,
509
+ "__relay_internal__pv__KadabraAreServiceEnabledrelayprovider": False,
510
+ "__relay_internal__pv__kadabra_render_reasoning_response_statesrelayprovider": True,
511
+ "__relay_internal__pv__kadabra_reasoning_cotrelayprovider": False,
512
+ "__relay_internal__pv__kadabra_enable_send_message_retryrelayprovider": True,
513
+ "__relay_internal__pv__KadabraEmailCalendarIntegrationrelayprovider": False,
514
+ "__relay_internal__pv__kadabra_reels_connect_featuresrelayprovider": False,
515
+ "__relay_internal__pv__AbraRedteamingrelayprovider": False,
516
+ "__relay_internal__pv__kadabra_enable_open_in_editor_message_actionrelayprovider": True,
517
+ "__relay_internal__pv__AbraThreadsEnabledrelayprovider": False,
518
+ "__relay_internal__pv__AbraQPDocUploadNuxTriggerNamerelayprovider": "meta_dot_ai_abra_web_doc_upload_nux_tour",
519
+ "__relay_internal__pv__AbraSurfaceNuxIDrelayprovider": "12177"
520
+ }
521
+
522
+ # Build data payload
523
+ data = {
524
+ 'av': '813590375178585',
525
+ '__user': '0',
526
+ '__a': '1',
527
+ '__req': 's',
528
+ '__hs': '20413.HYP:kadabra_pkg.2.1...0',
529
+ 'dpr': '1',
530
+ '__ccg': 'GOOD',
531
+ '__rev': '1030219547',
532
+ '__s': 'q59jx4:9bnqdw:3ats33',
533
+ '__hsi': '7575127759957881428',
534
+ '__dyn': '7xeUjG1mxu1syUqxemh0no6u5U4e2C1vzEdE98K360CEbo1nEhw2nVEtwMw6ywaq221FwpUO0n24oaEnxO0Bo7O2l0Fwqo31w9O1lwlE-U2zxe2GewbS361qw82dUlwhE-15wmo423-0j52oS0Io5d0bS1LBwNwKG0WE8oC1IwGw-wlUcE2-G2O7E5y1rwa211wo84y1iwfe1aw',
535
+ '__csr': 'gaJNBjWsAJvliQPqlWFFknAiUB2bBjWLmhyblepaGyVFGy8y2i5pEW68mwwwPwxgtNgv2AMEu6PAgrCwc7F212xxe5YyVC1pAg01sq99uQ1zK0dp75gKzAy8y0EjcgQ8Ek0yMJC6G1og5KrXD4GexS8wdasU8U1e4075UeEuwfCA8K0hWiU2tAyE5m0gm0Jo0xUGxh1veU0gGyWfe0iK1xo32yXhoKkw56pwMw1e25onU4i0TA0xaxu00B1Q2ha2K3V0eqCmawnEgg2Gw',
536
+ '__hsdp': 'gdDdNhMlJ8bNG7i42aHgWzckH57ylAt8NkkOGCVQ8Ay8myETxW1vh48gHx-UC9Bgpy87G0BUfU7i0JFUeo7Cm12wlo5OawRwDwzxW1zg33wgodU',
537
+ '__hblp': '08W5EWt0BzUWp5Q4vz4HOk5kVogDGqmHgyi8xq9gNrxG1vh8B2K6pry4mVk8x28wuE5a1DxO1Qwr84Cu3C1VBwCxK2W2qi2y1LwDwzyK445Gwi63-0wUkxa9AyEjgogy3-',
538
+ '__sjsp': 'gdDtsAFMlJ8bNG7i47AG5lxmUmDiFQca9U',
539
+ '__comet_req': '72',
540
+ 'fb_dtsg': self.fb_dtsg,
541
+ 'jazoest': '25499',
542
+ 'lsd': self.lsd,
543
+ '__spin_r': '1030219547',
544
+ '__spin_b': 'trunk',
545
+ '__spin_t': str(int(time.time())),
546
+ '__jssesw': '1',
547
+ '__crn': 'comet.kadabra.KadabraAssistantRoute',
548
+ 'fb_api_caller_class': 'RelayModern',
549
+ 'fb_api_req_friendly_name': 'KadabraPromptRootQuery',
550
+ 'server_timestamps': 'true',
551
+ 'variables': json.dumps(variables),
552
+ 'doc_id': '25290569913909283',
553
+ }
554
+
555
+ for attempt in range(1, max_attempts + 1):
556
+ try:
557
+ response = requests.post(
558
+ self.GRAPHQL_URL,
559
+ cookies=self.cookies,
560
+ headers=headers,
561
+ data=data,
562
+ timeout=30
563
+ )
564
+
565
+ if response.status_code == 200:
566
+ # Extract video URLs from response
567
+ video_urls = self._extract_video_urls_from_response(response.text)
568
+
569
+ if video_urls:
570
+ return video_urls
571
+ else:
572
+ time.sleep(wait_seconds)
573
+ else:
574
+ time.sleep(wait_seconds)
575
+
576
+ except Exception as e:
577
+ time.sleep(wait_seconds)
578
+
579
+ return []
580
+
581
+ @staticmethod
582
+ def _extract_video_urls_from_response(response_text: str) -> List[str]:
583
+ """
584
+ Extract video URLs from Meta AI GraphQL response.
585
+ Searches for URLs containing 'fbcdn' and video-related patterns.
586
+
587
+ Args:
588
+ response_text: The response text to extract URLs from
589
+
590
+ Returns:
591
+ List of video URLs
592
+ """
593
+ video_urls = set()
594
+
595
+ try:
596
+ # Try to parse as JSON
597
+ data = json.loads(response_text)
598
+
599
+ # Recursively search for video URLs
600
+ def search_for_urls(obj, path=""):
601
+ if isinstance(obj, dict):
602
+ for key, value in obj.items():
603
+ # Look for fields that might contain video URLs
604
+ if key in ['video_url', 'progressive_url', 'generated_video_uri', 'uri', 'url',
605
+ 'manifest_url', 'hls_playlist_url']:
606
+ if isinstance(value, str) and 'fbcdn' in value and '.mp4' in value:
607
+ video_urls.add(value)
608
+ search_for_urls(value, f"{path}.{key}")
609
+ elif isinstance(obj, list):
610
+ for i, item in enumerate(obj):
611
+ search_for_urls(item, f"{path}[{i}]")
612
+ elif isinstance(obj, str):
613
+ # Check if string contains video URL pattern
614
+ if 'fbcdn' in obj and ('.mp4' in obj or 'video' in obj.lower()):
615
+ # Extract URL from string if it's embedded
616
+ import re
617
+ urls = re.findall(r'https?://[^\s"\'<>]+\.mp4[^\s"\'<>]*', obj)
618
+ video_urls.update(urls)
619
+
620
+ search_for_urls(data)
621
+
622
+ except json.JSONDecodeError:
623
+ # If not valid JSON, try regex extraction
624
+ import re
625
+ urls = re.findall(r'https?://[^\s"\'<>]+fbcdn[^\s"\'<>]+\.mp4[^\s"\'<>]*', response_text)
626
+ video_urls.update(urls)
627
+
628
+ return list(video_urls)
629
+
630
+ def generate_video(
631
+ self,
632
+ prompt: str,
633
+ wait_before_poll: int = 10,
634
+ max_attempts: int = 30,
635
+ wait_seconds: int = 5,
636
+ verbose: bool = True
637
+ ) -> Dict:
638
+ """
639
+ Main function to generate video and retrieve URLs.
640
+
641
+ Args:
642
+ prompt: Text prompt for video generation
643
+ wait_before_poll: Seconds to wait before starting to poll
644
+ max_attempts: Maximum polling attempts
645
+ wait_seconds: Seconds between polling attempts
646
+ verbose: Whether to print status messages
647
+
648
+ Returns:
649
+ Dictionary with success status, conversation_id, prompt, video_urls, and timestamp
650
+ """
651
+ # Step 1: Create video generation request
652
+ conversation_id = self.create_video_generation_request(
653
+ prompt_text=prompt,
654
+ verbose=verbose
655
+ )
656
+
657
+ if not conversation_id:
658
+ return {"success": False, "error": "Failed to create video generation request"}
659
+
660
+ # Step 2: Wait a bit before polling
661
+ time.sleep(wait_before_poll)
662
+
663
+ # Step 3: Poll for video URLs
664
+ video_urls = self.fetch_video_urls(
665
+ conversation_id=conversation_id,
666
+ max_attempts=max_attempts,
667
+ wait_seconds=wait_seconds,
668
+ verbose=verbose
669
+ )
670
+
671
+ result = {
672
+ "success": len(video_urls) > 0,
673
+ "conversation_id": conversation_id,
674
+ "prompt": prompt,
675
+ "video_urls": video_urls,
676
+ "timestamp": time.time()
677
+ }
678
+
679
+ return result