From e5c8719554104dd789e054e6f7a68d0b6dcd3f3f Mon Sep 17 00:00:00 2001 From: Nicolas Date: Fri, 24 May 2024 14:53:04 -0700 Subject: [PATCH 01/12] Update blocklist.ts --- apps/api/src/scraper/WebScraper/utils/blocklist.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/api/src/scraper/WebScraper/utils/blocklist.ts b/apps/api/src/scraper/WebScraper/utils/blocklist.ts index c3d37c4..c6a1232 100644 --- a/apps/api/src/scraper/WebScraper/utils/blocklist.ts +++ b/apps/api/src/scraper/WebScraper/utils/blocklist.ts @@ -1,7 +1,6 @@ const socialMediaBlocklist = [ 'facebook.com', 'twitter.com', - 'x.com', 'instagram.com', 'linkedin.com', 'pinterest.com', From 2192978f91879ae620b6a7b1622aef64b820636c Mon Sep 17 00:00:00 2001 From: Keredu Date: Sat, 25 May 2024 00:12:26 +0200 Subject: [PATCH 02/12] Limit on /search is not deterministic --- apps/api/src/controllers/search.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/api/src/controllers/search.ts b/apps/api/src/controllers/search.ts index d98c08d..a73c625 100644 --- a/apps/api/src/controllers/search.ts +++ b/apps/api/src/controllers/search.ts @@ -28,11 +28,13 @@ export async function searchHelper( const tbs = searchOptions.tbs ?? null; const filter = searchOptions.filter ?? null; + const num_results = searchOptions.limit ?? 7; + const num_results_buffer = Math.floor(num_results * 1.5); let res = await search({ query: query, advanced: advanced, - num_results: searchOptions.limit ?? 7, + num_results: num_results_buffer, tbs: tbs, filter: filter, lang: searchOptions.lang ?? "en", @@ -47,6 +49,9 @@ export async function searchHelper( } res = res.filter((r) => !isUrlBlocked(r.url)); + if (res.length > num_results) { + res = res.slice(0, num_results); + } if (res.length === 0) { return { success: true, error: "No search results found", returnCode: 200 }; From 115204e6b6c6437dc5b3409a9f7b384a8a4fe5b8 Mon Sep 17 00:00:00 2001 From: Simon H Date: Sat, 25 May 2024 11:57:49 -0400 Subject: [PATCH 03/12] Feat: Provide more details for 429 error msg - Added better error code for when rate limit exceeded including consumed/remaining points, reset date and retry-after seconds --- apps/api/src/controllers/auth.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/api/src/controllers/auth.ts b/apps/api/src/controllers/auth.ts index b0bfabb..daf0ea6 100644 --- a/apps/api/src/controllers/auth.ts +++ b/apps/api/src/controllers/auth.ts @@ -1,12 +1,12 @@ import { parseApi } from "../../src/lib/parseApi"; -import { getRateLimiter, } from "../../src/services/rate-limiter"; +import { getRateLimiter, } from "../../src/services/rate-limiter"; import { AuthResponse, RateLimiterMode } from "../../src/types"; import { supabase_service } from "../../src/services/supabase"; import { withAuth } from "../../src/lib/withAuth"; import { RateLimiterRedis } from "rate-limiter-flexible"; import { setTraceAttributes } from '@hyperdx/node-opentelemetry'; -export async function authenticateUser(req, res, mode?: RateLimiterMode) : Promise { +export async function authenticateUser(req, res, mode?: RateLimiterMode): Promise { return withAuth(supaAuthenticateUser)(req, res, mode); } function setTrace(team_id: string, api_key: string) { @@ -18,7 +18,7 @@ function setTrace(team_id: string, api_key: string) { } catch (error) { console.error('Error setting trace attributes:', error); } - + } export async function supaAuthenticateUser( req, @@ -97,7 +97,7 @@ export async function supaAuthenticateUser( team_id: team_id, plan: plan } - switch (mode) { + switch (mode) { case RateLimiterMode.Crawl: rateLimiter = getRateLimiter(RateLimiterMode.Crawl, token, subscriptionData.plan); break; @@ -126,9 +126,11 @@ export async function supaAuthenticateUser( await rateLimiter.consume(iptoken); } catch (rateLimiterRes) { console.error(rateLimiterRes); + const secs = Math.round(rateLimiterRes.msBeforeNext / 1000) || 1; + const retryDate = new Date(Date.now() + rateLimiterRes.msBeforeNext); return { success: false, - error: "Rate limit exceeded. Too many requests, try again in 1 minute.", + error: `Rate limit exceeded for mode ${rateLimiter.keyPrefix}. Consumed points: ${rateLimiterRes.consumedPoints}, Remaining points: ${rateLimiterRes.remainingPoints}. Please retry after ${secs}s, resets at ${retryDate}`, status: 429, }; } @@ -155,9 +157,9 @@ export async function supaAuthenticateUser( normalizedApi = parseApi(token); const { data, error } = await supabase_service - .from("api_keys") - .select("*") - .eq("key", normalizedApi); + .from("api_keys") + .select("*") + .eq("key", normalizedApi); if (error || !data || data.length === 0) { return { @@ -170,7 +172,7 @@ export async function supaAuthenticateUser( subscriptionData = data[0]; } - return { success: true, team_id: subscriptionData.team_id }; + return { success: true, team_id: subscriptionData.team_id }; } function getPlanByPriceId(price_id: string) { From e5c6ac23fe521f19de8c20ea8caceaade5c7c9a4 Mon Sep 17 00:00:00 2001 From: Matt Joyce Date: Sun, 26 May 2024 10:01:35 +1000 Subject: [PATCH 04/12] Added long description to PyPi https://packaging.python.org/en/latest/guides/making-a-pypi-friendly-readme/ --- apps/python-sdk/setup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/python-sdk/setup.py b/apps/python-sdk/setup.py index 7df520e..f0359d5 100644 --- a/apps/python-sdk/setup.py +++ b/apps/python-sdk/setup.py @@ -1,5 +1,9 @@ +from pathlib import Path from setuptools import setup, find_packages +this_directory = Path(__file__).parent +long_description_content = (this_directory / "README.md").read_text() + setup( name='firecrawl-py', version='0.0.9', @@ -7,6 +11,8 @@ setup( author='Mendable.ai', author_email='nick@mendable.ai', description='Python SDK for Firecrawl API', + long_description=long_description_content, + long_description_content_type="text/markdown", packages=find_packages(), install_requires=[ 'requests', From cd7f260288de324eb11bc6a84a6e020782cb0246 Mon Sep 17 00:00:00 2001 From: Matt Joyce Date: Sun, 26 May 2024 11:33:28 +1000 Subject: [PATCH 05/12] Added PyPi classifiers These classifiers will help potential users find and understand the purpose and status of the project. use python 3.8 as the base, because that's what module 'requests' needs. --- apps/python-sdk/setup.py | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/apps/python-sdk/setup.py b/apps/python-sdk/setup.py index f0359d5..46b0f59 100644 --- a/apps/python-sdk/setup.py +++ b/apps/python-sdk/setup.py @@ -1,20 +1,42 @@ from pathlib import Path -from setuptools import setup, find_packages + +from setuptools import find_packages, setup this_directory = Path(__file__).parent long_description_content = (this_directory / "README.md").read_text() setup( - name='firecrawl-py', - version='0.0.9', - url='https://github.com/mendableai/firecrawl', - author='Mendable.ai', - author_email='nick@mendable.ai', - description='Python SDK for Firecrawl API', + name="firecrawl-py", + version="0.0.9", + url="https://github.com/mendableai/firecrawl", + author="Mendable.ai", + author_email="nick@mendable.ai", + description="Python SDK for Firecrawl API", long_description=long_description_content, long_description_content_type="text/markdown", packages=find_packages(), install_requires=[ - 'requests', + "requests", + ], + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Topic :: Internet", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: Indexing/Search", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Text Processing", + "Topic :: Text Processing :: Indexing", ], ) From f00dffbbb1f5f51275e81df6faf58b03b68e76c9 Mon Sep 17 00:00:00 2001 From: Matt Joyce Date: Sun, 26 May 2024 11:36:29 +1000 Subject: [PATCH 06/12] added misc PyPi keys help potential users find and understand the purpose and status of the project. --- apps/python-sdk/setup.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/python-sdk/setup.py b/apps/python-sdk/setup.py index 46b0f59..f6b798d 100644 --- a/apps/python-sdk/setup.py +++ b/apps/python-sdk/setup.py @@ -38,5 +38,12 @@ setup( "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing", "Topic :: Text Processing :: Indexing", - ], + ], + keywords="SDK API firecrawl", + project_urls={ + "Documentation": "https://github.com/mendableai/firecrawl/docs", + "Source": "https://github.com/mendableai/firecrawl", + "Tracker": "https://github.com/mendableai/firecrawl/issues", + }, + license="MIT", ) From b061e12030f0d77023884364265f932c58c0a4a4 Mon Sep 17 00:00:00 2001 From: Matt Joyce Date: Sun, 26 May 2024 11:37:47 +1000 Subject: [PATCH 07/12] added python versions requirement this is inline with requests module, a critical dependency --- apps/python-sdk/setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/python-sdk/setup.py b/apps/python-sdk/setup.py index f6b798d..e7139ce 100644 --- a/apps/python-sdk/setup.py +++ b/apps/python-sdk/setup.py @@ -18,6 +18,7 @@ setup( install_requires=[ "requests", ], + python_requires='>=3.8', classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", From 7948c6cee29d426485e9b1ab5e296c1d39c8eec7 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 26 May 2024 18:03:37 -0700 Subject: [PATCH 08/12] Nick: fixed pip issues --- .../build/lib/firecrawl/firecrawl.py | 185 ++++++++++++++++-- .../dist/firecrawl-py-0.0.10.tar.gz | Bin 0 -> 5356 bytes .../python-sdk/dist/firecrawl-py-0.0.9.tar.gz | Bin 4340 -> 0 bytes .../dist/firecrawl_py-0.0.10-py3-none-any.whl | Bin 0 -> 4161 bytes .../dist/firecrawl_py-0.0.9-py3-none-any.whl | Bin 3144 -> 0 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 254 -> 0 bytes .../__pycache__/firecrawl.cpython-311.pyc | Bin 6997 -> 0 bytes .../python-sdk/firecrawl_py.egg-info/PKG-INFO | 2 +- apps/python-sdk/setup.py | 2 +- 9 files changed, 166 insertions(+), 23 deletions(-) create mode 100644 apps/python-sdk/dist/firecrawl-py-0.0.10.tar.gz delete mode 100644 apps/python-sdk/dist/firecrawl-py-0.0.9.tar.gz create mode 100644 apps/python-sdk/dist/firecrawl_py-0.0.10-py3-none-any.whl delete mode 100644 apps/python-sdk/dist/firecrawl_py-0.0.9-py3-none-any.whl delete mode 100644 apps/python-sdk/firecrawl/__pycache__/__init__.cpython-311.pyc delete mode 100644 apps/python-sdk/firecrawl/__pycache__/firecrawl.cpython-311.pyc diff --git a/apps/python-sdk/build/lib/firecrawl/firecrawl.py b/apps/python-sdk/build/lib/firecrawl/firecrawl.py index 98cb8ed..6c0bc41 100644 --- a/apps/python-sdk/build/lib/firecrawl/firecrawl.py +++ b/apps/python-sdk/build/lib/firecrawl/firecrawl.py @@ -1,25 +1,57 @@ +""" +FirecrawlApp Module + +This module provides a class `FirecrawlApp` for interacting with the Firecrawl API. +It includes methods to scrape URLs, perform searches, initiate and monitor crawl jobs, +and check the status of these jobs. The module uses requests for HTTP communication +and handles retries for certain HTTP status codes. + +Classes: + - FirecrawlApp: Main class for interacting with the Firecrawl API. +""" + import os -from typing import Any, Dict, Optional -import requests import time +from typing import Any, Dict, Optional + +import requests + class FirecrawlApp: - def __init__(self, api_key=None, api_url='https://api.firecrawl.dev'): + """ + Initialize the FirecrawlApp instance. + + Args: + api_key (Optional[str]): API key for authenticating with the Firecrawl API. + api_url (Optional[str]): Base URL for the Firecrawl API. + """ + def __init__(self, api_key: Optional[str] = None, api_url: Optional[str] = None) -> None: self.api_key = api_key or os.getenv('FIRECRAWL_API_KEY') if self.api_key is None: raise ValueError('No API key provided') - self.api_url = api_url or os.getenv('FIRECRAWL_API_URL') - - - + self.api_url = api_url or os.getenv('FIRECRAWL_API_URL', 'https://api.firecrawl.dev') def scrape_url(self, url: str, params: Optional[Dict[str, Any]] = None) -> Any: + """ + Scrape the specified URL using the Firecrawl API. + + Args: + url (str): The URL to scrape. + params (Optional[Dict[str, Any]]): Additional parameters for the scrape request. + + Returns: + Any: The scraped data if the request is successful. + + Raises: + Exception: If the scrape request fails. + """ + headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {self.api_key}' } # Prepare the base scrape parameters with the URL scrape_params = {'url': url} - + # If there are additional params, process them if params: # Initialize extractorOptions if present @@ -32,7 +64,7 @@ class FirecrawlApp: extractor_options['mode'] = extractor_options.get('mode', 'llm-extraction') # Update the scrape_params with the processed extractorOptions scrape_params['extractorOptions'] = extractor_options - + # Include any other params directly at the top level of scrape_params for key, value in params.items(): if key != 'extractorOptions': @@ -41,11 +73,11 @@ class FirecrawlApp: response = requests.post( f'{self.api_url}/v0/scrape', headers=headers, - json=scrape_params + json=scrape_params, ) if response.status_code == 200: response = response.json() - if response['success']: + if response['success'] and 'data' in response: return response['data'] else: raise Exception(f'Failed to scrape URL. Error: {response["error"]}') @@ -54,8 +86,21 @@ class FirecrawlApp: raise Exception(f'Failed to scrape URL. Status code: {response.status_code}. Error: {error_message}') else: raise Exception(f'Failed to scrape URL. Status code: {response.status_code}') - + def search(self, query, params=None): + """ + Perform a search using the Firecrawl API. + + Args: + query (str): The search query. + params (Optional[Dict[str, Any]]): Additional parameters for the search request. + + Returns: + Any: The search results if the request is successful. + + Raises: + Exception: If the search request fails. + """ headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {self.api_key}' @@ -70,19 +115,36 @@ class FirecrawlApp: ) if response.status_code == 200: response = response.json() - if response['success'] == True: + + if response['success'] and 'data' in response: return response['data'] else: raise Exception(f'Failed to search. Error: {response["error"]}') - + elif response.status_code in [402, 409, 500]: error_message = response.json().get('error', 'Unknown error occurred') raise Exception(f'Failed to search. Status code: {response.status_code}. Error: {error_message}') else: raise Exception(f'Failed to search. Status code: {response.status_code}') - def crawl_url(self, url, params=None, wait_until_done=True, timeout=2): - headers = self._prepare_headers() + def crawl_url(self, url, params=None, wait_until_done=True, timeout=2, idempotency_key=None): + """ + Initiate a crawl job for the specified URL using the Firecrawl API. + + Args: + url (str): The URL to crawl. + params (Optional[Dict[str, Any]]): Additional parameters for the crawl request. + wait_until_done (bool): Whether to wait until the crawl job is completed. + timeout (int): Timeout between status checks when waiting for job completion. + idempotency_key (Optional[str]): A unique uuid key to ensure idempotency of requests. + + Returns: + Any: The crawl job ID or the crawl results if waiting until completion. + + Raises: + Exception: If the crawl job initiation or monitoring fails. + """ + headers = self._prepare_headers(idempotency_key) json_data = {'url': url} if params: json_data.update(params) @@ -97,6 +159,18 @@ class FirecrawlApp: self._handle_error(response, 'start crawl job') def check_crawl_status(self, job_id): + """ + Check the status of a crawl job using the Firecrawl API. + + Args: + job_id (str): The ID of the crawl job. + + Returns: + Any: The status of the crawl job. + + Raises: + Exception: If the status check request fails. + """ headers = self._prepare_headers() response = self._get_request(f'{self.api_url}/v0/crawl/status/{job_id}', headers) if response.status_code == 200: @@ -104,13 +178,45 @@ class FirecrawlApp: else: self._handle_error(response, 'check crawl status') - def _prepare_headers(self): + def _prepare_headers(self, idempotency_key=None): + """ + Prepare the headers for API requests. + + Args: + idempotency_key (Optional[str]): A unique key to ensure idempotency of requests. + + Returns: + Dict[str, str]: The headers including content type, authorization, and optionally idempotency key. + """ + if idempotency_key: + return { + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {self.api_key}', + 'x-idempotency-key': idempotency_key + } + return { 'Content-Type': 'application/json', - 'Authorization': f'Bearer {self.api_key}' + 'Authorization': f'Bearer {self.api_key}', } def _post_request(self, url, data, headers, retries=3, backoff_factor=0.5): + """ + Make a POST request with retries. + + Args: + url (str): The URL to send the POST request to. + data (Dict[str, Any]): The JSON data to include in the POST request. + headers (Dict[str, str]): The headers to include in the POST request. + retries (int): Number of retries for the request. + backoff_factor (float): Backoff factor for retries. + + Returns: + requests.Response: The response from the POST request. + + Raises: + requests.RequestException: If the request fails after the specified retries. + """ for attempt in range(retries): response = requests.post(url, headers=headers, json=data) if response.status_code == 502: @@ -120,6 +226,21 @@ class FirecrawlApp: return response def _get_request(self, url, headers, retries=3, backoff_factor=0.5): + """ + Make a GET request with retries. + + Args: + url (str): The URL to send the GET request to. + headers (Dict[str, str]): The headers to include in the GET request. + retries (int): Number of retries for the request. + backoff_factor (float): Backoff factor for retries. + + Returns: + requests.Response: The response from the GET request. + + Raises: + requests.RequestException: If the request fails after the specified retries. + """ for attempt in range(retries): response = requests.get(url, headers=headers) if response.status_code == 502: @@ -129,7 +250,20 @@ class FirecrawlApp: return response def _monitor_job_status(self, job_id, headers, timeout): - import time + """ + Monitor the status of a crawl job until completion. + + Args: + job_id (str): The ID of the crawl job. + headers (Dict[str, str]): The headers to include in the status check requests. + timeout (int): Timeout between status checks. + + Returns: + Any: The crawl results if the job is completed successfully. + + Raises: + Exception: If the job fails or an error occurs during status checks. + """ while True: status_response = self._get_request(f'{self.api_url}/v0/crawl/status/{job_id}', headers) if status_response.status_code == 200: @@ -140,8 +274,7 @@ class FirecrawlApp: else: raise Exception('Crawl job completed but no data was returned') elif status_data['status'] in ['active', 'paused', 'pending', 'queued']: - if timeout < 2: - timeout = 2 + timeout=max(timeout,2) time.sleep(timeout) # Wait for the specified timeout before checking again else: raise Exception(f'Crawl job failed or was stopped. Status: {status_data["status"]}') @@ -149,6 +282,16 @@ class FirecrawlApp: self._handle_error(status_response, 'check crawl status') def _handle_error(self, response, action): + """ + Handle errors from API responses. + + Args: + response (requests.Response): The response object from the API request. + action (str): Description of the action that was being performed. + + Raises: + Exception: An exception with a message containing the status code and error details from the response. + """ if response.status_code in [402, 408, 409, 500]: error_message = response.json().get('error', 'Unknown error occurred') raise Exception(f'Failed to {action}. Status code: {response.status_code}. Error: {error_message}') diff --git a/apps/python-sdk/dist/firecrawl-py-0.0.10.tar.gz b/apps/python-sdk/dist/firecrawl-py-0.0.10.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..59e42d15d1c8be849312b82375296c14525340d6 GIT binary patch literal 5356 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 E4^1)K*Z=?k literal 0 HcmV?d00001 diff --git a/apps/python-sdk/dist/firecrawl-py-0.0.9.tar.gz b/apps/python-sdk/dist/firecrawl-py-0.0.9.tar.gz deleted file mode 100644 index 55e0eed7b11f182f42a69f4f864156a6e79ba381..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4340 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 diff --git a/apps/python-sdk/dist/firecrawl_py-0.0.10-py3-none-any.whl b/apps/python-sdk/dist/firecrawl_py-0.0.10-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..36676fe13fdd4260d9ca6decb804ef29aae495a8 GIT binary patch literal 4161 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 F^nbsdBE|p! literal 0 HcmV?d00001 diff --git a/apps/python-sdk/dist/firecrawl_py-0.0.9-py3-none-any.whl b/apps/python-sdk/dist/firecrawl_py-0.0.9-py3-none-any.whl deleted file mode 100644 index 83cb5b77411b29a142592767d8f15946d19e22ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3144 zcmai$c{G%L8^^~wB2tzTQ<@~pm@&2t5oO9?msR|MNN5_4{4lbA2(UJiOun06+jBeK*E7 zCfj2`mh&gakpxHQT|7wyPe&>lhR3_Oxp?F8Pd6M`60E{#MAo&aOJDkJpwY^ATYl(izz}G+6tFW_x zKvcQUx5R*$29wW9Yji~I6W~3bP0%XMiAzj)xj-KPp;{B4mZM(T1R4{g9w$doSs+D8 zYeh}P-afM=p=^rMNt~$TiRGvpDeF)yC?WZ}B&mK;Wf`?dcP%Qv5ae1ic;<{tXCjyt zHkwbgS+%#Gb=&TzroSHr7R*YJ!ydlX6lM*s8a>prlT<%je0t1M=T$ZK5u2^5nxX00 zEQNm&ClS8QWS1@%u|E==%X_4GCvNGSRJT(^vB+oqYz-}A1_Y9)?^!=~q7VR|ZWE2l z1W6087|V+vq?bJ&17efZvSB9Nr2<8FiB;lKtixG_M($7T!YT7*Q=`3J2kXAL)ME#! zO&&F&LhpPpzfhBxNFZnVvO$O@VI9p|4z-<~2AY4Vfn(@R!B;K3I@O>O0eGMFoHY_x z^W?K)ijp~X3(5NWmBg%-*~$Wl^P8KsHq$i4CS7$N$>$T4bQH9;4d{brTTg$U-G_*m zIXq~@LLi&~_kDV+`DBBGZH}@!s0^pjBIHy57<~+bH?eWxs-FdGXe*KdwrValvn`hi zfV(-g?Xz`!(GVj9q&y?U@@FaALf?5b6h9#5Lv!B(NRp@`Kz(PnuRXTQ=O9no>hcH@aC+1zW11oqo*9Yi42-TB9IG?9t>papEp16}kF&5H9ZND} z6DQ>jZtRC%qiG2|4}N$ptj7_+kDfD@A|lgXN#)pZjb8b4j60p!@>XxtTG6{DQP%N?ia63lK444tU-#0yMH4uxFd~fY&6Q_oD zRn!GF2ENhNs@PH9>-B=_SW}-#aC-Gs|LHAE?H#9{76Yf)&a+}X2w6&+NV9j)Z3B@o?xyCg1q5O;*^WX?~E3a0&sptlcvdoPvXE%k*_skD>T^ETdCj%P6;>wxEU> zIqo>%(W~t-VsGW!gK)QB;mw~RGY*^MPMydS*8>^@TI*Ny8S+t#HIif=)#RKnjziOLBi#t9n0APW|-wWF-VdiF_}0sGJ1@M-h>+iE=lFUoONh*w?b!YRB9_Rq^Rc132S zERZQcT_v6l*QKz=+Y)`#6%#?0-Nvp6M6sr#N#g}f)AcfkF3r;yE3<`^l?$IQXdXZ`{jF8ySSWY?9C!ANuGeTMV6<+4^D28i^d~ zA!yQO|7@QgawJ-VcqZUl*l9N#h(&vb4WP3eZ_pfd?k3NjuBtb zW$|+kGeW;MnUxEl!*QDXCh+f?v@u2^&4gIS=#Fk-Qx&Do=d3cU>Pz)OPm2yy6%$A+ ztQ2c((h7lIh5_?WcByu$S9Ga&j|#T2VBMb}eZmSVCLOJ2rC0?;CG>kilvyQK;jTts zM?1^37yX<$I?Vl3l=yZ5X6m6LTRAlea-{UT+Po?5crwYCM233%d4CTpLz|h+6FiO( zE&$*)NBe)r#3GMbV2#2%Yy3l00pUY$UAOEK#at3;p=>vDVZ1o7?E=F{)I?FiW&p)* zb#wBsP3XBM^N4(JY*&xaEPRYDy`rRk@|1mu<{Mr`=(gxgD%C;z-E8tmXZ!Q(UAClZ z2f3nZSB%gf_c7;J8~yJcc|G`OT0nl-u`I0tMHM}h{3Yc?g`MFUmC;yTQpwP`8=M0UVj7~Yd)T!AS<8Gj|RS5Ok_DXJH ztw>cv#oq0r$RR|AcHZP$l80O&4A&X|L4G?E{m95*!i!3txj2_dV&vmYpE3F(_}7=K zDW`F9!BzqE*?F!@mt6AAQ7Fpp)WvGwNaAdjnpGy0c~b5SXi19nZdp)ZfhMc*Nmc`p zvcb7PE^cw2{~a(nC;s=76a4M-JrVvKH-AR_TcG?00086!TmFLh4&%hjpBevVc_-}Ru{0ESR8Z`g_ diff --git a/apps/python-sdk/firecrawl/__pycache__/__init__.cpython-311.pyc b/apps/python-sdk/firecrawl/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 605b3df712dacc3f938e664f38e99d9bfcddd4f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254 zcmZ3^%ge<81Z`7g(^P=;V-N=hn4pZ$LO{lJh7^Vr#vF!R#wbQch7_h?22JLdj6exZ z##=mYnMJ9|MTzA(js*pNnoPGi(_jKc%s?e889sxI`W31lTAW%`te=;eoS&0eoSc}O zSd^&mlAm0fo0?ZrtnZ##;!&EU57(@pSWr-`Ur2KczG$)vkyGXbZ?q#j-%+12ZEd;|&Jo3)oN*8&CxRaAQTu diff --git a/apps/python-sdk/firecrawl/__pycache__/firecrawl.cpython-311.pyc b/apps/python-sdk/firecrawl/__pycache__/firecrawl.cpython-311.pyc deleted file mode 100644 index 7c98fa33cdb39232d3c4b0ad07ee506b91bb20d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6997 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 Date: Sun, 26 May 2024 18:07:21 -0700 Subject: [PATCH 09/12] Update auth.ts --- apps/api/src/controllers/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/controllers/auth.ts b/apps/api/src/controllers/auth.ts index daf0ea6..a335f8c 100644 --- a/apps/api/src/controllers/auth.ts +++ b/apps/api/src/controllers/auth.ts @@ -130,7 +130,7 @@ export async function supaAuthenticateUser( const retryDate = new Date(Date.now() + rateLimiterRes.msBeforeNext); return { success: false, - error: `Rate limit exceeded for mode ${rateLimiter.keyPrefix}. Consumed points: ${rateLimiterRes.consumedPoints}, Remaining points: ${rateLimiterRes.remainingPoints}. Please retry after ${secs}s, resets at ${retryDate}`, + error: `Rate limit exceeded. Consumed points: ${rateLimiterRes.consumedPoints}, Remaining points: ${rateLimiterRes.remainingPoints}. Please retry after ${secs}s, resets at ${retryDate}`, status: 429, }; } From ed4226fd1f5843402880d0befedf7027ea8a8dad Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 26 May 2024 18:11:54 -0700 Subject: [PATCH 10/12] Update setup.py --- apps/python-sdk/setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/python-sdk/setup.py b/apps/python-sdk/setup.py index e7139ce..4709284 100644 --- a/apps/python-sdk/setup.py +++ b/apps/python-sdk/setup.py @@ -23,7 +23,7 @@ setup( "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", + "License :: OSI Approved :: AGPL 3.0 License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", @@ -42,9 +42,9 @@ setup( ], keywords="SDK API firecrawl", project_urls={ - "Documentation": "https://github.com/mendableai/firecrawl/docs", + "Documentation": "https://docs.firecrawl.dev", "Source": "https://github.com/mendableai/firecrawl", "Tracker": "https://github.com/mendableai/firecrawl/issues", }, - license="MIT", + license="AGPL 3.0 License", ) From 1de53cc4d0b98b8d61b9c8a592aba1c60840e2b6 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 26 May 2024 18:15:05 -0700 Subject: [PATCH 11/12] Nick: fixes --- .../dist/firecrawl-py-0.0.10.tar.gz | Bin 5356 -> 0 bytes .../dist/firecrawl-py-0.0.11.tar.gz | Bin 0 -> 6486 bytes .../dist/firecrawl_py-0.0.10-py3-none-any.whl | Bin 4161 -> 0 bytes .../dist/firecrawl_py-0.0.11-py3-none-any.whl | Bin 0 -> 6212 bytes .../python-sdk/firecrawl_py.egg-info/PKG-INFO | 155 +++++++++++++++++- apps/python-sdk/setup.py | 6 +- 6 files changed, 157 insertions(+), 4 deletions(-) delete mode 100644 apps/python-sdk/dist/firecrawl-py-0.0.10.tar.gz create mode 100644 apps/python-sdk/dist/firecrawl-py-0.0.11.tar.gz delete mode 100644 apps/python-sdk/dist/firecrawl_py-0.0.10-py3-none-any.whl create mode 100644 apps/python-sdk/dist/firecrawl_py-0.0.11-py3-none-any.whl diff --git a/apps/python-sdk/dist/firecrawl-py-0.0.10.tar.gz b/apps/python-sdk/dist/firecrawl-py-0.0.10.tar.gz deleted file mode 100644 index 59e42d15d1c8be849312b82375296c14525340d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5356 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 E4^1)K*Z=?k diff --git a/apps/python-sdk/dist/firecrawl-py-0.0.11.tar.gz b/apps/python-sdk/dist/firecrawl-py-0.0.11.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3dd82a93beece2dabb027ac75c62aa679d2f1a0f GIT binary patch literal 6486 zcma*LMNk|J7c5E$Is|uj3&Gt9F2O@^cbCBl3>MtoC3tX62r^jk3=YBF-3A7kx!+&) zcCT*L-E?)GK8s$QMfahN$G`~P(6vKG*g1OHT66Fi3w_}U=B`P4t|FPN(HAV6rxp=u9>IBJAXAe*HPRtQc{Qz~X7q0KPf89KV2EE$v z!Iudo*wqTi@<32)sn{IpdQFW3gWe2=B0}jeh&4?y*y`F!iGMt(~L@AZElg1OH{m|ZwTB`3;7&qoPExS zuxef2bboOzLnOk@7ZE`{uheA-kk%{c2I}*C^jeFX%#H}^>f*QqxmO7vW#1uaLRi+T zG7z+%5wvqdo`pk>2u16IZ~ZBE=SBA$xpVZ|0fXaUES6@CIZ-VqUMAM~J+XJA#}hwo zNQU?HzQj@$P#L-ph`K64h-JDo(qgd13puzuHCUkn1%3wt9)+=*)Q#ysZK=zVxM|X? zVKcrGum<(Rq(fZHcME@|562JvHZsuOt@yvf2?NyMQiw~5s<8G7Gv82luG1$jv0l3Q zp65pVxm364xTMrN_ACLyUUrh&Ek;@ETks>YNLswbr4>%L^bUQFBEQ6V`T1+RijRM|8cO*f9%rmK(LXxRm$WGH%$ z(F;$((;rJOIv*zoa3<-Et_B8%*AkIol~SSU_l`8Qd(k3clg(|#6>u5I9)9=fTdlyi zGCRS=J9zJV0IVwsCt2%J(0*~YU%i3e);qtn_#~R?*LsmC%AA*yjf<3wJvA24OMx!B zMa9LJyUYDAXM<$wfU1T5fu^P~fdXbfjZb)lMfphI;lRw&!^uoIv&>7(+CUMS=! zIQ*_i=aIz3^|LZ_#CCF8jtsf!?Bo?VcH23=`^&Z z$8)f&uO&ps+okj?=jmDAmk@dyMx5&aX;P+6UxJ;-5dV=;hEFO41SdRG=6DVpv232m z*%)|!-UHo{EhHe)N|g*2tzrTJvLP&__YNPZCQJC~hA%~l%{HwyV?DdlE6>pCy-!~E#p0NFio0XwNJj_Ax2rqMK7-V4ed zD&hIFN%C7>+3HdAjB!$L$7{G|VJIVYz|3?D7dJO6jswAC=F-w69nn^Ou+_Bi#L03= zZ)nk*rD0*B7`$kpSA$_vykg~H`;vOCd%Es>|dZ)2rf)5c4QVNvw_n=+-X#z(WtWcY3^Hi#7z&Au8md5 z6}|E;Cw3A^6^_y@6Csr1@r+bjgl}|>bCPA@;y1bMD__EE z+)W`@kM>e57u?^qYh&W>`Dyrc%Zrcy@#PQ0)%?s9tPeG3A^L_Hfrkd)`FD-XzUXs@ zq%#hdHo$FRp2nytR(`n|ri7Vu^47U9!5!`D*p9ymJTa@|r*iAPvS5bt`G;j6-hcWkNB`Dzo0e)YLC1dh=-^5iIH53K`?#cW9xy{5?=#tcxgqc&Hm&)UI#xj=yJrO`pt{sy%rE~q!NNcYq_`D4+I~-Du))yXIZ__UiNOpAtyKM@>xvodt$fng4`hP!~du+XVS{KBN1`MGT zVszo?ZZaEy$nBFfVw?m^ZDhB_Ge3m34Slx~2wUN|XhfMXXV^6Bm>0T`xbn4F+51*9 zUTTho+``{8rifORDudKxyFof1(I-z1;7Y{+{0=&5-=bjD+DjAYbGPxPK;v?@svr~1 z{!QW3NL8%2&9c1mR`M`VL-x(!8l${Tk{RH}{wd@F<+$?Ig1m++V7u8uPg~;fi+Zp= z3_Z_>;~Bjh&9q{%G6bMXyiv5o8sfhI>kKJ9`oPWBYu+}hIaG!7YuuZLdEi=6GxOF? zd*tDO#;Mxu=c;S{qTA-Gu45{}QZgP(LW4!@jEobJMW`(d38%*5pRK}oUS-}kf(1NM zHa;$G(acs;sO5n_k9I#hx|}shnEfn4?{$WkRjeWlokkM+_)3-$9t^cp$v?%aUx94^ z&;k6cr^`0HAW`M4+<#yWgj70Gl~I`VpHt8dUN#>NIQ)nRGK*ePa(f*}quaCKE?vf3 z0G7$%?2@rPqVdR1(9P3m$TnVMdx!7%u{5Lpl_>IGemUmlr)wqZU*h0;9cuAPq+Vh>s z^nHVX>fwlzJ$aLrZ#=Prq{gih&n3C%&CPXwD1yDnsNT*I zCSY|b&UIqNl#S2=*2$B|u%kN6P5vm0v?*mJPuV)%-~;dd7npv@s#_;`jrR#2#0N+` zv*MqQ-177>A2Gc28Ifr6)#8lv((I+Anl9%PF~0GNHLgp&O$YGo(xYb$d)iwBaIl4wxP_t+4HNA zQWY1UMAdfU51N$i2K%f4GQ7`!3|E1~ENBYZ7FM&E$*1<)rvN0wWD_yQW%Km-Df-R# zs-K~_xPqyhRMHg^T#MCUT;Pr>z7KJUs674`2;3-|SgUR0J@T}cg7jM@S*5u5H6r1a z1r{<@A1rFMa64}bK*%gT(-@fCab|XmQOT1NbBqX)9R-h`f}gp13ors&h+HU=2PAh= zdE!2)J~P7-I{bbuwK#qVmpPTmTE1qoe2Cp3n227Fn)ggfNo6AR){bvVHgcOMyg=ic zE!FU(7B4_c7u`Qcfi2pQ$4E(esKPaI50>mKg~^uo?nb#ckOq@QTvU5cO?|n4s5(%M zn;YVM10PhA`DXZPUIKCa)LZQW*P3#c+ylMJYgkcO4iTmnmlRCUunj@((JGJkU${hC zlryRao8)${Hqq6>xQ~#rEf_T%d1jDft&N+eO)|B{7L7F9*XF$%$Qy|wumJ@1I%aMK z%s7cm9z+wvUJ#@BuK^BOEBmp?3}CT$ZjK*je~)9j#)M~EeBlxuyTJ*N%16Tna8?ai zYCs7p121jYoufrn2!yj#i@D``knR~;j!ypCT4c`Ggd-EJRu>f7o^cA^6N)PxUM##`+M0|tRQ=^DWcak2ma?qs z&PEY26vS=v@oV45uuOGw;oeRkN?x%DEiKm#4ApUFAehu z%;M1b1~D=3?0k|hec7DDz3k+h+74xik(K!8lF?=DOVmh~M2(7uXWxay`vXE@v3 z(wzFDkBAWqD8H|NYzUwx*Xi)E9XT3Ln~AyWT2H$zwcLY zJk=_{{a1YH`^?$08k~fHRVbjXUwli#jTXtum7YLJSEa!!tpfqv!ml(Yq~Zjn-SRIA zN%#pW(w#_Y02B`XC$ILIy@zFO$*WvmtUBe$Sm)TCY2)WeL&2hg*HN?5D4k6GM|&?oz)jB@`c(xa8UyJHMB97tec$Ii zBY#q{V}Bo?h@W+5F-~;k$kF@8T;?NCEJQ)ny{ZsF6ldsr3jUrU>~5?#s(|b(RkI{; zvozZn2HnD%D#H^P^zMIHtJmIBf{hoYNk|)yKY-Q@!3LB5CaA^x(Q2;^16(ul0xXtC zZ~LZ}I})_c2JwPu?}AZ`ygJeJW+{bbnEpw^fU@c0su5o;2@YevqAT}Nek5QR$1p~Y z;yO-I8`N(uK(7v*)=sM|ns{|xyXQF2QMJ802m1W3`NQ!$ zmi9}G4S)9jW!OJPWajCeAsgiJWH8xO%-{#7Meq+-wwb;aJ?Rv3a-zO8tP28IoXt4Bi9#>6-S3EYVuo40_9nZ}CU_MP?Z@17bT?be zN&D;%r*H=AC^)+w=6+Gzq8LL8dHHSOjUrpfoyK|s(h^gJ=q~H8X3e1#qI4?Ey>I2z zmTOueSu`|_{;Qn0_*M>wI4?MNLP(f7*-8OWmbiuLZ08@}#0VJwJZZ$^AC*euqcJ<{ z8~cQXjW5%jhvoTA@6utv8f2&=xvEjpkteVBxyPNuzvCJy(vlolpVs1Fwj6ya^v1=I znFvL?cKFk^hG6T$czAnRAxW;tT)u}8<R<$$k7Y{M>E#UjC2c{1F{ zN;&VX9P9SAF}!H>0mC|XF;l0=IU;$PDbtU0>574`cfO*%QaNl4VIZWQC&&Q#P`a<8 zniN7DaXsyqwuNRa1@;Z+SV#_q}*-3p5-puVgx}PgmF9jJ_FW9lH~ML_OG)M{cKi ztw6=A;?}!)SR(lySCb(|Ta%+zk0+3u-foxF68HoDH$8nMrSk_l`ZF{$i*rd-73+DQ znASF6)7(WecNRit(A?P*`E}vnhG~%0{-IDtB}+IMygBq2a{+8DeUvU^E?(4nD8(mW)(>bmDIs-Lx?weYY@KbKDF^*r3$R?DL z0~OuCI61=iEm)6$AVEQo*q$Uu%%2k4^jbXVL>iG8|{tO+3iZtfrWkgT{vNU$7y z{X|%wBon|lCqtHus4FtoB@1ODRS&WIDHX!$%ByV0QMak=+3@` zoXEUcV(5i4fN2(?|A;Ye72e>7+L24F#WgbiDeOaEa>-DCjuw?muGHj|?y{C8&Cy}t zRfI$f8GZu^(t{0$i|PQkIR~EVLItLNTR@eUX{%HJ7I(Vwm4X&*n?1sy7&#DEHc?D% z#F(Ot$!zqjuDPKI{4+=!k^c%-L~x%X(tkFtDqWff`=7mndkQy78jnCJh!Ak{ zp>*ymcoQKS)ydKDr43ZZyF0htyWYAX4$M(<^dsKeL`^rSI;LW4C;M?Ixs#WW6=~Ij zdDxbSK7=FObGkvGy+bd`r7@Cyx#EpOI7c5=`Wsf|<=@MUo4j@>21^$iQiu_fUVX6@ z*{_nAco+IkO}KzB__ECGJcCw!dF7YB(SGZ{+>L4f-4$xj;i~&Au8Vo4j^XMomH9JV z@VJwTC~)LszsY#?2$aWR2w|v+2Mbg35dRB0!pZvL-YNaA;cN1-@B|1+V2EXR4pr^Q zqz&S3IZ`q11q$WSZ{{zyMkQ|By5Nl4F&AIW`dRF5x|?0^eD{07Z(&z!_>KA^X#d?c z42Uk=>u#pg^VrJ>scCHZN&!g|pA^#Z_q$Ddgj0jlhs(|=YuWb*?CI)|ycI7A%Y~!t zuBbNE0W~&FJj0k)6D!}_>0v&R?@B&+b}UTh(W@XCu!;xLx|8ziLvuKSCNm`u#%X}I z$(=1DCd<|hXaAQmjNfe8+DerL?z{v34~oDJFAsNvRmt2qn&*2`0rQXUKf79g5+T+% zFLVFbJ!o-p&1h&>fTRbnDiq5z13$XqgFmE*){KfdEP^vLzhsPtd(ZtLTN|b9sC4)+ z$nG2$$}N3>juZ0smg0Z4pc!!h+dcEnh~1Ud%|zYwR!&2|Gz~7v(0DTFl${IKQ_NjndZSHAN0y^py8FTyV`j{iG!DB1!1uqpu352h>w z`B^eU7W~r!r4GVxXkWtn@sEuZ3CW(_4-nGBFCh2L$^UE}=34ysc6L6KHb0v>1G&4S zpCc~%{voQ!L2I`ZqGRos>McEMtXFdc&)uRNOqNHjXN+!EWJ-`bvZRIJL@u+nsfP~KKl$vB@yB{$U zE17kO|J*11Vh{PO+xd$HDzYAT>!c{yKY!y&@m#hNRn;*1ekU$RTU|6+@tNk6A!+nK zyM6{t(=Upez?BBJrHrc%^8t6;7tygw5Iw0(W&AG P80hKjTOHCB64L(xRtnh| literal 0 HcmV?d00001 diff --git a/apps/python-sdk/dist/firecrawl_py-0.0.10-py3-none-any.whl b/apps/python-sdk/dist/firecrawl_py-0.0.10-py3-none-any.whl deleted file mode 100644 index 36676fe13fdd4260d9ca6decb804ef29aae495a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4161 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 F^nbsdBE|p! diff --git a/apps/python-sdk/dist/firecrawl_py-0.0.11-py3-none-any.whl b/apps/python-sdk/dist/firecrawl_py-0.0.11-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..4d7e3aacd02369253784efb5ab05decd52cdf692 GIT binary patch literal 6212 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 literal 0 HcmV?d00001 diff --git a/apps/python-sdk/firecrawl_py.egg-info/PKG-INFO b/apps/python-sdk/firecrawl_py.egg-info/PKG-INFO index 16af620..7d4b835 100644 --- a/apps/python-sdk/firecrawl_py.egg-info/PKG-INFO +++ b/apps/python-sdk/firecrawl_py.egg-info/PKG-INFO @@ -1,7 +1,160 @@ Metadata-Version: 2.1 Name: firecrawl-py -Version: 0.0.10 +Version: 0.0.11 Summary: Python SDK for Firecrawl API Home-page: https://github.com/mendableai/firecrawl Author: Mendable.ai Author-email: nick@mendable.ai +License: GNU General Public License v3 (GPLv3) +Project-URL: Documentation, https://docs.firecrawl.dev +Project-URL: Source, https://github.com/mendableai/firecrawl +Project-URL: Tracker, https://github.com/mendableai/firecrawl/issues +Keywords: SDK API firecrawl +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) +Classifier: Natural Language :: English +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Topic :: Internet +Classifier: Topic :: Internet :: WWW/HTTP +Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search +Classifier: Topic :: Software Development +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing +Classifier: Topic :: Text Processing :: Indexing +Requires-Python: >=3.8 +Description-Content-Type: text/markdown + +# Firecrawl Python SDK + +The Firecrawl Python SDK is a library that allows you to easily scrape and crawl websites, and output the data in a format ready for use with language models (LLMs). It provides a simple and intuitive interface for interacting with the Firecrawl API. + +## Installation + +To install the Firecrawl Python SDK, you can use pip: + +```bash +pip install firecrawl-py +``` + +## Usage + +1. Get an API key from [firecrawl.dev](https://firecrawl.dev) +2. Set the API key as an environment variable named `FIRECRAWL_API_KEY` or pass it as a parameter to the `FirecrawlApp` class. + + +Here's an example of how to use the SDK: + +```python +from firecrawl import FirecrawlApp + +# Initialize the FirecrawlApp with your API key +app = FirecrawlApp(api_key='your_api_key') + +# Scrape a single URL +url = 'https://mendable.ai' +scraped_data = app.scrape_url(url) + +# Crawl a website +crawl_url = 'https://mendable.ai' +params = { + 'pageOptions': { + 'onlyMainContent': True + } +} +crawl_result = app.crawl_url(crawl_url, params=params) +``` + +### Scraping a URL + +To scrape a single URL, use the `scrape_url` method. It takes the URL as a parameter and returns the scraped data as a dictionary. + +```python +url = 'https://example.com' +scraped_data = app.scrape_url(url) +``` +### Extracting structured data from a URL + +With LLM extraction, you can easily extract structured data from any URL. We support pydantic schemas to make it easier for you too. Here is how you to use it: + +```python +class ArticleSchema(BaseModel): + title: str + points: int + by: str + commentsURL: str + +class TopArticlesSchema(BaseModel): + top: List[ArticleSchema] = Field(..., max_items=5, description="Top 5 stories") + +data = app.scrape_url('https://news.ycombinator.com', { + 'extractorOptions': { + 'extractionSchema': TopArticlesSchema.model_json_schema(), + 'mode': 'llm-extraction' + }, + 'pageOptions':{ + 'onlyMainContent': True + } +}) +print(data["llm_extraction"]) +``` + +### Search for a query + +Used to search the web, get the most relevant results, scrap each page and return the markdown. + +```python +query = 'what is mendable?' +search_result = app.search(query) +``` + +### Crawling a Website + +To crawl a website, use the `crawl_url` method. It takes the starting URL and optional parameters as arguments. The `params` argument allows you to specify additional options for the crawl job, such as the maximum number of pages to crawl, allowed domains, and the output format. + +The `wait_until_done` parameter determines whether the method should wait for the crawl job to complete before returning the result. If set to `True`, the method will periodically check the status of the crawl job until it is completed or the specified `timeout` (in seconds) is reached. If set to `False`, the method will return immediately with the job ID, and you can manually check the status of the crawl job using the `check_crawl_status` method. + +```python +crawl_url = 'https://example.com' +params = { + 'crawlerOptions': { + 'excludes': ['blog/*'], + 'includes': [], # leave empty for all pages + 'limit': 1000, + }, + 'pageOptions': { + 'onlyMainContent': True + } +} +crawl_result = app.crawl_url(crawl_url, params=params, wait_until_done=True, timeout=5) +``` + +If `wait_until_done` is set to `True`, the `crawl_url` method will return the crawl result once the job is completed. If the job fails or is stopped, an exception will be raised. + +### Checking Crawl Status + +To check the status of a crawl job, use the `check_crawl_status` method. It takes the job ID as a parameter and returns the current status of the crawl job. + +```python +job_id = crawl_result['jobId'] +status = app.check_crawl_status(job_id) +``` + +## Error Handling + +The SDK handles errors returned by the Firecrawl API and raises appropriate exceptions. If an error occurs during a request, an exception will be raised with a descriptive error message. + +## Contributing + +Contributions to the Firecrawl Python SDK are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the GitHub repository. + +## License + +The Firecrawl Python SDK is open-source and released under the [MIT License](https://opensource.org/licenses/MIT). diff --git a/apps/python-sdk/setup.py b/apps/python-sdk/setup.py index 2e47bd8..63b5c9f 100644 --- a/apps/python-sdk/setup.py +++ b/apps/python-sdk/setup.py @@ -7,7 +7,7 @@ long_description_content = (this_directory / "README.md").read_text() setup( name="firecrawl-py", - version="0.0.10", + version="0.0.11", url="https://github.com/mendableai/firecrawl", author="Mendable.ai", author_email="nick@mendable.ai", @@ -23,7 +23,7 @@ setup( "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", - "License :: OSI Approved :: AGPL 3.0 License", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", @@ -46,5 +46,5 @@ setup( "Source": "https://github.com/mendableai/firecrawl", "Tracker": "https://github.com/mendableai/firecrawl/issues", }, - license="AGPL 3.0 License", + license="GNU General Public License v3 (GPLv3)", ) From 1ef307cb6fa2513cfa0b4e267c27785e28afb1d5 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Mon, 27 May 2024 10:01:12 -0700 Subject: [PATCH 12/12] Nick: checks --- apps/api/fly.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/api/fly.toml b/apps/api/fly.toml index ca619d1..0656a2c 100644 --- a/apps/api/fly.toml +++ b/apps/api/fly.toml @@ -27,6 +27,13 @@ kill_timeout = '5s' hard_limit = 200 soft_limit = 100 +[[http_service.checks]] + grace_period = "10s" + interval = "30s" + method = "GET" + timeout = "5s" + path = "/" + [[services]] protocol = 'tcp' internal_port = 8080