import asyncio from typing import List, Optional from fastapi import Request from langchain_core.documents import Document from langchain_community.document_loaders.firecrawl import ( FireCrawlLoader as BasFireCrawlLoader, ) from firecrawl.v2.utils.error_handler import ( WebsiteNotSupportedError, PaymentRequiredError, BadRequestError, UnauthorizedError, ) from ..core.logger import SingletonLogger from ..utils.api_key_utils import get_api_key_for_service class FirecrawlLoader: @staticmethod async def _load_single(url: str, api_key: str) -> List[Document]: logger = SingletonLogger().get_logger() loader = BasFireCrawlLoader( url=url, api_key=api_key, mode="scrape", params={"formats": ["markdown"]}, ) try: docs = await loader.aload() return docs or [] except ( WebsiteNotSupportedError, PaymentRequiredError, BadRequestError, UnauthorizedError, ): logger.warning( "Website not supported/payment required/bad request/unauthorized for URL: %s", url, ) return [ Document( page_content="Website not supported/payment required/bad request/unauthorized", metadata={"url": url}, ) ] except Exception: logger.exception("Error while loading url with firecrawl: %s", url) return [] @staticmethod async def scrape( urls: List[str], api_key: Optional[str] = None, request: Optional[Request] = None, ) -> List[Document]: logger = SingletonLogger().get_logger() try: if not api_key and request: api_key = get_api_key_for_service(request, "firecrawl") if not urls: return [] if isinstance(urls, str): urls = [urls] tasks = [FirecrawlLoader._load_single(url, api_key) for url in urls] results = await asyncio.gather(*tasks) documents: List[Document] = [] for res in results: if res: documents.extend( [ Document( page_content=doc.page_content, metadata={ "title": doc.metadata.get("title", ""), "description": doc.metadata.get("description", ""), "url": doc.metadata.get("url", ""), "image": doc.metadata.get("og_image", ""), "favicon": doc.metadata.get("favicon", ""), "sitename": doc.metadata.get("og:site_name", ""), }, ) for doc in res ] ) return documents except Exception: logger.exception("Error while loading urls with firecrawl: %s", urls) return []