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.
- metaai_api/__init__.py +20 -0
- metaai_api/api_server.py +256 -0
- metaai_api/client.py +140 -0
- metaai_api/exceptions.py +6 -0
- metaai_api/main.py +534 -0
- metaai_api/utils.py +291 -0
- metaai_api/video_generation.py +679 -0
- metaai_sdk-2.0.0.dist-info/METADATA +846 -0
- metaai_sdk-2.0.0.dist-info/RECORD +12 -0
- metaai_sdk-2.0.0.dist-info/WHEEL +5 -0
- metaai_sdk-2.0.0.dist-info/licenses/LICENSE +28 -0
- metaai_sdk-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -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
|