samuel-z-chen commited on
Commit
e3f4921
·
2 Parent(s): d6fd606 59195c9

Merge remote-tracking branch 'origin/main'

Browse files
README.md CHANGED
@@ -26,6 +26,7 @@ This repository hosts the code of LightRAG. The structure of this code is based
26
  </div>
27
 
28
  ## 🎉 News
 
29
  - [x] [2025.01.06]🎯📢You can now [use PostgreSQL for Storage](#using-postgresql-for-storage).
30
  - [x] [2024.12.31]🎯📢LightRAG now supports [deletion by document ID](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#delete).
31
  - [x] [2024.11.25]🎯📢LightRAG now supports seamless integration of [custom knowledge graphs](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#insert-custom-kg), empowering users to enhance the system with their own domain expertise.
 
26
  </div>
27
 
28
  ## 🎉 News
29
+ - [x] [2025.01.13]🎯📢Our team has launched [MiniRAG](https://github.com/HKUDS/MiniRAG) for small models.
30
  - [x] [2025.01.06]🎯📢You can now [use PostgreSQL for Storage](#using-postgresql-for-storage).
31
  - [x] [2024.12.31]🎯📢LightRAG now supports [deletion by document ID](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#delete).
32
  - [x] [2024.11.25]🎯📢LightRAG now supports seamless integration of [custom knowledge graphs](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#insert-custom-kg), empowering users to enhance the system with their own domain expertise.
lightrag/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
  from .lightrag import LightRAG as LightRAG, QueryParam as QueryParam
2
 
3
- __version__ = "1.1.0"
4
  __author__ = "Zirui Guo"
5
  __url__ = "https://github.com/HKUDS/LightRAG"
 
1
  from .lightrag import LightRAG as LightRAG, QueryParam as QueryParam
2
 
3
+ __version__ = "1.1.1"
4
  __author__ = "Zirui Guo"
5
  __url__ = "https://github.com/HKUDS/LightRAG"
lightrag/api/lightrag_server.py CHANGED
@@ -9,7 +9,7 @@ from lightrag.llm import openai_complete_if_cache, openai_embedding
9
  from lightrag.llm import azure_openai_complete_if_cache, azure_openai_embedding
10
 
11
  from lightrag.utils import EmbeddingFunc
12
- from typing import Optional, List
13
  from enum import Enum
14
  from pathlib import Path
15
  import shutil
@@ -22,6 +22,7 @@ from fastapi.security import APIKeyHeader
22
  from fastapi.middleware.cors import CORSMiddleware
23
 
24
  from starlette.status import HTTP_403_FORBIDDEN
 
25
 
26
 
27
  def get_default_host(binding_type: str) -> str:
@@ -174,7 +175,11 @@ def parse_args():
174
  class DocumentManager:
175
  """Handles document operations and tracking"""
176
 
177
- def __init__(self, input_dir: str, supported_extensions: tuple = (".txt", ".md")):
 
 
 
 
178
  self.input_dir = Path(input_dir)
179
  self.supported_extensions = supported_extensions
180
  self.indexed_files = set()
@@ -289,7 +294,7 @@ def create_app(args):
289
  + "(With authentication)"
290
  if api_key
291
  else "",
292
- version="1.0.1",
293
  openapi_tags=[{"name": "api"}],
294
  )
295
 
@@ -356,6 +361,80 @@ def create_app(args):
356
  ),
357
  )
358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  @app.on_event("startup")
360
  async def startup_event():
361
  """Index all files in input directory during startup"""
@@ -363,13 +442,7 @@ def create_app(args):
363
  new_files = doc_manager.scan_directory()
364
  for file_path in new_files:
365
  try:
366
- # Use async file reading
367
- async with aiofiles.open(file_path, "r", encoding="utf-8") as f:
368
- content = await f.read()
369
- # Use the async version of insert directly
370
- await rag.ainsert(content)
371
- doc_manager.mark_as_indexed(file_path)
372
- logging.info(f"Indexed file: {file_path}")
373
  except Exception as e:
374
  trace_exception(e)
375
  logging.error(f"Error indexing file {file_path}: {str(e)}")
@@ -388,11 +461,8 @@ def create_app(args):
388
 
389
  for file_path in new_files:
390
  try:
391
- with open(file_path, "r", encoding="utf-8") as f:
392
- content = f.read()
393
- await rag.ainsert(content)
394
- doc_manager.mark_as_indexed(file_path)
395
- indexed_count += 1
396
  except Exception as e:
397
  logging.error(f"Error indexing file {file_path}: {str(e)}")
398
 
@@ -419,10 +489,7 @@ def create_app(args):
419
  shutil.copyfileobj(file.file, buffer)
420
 
421
  # Immediately index the uploaded file
422
- with open(file_path, "r", encoding="utf-8") as f:
423
- content = f.read()
424
- await rag.ainsert(content)
425
- doc_manager.mark_as_indexed(file_path)
426
 
427
  return {
428
  "status": "success",
@@ -483,11 +550,11 @@ def create_app(args):
483
  )
484
  async def insert_text(request: InsertTextRequest):
485
  try:
486
- rag.insert(request.text)
487
  return InsertResponse(
488
  status="success",
489
  message="Text successfully inserted",
490
- document_count=len(rag),
491
  )
492
  except Exception as e:
493
  raise HTTPException(status_code=500, detail=str(e))
@@ -498,26 +565,103 @@ def create_app(args):
498
  dependencies=[Depends(optional_api_key)],
499
  )
500
  async def insert_file(file: UploadFile = File(...), description: str = Form(None)):
 
 
 
 
 
 
 
 
 
 
 
 
501
  try:
502
- content = await file.read()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
 
504
- if file.filename.endswith((".txt", ".md")):
505
- text = content.decode("utf-8")
506
- await rag.ainsert(text)
 
 
507
  else:
508
  raise HTTPException(
509
  status_code=400,
510
- detail="Unsupported file type. Only .txt and .md files are supported",
511
  )
512
 
513
- return InsertResponse(
514
- status="success",
515
- message=f"File '{file.filename}' successfully inserted",
516
- document_count=1,
517
- )
518
  except UnicodeDecodeError:
519
  raise HTTPException(status_code=400, detail="File encoding not supported")
520
  except Exception as e:
 
521
  raise HTTPException(status_code=500, detail=str(e))
522
 
523
  @app.post(
@@ -526,32 +670,110 @@ def create_app(args):
526
  dependencies=[Depends(optional_api_key)],
527
  )
528
  async def insert_batch(files: List[UploadFile] = File(...)):
 
 
 
 
 
 
 
 
 
 
 
529
  try:
530
  inserted_count = 0
531
  failed_files = []
532
 
533
  for file in files:
534
  try:
535
- content = await file.read()
536
- if file.filename.endswith((".txt", ".md")):
537
- text = content.decode("utf-8")
538
- await rag.ainsert(text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  inserted_count += 1
 
540
  else:
541
- failed_files.append(f"{file.filename} (unsupported type)")
 
 
 
542
  except Exception as e:
543
  failed_files.append(f"{file.filename} ({str(e)})")
544
-
545
- status_message = f"Successfully inserted {inserted_count} documents"
546
- if failed_files:
547
- status_message += f". Failed files: {', '.join(failed_files)}"
 
 
 
 
 
 
 
 
 
 
 
 
548
 
549
  return InsertResponse(
550
- status="success" if inserted_count > 0 else "partial_success",
551
  message=status_message,
552
- document_count=len(files),
553
  )
 
554
  except Exception as e:
 
555
  raise HTTPException(status_code=500, detail=str(e))
556
 
557
  @app.delete(
 
9
  from lightrag.llm import azure_openai_complete_if_cache, azure_openai_embedding
10
 
11
  from lightrag.utils import EmbeddingFunc
12
+ from typing import Optional, List, Union
13
  from enum import Enum
14
  from pathlib import Path
15
  import shutil
 
22
  from fastapi.middleware.cors import CORSMiddleware
23
 
24
  from starlette.status import HTTP_403_FORBIDDEN
25
+ import pipmaster as pm
26
 
27
 
28
  def get_default_host(binding_type: str) -> str:
 
175
  class DocumentManager:
176
  """Handles document operations and tracking"""
177
 
178
+ def __init__(
179
+ self,
180
+ input_dir: str,
181
+ supported_extensions: tuple = (".txt", ".md", ".pdf", ".docx", ".pptx"),
182
+ ):
183
  self.input_dir = Path(input_dir)
184
  self.supported_extensions = supported_extensions
185
  self.indexed_files = set()
 
294
  + "(With authentication)"
295
  if api_key
296
  else "",
297
+ version="1.0.2",
298
  openapi_tags=[{"name": "api"}],
299
  )
300
 
 
361
  ),
362
  )
363
 
364
+ async def index_file(file_path: Union[str, Path]) -> None:
365
+ """Index all files inside the folder with support for multiple file formats
366
+
367
+ Args:
368
+ file_path: Path to the file to be indexed (str or Path object)
369
+
370
+ Raises:
371
+ ValueError: If file format is not supported
372
+ FileNotFoundError: If file doesn't exist
373
+ """
374
+ if not pm.is_installed("aiofiles"):
375
+ pm.install("aiofiles")
376
+
377
+ # Convert to Path object if string
378
+ file_path = Path(file_path)
379
+
380
+ # Check if file exists
381
+ if not file_path.exists():
382
+ raise FileNotFoundError(f"File not found: {file_path}")
383
+
384
+ content = ""
385
+ # Get file extension in lowercase
386
+ ext = file_path.suffix.lower()
387
+
388
+ match ext:
389
+ case ".txt" | ".md":
390
+ # Text files handling
391
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as f:
392
+ content = await f.read()
393
+
394
+ case ".pdf":
395
+ if not pm.is_installed("pypdf2"):
396
+ pm.install("pypdf2")
397
+ from pypdf2 import PdfReader
398
+
399
+ # PDF handling
400
+ reader = PdfReader(str(file_path))
401
+ content = ""
402
+ for page in reader.pages:
403
+ content += page.extract_text() + "\n"
404
+
405
+ case ".docx":
406
+ if not pm.is_installed("docx"):
407
+ pm.install("docx")
408
+ from docx import Document
409
+
410
+ # Word document handling
411
+ doc = Document(file_path)
412
+ content = "\n".join([paragraph.text for paragraph in doc.paragraphs])
413
+
414
+ case ".pptx":
415
+ if not pm.is_installed("pptx"):
416
+ pm.install("pptx")
417
+ from pptx import Presentation
418
+
419
+ # PowerPoint handling
420
+ prs = Presentation(file_path)
421
+ content = ""
422
+ for slide in prs.slides:
423
+ for shape in slide.shapes:
424
+ if hasattr(shape, "text"):
425
+ content += shape.text + "\n"
426
+
427
+ case _:
428
+ raise ValueError(f"Unsupported file format: {ext}")
429
+
430
+ # Insert content into RAG system
431
+ if content:
432
+ await rag.ainsert(content)
433
+ doc_manager.mark_as_indexed(file_path)
434
+ logging.info(f"Successfully indexed file: {file_path}")
435
+ else:
436
+ logging.warning(f"No content extracted from file: {file_path}")
437
+
438
  @app.on_event("startup")
439
  async def startup_event():
440
  """Index all files in input directory during startup"""
 
442
  new_files = doc_manager.scan_directory()
443
  for file_path in new_files:
444
  try:
445
+ await index_file(file_path)
 
 
 
 
 
 
446
  except Exception as e:
447
  trace_exception(e)
448
  logging.error(f"Error indexing file {file_path}: {str(e)}")
 
461
 
462
  for file_path in new_files:
463
  try:
464
+ await index_file(file_path)
465
+ indexed_count += 1
 
 
 
466
  except Exception as e:
467
  logging.error(f"Error indexing file {file_path}: {str(e)}")
468
 
 
489
  shutil.copyfileobj(file.file, buffer)
490
 
491
  # Immediately index the uploaded file
492
+ await index_file(file_path)
 
 
 
493
 
494
  return {
495
  "status": "success",
 
550
  )
551
  async def insert_text(request: InsertTextRequest):
552
  try:
553
+ await rag.ainsert(request.text)
554
  return InsertResponse(
555
  status="success",
556
  message="Text successfully inserted",
557
+ document_count=1,
558
  )
559
  except Exception as e:
560
  raise HTTPException(status_code=500, detail=str(e))
 
565
  dependencies=[Depends(optional_api_key)],
566
  )
567
  async def insert_file(file: UploadFile = File(...), description: str = Form(None)):
568
+ """Insert a file directly into the RAG system
569
+
570
+ Args:
571
+ file: Uploaded file
572
+ description: Optional description of the file
573
+
574
+ Returns:
575
+ InsertResponse: Status of the insertion operation
576
+
577
+ Raises:
578
+ HTTPException: For unsupported file types or processing errors
579
+ """
580
  try:
581
+ content = ""
582
+ # Get file extension in lowercase
583
+ ext = Path(file.filename).suffix.lower()
584
+
585
+ match ext:
586
+ case ".txt" | ".md":
587
+ # Text files handling
588
+ text_content = await file.read()
589
+ content = text_content.decode("utf-8")
590
+
591
+ case ".pdf":
592
+ if not pm.is_installed("pypdf2"):
593
+ pm.install("pypdf2")
594
+ from pypdf2 import PdfReader
595
+ from io import BytesIO
596
+
597
+ # Read PDF from memory
598
+ pdf_content = await file.read()
599
+ pdf_file = BytesIO(pdf_content)
600
+ reader = PdfReader(pdf_file)
601
+ content = ""
602
+ for page in reader.pages:
603
+ content += page.extract_text() + "\n"
604
+
605
+ case ".docx":
606
+ if not pm.is_installed("docx"):
607
+ pm.install("docx")
608
+ from docx import Document
609
+ from io import BytesIO
610
+
611
+ # Read DOCX from memory
612
+ docx_content = await file.read()
613
+ docx_file = BytesIO(docx_content)
614
+ doc = Document(docx_file)
615
+ content = "\n".join(
616
+ [paragraph.text for paragraph in doc.paragraphs]
617
+ )
618
+
619
+ case ".pptx":
620
+ if not pm.is_installed("pptx"):
621
+ pm.install("pptx")
622
+ from pptx import Presentation
623
+ from io import BytesIO
624
+
625
+ # Read PPTX from memory
626
+ pptx_content = await file.read()
627
+ pptx_file = BytesIO(pptx_content)
628
+ prs = Presentation(pptx_file)
629
+ content = ""
630
+ for slide in prs.slides:
631
+ for shape in slide.shapes:
632
+ if hasattr(shape, "text"):
633
+ content += shape.text + "\n"
634
+
635
+ case _:
636
+ raise HTTPException(
637
+ status_code=400,
638
+ detail=f"Unsupported file type. Supported types: {doc_manager.supported_extensions}",
639
+ )
640
+
641
+ # Insert content into RAG system
642
+ if content:
643
+ # Add description if provided
644
+ if description:
645
+ content = f"{description}\n\n{content}"
646
+
647
+ await rag.ainsert(content)
648
+ logging.info(f"Successfully indexed file: {file.filename}")
649
 
650
+ return InsertResponse(
651
+ status="success",
652
+ message=f"File '{file.filename}' successfully inserted",
653
+ document_count=1,
654
+ )
655
  else:
656
  raise HTTPException(
657
  status_code=400,
658
+ detail="No content could be extracted from the file",
659
  )
660
 
 
 
 
 
 
661
  except UnicodeDecodeError:
662
  raise HTTPException(status_code=400, detail="File encoding not supported")
663
  except Exception as e:
664
+ logging.error(f"Error processing file {file.filename}: {str(e)}")
665
  raise HTTPException(status_code=500, detail=str(e))
666
 
667
  @app.post(
 
670
  dependencies=[Depends(optional_api_key)],
671
  )
672
  async def insert_batch(files: List[UploadFile] = File(...)):
673
+ """Process multiple files in batch mode
674
+
675
+ Args:
676
+ files: List of files to process
677
+
678
+ Returns:
679
+ InsertResponse: Status of the batch insertion operation
680
+
681
+ Raises:
682
+ HTTPException: For processing errors
683
+ """
684
  try:
685
  inserted_count = 0
686
  failed_files = []
687
 
688
  for file in files:
689
  try:
690
+ content = ""
691
+ ext = Path(file.filename).suffix.lower()
692
+
693
+ match ext:
694
+ case ".txt" | ".md":
695
+ text_content = await file.read()
696
+ content = text_content.decode("utf-8")
697
+
698
+ case ".pdf":
699
+ if not pm.is_installed("pypdf2"):
700
+ pm.install("pypdf2")
701
+ from pypdf2 import PdfReader
702
+ from io import BytesIO
703
+
704
+ pdf_content = await file.read()
705
+ pdf_file = BytesIO(pdf_content)
706
+ reader = PdfReader(pdf_file)
707
+ for page in reader.pages:
708
+ content += page.extract_text() + "\n"
709
+
710
+ case ".docx":
711
+ if not pm.is_installed("docx"):
712
+ pm.install("docx")
713
+ from docx import Document
714
+ from io import BytesIO
715
+
716
+ docx_content = await file.read()
717
+ docx_file = BytesIO(docx_content)
718
+ doc = Document(docx_file)
719
+ content = "\n".join(
720
+ [paragraph.text for paragraph in doc.paragraphs]
721
+ )
722
+
723
+ case ".pptx":
724
+ if not pm.is_installed("pptx"):
725
+ pm.install("pptx")
726
+ from pptx import Presentation
727
+ from io import BytesIO
728
+
729
+ pptx_content = await file.read()
730
+ pptx_file = BytesIO(pptx_content)
731
+ prs = Presentation(pptx_file)
732
+ for slide in prs.slides:
733
+ for shape in slide.shapes:
734
+ if hasattr(shape, "text"):
735
+ content += shape.text + "\n"
736
+
737
+ case _:
738
+ failed_files.append(f"{file.filename} (unsupported type)")
739
+ continue
740
+
741
+ if content:
742
+ await rag.ainsert(content)
743
  inserted_count += 1
744
+ logging.info(f"Successfully indexed file: {file.filename}")
745
  else:
746
+ failed_files.append(f"{file.filename} (no content extracted)")
747
+
748
+ except UnicodeDecodeError:
749
+ failed_files.append(f"{file.filename} (encoding error)")
750
  except Exception as e:
751
  failed_files.append(f"{file.filename} ({str(e)})")
752
+ logging.error(f"Error processing file {file.filename}: {str(e)}")
753
+
754
+ # Prepare status message
755
+ if inserted_count == len(files):
756
+ status = "success"
757
+ status_message = f"Successfully inserted all {inserted_count} documents"
758
+ elif inserted_count > 0:
759
+ status = "partial_success"
760
+ status_message = f"Successfully inserted {inserted_count} out of {len(files)} documents"
761
+ if failed_files:
762
+ status_message += f". Failed files: {', '.join(failed_files)}"
763
+ else:
764
+ status = "failure"
765
+ status_message = "No documents were successfully inserted"
766
+ if failed_files:
767
+ status_message += f". Failed files: {', '.join(failed_files)}"
768
 
769
  return InsertResponse(
770
+ status=status,
771
  message=status_message,
772
+ document_count=inserted_count,
773
  )
774
+
775
  except Exception as e:
776
+ logging.error(f"Batch processing error: {str(e)}")
777
  raise HTTPException(status_code=500, detail=str(e))
778
 
779
  @app.delete(
lightrag/api/requirements.txt CHANGED
@@ -7,6 +7,7 @@ nest_asyncio
7
  numpy
8
  ollama
9
  openai
 
10
  python-dotenv
11
  python-multipart
12
  tenacity
 
7
  numpy
8
  ollama
9
  openai
10
+ pipmaster
11
  python-dotenv
12
  python-multipart
13
  tenacity
lightrag/kg/mongo_impl.py CHANGED
@@ -2,7 +2,7 @@ import os
2
  from tqdm.asyncio import tqdm as tqdm_async
3
  from dataclasses import dataclass
4
  from pymongo import MongoClient
5
-
6
  from lightrag.utils import logger
7
 
8
  from lightrag.base import BaseKVStorage
@@ -41,11 +41,35 @@ class MongoKVStorage(BaseKVStorage):
41
  return set([s for s in data if s not in existing_ids])
42
 
43
  async def upsert(self, data: dict[str, dict]):
44
- for k, v in tqdm_async(data.items(), desc="Upserting"):
45
- self._data.update_one({"_id": k}, {"$set": v}, upsert=True)
46
- data[k]["_id"] = k
 
 
 
 
 
 
 
 
 
 
 
47
  return data
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  async def drop(self):
50
  """ """
51
  pass
 
2
  from tqdm.asyncio import tqdm as tqdm_async
3
  from dataclasses import dataclass
4
  from pymongo import MongoClient
5
+ from typing import Union
6
  from lightrag.utils import logger
7
 
8
  from lightrag.base import BaseKVStorage
 
41
  return set([s for s in data if s not in existing_ids])
42
 
43
  async def upsert(self, data: dict[str, dict]):
44
+ if self.namespace == "llm_response_cache":
45
+ for mode, items in data.items():
46
+ for k, v in tqdm_async(items.items(), desc="Upserting"):
47
+ key = f"{mode}_{k}"
48
+ result = self._data.update_one(
49
+ {"_id": key}, {"$setOnInsert": v}, upsert=True
50
+ )
51
+ if result.upserted_id:
52
+ logger.debug(f"\nInserted new document with key: {key}")
53
+ data[mode][k]["_id"] = key
54
+ else:
55
+ for k, v in tqdm_async(data.items(), desc="Upserting"):
56
+ self._data.update_one({"_id": k}, {"$set": v}, upsert=True)
57
+ data[k]["_id"] = k
58
  return data
59
 
60
+ async def get_by_mode_and_id(self, mode: str, id: str) -> Union[dict, None]:
61
+ if "llm_response_cache" == self.namespace:
62
+ res = {}
63
+ v = self._data.find_one({"_id": mode + "_" + id})
64
+ if v:
65
+ res[id] = v
66
+ logger.debug(f"llm_response_cache find one by:{id}")
67
+ return res
68
+ else:
69
+ return None
70
+ else:
71
+ return None
72
+
73
  async def drop(self):
74
  """ """
75
  pass
lightrag/kg/neo4j_impl.py CHANGED
@@ -39,6 +39,7 @@ class Neo4JStorage(BaseGraphStorage):
39
  URI = os.environ["NEO4J_URI"]
40
  USERNAME = os.environ["NEO4J_USERNAME"]
41
  PASSWORD = os.environ["NEO4J_PASSWORD"]
 
42
  DATABASE = os.environ.get(
43
  "NEO4J_DATABASE"
44
  ) # If this param is None, the home database will be used. If it is not None, the specified database will be used.
@@ -47,7 +48,11 @@ class Neo4JStorage(BaseGraphStorage):
47
  URI, auth=(USERNAME, PASSWORD)
48
  )
49
  _database_name = "home database" if DATABASE is None else f"database {DATABASE}"
50
- with GraphDatabase.driver(URI, auth=(USERNAME, PASSWORD)) as _sync_driver:
 
 
 
 
51
  try:
52
  with _sync_driver.session(database=DATABASE) as session:
53
  try:
 
39
  URI = os.environ["NEO4J_URI"]
40
  USERNAME = os.environ["NEO4J_USERNAME"]
41
  PASSWORD = os.environ["NEO4J_PASSWORD"]
42
+ MAX_CONNECTION_POOL_SIZE = os.environ.get("NEO4J_MAX_CONNECTION_POOL_SIZE", 800)
43
  DATABASE = os.environ.get(
44
  "NEO4J_DATABASE"
45
  ) # If this param is None, the home database will be used. If it is not None, the specified database will be used.
 
48
  URI, auth=(USERNAME, PASSWORD)
49
  )
50
  _database_name = "home database" if DATABASE is None else f"database {DATABASE}"
51
+ with GraphDatabase.driver(
52
+ URI,
53
+ auth=(USERNAME, PASSWORD),
54
+ max_connection_pool_size=MAX_CONNECTION_POOL_SIZE,
55
+ ) as _sync_driver:
56
  try:
57
  with _sync_driver.session(database=DATABASE) as session:
58
  try: