metaai-sdk 2.3.6__tar.gz → 3.0.0__tar.gz
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_sdk-2.3.6 → metaai_sdk-3.0.0}/PKG-INFO +1 -1
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_api/api_server.py +28 -7
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_sdk.egg-info/PKG-INFO +1 -1
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_sdk.egg-info/SOURCES.txt +5 -0
- metaai_sdk-3.0.0/test_api_quick.py +179 -0
- metaai_sdk-3.0.0/test_comprehensive.py +513 -0
- metaai_sdk-3.0.0/test_orientation.py +117 -0
- metaai_sdk-3.0.0/test_orientation_all.py +212 -0
- metaai_sdk-3.0.0/test_video_orientation.py +121 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/.env.example +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/CHANGELOG.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/CONTRIBUTING.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/ChatGPT Image Jan 14, 2026, 06_59_02 PM.png +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/DEPLOYMENT_FIX.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/Dockerfile +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/IMAGE_UPLOAD_README.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/IMPLEMENTATION_SUMMARY.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/LICENSE +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/MANIFEST.in +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/QUICK_REFERENCE.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/QUICK_USAGE.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/README.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/SECURITY.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/VIDEO_GENERATION_README.md +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/analyze_debug_responses.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/debug_async_video_test.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/download.jpg +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/enable_debug_logging.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/examples/complete_workflow_example.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/examples/image_upload_example.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/examples/image_workflow_complete.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/examples/practical_use_cases.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/examples/simple_example.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/examples/test_example.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/examples/video_generation.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/final_comprehensive_test.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/meta_ai_debug.log +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/pyproject.toml +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/quick_video_test.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/requirements.txt +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/setup.cfg +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_api/__init__.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_api/client.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_api/exceptions.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_api/image_upload.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_api/main.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_api/utils.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_api/video_generation.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_sdk.egg-info/dependency_links.txt +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_sdk.egg-info/requires.txt +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/src/metaai_sdk.egg-info/top_level.txt +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/test_endpoints.py +0 -0
- {metaai_sdk-2.3.6 → metaai_sdk-3.0.0}/test_image_upload.py +0 -0
|
@@ -107,12 +107,14 @@ class ImageRequest(BaseModel):
|
|
|
107
107
|
new_conversation: bool = False
|
|
108
108
|
media_ids: Optional[list] = None
|
|
109
109
|
attachment_metadata: Optional[dict] = None # {'file_size': int, 'mime_type': str}
|
|
110
|
+
orientation: Optional[str] = None # 'VERTICAL', 'LANDSCAPE' (not HORIZONTAL), or 'SQUARE'
|
|
110
111
|
|
|
111
112
|
|
|
112
113
|
class VideoRequest(BaseModel):
|
|
113
114
|
prompt: str
|
|
114
115
|
media_ids: Optional[list] = None
|
|
115
116
|
attachment_metadata: Optional[dict] = None # {'file_size': int, 'mime_type': str}
|
|
117
|
+
orientation: Optional[str] = None # 'VERTICAL', 'LANDSCAPE', or 'SQUARE'
|
|
116
118
|
wait_before_poll: int = Field(10, ge=0, le=60)
|
|
117
119
|
max_attempts: int = Field(30, ge=1, le=60)
|
|
118
120
|
wait_seconds: int = Field(5, ge=1, le=30)
|
|
@@ -206,7 +208,14 @@ async def chat(body: ChatRequest, cookies: Dict[str, str] = Depends(get_cookies)
|
|
|
206
208
|
raise HTTPException(status_code=400, detail="Streaming not supported via HTTP JSON; set stream=false")
|
|
207
209
|
ai = MetaAI(cookies=cookies, proxy=_get_proxies())
|
|
208
210
|
try:
|
|
209
|
-
return cast(Dict[str, Any],
|
|
211
|
+
return cast(Dict[str, Any], await run_in_threadpool(
|
|
212
|
+
ai.prompt,
|
|
213
|
+
body.message,
|
|
214
|
+
stream=False,
|
|
215
|
+
new_conversation=body.new_conversation,
|
|
216
|
+
media_ids=body.media_ids,
|
|
217
|
+
attachment_metadata=body.attachment_metadata
|
|
218
|
+
))
|
|
210
219
|
except Exception as exc: # noqa: BLE001
|
|
211
220
|
await cache.refresh_after_error()
|
|
212
221
|
raise HTTPException(status_code=502, detail=str(exc)) from exc
|
|
@@ -218,13 +227,15 @@ async def image(body: ImageRequest, cookies: Dict[str, str] = Depends(get_cookie
|
|
|
218
227
|
try:
|
|
219
228
|
# Automatically prepend "generate image of" to the prompt
|
|
220
229
|
prompt = f"generate image of {body.prompt}" if not body.prompt.lower().startswith(("generate image", "create image")) else body.prompt
|
|
221
|
-
return cast(Dict[str, Any],
|
|
222
|
-
prompt,
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
230
|
+
return cast(Dict[str, Any], await run_in_threadpool(
|
|
231
|
+
ai.prompt,
|
|
232
|
+
prompt,
|
|
233
|
+
stream=False,
|
|
234
|
+
new_conversation=body.new_conversation,
|
|
235
|
+
media_ids=body.media_ids,
|
|
226
236
|
attachment_metadata=body.attachment_metadata,
|
|
227
|
-
is_image_generation=True # Image generation uses DISCOVER entrypoint
|
|
237
|
+
is_image_generation=True, # Image generation uses DISCOVER entrypoint
|
|
238
|
+
orientation=body.orientation # Support VERTICAL, HORIZONTAL, SQUARE
|
|
228
239
|
))
|
|
229
240
|
except Exception as exc: # noqa: BLE001
|
|
230
241
|
await cache.refresh_after_error()
|
|
@@ -233,6 +244,10 @@ async def image(body: ImageRequest, cookies: Dict[str, str] = Depends(get_cookie
|
|
|
233
244
|
|
|
234
245
|
@app.post("/video")
|
|
235
246
|
async def video(body: VideoRequest, cookies: Dict[str, str] = Depends(get_cookies)) -> Dict[str, Any]:
|
|
247
|
+
# Force refresh cookies before video generation for best results
|
|
248
|
+
await cache.refresh_if_needed(force=True)
|
|
249
|
+
cookies = await cache.snapshot()
|
|
250
|
+
|
|
236
251
|
ai = MetaAI(cookies=cookies, proxy=_get_proxies())
|
|
237
252
|
try:
|
|
238
253
|
# Automatically prepend "generate a video" to the prompt
|
|
@@ -242,6 +257,7 @@ async def video(body: VideoRequest, cookies: Dict[str, str] = Depends(get_cookie
|
|
|
242
257
|
prompt,
|
|
243
258
|
body.media_ids,
|
|
244
259
|
body.attachment_metadata,
|
|
260
|
+
body.orientation,
|
|
245
261
|
body.wait_before_poll,
|
|
246
262
|
body.max_attempts,
|
|
247
263
|
body.wait_seconds,
|
|
@@ -254,6 +270,10 @@ async def video(body: VideoRequest, cookies: Dict[str, str] = Depends(get_cookie
|
|
|
254
270
|
|
|
255
271
|
@app.post("/video/async")
|
|
256
272
|
async def video_async(body: VideoRequest, cookies: Dict[str, str] = Depends(get_cookies)) -> Dict[str, str]:
|
|
273
|
+
# Force refresh cookies before video generation
|
|
274
|
+
await cache.refresh_if_needed(force=True)
|
|
275
|
+
cookies = await cache.snapshot()
|
|
276
|
+
|
|
257
277
|
job = await jobs.create()
|
|
258
278
|
asyncio.create_task(_run_video_job(job.job_id, body, cookies))
|
|
259
279
|
return {"job_id": job.job_id, "status": "pending"}
|
|
@@ -322,6 +342,7 @@ async def _run_video_job(job_id: str, body: VideoRequest, cookies: Dict[str, str
|
|
|
322
342
|
body.prompt,
|
|
323
343
|
body.media_ids,
|
|
324
344
|
body.attachment_metadata,
|
|
345
|
+
body.orientation,
|
|
325
346
|
body.wait_before_poll,
|
|
326
347
|
body.max_attempts,
|
|
327
348
|
body.wait_seconds,
|
|
@@ -22,8 +22,13 @@ meta_ai_debug.log
|
|
|
22
22
|
pyproject.toml
|
|
23
23
|
quick_video_test.py
|
|
24
24
|
requirements.txt
|
|
25
|
+
test_api_quick.py
|
|
26
|
+
test_comprehensive.py
|
|
25
27
|
test_endpoints.py
|
|
26
28
|
test_image_upload.py
|
|
29
|
+
test_orientation.py
|
|
30
|
+
test_orientation_all.py
|
|
31
|
+
test_video_orientation.py
|
|
27
32
|
examples/complete_workflow_example.py
|
|
28
33
|
examples/image_upload_example.py
|
|
29
34
|
examples/image_workflow_complete.py
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Quick API test with timeout handling
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
API_URL = "http://localhost:8000"
|
|
9
|
+
TIMEOUT = 120 # 2 minutes timeout for each request
|
|
10
|
+
|
|
11
|
+
def test_health():
|
|
12
|
+
"""Test health check endpoint"""
|
|
13
|
+
print("\n" + "="*70)
|
|
14
|
+
print("TEST: Health Check")
|
|
15
|
+
print("="*70)
|
|
16
|
+
try:
|
|
17
|
+
response = requests.get(f"{API_URL}/healthz", timeout=5)
|
|
18
|
+
print(f"✓ Status: {response.status_code}")
|
|
19
|
+
print(f" Response: {response.json()}")
|
|
20
|
+
return True
|
|
21
|
+
except Exception as e:
|
|
22
|
+
print(f"✗ Error: {e}")
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
def test_chat():
|
|
26
|
+
"""Test basic chat endpoint"""
|
|
27
|
+
print("\n" + "="*70)
|
|
28
|
+
print("TEST: Chat Endpoint (Simple)")
|
|
29
|
+
print("="*70)
|
|
30
|
+
try:
|
|
31
|
+
payload = {
|
|
32
|
+
"message": "What is 2+2?",
|
|
33
|
+
"stream": False,
|
|
34
|
+
"new_conversation": True
|
|
35
|
+
}
|
|
36
|
+
print(f"Request: {payload}")
|
|
37
|
+
response = requests.post(
|
|
38
|
+
f"{API_URL}/chat",
|
|
39
|
+
headers={"Content-Type": "application/json"},
|
|
40
|
+
json=payload,
|
|
41
|
+
timeout=TIMEOUT
|
|
42
|
+
)
|
|
43
|
+
print(f"✓ Status: {response.status_code}")
|
|
44
|
+
if response.status_code == 200:
|
|
45
|
+
result = response.json()
|
|
46
|
+
print(f" Message: {result.get('message', 'No message')[:200]}")
|
|
47
|
+
return True
|
|
48
|
+
else:
|
|
49
|
+
print(f" Error: {response.text}")
|
|
50
|
+
return False
|
|
51
|
+
except requests.Timeout:
|
|
52
|
+
print(f"✗ Timeout after {TIMEOUT}s")
|
|
53
|
+
return False
|
|
54
|
+
except Exception as e:
|
|
55
|
+
print(f"✗ Error: {e}")
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
def test_upload():
|
|
59
|
+
"""Test image upload endpoint"""
|
|
60
|
+
print("\n" + "="*70)
|
|
61
|
+
print("TEST: Image Upload")
|
|
62
|
+
print("="*70)
|
|
63
|
+
|
|
64
|
+
import os
|
|
65
|
+
from pathlib import Path
|
|
66
|
+
|
|
67
|
+
# Find an image to upload
|
|
68
|
+
image_path = r"C:\Users\spike\Downloads\meta-ai-api-main\ChatGPT Image Jan 14, 2026, 06_59_02 PM.png"
|
|
69
|
+
|
|
70
|
+
if not os.path.exists(image_path):
|
|
71
|
+
print(f"✗ Image not found: {image_path}")
|
|
72
|
+
return False, None
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
with open(image_path, 'rb') as f:
|
|
76
|
+
files = {'file': f}
|
|
77
|
+
response = requests.post(
|
|
78
|
+
f"{API_URL}/upload",
|
|
79
|
+
files=files,
|
|
80
|
+
timeout=TIMEOUT
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
print(f"✓ Status: {response.status_code}")
|
|
84
|
+
if response.status_code == 200:
|
|
85
|
+
result = response.json()
|
|
86
|
+
media_id = result.get('media_id')
|
|
87
|
+
print(f" Media ID: {media_id}")
|
|
88
|
+
print(f" File Size: {result.get('file_size')} bytes")
|
|
89
|
+
print(f" MIME Type: {result.get('mime_type')}")
|
|
90
|
+
metadata = {
|
|
91
|
+
'file_size': result.get('file_size'),
|
|
92
|
+
'mime_type': result.get('mime_type')
|
|
93
|
+
}
|
|
94
|
+
return True, (media_id, metadata)
|
|
95
|
+
else:
|
|
96
|
+
print(f" Error: {response.text}")
|
|
97
|
+
return False, None
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(f"✗ Error: {e}")
|
|
100
|
+
return False, None
|
|
101
|
+
|
|
102
|
+
def test_image_generation():
|
|
103
|
+
"""Test image generation endpoint"""
|
|
104
|
+
print("\n" + "="*70)
|
|
105
|
+
print("TEST: Image Generation")
|
|
106
|
+
print("="*70)
|
|
107
|
+
try:
|
|
108
|
+
payload = {
|
|
109
|
+
"prompt": "a cute cat wearing sunglasses",
|
|
110
|
+
"new_conversation": True
|
|
111
|
+
}
|
|
112
|
+
print(f"Request: {payload}")
|
|
113
|
+
response = requests.post(
|
|
114
|
+
f"{API_URL}/image",
|
|
115
|
+
headers={"Content-Type": "application/json"},
|
|
116
|
+
json=payload,
|
|
117
|
+
timeout=TIMEOUT
|
|
118
|
+
)
|
|
119
|
+
print(f"✓ Status: {response.status_code}")
|
|
120
|
+
if response.status_code == 200:
|
|
121
|
+
result = response.json()
|
|
122
|
+
print(f" Message: {result.get('message', 'No message')[:200]}")
|
|
123
|
+
media = result.get('media', [])
|
|
124
|
+
print(f" Media count: {len(media)}")
|
|
125
|
+
for i, m in enumerate(media[:2], 1):
|
|
126
|
+
print(f" {i}. {m.get('url', 'No URL')[:80]}...")
|
|
127
|
+
return True
|
|
128
|
+
else:
|
|
129
|
+
print(f" Error: {response.text}")
|
|
130
|
+
return False
|
|
131
|
+
except requests.Timeout:
|
|
132
|
+
print(f"✗ Timeout after {TIMEOUT}s")
|
|
133
|
+
return False
|
|
134
|
+
except Exception as e:
|
|
135
|
+
print(f"✗ Error: {e}")
|
|
136
|
+
return False
|
|
137
|
+
|
|
138
|
+
def main():
|
|
139
|
+
"""Run all tests"""
|
|
140
|
+
print("\n" + "+"*70)
|
|
141
|
+
print(" API QUICK TEST SUITE")
|
|
142
|
+
print("+"*70)
|
|
143
|
+
print(f"\nAPI URL: {API_URL}")
|
|
144
|
+
print(f"Timeout: {TIMEOUT}s per request\n")
|
|
145
|
+
|
|
146
|
+
results = {}
|
|
147
|
+
|
|
148
|
+
# Test 1: Health
|
|
149
|
+
results['health'] = test_health()
|
|
150
|
+
|
|
151
|
+
# Test 2: Chat
|
|
152
|
+
results['chat'] = test_chat()
|
|
153
|
+
|
|
154
|
+
# Test 3: Upload
|
|
155
|
+
upload_success, upload_data = test_upload()
|
|
156
|
+
results['upload'] = upload_success
|
|
157
|
+
|
|
158
|
+
# Test 4: Image Generation
|
|
159
|
+
results['image'] = test_image_generation()
|
|
160
|
+
|
|
161
|
+
# Summary
|
|
162
|
+
print("\n" + "="*70)
|
|
163
|
+
print("SUMMARY")
|
|
164
|
+
print("="*70)
|
|
165
|
+
for test_name, passed in results.items():
|
|
166
|
+
status = "✓ PASS" if passed else "✗ FAIL"
|
|
167
|
+
print(f"{test_name.ljust(20)}: {status}")
|
|
168
|
+
|
|
169
|
+
total = len(results)
|
|
170
|
+
passed = sum(results.values())
|
|
171
|
+
print(f"\nTotal: {passed}/{total} tests passed")
|
|
172
|
+
|
|
173
|
+
if passed == total:
|
|
174
|
+
print("\n✓ All tests passed!")
|
|
175
|
+
else:
|
|
176
|
+
print(f"\n✗ {total - passed} test(s) failed")
|
|
177
|
+
|
|
178
|
+
if __name__ == "__main__":
|
|
179
|
+
main()
|