firecrawl 4.2.0__py3-none-any.whl → 4.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of firecrawl might be problematic. Click here for more details.
- firecrawl/__init__.py +1 -1
- firecrawl/__tests__/e2e/v2/aio/test_aio_usage.py +7 -0
- firecrawl/client.py +20 -5
- firecrawl/types.py +6 -0
- firecrawl/v1/client.py +142 -0
- firecrawl/v2/client.py +8 -0
- firecrawl/v2/client_async.py +12 -0
- firecrawl/v2/methods/aio/usage.py +50 -3
- firecrawl/v2/methods/usage.py +31 -3
- firecrawl/v2/types.py +26 -0
- {firecrawl-4.2.0.dist-info → firecrawl-4.3.1.dist-info}/METADATA +1 -1
- {firecrawl-4.2.0.dist-info → firecrawl-4.3.1.dist-info}/RECORD +15 -15
- {firecrawl-4.2.0.dist-info → firecrawl-4.3.1.dist-info}/WHEEL +0 -0
- {firecrawl-4.2.0.dist-info → firecrawl-4.3.1.dist-info}/licenses/LICENSE +0 -0
- {firecrawl-4.2.0.dist-info → firecrawl-4.3.1.dist-info}/top_level.txt +0 -0
firecrawl/__init__.py
CHANGED
|
@@ -33,3 +33,10 @@ async def test_async_get_token_usage():
|
|
|
33
33
|
tokens = await client.get_token_usage()
|
|
34
34
|
assert hasattr(tokens, "remaining_tokens")
|
|
35
35
|
|
|
36
|
+
|
|
37
|
+
@pytest.mark.asyncio
|
|
38
|
+
async def test_async_get_queue_status():
|
|
39
|
+
client = AsyncFirecrawl(api_key=os.getenv("API_KEY"), api_url=os.getenv("API_URL"))
|
|
40
|
+
status = await client.get_queue_status()
|
|
41
|
+
assert hasattr(status, "jobs_in_queue")
|
|
42
|
+
|
firecrawl/client.py
CHANGED
|
@@ -56,23 +56,34 @@ class V2Proxy:
|
|
|
56
56
|
self._client = client_instance
|
|
57
57
|
|
|
58
58
|
if client_instance:
|
|
59
|
+
self.scrape = client_instance.scrape
|
|
59
60
|
self.search = client_instance.search
|
|
60
61
|
self.crawl = client_instance.crawl
|
|
62
|
+
self.start_crawl = client_instance.start_crawl
|
|
61
63
|
self.get_crawl_status = client_instance.get_crawl_status
|
|
62
64
|
self.cancel_crawl = client_instance.cancel_crawl
|
|
63
|
-
self.
|
|
65
|
+
self.get_crawl_errors = client_instance.get_crawl_errors
|
|
66
|
+
self.get_active_crawls = client_instance.get_active_crawls
|
|
67
|
+
self.active_crawls = client_instance.active_crawls
|
|
64
68
|
self.crawl_params_preview = client_instance.crawl_params_preview
|
|
69
|
+
|
|
65
70
|
self.extract = client_instance.extract
|
|
71
|
+
self.start_extract = client_instance.start_extract
|
|
72
|
+
self.get_extract_status = client_instance.get_extract_status
|
|
73
|
+
|
|
66
74
|
self.start_batch_scrape = client_instance.start_batch_scrape
|
|
67
75
|
self.get_batch_scrape_status = client_instance.get_batch_scrape_status
|
|
68
76
|
self.cancel_batch_scrape = client_instance.cancel_batch_scrape
|
|
69
77
|
self.batch_scrape = client_instance.batch_scrape
|
|
70
78
|
self.get_batch_scrape_errors = client_instance.get_batch_scrape_errors
|
|
71
|
-
|
|
79
|
+
|
|
72
80
|
self.map = client_instance.map
|
|
73
81
|
self.get_concurrency = client_instance.get_concurrency
|
|
74
82
|
self.get_credit_usage = client_instance.get_credit_usage
|
|
75
83
|
self.get_token_usage = client_instance.get_token_usage
|
|
84
|
+
self.get_queue_status = client_instance.get_queue_status
|
|
85
|
+
|
|
86
|
+
self.watcher = client_instance.watcher
|
|
76
87
|
|
|
77
88
|
def __getattr__(self, name):
|
|
78
89
|
"""Forward attribute access to the underlying client."""
|
|
@@ -99,9 +110,9 @@ class AsyncV1Proxy:
|
|
|
99
110
|
|
|
100
111
|
class AsyncV2Proxy:
|
|
101
112
|
"""Proxy class that forwards method calls to the appropriate version client."""
|
|
102
|
-
_client: Optional[
|
|
113
|
+
_client: Optional[AsyncFirecrawlClient] = None
|
|
103
114
|
|
|
104
|
-
def __init__(self, client_instance: Optional[
|
|
115
|
+
def __init__(self, client_instance: Optional[AsyncFirecrawlClient] = None):
|
|
105
116
|
self._client = client_instance
|
|
106
117
|
|
|
107
118
|
if client_instance:
|
|
@@ -132,6 +143,8 @@ class AsyncV2Proxy:
|
|
|
132
143
|
self.get_concurrency = client_instance.get_concurrency
|
|
133
144
|
self.get_credit_usage = client_instance.get_credit_usage
|
|
134
145
|
self.get_token_usage = client_instance.get_token_usage
|
|
146
|
+
self.get_queue_status = client_instance.get_queue_status
|
|
147
|
+
|
|
135
148
|
self.watcher = client_instance.watcher
|
|
136
149
|
|
|
137
150
|
def __getattr__(self, name):
|
|
@@ -193,7 +206,8 @@ class Firecrawl:
|
|
|
193
206
|
self.get_concurrency = self._v2_client.get_concurrency
|
|
194
207
|
self.get_credit_usage = self._v2_client.get_credit_usage
|
|
195
208
|
self.get_token_usage = self._v2_client.get_token_usage
|
|
196
|
-
|
|
209
|
+
self.get_queue_status = self._v2_client.get_queue_status
|
|
210
|
+
|
|
197
211
|
self.watcher = self._v2_client.watcher
|
|
198
212
|
|
|
199
213
|
class AsyncFirecrawl:
|
|
@@ -238,6 +252,7 @@ class AsyncFirecrawl:
|
|
|
238
252
|
self.get_concurrency = self._v2_client.get_concurrency
|
|
239
253
|
self.get_credit_usage = self._v2_client.get_credit_usage
|
|
240
254
|
self.get_token_usage = self._v2_client.get_token_usage
|
|
255
|
+
self.get_queue_status = self._v2_client.get_queue_status
|
|
241
256
|
|
|
242
257
|
self.watcher = self._v2_client.watcher
|
|
243
258
|
|
firecrawl/types.py
CHANGED
|
@@ -65,6 +65,9 @@ from .v2.types import (
|
|
|
65
65
|
ExecuteJavascriptAction,
|
|
66
66
|
PDFAction,
|
|
67
67
|
|
|
68
|
+
# Usage types
|
|
69
|
+
QueueStatusResponse,
|
|
70
|
+
|
|
68
71
|
# Location and format types
|
|
69
72
|
Location,
|
|
70
73
|
|
|
@@ -142,6 +145,9 @@ __all__ = [
|
|
|
142
145
|
'ScrapeAction',
|
|
143
146
|
'ExecuteJavascriptAction',
|
|
144
147
|
'PDFAction',
|
|
148
|
+
|
|
149
|
+
# Usage types
|
|
150
|
+
'QueueStatusResponse',
|
|
145
151
|
|
|
146
152
|
# Location and format types
|
|
147
153
|
'Location',
|
firecrawl/v1/client.py
CHANGED
|
@@ -358,6 +358,46 @@ class V1SearchResponse(pydantic.BaseModel):
|
|
|
358
358
|
warning: Optional[str] = None
|
|
359
359
|
error: Optional[str] = None
|
|
360
360
|
|
|
361
|
+
class V1CreditUsageData(pydantic.BaseModel):
|
|
362
|
+
remaining_credits: int
|
|
363
|
+
plan_credits: Optional[int] = None
|
|
364
|
+
billing_period_start: Optional[str] = None
|
|
365
|
+
billing_period_end: Optional[str] = None
|
|
366
|
+
|
|
367
|
+
class V1CreditUsageResponse(pydantic.BaseModel):
|
|
368
|
+
success: bool
|
|
369
|
+
data: V1CreditUsageData
|
|
370
|
+
|
|
371
|
+
class V1TokenUsageData(pydantic.BaseModel):
|
|
372
|
+
remaining_tokens: int
|
|
373
|
+
plan_tokens: Optional[int] = None
|
|
374
|
+
billing_period_start: Optional[str] = None
|
|
375
|
+
billing_period_end: Optional[str] = None
|
|
376
|
+
|
|
377
|
+
class V1TokenUsageResponse(pydantic.BaseModel):
|
|
378
|
+
success: bool
|
|
379
|
+
data: V1TokenUsageData
|
|
380
|
+
|
|
381
|
+
class V1CreditUsageHistoricalPeriod(pydantic.BaseModel):
|
|
382
|
+
startDate: Optional[str] = None
|
|
383
|
+
endDate: Optional[str] = None
|
|
384
|
+
apiKey: Optional[str] = None
|
|
385
|
+
creditsUsed: int
|
|
386
|
+
|
|
387
|
+
class V1CreditUsageHistoricalResponse(pydantic.BaseModel):
|
|
388
|
+
success: bool
|
|
389
|
+
periods: List[V1CreditUsageHistoricalPeriod]
|
|
390
|
+
|
|
391
|
+
class V1TokenUsageHistoricalPeriod(pydantic.BaseModel):
|
|
392
|
+
startDate: Optional[str] = None
|
|
393
|
+
endDate: Optional[str] = None
|
|
394
|
+
apiKey: Optional[str] = None
|
|
395
|
+
tokensUsed: int
|
|
396
|
+
|
|
397
|
+
class V1TokenUsageHistoricalResponse(pydantic.BaseModel):
|
|
398
|
+
success: bool
|
|
399
|
+
periods: List[V1TokenUsageHistoricalPeriod]
|
|
400
|
+
|
|
361
401
|
class V1GenerateLLMsTextParams(pydantic.BaseModel):
|
|
362
402
|
"""
|
|
363
403
|
Parameters for the LLMs.txt generation operation.
|
|
@@ -722,6 +762,90 @@ class V1FirecrawlApp:
|
|
|
722
762
|
else:
|
|
723
763
|
self._handle_error(response, 'search')
|
|
724
764
|
|
|
765
|
+
def get_credit_usage(self) -> V1CreditUsageResponse:
|
|
766
|
+
"""Get current credit usage and billing period (v1)."""
|
|
767
|
+
_headers = self._prepare_headers()
|
|
768
|
+
response = self._get_request(
|
|
769
|
+
f"{self.api_url}/v1/team/credit-usage",
|
|
770
|
+
_headers
|
|
771
|
+
)
|
|
772
|
+
|
|
773
|
+
if response.status_code == 200:
|
|
774
|
+
try:
|
|
775
|
+
response_json = response.json()
|
|
776
|
+
if response_json.get('success') and 'data' in response_json:
|
|
777
|
+
return V1CreditUsageResponse(**response_json)
|
|
778
|
+
elif "error" in response_json:
|
|
779
|
+
raise Exception(f"Failed to get credit usage. Error: {response_json['error']}")
|
|
780
|
+
else:
|
|
781
|
+
raise Exception(f"Failed to get credit usage. Error: {response_json}")
|
|
782
|
+
except ValueError:
|
|
783
|
+
raise Exception('Failed to parse Firecrawl response as JSON.')
|
|
784
|
+
else:
|
|
785
|
+
self._handle_error(response, 'get credit usage')
|
|
786
|
+
|
|
787
|
+
def get_token_usage(self) -> V1TokenUsageResponse:
|
|
788
|
+
"""Get current token usage and billing period (v1)."""
|
|
789
|
+
_headers = self._prepare_headers()
|
|
790
|
+
response = self._get_request(
|
|
791
|
+
f"{self.api_url}/v1/team/token-usage",
|
|
792
|
+
_headers
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
if response.status_code == 200:
|
|
796
|
+
try:
|
|
797
|
+
response_json = response.json()
|
|
798
|
+
if response_json.get('success') and 'data' in response_json:
|
|
799
|
+
return V1TokenUsageResponse(**response_json)
|
|
800
|
+
elif "error" in response_json:
|
|
801
|
+
raise Exception(f"Failed to get token usage. Error: {response_json['error']}")
|
|
802
|
+
else:
|
|
803
|
+
raise Exception(f"Failed to get token usage. Error: {response_json}")
|
|
804
|
+
except ValueError:
|
|
805
|
+
raise Exception('Failed to parse Firecrawl response as JSON.')
|
|
806
|
+
else:
|
|
807
|
+
self._handle_error(response, 'get token usage')
|
|
808
|
+
|
|
809
|
+
def get_credit_usage_historical(self, by_api_key: bool = False) -> V1CreditUsageHistoricalResponse:
|
|
810
|
+
"""Get historical credit usage (v1)."""
|
|
811
|
+
_headers = self._prepare_headers()
|
|
812
|
+
url = f"{self.api_url}/v1/team/credit-usage/historical" + ("?byApiKey=true" if by_api_key else "")
|
|
813
|
+
response = self._get_request(url, _headers)
|
|
814
|
+
|
|
815
|
+
if response.status_code == 200:
|
|
816
|
+
try:
|
|
817
|
+
response_json = response.json()
|
|
818
|
+
if response_json.get('success') and 'periods' in response_json:
|
|
819
|
+
return V1CreditUsageHistoricalResponse(**response_json)
|
|
820
|
+
elif "error" in response_json:
|
|
821
|
+
raise Exception(f"Failed to get historical credit usage. Error: {response_json['error']}")
|
|
822
|
+
else:
|
|
823
|
+
raise Exception(f"Failed to get historical credit usage. Error: {response_json}")
|
|
824
|
+
except ValueError:
|
|
825
|
+
raise Exception('Failed to parse Firecrawl response as JSON.')
|
|
826
|
+
else:
|
|
827
|
+
self._handle_error(response, 'get credit usage historical')
|
|
828
|
+
|
|
829
|
+
def get_token_usage_historical(self, by_api_key: bool = False) -> V1TokenUsageHistoricalResponse:
|
|
830
|
+
"""Get historical token usage (v1)."""
|
|
831
|
+
_headers = self._prepare_headers()
|
|
832
|
+
url = f"{self.api_url}/v1/team/token-usage/historical" + ("?byApiKey=true" if by_api_key else "")
|
|
833
|
+
response = self._get_request(url, _headers)
|
|
834
|
+
|
|
835
|
+
if response.status_code == 200:
|
|
836
|
+
try:
|
|
837
|
+
response_json = response.json()
|
|
838
|
+
if response_json.get('success') and 'periods' in response_json:
|
|
839
|
+
return V1TokenUsageHistoricalResponse(**response_json)
|
|
840
|
+
elif "error" in response_json:
|
|
841
|
+
raise Exception(f"Failed to get historical token usage. Error: {response_json['error']}")
|
|
842
|
+
else:
|
|
843
|
+
raise Exception(f"Failed to get historical token usage. Error: {response_json}")
|
|
844
|
+
except ValueError:
|
|
845
|
+
raise Exception('Failed to parse Firecrawl response as JSON.')
|
|
846
|
+
else:
|
|
847
|
+
self._handle_error(response, 'get token usage historical')
|
|
848
|
+
|
|
725
849
|
def crawl_url(
|
|
726
850
|
self,
|
|
727
851
|
url: str,
|
|
@@ -2913,6 +3037,24 @@ class AsyncV1FirecrawlApp(V1FirecrawlApp):
|
|
|
2913
3037
|
"""
|
|
2914
3038
|
return self._get_error_message(status_code, action, error_message, error_details)
|
|
2915
3039
|
|
|
3040
|
+
async def get_credit_usage(self) -> V1CreditUsageResponse:
|
|
3041
|
+
"""Get current credit usage and billing period (v1, async)."""
|
|
3042
|
+
headers = self._prepare_headers()
|
|
3043
|
+
resp = await self._async_get_request(
|
|
3044
|
+
f"{self.api_url}/v1/team/credit-usage",
|
|
3045
|
+
headers
|
|
3046
|
+
)
|
|
3047
|
+
return V1CreditUsageResponse(**resp)
|
|
3048
|
+
|
|
3049
|
+
async def get_token_usage(self) -> V1TokenUsageResponse:
|
|
3050
|
+
"""Get current token usage and billing period (v1, async)."""
|
|
3051
|
+
headers = self._prepare_headers()
|
|
3052
|
+
resp = await self._async_get_request(
|
|
3053
|
+
f"{self.api_url}/v1/team/token-usage",
|
|
3054
|
+
headers
|
|
3055
|
+
)
|
|
3056
|
+
return V1TokenUsageResponse(**resp)
|
|
3057
|
+
|
|
2916
3058
|
async def crawl_url_and_watch(
|
|
2917
3059
|
self,
|
|
2918
3060
|
url: str,
|
firecrawl/v2/client.py
CHANGED
|
@@ -727,6 +727,14 @@ class FirecrawlClient:
|
|
|
727
727
|
"""Get recent token usage metrics (v2)."""
|
|
728
728
|
return usage_methods.get_token_usage(self.http_client)
|
|
729
729
|
|
|
730
|
+
def get_credit_usage_historical(self, by_api_key: bool = False):
|
|
731
|
+
"""Get historical credit usage (v2)."""
|
|
732
|
+
return usage_methods.get_credit_usage_historical(self.http_client, by_api_key)
|
|
733
|
+
|
|
734
|
+
def get_token_usage_historical(self, by_api_key: bool = False):
|
|
735
|
+
"""Get historical token usage (v2)."""
|
|
736
|
+
return usage_methods.get_token_usage_historical(self.http_client, by_api_key)
|
|
737
|
+
|
|
730
738
|
def get_queue_status(self):
|
|
731
739
|
"""Get metrics about the team's scrape queue."""
|
|
732
740
|
return usage_methods.get_queue_status(self.http_client)
|
firecrawl/v2/client_async.py
CHANGED
|
@@ -253,6 +253,18 @@ class AsyncFirecrawlClient:
|
|
|
253
253
|
async def get_token_usage(self):
|
|
254
254
|
from .methods.aio import usage as async_usage # type: ignore[attr-defined]
|
|
255
255
|
return await async_usage.get_token_usage(self.async_http_client)
|
|
256
|
+
|
|
257
|
+
async def get_credit_usage_historical(self, by_api_key: bool = False):
|
|
258
|
+
from .methods.aio import usage as async_usage # type: ignore[attr-defined]
|
|
259
|
+
return await async_usage.get_credit_usage_historical(self.async_http_client, by_api_key)
|
|
260
|
+
|
|
261
|
+
async def get_token_usage_historical(self, by_api_key: bool = False):
|
|
262
|
+
from .methods.aio import usage as async_usage # type: ignore[attr-defined]
|
|
263
|
+
return await async_usage.get_token_usage_historical(self.async_http_client, by_api_key)
|
|
264
|
+
|
|
265
|
+
async def get_queue_status(self):
|
|
266
|
+
from .methods.aio import usage as async_usage # type: ignore[attr-defined]
|
|
267
|
+
return await async_usage.get_queue_status(self.async_http_client)
|
|
256
268
|
|
|
257
269
|
# Watcher (sync object usable from async contexts)
|
|
258
270
|
def watcher(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from ...utils.http_client_async import AsyncHttpClient
|
|
2
2
|
from ...utils.error_handler import handle_response_error
|
|
3
|
-
from ...types import ConcurrencyCheck, CreditUsage, TokenUsage
|
|
3
|
+
from ...types import ConcurrencyCheck, CreditUsage, TokenUsage, CreditUsageHistoricalResponse, TokenUsageHistoricalResponse, QueueStatusResponse
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
async def get_concurrency(client: AsyncHttpClient) -> ConcurrencyCheck:
|
|
@@ -25,7 +25,12 @@ async def get_credit_usage(client: AsyncHttpClient) -> CreditUsage:
|
|
|
25
25
|
if not body.get("success"):
|
|
26
26
|
raise Exception(body.get("error", "Unknown error"))
|
|
27
27
|
data = body.get("data", body)
|
|
28
|
-
return CreditUsage(
|
|
28
|
+
return CreditUsage(
|
|
29
|
+
remaining_credits=data.get("remainingCredits", data.get("remaining_credits", 0)),
|
|
30
|
+
plan_credits=data.get("planCredits", data.get("plan_credits")),
|
|
31
|
+
billing_period_start=data.get("billingPeriodStart", data.get("billing_period_start")),
|
|
32
|
+
billing_period_end=data.get("billingPeriodEnd", data.get("billing_period_end")),
|
|
33
|
+
)
|
|
29
34
|
|
|
30
35
|
|
|
31
36
|
async def get_token_usage(client: AsyncHttpClient) -> TokenUsage:
|
|
@@ -37,6 +42,48 @@ async def get_token_usage(client: AsyncHttpClient) -> TokenUsage:
|
|
|
37
42
|
raise Exception(body.get("error", "Unknown error"))
|
|
38
43
|
data = body.get("data", body)
|
|
39
44
|
return TokenUsage(
|
|
40
|
-
remaining_tokens=data.get("remainingTokens", 0)
|
|
45
|
+
remaining_tokens=data.get("remainingTokens", data.get("remaining_tokens", 0)),
|
|
46
|
+
plan_tokens=data.get("planTokens", data.get("plan_tokens")),
|
|
47
|
+
billing_period_start=data.get("billingPeriodStart", data.get("billing_period_start")),
|
|
48
|
+
billing_period_end=data.get("billingPeriodEnd", data.get("billing_period_end")),
|
|
41
49
|
)
|
|
42
50
|
|
|
51
|
+
|
|
52
|
+
async def get_queue_status(client: AsyncHttpClient) -> QueueStatusResponse:
|
|
53
|
+
resp = await client.get("/v2/team/queue-status")
|
|
54
|
+
if resp.status_code >= 400:
|
|
55
|
+
handle_response_error(resp, "get queue status")
|
|
56
|
+
body = resp.json()
|
|
57
|
+
if not body.get("success"):
|
|
58
|
+
raise Exception(body.get("error", "Unknown error"))
|
|
59
|
+
data = body.get("data", body)
|
|
60
|
+
return QueueStatusResponse(
|
|
61
|
+
jobs_in_queue=data.get("jobsInQueue", 0),
|
|
62
|
+
active_jobs_in_queue=data.get("activeJobsInQueue", 0),
|
|
63
|
+
waiting_jobs_in_queue=data.get("waitingJobsInQueue", 0),
|
|
64
|
+
max_concurrency=data.get("maxConcurrency", 0),
|
|
65
|
+
most_recent_success=data.get("mostRecentSuccess", None),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
async def get_credit_usage_historical(client: AsyncHttpClient, by_api_key: bool = False) -> CreditUsageHistoricalResponse:
|
|
70
|
+
query = "?byApiKey=true" if by_api_key else ""
|
|
71
|
+
resp = await client.get(f"/v2/team/credit-usage/historical{query}")
|
|
72
|
+
if resp.status_code >= 400:
|
|
73
|
+
handle_response_error(resp, "get credit usage historical")
|
|
74
|
+
body = resp.json()
|
|
75
|
+
if not body.get("success"):
|
|
76
|
+
raise Exception(body.get("error", "Unknown error"))
|
|
77
|
+
return CreditUsageHistoricalResponse(**body)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
async def get_token_usage_historical(client: AsyncHttpClient, by_api_key: bool = False) -> TokenUsageHistoricalResponse:
|
|
81
|
+
query = "?byApiKey=true" if by_api_key else ""
|
|
82
|
+
resp = await client.get(f"/v2/team/token-usage/historical{query}")
|
|
83
|
+
if resp.status_code >= 400:
|
|
84
|
+
handle_response_error(resp, "get token usage historical")
|
|
85
|
+
body = resp.json()
|
|
86
|
+
if not body.get("success"):
|
|
87
|
+
raise Exception(body.get("error", "Unknown error"))
|
|
88
|
+
return TokenUsageHistoricalResponse(**body)
|
|
89
|
+
|
firecrawl/v2/methods/usage.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from ..utils import HttpClient, handle_response_error
|
|
2
|
-
from ..types import ConcurrencyCheck, CreditUsage, QueueStatusResponse, TokenUsage
|
|
2
|
+
from ..types import ConcurrencyCheck, CreditUsage, QueueStatusResponse, TokenUsage, CreditUsageHistoricalResponse, TokenUsageHistoricalResponse
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def get_concurrency(client: HttpClient) -> ConcurrencyCheck:
|
|
@@ -24,7 +24,12 @@ def get_credit_usage(client: HttpClient) -> CreditUsage:
|
|
|
24
24
|
if not body.get("success"):
|
|
25
25
|
raise Exception(body.get("error", "Unknown error"))
|
|
26
26
|
data = body.get("data", body)
|
|
27
|
-
return CreditUsage(
|
|
27
|
+
return CreditUsage(
|
|
28
|
+
remaining_credits=data.get("remainingCredits", data.get("remaining_credits", 0)),
|
|
29
|
+
plan_credits=data.get("planCredits", data.get("plan_credits")),
|
|
30
|
+
billing_period_start=data.get("billingPeriodStart", data.get("billing_period_start")),
|
|
31
|
+
billing_period_end=data.get("billingPeriodEnd", data.get("billing_period_end")),
|
|
32
|
+
)
|
|
28
33
|
|
|
29
34
|
|
|
30
35
|
def get_token_usage(client: HttpClient) -> TokenUsage:
|
|
@@ -36,7 +41,10 @@ def get_token_usage(client: HttpClient) -> TokenUsage:
|
|
|
36
41
|
raise Exception(body.get("error", "Unknown error"))
|
|
37
42
|
data = body.get("data", body)
|
|
38
43
|
return TokenUsage(
|
|
39
|
-
remaining_tokens=data.get("remainingTokens", 0)
|
|
44
|
+
remaining_tokens=data.get("remainingTokens", data.get("remaining_tokens", 0)),
|
|
45
|
+
plan_tokens=data.get("planTokens", data.get("plan_tokens")),
|
|
46
|
+
billing_period_start=data.get("billingPeriodStart", data.get("billing_period_start")),
|
|
47
|
+
billing_period_end=data.get("billingPeriodEnd", data.get("billing_period_end")),
|
|
40
48
|
)
|
|
41
49
|
|
|
42
50
|
def get_queue_status(client: HttpClient) -> QueueStatusResponse:
|
|
@@ -54,3 +62,23 @@ def get_queue_status(client: HttpClient) -> QueueStatusResponse:
|
|
|
54
62
|
max_concurrency=data.get("maxConcurrency", 0),
|
|
55
63
|
most_recent_success=data.get("mostRecentSuccess", None),
|
|
56
64
|
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_credit_usage_historical(client: HttpClient, by_api_key: bool = False) -> CreditUsageHistoricalResponse:
|
|
68
|
+
resp = client.get(f"/v2/team/credit-usage/historical{'?byApiKey=true' if by_api_key else ''}")
|
|
69
|
+
if not resp.ok:
|
|
70
|
+
handle_response_error(resp, "get credit usage historical")
|
|
71
|
+
body = resp.json()
|
|
72
|
+
if not body.get("success"):
|
|
73
|
+
raise Exception(body.get("error", "Unknown error"))
|
|
74
|
+
return CreditUsageHistoricalResponse(**body)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_token_usage_historical(client: HttpClient, by_api_key: bool = False) -> TokenUsageHistoricalResponse:
|
|
78
|
+
resp = client.get(f"/v2/team/token-usage/historical{'?byApiKey=true' if by_api_key else ''}")
|
|
79
|
+
if not resp.ok:
|
|
80
|
+
handle_response_error(resp, "get token usage historical")
|
|
81
|
+
body = resp.json()
|
|
82
|
+
if not body.get("success"):
|
|
83
|
+
raise Exception(body.get("error", "Unknown error"))
|
|
84
|
+
return TokenUsageHistoricalResponse(**body)
|
firecrawl/v2/types.py
CHANGED
|
@@ -480,10 +480,16 @@ class ConcurrencyCheck(BaseModel):
|
|
|
480
480
|
class CreditUsage(BaseModel):
|
|
481
481
|
"""Remaining credits for the team/API key."""
|
|
482
482
|
remaining_credits: int
|
|
483
|
+
plan_credits: Optional[int] = None
|
|
484
|
+
billing_period_start: Optional[str] = None
|
|
485
|
+
billing_period_end: Optional[str] = None
|
|
483
486
|
|
|
484
487
|
class TokenUsage(BaseModel):
|
|
485
488
|
"""Recent token usage metrics (if available)."""
|
|
486
489
|
remaining_tokens: int
|
|
490
|
+
plan_tokens: Optional[int] = None
|
|
491
|
+
billing_period_start: Optional[str] = None
|
|
492
|
+
billing_period_end: Optional[str] = None
|
|
487
493
|
|
|
488
494
|
class QueueStatusResponse(BaseModel):
|
|
489
495
|
"""Metrics about the team's scrape queue."""
|
|
@@ -493,6 +499,26 @@ class QueueStatusResponse(BaseModel):
|
|
|
493
499
|
max_concurrency: int
|
|
494
500
|
most_recent_success: Optional[datetime] = None
|
|
495
501
|
|
|
502
|
+
class CreditUsageHistoricalPeriod(BaseModel):
|
|
503
|
+
startDate: Optional[str] = None
|
|
504
|
+
endDate: Optional[str] = None
|
|
505
|
+
apiKey: Optional[str] = None
|
|
506
|
+
creditsUsed: int
|
|
507
|
+
|
|
508
|
+
class CreditUsageHistoricalResponse(BaseModel):
|
|
509
|
+
success: bool
|
|
510
|
+
periods: List[CreditUsageHistoricalPeriod]
|
|
511
|
+
|
|
512
|
+
class TokenUsageHistoricalPeriod(BaseModel):
|
|
513
|
+
startDate: Optional[str] = None
|
|
514
|
+
endDate: Optional[str] = None
|
|
515
|
+
apiKey: Optional[str] = None
|
|
516
|
+
tokensUsed: int
|
|
517
|
+
|
|
518
|
+
class TokenUsageHistoricalResponse(BaseModel):
|
|
519
|
+
success: bool
|
|
520
|
+
periods: List[TokenUsageHistoricalPeriod]
|
|
521
|
+
|
|
496
522
|
# Action types
|
|
497
523
|
class WaitAction(BaseModel):
|
|
498
524
|
"""Wait action to perform during scraping."""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
firecrawl/__init__.py,sha256=
|
|
2
|
-
firecrawl/client.py,sha256=
|
|
1
|
+
firecrawl/__init__.py,sha256=MG1HrZZkQQ5l3Lnv3o1MwDyqK6EDLWl4Ej975X-bu4o,2192
|
|
2
|
+
firecrawl/client.py,sha256=Lmrg2jniCETU6_xVMn_fgLrgDXiBixK9hSkkdsCGiog,11840
|
|
3
3
|
firecrawl/firecrawl.backup.py,sha256=v1FEN3jR4g5Aupg4xp6SLkuFvYMQuUKND2YELbYjE6c,200430
|
|
4
|
-
firecrawl/types.py,sha256=
|
|
4
|
+
firecrawl/types.py,sha256=T1g8r12xIWxJSoSNrL58SSgc1F8SykrwVx92BhTvZuc,2926
|
|
5
5
|
firecrawl/__tests__/e2e/v2/conftest.py,sha256=I28TUpN5j0-9gM79NlbrDS8Jlsheao657od2f-2xK0Y,2587
|
|
6
6
|
firecrawl/__tests__/e2e/v2/test_async.py,sha256=ZXpf1FVOJgNclITglrxIyFwP4cOiqzWLicGaxIm70BQ,2526
|
|
7
7
|
firecrawl/__tests__/e2e/v2/test_batch_scrape.py,sha256=H9GtuwHIFdOQ958SOVThi_kvDDxcXAK_ECRh95ogonQ,3265
|
|
@@ -18,7 +18,7 @@ firecrawl/__tests__/e2e/v2/aio/test_aio_extract.py,sha256=3CNRIFzgBMcOYOLhnKcK1k
|
|
|
18
18
|
firecrawl/__tests__/e2e/v2/aio/test_aio_map.py,sha256=nckl1kbiEaaTdu5lm__tOoTDG-txTYwwSH3KZEvyKzc,1199
|
|
19
19
|
firecrawl/__tests__/e2e/v2/aio/test_aio_scrape.py,sha256=b17A7advBEjxrjdait2w8GHztZeKy_P3zZ3ixm5H7xw,4453
|
|
20
20
|
firecrawl/__tests__/e2e/v2/aio/test_aio_search.py,sha256=ehV0Ai_hknAkaoE551j2lbktV4bi_J0h3FKzC7G15Iw,8246
|
|
21
|
-
firecrawl/__tests__/e2e/v2/aio/test_aio_usage.py,sha256=
|
|
21
|
+
firecrawl/__tests__/e2e/v2/aio/test_aio_usage.py,sha256=lVGfwR79eaZamUZXgKStUJcpclCnnlpwHGo2pMOUhCY,1255
|
|
22
22
|
firecrawl/__tests__/e2e/v2/aio/test_aio_watcher.py,sha256=hwES4Nu5c0hniZ9heIPDfvh_2JmJ2wPoX9ULTZ0Asjs,1471
|
|
23
23
|
firecrawl/__tests__/unit/v2/methods/test_batch_request_preparation.py,sha256=HeOxN-sPYSssytcIRAEicJSZsFt_Oa5qGXAtdumR54c,4040
|
|
24
24
|
firecrawl/__tests__/unit/v2/methods/test_crawl_params.py,sha256=p9hzg14uAs1iHKXPDSXhGU6hEzPBF_Ae34RAf5XYa10,2387
|
|
@@ -42,11 +42,11 @@ firecrawl/__tests__/unit/v2/methods/aio/test_ensure_async.py,sha256=pUwuWhRbVUTb
|
|
|
42
42
|
firecrawl/__tests__/unit/v2/utils/test_validation.py,sha256=E4n4jpBhH_W7E0ikI5r8KMAKiOhbfGD3i_B8-dv3PlI,10803
|
|
43
43
|
firecrawl/__tests__/unit/v2/watcher/test_ws_watcher.py,sha256=87w47n0iOihtu4jTR4-4rw1-xVKWmLg2BOBGxjQPnUk,9517
|
|
44
44
|
firecrawl/v1/__init__.py,sha256=aP1oisPeZVGGZynvENc07JySMOZfv_4zAlxQ0ecMJXA,481
|
|
45
|
-
firecrawl/v1/client.py,sha256=
|
|
45
|
+
firecrawl/v1/client.py,sha256=33o_sPOyPsRfM1j2PUiKTkvbnPCkmL7-Ou54D1sx-rE,207710
|
|
46
46
|
firecrawl/v2/__init__.py,sha256=Jc6a8tBjYG5OPkjDM5pl-notyys-7DEj7PLEfepv3fc,137
|
|
47
|
-
firecrawl/v2/client.py,sha256=
|
|
48
|
-
firecrawl/v2/client_async.py,sha256=
|
|
49
|
-
firecrawl/v2/types.py,sha256=
|
|
47
|
+
firecrawl/v2/client.py,sha256=aEISMnyKKzh5jcrLdpkC3WCZ7cMWj5vo1Gk7ljc9gwk,31821
|
|
48
|
+
firecrawl/v2/client_async.py,sha256=HAewaYnHrvQQgkSQfwwNeWvAuj3JZqceQk6T10RKxeg,11204
|
|
49
|
+
firecrawl/v2/types.py,sha256=itKhycxDQ9a3wltK28qFLxLVVvsvb5APoS1kOiiS8ac,24341
|
|
50
50
|
firecrawl/v2/watcher.py,sha256=FOU71tqSKxgeuGycu4ye0SLc2dw7clIcoQjPsi-4Csc,14229
|
|
51
51
|
firecrawl/v2/watcher_async.py,sha256=AVjW2mgABniolSsauK4u0FW8ya6WzRUdyEg2R-8vGCw,10278
|
|
52
52
|
firecrawl/v2/methods/batch.py,sha256=jFSIPtvulUrPz3Y3zT1gDNwYEf8Botpfh4GOeYsVYRI,14852
|
|
@@ -55,7 +55,7 @@ firecrawl/v2/methods/extract.py,sha256=-Jr4BtraU3b7hd3JIY73V-S69rUclxyXyUpoQb6DC
|
|
|
55
55
|
firecrawl/v2/methods/map.py,sha256=4SADb0-lkbdOWDmO6k8_TzK0yRti5xsN40N45nUl9uA,2592
|
|
56
56
|
firecrawl/v2/methods/scrape.py,sha256=CSHBwC-P91UfrW3zHirjNAs2h899FKcWvd1DY_4fJdo,1921
|
|
57
57
|
firecrawl/v2/methods/search.py,sha256=6BKiQ1aKJjWBKm9BBtKxFKGD74kCKBeMIp_OgjcDFAw,7673
|
|
58
|
-
firecrawl/v2/methods/usage.py,sha256=
|
|
58
|
+
firecrawl/v2/methods/usage.py,sha256=NqkmFd-ziw8ijbZxwaxjxZHl85u0LTe_TYqr_NGWFwE,3693
|
|
59
59
|
firecrawl/v2/methods/aio/__init__.py,sha256=RocMJnGwnLIvGu3G8ZvY8INkipC7WHZiu2bE31eSyJs,35
|
|
60
60
|
firecrawl/v2/methods/aio/batch.py,sha256=4Uj05ffpMhQA2J_mkvHYYogdXb0IgbKGbomO43b4m94,6741
|
|
61
61
|
firecrawl/v2/methods/aio/crawl.py,sha256=j2Tb2AcGsT6bCiUbB2yjrfvGZqkinUt0tU-SzWmB7Jw,11551
|
|
@@ -63,7 +63,7 @@ firecrawl/v2/methods/aio/extract.py,sha256=IfNr2ETqt4dR73JFzrEYI4kk5vpKnJOG0BmPE
|
|
|
63
63
|
firecrawl/v2/methods/aio/map.py,sha256=EuT-5A0cQr_e5SBfEZ6pnl8u0JUwEEvSwhyT2N-QoKU,2326
|
|
64
64
|
firecrawl/v2/methods/aio/scrape.py,sha256=ilA9qco8YGwCFpE0PN1XBQUyuHPQwH2QioZ-xsfxhgU,1386
|
|
65
65
|
firecrawl/v2/methods/aio/search.py,sha256=_TqTFGQLlOCCLNdWcOvakTqPGD2r9AOlBg8RasOgmvw,6177
|
|
66
|
-
firecrawl/v2/methods/aio/usage.py,sha256=
|
|
66
|
+
firecrawl/v2/methods/aio/usage.py,sha256=iUzTkdAWRheq-V5rRXcW0bc3MSODaVS1AqroRF0fO9M,3964
|
|
67
67
|
firecrawl/v2/utils/__init__.py,sha256=i1GgxySmqEXpWSBQCu3iZBPIJG7fXj0QXCDWGwerWNs,338
|
|
68
68
|
firecrawl/v2/utils/error_handler.py,sha256=Iuf916dHphDY8ObNNlWy75628DFeJ0Rv8ljRp4LttLE,4199
|
|
69
69
|
firecrawl/v2/utils/get_version.py,sha256=0CxW_41q2hlzIxEWOivUCaYw3GFiSIH32RPUMcIgwAY,492
|
|
@@ -71,10 +71,10 @@ firecrawl/v2/utils/http_client.py,sha256=gUrC1CvU5sj03w27Lbq-3-yH38Yi_OXiI01-piw
|
|
|
71
71
|
firecrawl/v2/utils/http_client_async.py,sha256=iy89_bk2HS3afSRHZ8016eMCa9Fk-5MFTntcOHfbPgE,1936
|
|
72
72
|
firecrawl/v2/utils/normalize.py,sha256=nlTU6QRghT1YKZzNZlIQj4STSRuSUGrS9cCErZIcY5w,3636
|
|
73
73
|
firecrawl/v2/utils/validation.py,sha256=qWWiWaVcvODmVxf9rxIVy1j_dyuJCvdMMUoYhvWUEIU,15269
|
|
74
|
-
firecrawl-4.
|
|
74
|
+
firecrawl-4.3.1.dist-info/licenses/LICENSE,sha256=nPCunEDwjRGHlmjvsiDUyIWbkqqyj3Ej84ntnh0g0zA,1084
|
|
75
75
|
tests/test_change_tracking.py,sha256=_IJ5ShLcoj2fHDBaw-nE4I4lHdmDB617ocK_XMHhXps,4177
|
|
76
76
|
tests/test_timeout_conversion.py,sha256=PWlIEMASQNhu4cp1OW_ebklnE9NCiigPnEFCtI5N3w0,3996
|
|
77
|
-
firecrawl-4.
|
|
78
|
-
firecrawl-4.
|
|
79
|
-
firecrawl-4.
|
|
80
|
-
firecrawl-4.
|
|
77
|
+
firecrawl-4.3.1.dist-info/METADATA,sha256=CAAwyLn1HTzmj8hXMY9tWPm5ZzOl_kCJvdaM7cUH3gA,7392
|
|
78
|
+
firecrawl-4.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
79
|
+
firecrawl-4.3.1.dist-info/top_level.txt,sha256=8T3jOaSN5mtLghO-R3MQ8KO290gIX8hmfxQmglBPdLE,16
|
|
80
|
+
firecrawl-4.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|