Skip to content

Commit 9c64d84

Browse files
committed
refac
1 parent 40f5b3d commit 9c64d84

2 files changed

Lines changed: 59 additions & 93 deletions

File tree

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
from typing import Optional, List
33

4+
import requests
45
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
56

67
log = logging.getLogger(__name__)
@@ -14,23 +15,38 @@ def search_firecrawl(
1415
filter_list: Optional[List[str]] = None,
1516
) -> List[SearchResult]:
1617
try:
17-
from firecrawl import FirecrawlApp
18+
url = firecrawl_url.rstrip('/')
19+
response = requests.post(
20+
f'{url}/v1/search',
21+
headers={
22+
'Content-Type': 'application/json',
23+
'Authorization': f'Bearer {firecrawl_api_key}',
24+
},
25+
json={
26+
'query': query,
27+
'limit': count,
28+
'timeout': count * 3000,
29+
},
30+
timeout=count * 3 + 10,
31+
)
32+
response.raise_for_status()
33+
data = response.json().get('data', {})
1834

19-
firecrawl = FirecrawlApp(api_key=firecrawl_api_key, api_url=firecrawl_url)
20-
response = firecrawl.search(query=query, limit=count, ignore_invalid_urls=True, timeout=count * 3)
21-
results = response.web
22-
if filter_list:
23-
results = get_filtered_results(results, filter_list)
2435
results = [
2536
SearchResult(
26-
link=result.url,
27-
title=result.title,
28-
snippet=result.description,
37+
link=r.get('url', ''),
38+
title=r.get('title', ''),
39+
snippet=r.get('description', ''),
2940
)
30-
for result in results[:count]
41+
for r in data.get('web', [])
3142
]
32-
log.info(f'External search results: {results}')
43+
44+
if filter_list:
45+
results = get_filtered_results(results, filter_list)
46+
47+
results = results[:count]
48+
log.info(f'FireCrawl search results: {results}')
3349
return results
3450
except Exception as e:
35-
log.error(f'Error in External search: {e}')
51+
log.error(f'Error in FireCrawl search: {e}')
3652
return []

backend/open_webui/retrieval/web/utils.py

Lines changed: 31 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -192,27 +192,6 @@ def __init__(
192192
proxy: Optional[Dict[str, str]] = None,
193193
params: Optional[Dict] = None,
194194
):
195-
"""Concurrent document loader for FireCrawl operations.
196-
197-
Executes multiple FireCrawlLoader instances concurrently using thread pooling
198-
to improve bulk processing efficiency.
199-
Args:
200-
web_paths: List of URLs/paths to process.
201-
verify_ssl: If True, verify SSL certificates.
202-
trust_env: If True, use proxy settings from environment variables.
203-
requests_per_second: Number of requests per second to limit to.
204-
continue_on_failure (bool): If True, continue loading other URLs on failure.
205-
api_key: API key for FireCrawl service. Defaults to None
206-
(uses FIRE_CRAWL_API_KEY environment variable if not provided).
207-
api_url: Base URL for FireCrawl API. Defaults to official API endpoint.
208-
mode: Operation mode selection:
209-
- 'crawl': Website crawling mode
210-
- 'scrape': Direct page scraping (default)
211-
- 'map': Site map generation
212-
proxy: Proxy override settings for the FireCrawl API.
213-
params: The parameters to pass to the Firecrawl API.
214-
For more details, visit: https://docs.firecrawl.dev/sdks/python#batch-scrape
215-
"""
216195
proxy_server = proxy.get('server') if proxy else None
217196
if trust_env and not proxy_server:
218197
env_proxies = urllib.request.getproxies()
@@ -229,83 +208,54 @@ def __init__(
229208
self.trust_env = trust_env
230209
self.continue_on_failure = continue_on_failure
231210
self.api_key = api_key
232-
self.api_url = api_url
211+
self.api_url = (api_url or 'https://api.firecrawl.dev').rstrip('/')
233212
self.timeout = timeout
234213
self.mode = mode
235214
self.params = params or {}
236215

237216
def lazy_load(self) -> Iterator[Document]:
238-
"""Load documents using FireCrawl batch_scrape."""
239-
log.debug(
240-
'Starting FireCrawl batch scrape for %d URLs, mode: %s, params: %s',
241-
len(self.web_paths),
242-
self.mode,
243-
self.params,
244-
)
245217
try:
246-
from firecrawl import FirecrawlApp
247-
248-
firecrawl = FirecrawlApp(api_key=self.api_key, api_url=self.api_url)
249-
result = firecrawl.batch_scrape(
250-
self.web_paths,
251-
formats=['markdown'],
252-
skip_tls_verification=not self.verify_ssl,
253-
ignore_invalid_urls=True,
254-
remove_base64_images=True,
255-
max_age=300000, # 5 minutes https://docs.firecrawl.dev/features/fast-scraping#common-maxage-values
256-
wait_timeout=self.timeout if self.timeout else len(self.web_paths) * 3,
257-
**self.params,
258-
)
259-
260-
if result.status != 'completed':
261-
raise RuntimeError(f'FireCrawl batch scrape did not complete successfully. result: {result}')
218+
headers = {
219+
'Content-Type': 'application/json',
220+
'Authorization': f'Bearer {self.api_key}',
221+
}
222+
223+
for url in self.web_paths:
224+
payload = {
225+
'url': url,
226+
'formats': ['markdown'],
227+
**self.params,
228+
}
229+
if self.timeout:
230+
payload['timeout'] = self.timeout * 1000
231+
232+
response = requests.post(
233+
f'{self.api_url}/v1/scrape',
234+
headers=headers,
235+
json=payload,
236+
timeout=self.timeout or 60,
237+
verify=self.verify_ssl,
238+
)
239+
response.raise_for_status()
240+
data = response.json().get('data', {})
241+
metadata = data.get('metadata', {})
242+
source = metadata.get('url') or metadata.get('sourceURL') or url
262243

263-
for data in result.data:
264-
metadata = data.metadata or {}
265244
yield Document(
266-
page_content=data.markdown or '',
267-
metadata={'source': metadata.url or metadata.source_url or ''},
245+
page_content=data.get('markdown', ''),
246+
metadata={'source': source},
268247
)
269-
270248
except Exception as e:
271249
if self.continue_on_failure:
272250
log.exception(f'Error extracting content from URLs: {e}')
273251
else:
274252
raise e
275253

276254
async def alazy_load(self):
277-
"""Async version of lazy_load."""
278-
log.debug(
279-
'Starting FireCrawl batch scrape for %d URLs, mode: %s, params: %s',
280-
len(self.web_paths),
281-
self.mode,
282-
self.params,
283-
)
284255
try:
285-
from firecrawl import FirecrawlApp
286-
287-
firecrawl = FirecrawlApp(api_key=self.api_key, api_url=self.api_url)
288-
result = firecrawl.batch_scrape(
289-
self.web_paths,
290-
formats=['markdown'],
291-
skip_tls_verification=not self.verify_ssl,
292-
ignore_invalid_urls=True,
293-
remove_base64_images=True,
294-
max_age=300000, # 5 minutes https://docs.firecrawl.dev/features/fast-scraping#common-maxage-values
295-
wait_timeout=self.timeout if self.timeout else len(self.web_paths) * 3,
296-
**self.params,
297-
)
298-
299-
if result.status != 'completed':
300-
raise RuntimeError(f'FireCrawl batch scrape did not complete successfully. result: {result}')
301-
302-
for data in result.data:
303-
metadata = data.metadata or {}
304-
yield Document(
305-
page_content=data.markdown or '',
306-
metadata={'source': metadata.url or metadata.source_url or ''},
307-
)
308-
256+
docs = await run_in_threadpool(lambda: list(self.lazy_load()))
257+
for doc in docs:
258+
yield doc
309259
except Exception as e:
310260
if self.continue_on_failure:
311261
log.exception(f'Error extracting content from URLs: {e}')

0 commit comments

Comments
 (0)