Repository: Strvm/meta-ai-api
Branch: main
Commit: 89655182ef3e
Files: 11
Total size: 39.0 KB
Directory structure:
gitextract_aa7abxek/
├── .github/
│ └── workflows/
│ └── python-publish.yml
├── .gitignore
├── README.md
├── pyproject.toml
├── requirements.txt
├── setup.cfg
├── setup.py
└── src/
└── meta_ai_api/
├── __init__.py
├── exceptions.py
├── main.py
└── utils.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/python-publish.yml
================================================
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Upload Python Package
on:
release:
types: [published]
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
pip install wheel
pip install setuptools
- name: Build package
run: python3 setup.py sdist bdist_wheel
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.idea
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
================================================
FILE: README.md
================================================
# MetaAI API Wrapper
MetaAI is a Python library designed to interact with Meta's AI APIs that run in the backend of https://www.meta.ai/. It encapsulates the complexities of authentication and communication with the APIs, providing a straightforward interface for sending queries and receiving responses.
With this you can easily prompt the AI with a message and get a response, directly from your Python code. **NO API KEY REQUIRED**
**Meta AI is connected to the internet, so you will be able to get the latest real-time responses from the AI.** (powered by Bing)
Meta AI is running Llama 3 LLM.
## Features
- **Prompt AI**: Send a message to the AI and get a response from Llama 3.
- **Image Generation**: Generate images using the AI. (Only for FB authenticated users)
- **Get Up To Date Information**: Get the latest information from the AI thanks to its connection to the internet.
- **Get Sources**: Get the sources of the information provided by the AI.
- **Streaming**: Stream the AI's response in real-time or get the final response.
- **Follow Conversations**: Start a new conversation or follow up on an existing one.
## Usage
**Download**:
```bash
pip install meta-ai-api
```
**Initialization**:
```python
from meta_ai_api import MetaAI
ai = MetaAI()
response = ai.prompt(message="Whats the weather in San Francisco today? And what is the date?")
print(response)
```
```json
{
"message":"The weather in San Francisco today is mostly clear to overcast, with no precipitation, a wind speed between 0 and 8 miles per hour and temperatures ranging from 51 to 55 degrees Fahrenheit ¹. The date is Friday, April 19, 2024 ². Please note that the weather forecast is continually changing ³ ⁴ ⁵ ⁶.\n",
"sources":[
{
"link":"https://www.wolframalpha.com/input?i=San+Francisco+weather+today+and+date",
"title":"WolframAlpha"
},
{
"link":"https://www.timeanddate.com/weather/usa/san-francisco",
"title":"Weather for San Francisco, California, USA - timeanddate.com"
},
{
"link":"https://www.accuweather.com/en/us/san-francisco/94103/weather-today/347629",
"title":"Weather Today for San Francisco, CA | AccuWeather"
},
{
"link":"https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629",
"title":"San Francisco, CA Weather Forecast | AccuWeather"
},
{
"link":"https://forecast.weather.gov/zipcity.php?inputstring=San%20francisco%2CCA",
"title":"National Weather Service"
},
{
"link":"https://www.wunderground.com/weather/us/ca/san-francisco",
"title":"San Francisco, CA Weather Conditions | Weather Underground"
}
]
}
```
---
### Follow conversations:
```python
```python
meta = MetaAI()
print(meta.prompt("what is 2 + 2?"))
print(meta.prompt("what was my previous question?"))
```
```
{'message': '2 + 2 = 4\n', 'sources': [], 'media': []}
{'message': 'Your previous question was "what is 2 + 2?"\n', 'sources': [], 'media': []}
```
And to start a new one:
```python
meta = MetaAI()
print(meta.prompt("what is 2 + 2?"))
print(meta.prompt("what was my previous question?", new_conversation=True))
```
```
{'message': '2 + 2 = 4\n', 'sources': [], 'media': []}
{'message': "This is the beginning of our conversation, so I don't have a previous question to refer to. I'm happy to chat with you, though! What's on your mind today?\n", 'sources': [], 'media': []}
```
---
```python
from meta_ai_api import MetaAI
ai = MetaAI()
response = ai.prompt(message="What was the Warriors score last game?")
print(response)
```
```json
{
"message":"The Golden State Warriors' last game was against the Sacramento Kings, and they lost 118-94 ¹ ². Stephen Curry scored 22 points, and the Kings' win eliminated the Warriors from the playoffs ³. The Warriors finished the season 46-36 and 10th in the Western Conference ⁴ ³.\n",
"sources":[
{
"link":"https://sportradar.com/",
"title":"Game Info of NBA from sportradar.com"
},
{
"link":"https://www.sofascore.com/team/basketball/golden-state-warriors/3428",
"title":"Golden State Warriors live scores & schedule - Sofascore"
},
{
"link":"https://www.foxsports.com/nba/golden-state-warriors-team-schedule",
"title":"Golden State Warriors Schedule & Scores - NBA - FOX Sports"
},
{
"link":"https://en.wikipedia.org/wiki/History_of_the_Golden_State_Warriors",
"title":"History of the Golden State Warriors"
}
]
}
```
**Using proxy**:
```python
from meta_ai_api import MetaAI
proxy = {
'http': 'http://proxy_address:port',
'https': 'https://proxy_address:port'
}
ai = MetaAI(proxy=proxy)
response = ai.prompt(message="How to find out which mushrooms are edible?")
print(response)
```
**Streaming Response**:
```python
from meta_ai_api import MetaAI
ai = MetaAI()
response = ai.prompt(message="What was the Warriors score last game?", stream=True)
for r in response:
print(r)
```
```
{'message': '\n', 'sources': []}
{'message': 'The\n', 'sources': []}
{'message': 'The Golden\n', 'sources': []}
{'message': 'The Golden State\n', 'sources': []}
{'message': 'The Golden State Warriors\n', 'sources': []}
{'message': "The Golden State Warriors'\n", 'sources': []}
{'message': "The Golden State Warriors' last\n", 'sources': []}
{'message': "The Golden State Warriors' last game\n", 'sources': []}
{'message': "The Golden State Warriors' last game was\n", 'sources': []}
{'message': "The Golden State Warriors' last game was against\n", 'sources': []}
{'message': "The Golden State Warriors' last game was against the\n", 'sources': []}
{'message': "The Golden State Warriors' last game was against the Sacramento\n", 'sources': []}
{'message': "The Golden State Warriors' last game was against the Sacramento Kings\n", 'sources': []}
{'message': "The Golden State Warriors' last game was against the Sacramento Kings on\n", 'sources': []}
{'message': "The Golden State Warriors' last game was against the Sacramento Kings on April\n", 'sources': []}
...
{'message': "The Golden State Warriors' last game was against the Sacramento Kings on April 16, 2024, at the Golden 1 Center in Sacramento, California. The Kings won the game with a score of 118-94, with the Warriors scoring 22 points in the first quarter, 28 in the second, 26 in the third and 18 in the fourth quarter ¹.\n", 'sources': [{'link': 'https://sportradar.com/', 'title': 'Game Info of NBA from sportradar.com'}]}
```
**Generate Image**:
By default image generation is only available for FB authenticated users. If you go on https://www.meta.ai/ , and ask the AI to generate an image, you will be prompted to authenticate with Facebook.
So if you want to generate images using this library, you need to authenticate using your FB credentials.
**Note**: There seems to be higher rate limits for authenticated users. So only authenticate to generate images.
```python
from meta_ai_api import MetaAI
ai = MetaAI(fb_email="your_fb_email", fb_password="your_fb_password")
resp = ai.prompt(message="Generate an image of a tech CEO")
print(resp)
```
```json
{
"message":"\n",
"sources":[
],
"media":[
{
"url":"https://scontent-lax3-1.xx.fbcdn.net/o1/v/t0/f1/m247/4282108942387920518_1946149595_21-04-2024-14-17-48.jpeg?_nc_ht=scontent-lax3-1.xx.fbcdn.net&_nc_cat=103&ccb=9-4&oh=00_AfCnbCX7nl_J5kF6mahnams4d99Rs5WZA780HGS_scfc6A&oe=662771EE&_nc_sid=5b3566",
"type":"IMAGE",
"prompt":"a tech CEO"
},
{
"url":"https://scontent-lax3-1.xx.fbcdn.net/o1/v/t0/f1/m247/3356467762794691754_1025991308_21-04-2024-14-17-48.jpeg?_nc_ht=scontent-lax3-1.xx.fbcdn.net&_nc_cat=108&ccb=9-4&oh=00_AfBLmSbTSqshNAL82KIFk8hGXyL8iK_CZLGcMmmddPrxuA&oe=66276EDD&_nc_sid=5b3566",
"type":"IMAGE",
"prompt":"a tech CEO"
},
{
"url":"https://scontent-lax3-1.xx.fbcdn.net/o1/v/t0/f1/m247/127487551948523111_2181921077_21-04-2024-14-17-48.jpeg?_nc_ht=scontent-lax3-1.xx.fbcdn.net&_nc_cat=104&ccb=9-4&oh=00_AfAejXKeKPA4vyKXoc6UR0rEirvZwi41P3KiCSQmHRHsEw&oe=66276E45&_nc_sid=5b3566",
"type":"IMAGE",
"prompt":"a tech CEO"
},
{
"url":"https://scontent-lax3-1.xx.fbcdn.net/o1/v/t0/f1/m247/3497663176351797954_3954783377_21-04-2024-14-17-47.jpeg?_nc_ht=scontent-lax3-1.xx.fbcdn.net&_nc_cat=110&ccb=9-4&oh=00_AfBp3bAfcuofqtI-z9D4bHw-GuGgCNPH_xhMM0PG_95S9Q&oe=66277AE9&_nc_sid=5b3566",
"type":"IMAGE",
"prompt":"a tech CEO"
}
]
}
```

# Educational Purpose:
This repository is intended for educational purposes only. It is a tool to demonstrate how to interact with Meta's AI APIs, providing an example for learning and experimentation. Users should adhere to Meta's terms of service and use the library responsibly.
# Copyright:
This program is licensed under the GNU GPL v3. All code has been written by me, Strvm.
# Copyright Notice:
```
Strvm/meta-ai-api: a reverse engineered API wrapper for MetaAI
Copyright (C) 2023 Strvm
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
```
# Meta Copyright:
For more information related to the license tied to Llama, please visit https://www.llama.com/llama3/license/
================================================
FILE: pyproject.toml
================================================
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "meta_ai_api"
version = "0.1.0"
description = "Interact with the Meta AI API"
authors = ["Romeo Phillips"]
[tool.poetry.dependencies]
python = "^3.7"
requests = "2.31.0"
requests-html = "0.10.0"
lxml_html_cleaner = "0.1.1"
bs4 = "0.0.2"
[build]
script = "build.py"
================================================
FILE: requirements.txt
================================================
requests==2.31.0
requests-html==0.10.0
lxml_html_clean==0.1.1
bs4==0.0.2
================================================
FILE: setup.cfg
================================================
[metadata]
version = attr: meta_ai_api.__version__
================================================
FILE: setup.py
================================================
import setuptools
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
setuptools.setup(
name="meta_ai_api",
author="Roméo Phillips",
author_email="phillipsromeo@gmail.com",
description="Meta AI API Wrapper to interact with the Meta AI API",
keywords="llm, ai, meta_ai_api",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/tomchen/example_pypi_package",
project_urls={
"Documentation": "https://github.com/Strvm/meta-ai-api",
"Bug Reports": "https://github.com/Strvm/meta-ai-api",
"Source Code": "https://github.com/Strvm/meta-ai-api",
},
package_dir={"": "src"},
packages=setuptools.find_packages(where="src"),
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3 :: Only",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires=">=3.6",
extras_require={
"dev": ["check-manifest"],
},
install_requires=["requests", "requests-html", "lxml_html_clean"],
)
================================================
FILE: src/meta_ai_api/__init__.py
================================================
__version__ = "1.2.5"
from .main import MetaAI # noqa
================================================
FILE: src/meta_ai_api/exceptions.py
================================================
class FacebookInvalidCredentialsException(Exception):
pass
class FacebookRegionBlocked(Exception):
pass
================================================
FILE: src/meta_ai_api/main.py
================================================
import json
import logging
import time
import urllib
import uuid
from typing import Dict, List, Generator, Iterator
import requests
from requests_html import HTMLSession
from meta_ai_api.utils import (
generate_offline_threading_id,
extract_value,
format_response,
)
from meta_ai_api.utils import get_fb_session, get_session
from meta_ai_api.exceptions import FacebookRegionBlocked
MAX_RETRIES = 3
class MetaAI:
"""
A class to interact with the Meta AI API to obtain and use access tokens for sending
and receiving messages from the Meta AI Chat API.
"""
def __init__(
self, fb_email: str = None, fb_password: str = None, proxy: dict = None
):
self.session = get_session()
self.session.headers.update(
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
}
)
self.access_token = None
self.fb_email = fb_email
self.fb_password = fb_password
self.proxy = proxy
self.is_authed = fb_password is not None and fb_email is not None
self.cookies = self.get_cookies()
self.external_conversation_id = None
self.offline_threading_id = None
def get_access_token(self) -> str:
"""
Retrieves an access token using Meta's authentication API.
Returns:
str: A valid access token.
"""
if self.access_token:
return self.access_token
url = "https://www.meta.ai/api/graphql/"
payload = {
"lsd": self.cookies["lsd"],
"fb_api_caller_class": "RelayModern",
"fb_api_req_friendly_name": "useAbraAcceptTOSForTempUserMutation",
"variables": {
"dob": "1999-01-01",
"icebreaker_type": "TEXT",
"__relay_internal__pv__WebPixelRatiorelayprovider": 1,
},
"doc_id": "7604648749596940",
}
payload = urllib.parse.urlencode(payload) # noqa
headers = {
"content-type": "application/x-www-form-urlencoded",
"cookie": f'_js_datr={self.cookies["_js_datr"]}; '
f'abra_csrf={self.cookies["abra_csrf"]}; datr={self.cookies["datr"]};',
"sec-fetch-site": "same-origin",
"x-fb-friendly-name": "useAbraAcceptTOSForTempUserMutation",
}
response = self.session.post(url, headers=headers, data=payload)
try:
auth_json = response.json()
except json.JSONDecodeError:
raise FacebookRegionBlocked(
"Unable to receive a valid response from Meta AI. This is likely due to your region being blocked. "
"Try manually accessing https://www.meta.ai/ to confirm."
)
access_token = auth_json["data"]["xab_abra_accept_terms_of_service"][
"new_temp_user_auth"
]["access_token"]
# Need to sleep for a bit, for some reason the API doesn't like it when we send request too quickly
# (maybe Meta needs to register Cookies on their side?)
time.sleep(1)
return access_token
def prompt(
self,
message: str,
stream: bool = False,
attempts: int = 0,
new_conversation: bool = False,
) -> Dict or Generator[Dict, None, None]:
"""
Sends a message to the Meta AI and returns the response.
Args:
message (str): The message to send.
stream (bool): Whether to stream the response or not. Defaults to False.
attempts (int): The number of attempts to retry if an error occurs. Defaults to 0.
new_conversation (bool): Whether to start a new conversation or not. Defaults to False.
Returns:
dict: A dictionary containing the response message and sources.
Raises:
Exception: If unable to obtain a valid response after several attempts.
"""
if not self.is_authed:
self.access_token = self.get_access_token()
auth_payload = {"access_token": self.access_token}
url = "https://graph.meta.ai/graphql?locale=user"
else:
auth_payload = {"fb_dtsg": self.cookies["fb_dtsg"]}
url = "https://www.meta.ai/api/graphql/"
if not self.external_conversation_id or new_conversation:
external_id = str(uuid.uuid4())
self.external_conversation_id = external_id
payload = {
**auth_payload,
"fb_api_caller_class": "RelayModern",
"fb_api_req_friendly_name": "useAbraSendMessageMutation",
"variables": json.dumps(
{
"message": {"sensitive_string_value": message},
"externalConversationId": self.external_conversation_id,
"offlineThreadingId": generate_offline_threading_id(),
"suggestedPromptIndex": None,
"flashVideoRecapInput": {"images": []},
"flashPreviewInput": None,
"promptPrefix": None,
"entrypoint": "ABRA__CHAT__TEXT",
"icebreaker_type": "TEXT",
"__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
"__relay_internal__pv__WebPixelRatiorelayprovider": 1,
}
),
"server_timestamps": "true",
"doc_id": "7783822248314888",
}
payload = urllib.parse.urlencode(payload) # noqa
headers = {
"content-type": "application/x-www-form-urlencoded",
"x-fb-friendly-name": "useAbraSendMessageMutation",
}
if self.is_authed:
headers["cookie"] = f'abra_sess={self.cookies["abra_sess"]}'
# Recreate the session to avoid cookie leakage when user is authenticated
self.session = requests.Session()
self.session.proxies = self.proxy
response = self.session.post(url, headers=headers, data=payload, stream=stream)
if not stream:
raw_response = response.text
last_streamed_response = self.extract_last_response(raw_response)
if not last_streamed_response:
return self.retry(message, stream=stream, attempts=attempts)
extracted_data = self.extract_data(last_streamed_response)
return extracted_data
else:
lines = response.iter_lines()
is_error = json.loads(next(lines))
if len(is_error.get("errors", [])) > 0:
return self.retry(message, stream=stream, attempts=attempts)
return self.stream_response(lines)
def retry(self, message: str, stream: bool = False, attempts: int = 0):
"""
Retries the prompt function if an error occurs.
"""
if attempts <= MAX_RETRIES:
logging.warning(
f"Was unable to obtain a valid response from Meta AI. Retrying... Attempt {attempts + 1}/{MAX_RETRIES}."
)
time.sleep(3)
return self.prompt(message, stream=stream, attempts=attempts + 1)
else:
raise Exception(
"Unable to obtain a valid response from Meta AI. Try again later."
)
def extract_last_response(self, response: str) -> Dict:
"""
Extracts the last response from the Meta AI API.
Args:
response (str): The response to extract the last response from.
Returns:
dict: A dictionary containing the last response.
"""
last_streamed_response = None
for line in response.split("\n"):
try:
json_line = json.loads(line)
except json.JSONDecodeError:
continue
bot_response_message = (
json_line.get("data", {})
.get("node", {})
.get("bot_response_message", {})
)
chat_id = bot_response_message.get("id")
if chat_id:
external_conversation_id, offline_threading_id, _ = chat_id.split("_")
self.external_conversation_id = external_conversation_id
self.offline_threading_id = offline_threading_id
streaming_state = bot_response_message.get("streaming_state")
if streaming_state == "OVERALL_DONE":
last_streamed_response = json_line
return last_streamed_response
def stream_response(self, lines: Iterator[str]):
"""
Streams the response from the Meta AI API.
Args:
lines (Iterator[str]): The lines to stream.
Yields:
dict: A dictionary containing the response message and sources.
"""
for line in lines:
if line:
json_line = json.loads(line)
extracted_data = self.extract_data(json_line)
if not extracted_data.get("message"):
continue
yield extracted_data
def extract_data(self, json_line: dict):
"""
Extract data and sources from a parsed JSON line.
Args:
json_line (dict): Parsed JSON line.
Returns:
Tuple (str, list): Response message and list of sources.
"""
bot_response_message = (
json_line.get("data", {}).get("node", {}).get("bot_response_message", {})
)
response = format_response(response=json_line)
fetch_id = bot_response_message.get("fetch_id")
sources = self.fetch_sources(fetch_id) if fetch_id else []
medias = self.extract_media(bot_response_message)
return {"message": response, "sources": sources, "media": medias}
@staticmethod
def extract_media(json_line: dict) -> List[Dict]:
"""
Extract media from a parsed JSON line.
Args:
json_line (dict): Parsed JSON line.
Returns:
list: A list of dictionaries containing the extracted media.
"""
medias = []
imagine_card = json_line.get("imagine_card", {})
session = imagine_card.get("session", {}) if imagine_card else {}
media_sets = (
(json_line.get("imagine_card", {}).get("session", {}).get("media_sets", []))
if imagine_card and session
else []
)
for media_set in media_sets:
imagine_media = media_set.get("imagine_media", [])
for media in imagine_media:
medias.append(
{
"url": media.get("uri"),
"type": media.get("media_type"),
"prompt": media.get("prompt"),
}
)
return medias
def get_cookies(self) -> dict:
"""
Extracts necessary cookies from the Meta AI main page.
Returns:
dict: A dictionary containing essential cookies.
"""
session = HTMLSession()
headers = {}
if self.fb_email is not None and self.fb_password is not None:
fb_session = get_fb_session(self.fb_email, self.fb_password)
headers = {"cookie": f"abra_sess={fb_session['abra_sess']}"}
response = session.get(
"https://www.meta.ai/",
headers=headers,
)
cookies = {
"_js_datr": extract_value(
response.text, start_str='_js_datr":{"value":"', end_str='",'
),
"datr": extract_value(
response.text, start_str='datr":{"value":"', end_str='",'
),
"lsd": extract_value(
response.text, start_str='"LSD",[],{"token":"', end_str='"}'
),
"fb_dtsg": extract_value(
response.text, start_str='DTSGInitData",[],{"token":"', end_str='"'
),
}
if len(headers) > 0:
cookies["abra_sess"] = fb_session["abra_sess"]
else:
cookies["abra_csrf"] = extract_value(
response.text, start_str='abra_csrf":{"value":"', end_str='",'
)
return cookies
def fetch_sources(self, fetch_id: str) -> List[Dict]:
"""
Fetches sources from the Meta AI API based on the given query.
Args:
fetch_id (str): The fetch ID to use for the query.
Returns:
list: A list of dictionaries containing the fetched sources.
"""
url = "https://graph.meta.ai/graphql?locale=user"
payload = {
"access_token": self.access_token,
"fb_api_caller_class": "RelayModern",
"fb_api_req_friendly_name": "AbraSearchPluginDialogQuery",
"variables": json.dumps({"abraMessageFetchID": fetch_id}),
"server_timestamps": "true",
"doc_id": "6946734308765963",
}
payload = urllib.parse.urlencode(payload) # noqa
headers = {
"authority": "graph.meta.ai",
"accept-language": "en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7",
"content-type": "application/x-www-form-urlencoded",
"cookie": f'dpr=2; abra_csrf={self.cookies.get("abra_csrf")}; datr={self.cookies.get("datr")}; ps_n=1; ps_l=1',
"x-fb-friendly-name": "AbraSearchPluginDialogQuery",
}
response = self.session.post(url, headers=headers, data=payload)
response_json = response.json()
message = response_json.get("data", {}).get("message", {})
search_results = (
(response_json.get("data", {}).get("message", {}).get("searchResults"))
if message
else None
)
if search_results is None:
return []
references = search_results["references"]
return references
if __name__ == "__main__":
meta = MetaAI()
resp = meta.prompt("What was the Warriors score last game?", stream=False)
print(resp)
================================================
FILE: src/meta_ai_api/utils.py
================================================
import logging
import random
import time
from typing import Dict, Optional
from requests_html import HTMLSession
import requests
from bs4 import BeautifulSoup
from meta_ai_api.exceptions import FacebookInvalidCredentialsException
def generate_offline_threading_id() -> str:
"""
Generates an offline threading ID.
Returns:
str: The generated offline threading ID.
"""
# Maximum value for a 64-bit integer in Python
max_int = (1 << 64) - 1
mask22_bits = (1 << 22) - 1
# Function to get the current timestamp in milliseconds
def get_current_timestamp():
return int(time.time() * 1000)
# Function to generate a random 64-bit integer
def get_random_64bit_int():
return random.getrandbits(64)
# Combine timestamp and random value
def combine_and_mask(timestamp, random_value):
shifted_timestamp = timestamp << 22
masked_random = random_value & mask22_bits
return (shifted_timestamp | masked_random) & max_int
timestamp = get_current_timestamp()
random_value = get_random_64bit_int()
threading_id = combine_and_mask(timestamp, random_value)
return str(threading_id)
def extract_value(text: str, start_str: str, end_str: str) -> str:
"""
Helper function to extract a specific value from the given text using a key.
Args:
text (str): The text from which to extract the value.
start_str (str): The starting key.
end_str (str): The ending key.
Returns:
str: The extracted value.
"""
start = text.find(start_str) + len(start_str)
end = text.find(end_str, start)
return text[start:end]
def format_response(response: dict) -> str:
"""
Formats the response from Meta AI to remove unnecessary characters.
Args:
response (dict): The dictionnary containing the response to format.
Returns:
str: The formatted response.
"""
text = ""
for content in (
response.get("data", {})
.get("node", {})
.get("bot_response_message", {})
.get("composed_text", {})
.get("content", [])
):
text += content["text"] + "\n"
return text
# Function to perform the login
def get_fb_session(email, password, proxies=None):
login_url = "https://www.facebook.com/login/?next"
headers = {
"authority": "mbasic.facebook.com",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "en-US,en;q=0.9",
"sec-ch-ua": '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
}
# Send the GET request
response = requests.get(login_url, headers=headers, proxies=proxies)
soup = BeautifulSoup(response.text, "html.parser")
# Parse necessary parameters from the login form
lsd = soup.find("input", {"name": "lsd"})["value"]
jazoest = soup.find("input", {"name": "jazoest"})["value"]
# Define the URL and body for the POST request to submit the login form
post_url = "https://www.facebook.com/login/?next"
data = {
"lsd": lsd,
"jazoest": jazoest,
"login_source": "comet_headerless_login",
"email": email,
"pass": password,
"login": "1",
"next": None,
}
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": None,
"Referer": "https://www.facebook.com/",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "https://www.facebook.com",
"DNT": "1",
"Sec-GPC": "1",
"Connection": "keep-alive",
"cookie": f"datr={response.cookies.get('datr')};",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-User": "?1",
"Priority": "u=0, i",
}
from requests import cookies
# Send the POST request
session = requests.session()
jar = cookies.RequestsCookieJar()
session.proxies = proxies
session.cookies = jar
result = session.post(post_url, headers=headers, data=data)
if "sb" not in jar or "xs" not in jar:
raise FacebookInvalidCredentialsException(
"Was not able to login to Facebook. Please check your credentials. "
"You may also have been rate limited. Try to connect to Facebook manually."
)
cookies = {
**result.cookies.get_dict(),
"sb": jar["sb"],
"xs": jar["xs"],
"fr": jar["fr"],
"c_user": jar["c_user"],
}
response_login = {
"cookies": cookies,
"headers": result.headers,
"response": response.text,
}
meta_ai_cookies = get_cookies()
url = "https://www.meta.ai/state/"
payload = f'__a=1&lsd={meta_ai_cookies["lsd"]}'
headers = {
"authority": "www.meta.ai",
"accept": "*/*",
"accept-language": "en-US,en;q=0.9",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"cookie": f'ps_n=1; ps_l=1; dpr=2; _js_datr={meta_ai_cookies["_js_datr"]}; abra_csrf={meta_ai_cookies["abra_csrf"]}; datr={meta_ai_cookies["datr"]};; ps_l=1; ps_n=1',
"origin": "https://www.meta.ai",
"pragma": "no-cache",
"referer": "https://www.meta.ai/",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
}
response = requests.request(
"POST", url, headers=headers, data=payload, proxies=proxies
)
state = extract_value(response.text, start_str='"state":"', end_str='"')
url = f"https://www.facebook.com/oidc/?app_id=1358015658191005&scope=openid%20linking&response_type=code&redirect_uri=https%3A%2F%2Fwww.meta.ai%2Fauth%2F&no_universal_links=1&deoia=1&state={state}"
payload = {}
headers = {
"authority": "www.facebook.com",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "en-US,en;q=0.9",
"cache-control": "no-cache",
"cookie": f"datr={response_login['cookies']['datr']}; sb={response_login['cookies']['sb']}; c_user={response_login['cookies']['c_user']}; xs={response_login['cookies']['xs']}; fr={response_login['cookies']['fr']}; abra_csrf={meta_ai_cookies['abra_csrf']};",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "cross-site",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
}
session = requests.session()
session.proxies = proxies
response = session.get(url, headers=headers, data=payload, allow_redirects=False)
next_url = response.headers["Location"]
url = next_url
payload = {}
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:125.0) Gecko/20100101 Firefox/125.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Referer": "https://www.meta.ai/",
"Connection": "keep-alive",
"Cookie": f'dpr=2; abra_csrf={meta_ai_cookies["abra_csrf"]}; datr={meta_ai_cookies["_js_datr"]}',
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "cross-site",
"Sec-Fetch-User": "?1",
"TE": "trailers",
}
session.get(url, headers=headers, data=payload)
cookies = session.cookies.get_dict()
if "abra_sess" not in cookies:
raise FacebookInvalidCredentialsException(
"Was not able to login to Facebook. Please check your credentials. "
"You may also have been rate limited. Try to connect to Facebook manually."
)
logging.info("Successfully logged in to Facebook.")
return cookies
def get_cookies() -> dict:
"""
Extracts necessary cookies from the Meta AI main page.
Returns:
dict: A dictionary containing essential cookies.
"""
session = HTMLSession()
response = session.get("https://www.meta.ai/")
return {
"_js_datr": extract_value(
response.text, start_str='_js_datr":{"value":"', end_str='",'
),
"abra_csrf": extract_value(
response.text, start_str='abra_csrf":{"value":"', end_str='",'
),
"datr": extract_value(
response.text, start_str='datr":{"value":"', end_str='",'
),
"lsd": extract_value(
response.text, start_str='"LSD",[],{"token":"', end_str='"}'
),
}
def get_session(
proxy: Optional[Dict] = None, test_url: str = "https://api.ipify.org/?format=json"
) -> requests.Session:
"""
Get a session with the proxy set.
Args:
proxy (Dict): The proxy to use
test_url (str): A test site from which we check that the proxy is installed correctly.
Returns:
requests.Session: A session with the proxy set.
"""
session = requests.Session()
if not proxy:
return session
response = session.get(test_url, proxies=proxy, timeout=10)
if response.status_code == 200:
session.proxies = proxy
return session
else:
raise Exception("Proxy is not working.")
gitextract_aa7abxek/
├── .github/
│ └── workflows/
│ └── python-publish.yml
├── .gitignore
├── README.md
├── pyproject.toml
├── requirements.txt
├── setup.cfg
├── setup.py
└── src/
└── meta_ai_api/
├── __init__.py
├── exceptions.py
├── main.py
└── utils.py
SYMBOL INDEX (19 symbols across 3 files)
FILE: src/meta_ai_api/exceptions.py
class FacebookInvalidCredentialsException (line 1) | class FacebookInvalidCredentialsException(Exception):
class FacebookRegionBlocked (line 5) | class FacebookRegionBlocked(Exception):
FILE: src/meta_ai_api/main.py
class MetaAI (line 24) | class MetaAI:
method __init__ (line 30) | def __init__(
method get_access_token (line 50) | def get_access_token(self) -> str:
method prompt (line 102) | def prompt(
method retry (line 186) | def retry(self, message: str, stream: bool = False, attempts: int = 0):
method extract_last_response (line 201) | def extract_last_response(self, response: str) -> Dict:
method stream_response (line 235) | def stream_response(self, lines: Iterator[str]):
method extract_data (line 253) | def extract_data(self, json_line: dict):
method extract_media (line 273) | def extract_media(json_line: dict) -> List[Dict]:
method get_cookies (line 303) | def get_cookies(self) -> dict:
method fetch_sources (line 342) | def fetch_sources(self, fetch_id: str) -> List[Dict]:
FILE: src/meta_ai_api/utils.py
function generate_offline_threading_id (line 13) | def generate_offline_threading_id() -> str:
function extract_value (line 45) | def extract_value(text: str, start_str: str, end_str: str) -> str:
function format_response (line 62) | def format_response(response: dict) -> str:
function get_fb_session (line 85) | def get_fb_session(email, password, proxies=None):
function get_cookies (line 245) | def get_cookies() -> dict:
function get_session (line 270) | def get_session(
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (43K chars).
[
{
"path": ".github/workflows/python-publish.yml",
"chars": 1159,
"preview": "# This workflow will upload a Python Package using Twine when a release is created\n# For more information see: https://d"
},
{
"path": ".gitignore",
"chars": 2040,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
},
{
"path": "README.md",
"chars": 9945,
"preview": "# MetaAI API Wrapper\n\nMetaAI is a Python library designed to interact with Meta's AI APIs that run in the backend of htt"
},
{
"path": "pyproject.toml",
"chars": 379,
"preview": "[build-system]\nrequires = [\"poetry-core>=1.0.0\"]\nbuild-backend = \"poetry.core.masonry.api\"\n\n[tool.poetry]\nname = \"meta_a"
},
{
"path": "requirements.txt",
"chars": 72,
"preview": "requests==2.31.0\nrequests-html==0.10.0\nlxml_html_clean==0.1.1\nbs4==0.0.2"
},
{
"path": "setup.cfg",
"chars": 50,
"preview": "[metadata]\nversion = attr: meta_ai_api.__version__"
},
{
"path": "setup.py",
"chars": 1515,
"preview": "import setuptools\n\nwith open(\"README.md\", \"r\", encoding=\"utf-8\") as fh:\n long_description = fh.read()\n\nsetuptools.set"
},
{
"path": "src/meta_ai_api/__init__.py",
"chars": 55,
"preview": "__version__ = \"1.2.5\"\nfrom .main import MetaAI # noqa\n"
},
{
"path": "src/meta_ai_api/exceptions.py",
"chars": 114,
"preview": "class FacebookInvalidCredentialsException(Exception):\n pass\n\n\nclass FacebookRegionBlocked(Exception):\n pass\n"
},
{
"path": "src/meta_ai_api/main.py",
"chars": 14194,
"preview": "import json\nimport logging\nimport time\nimport urllib\nimport uuid\nfrom typing import Dict, List, Generator, Iterator\n\nimp"
},
{
"path": "src/meta_ai_api/utils.py",
"chars": 10395,
"preview": "import logging\nimport random\nimport time\nfrom typing import Dict, Optional\n\nfrom requests_html import HTMLSession\nimport"
}
]
About this extraction
This page contains the full source code of the Strvm/meta-ai-api GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (39.0 KB), approximately 10.2k tokens, and a symbol index with 19 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.