zrguo commited on
Commit
0a5a0dc
·
unverified ·
2 Parent(s): 82dbd17 87708b2

Merge pull request #785 from danielaskdd/improve-CORS-handling

Browse files
.env.example CHANGED
@@ -1,19 +1,20 @@
1
  ### Server Configuration
2
- #HOST=0.0.0.0
3
- #PORT=9621
4
- #NAMESPACE_PREFIX=lightrag # separating data from difference Lightrag instances
 
5
 
6
  ### Optional SSL Configuration
7
- #SSL=true
8
- #SSL_CERTFILE=/path/to/cert.pem
9
- #SSL_KEYFILE=/path/to/key.pem
10
 
11
  ### Security (empty for no api-key is needed)
12
  # LIGHTRAG_API_KEY=your-secure-api-key-here
13
 
14
  ### Directory Configuration
15
- # WORKING_DIR=./rag_storage
16
- # INPUT_DIR=./inputs
17
 
18
  ### Logging level
19
  LOG_LEVEL=INFO
 
1
  ### Server Configuration
2
+ # HOST=0.0.0.0
3
+ # PORT=9621
4
+ # NAMESPACE_PREFIX=lightrag # separating data from difference Lightrag instances
5
+ # CORS_ORIGINS=http://localhost:3000,http://localhost:8080
6
 
7
  ### Optional SSL Configuration
8
+ # SSL=true
9
+ # SSL_CERTFILE=/path/to/cert.pem
10
+ # SSL_KEYFILE=/path/to/key.pem
11
 
12
  ### Security (empty for no api-key is needed)
13
  # LIGHTRAG_API_KEY=your-secure-api-key-here
14
 
15
  ### Directory Configuration
16
+ # WORKING_DIR=<absolute_path_for_working_dir>
17
+ # INPUT_DIR=<absolute_path_for_doc_input_dir>
18
 
19
  ### Logging level
20
  LOG_LEVEL=INFO
lightrag/api/README.md CHANGED
@@ -74,30 +74,38 @@ LLM_MODEL=model_name_of_azure_ai
74
  LLM_BINDING_API_KEY=api_key_of_azure_ai
75
  ```
76
 
77
- ### About Ollama API
78
 
79
- We provide an Ollama-compatible interfaces for LightRAG, aiming to emulate LightRAG as an Ollama chat model. This allows AI chat frontends supporting Ollama, such as Open WebUI, to access LightRAG easily.
80
 
81
- #### Choose Query mode in chat
 
 
 
 
82
 
83
- A query prefix in the query string can determines which LightRAG query mode is used to generate the respond for the query. The supported prefixes include:
84
 
85
- ```
86
- /local
87
- /global
88
- /hybrid
89
- /naive
90
- /mix
91
- /bypass
92
  ```
93
 
94
- For example, chat message "/mix 唐僧有几个徒弟" will trigger a mix mode query for LighRAG. A chat message without query prefix will trigger a hybrid mode query by default。
95
 
96
- "/bypass" is not a LightRAG query mode, it will tell API Server to pass the query directly to the underlying LLM with chat history. So user can use LLM to answer question base on the LightRAG query results. (If you are using Open WebUI as front end, you can just switch the model to a normal LLM instead of using /bypass prefix)
 
 
 
 
 
 
97
 
98
- #### Connect Open WebUI to LightRAG
99
 
100
- After starting the lightrag-server, you can add an Ollama-type connection in the Open WebUI admin pannel. And then a model named lightrag:latest will appear in Open WebUI's model management interface. Users can then send queries to LightRAG through the chat interface.
101
 
102
  ## Configuration
103
 
@@ -379,7 +387,7 @@ curl -X DELETE "http://localhost:9621/documents"
379
 
380
  #### GET /api/version
381
 
382
- Get Ollama version information
383
 
384
  ```bash
385
  curl http://localhost:9621/api/version
@@ -387,7 +395,7 @@ curl http://localhost:9621/api/version
387
 
388
  #### GET /api/tags
389
 
390
- Get Ollama available models
391
 
392
  ```bash
393
  curl http://localhost:9621/api/tags
@@ -395,7 +403,7 @@ curl http://localhost:9621/api/tags
395
 
396
  #### POST /api/chat
397
 
398
- Handle chat completion requests
399
 
400
  ```shell
401
  curl -N -X POST http://localhost:9621/api/chat -H "Content-Type: application/json" -d \
@@ -404,6 +412,10 @@ curl -N -X POST http://localhost:9621/api/chat -H "Content-Type: application/jso
404
 
405
  > For more information about Ollama API pls. visit : [Ollama API documentation](https://github.com/ollama/ollama/blob/main/docs/api.md)
406
 
 
 
 
 
407
  ### Utility Endpoints
408
 
409
  #### GET /health
@@ -413,7 +425,35 @@ Check server health and configuration.
413
  curl "http://localhost:9621/health"
414
  ```
415
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
  ## Development
 
417
  Contribute to the project: [Guide](contributor-readme.MD)
418
 
419
  ### Running in Development Mode
@@ -471,34 +511,3 @@ This intelligent caching mechanism:
471
  - Only new documents in the input directory will be processed
472
  - This optimization significantly reduces startup time for subsequent runs
473
  - The working directory (`--working-dir`) stores the vectorized documents database
474
-
475
- ## Install Lightrag as a Linux Service
476
-
477
- Create a your service file `lightrag.sevice` from the sample file : `lightrag.sevice.example`. Modified the WorkingDirectoryand EexecStart in the service file:
478
-
479
- ```text
480
- Description=LightRAG Ollama Service
481
- WorkingDirectory=<lightrag installed directory>
482
- ExecStart=<lightrag installed directory>/lightrag/api/lightrag-api
483
- ```
484
-
485
- Modify your service startup script: `lightrag-api`. Change you python virtual environment activation command as needed:
486
-
487
- ```shell
488
- #!/bin/bash
489
-
490
- # your python virtual environment activation
491
- source /home/netman/lightrag-xyj/venv/bin/activate
492
- # start lightrag api server
493
- lightrag-server
494
- ```
495
-
496
- Install LightRAG service. If your system is Ubuntu, the following commands will work:
497
-
498
- ```shell
499
- sudo cp lightrag.service /etc/systemd/system/
500
- sudo systemctl daemon-reload
501
- sudo systemctl start lightrag.service
502
- sudo systemctl status lightrag.service
503
- sudo systemctl enable lightrag.service
504
- ```
 
74
  LLM_BINDING_API_KEY=api_key_of_azure_ai
75
  ```
76
 
77
+ ### 3. Install Lightrag as a Linux Service
78
 
79
+ Create a your service file `lightrag.sevice` from the sample file : `lightrag.sevice.example`. Modified the WorkingDirectoryand EexecStart in the service file:
80
 
81
+ ```text
82
+ Description=LightRAG Ollama Service
83
+ WorkingDirectory=<lightrag installed directory>
84
+ ExecStart=<lightrag installed directory>/lightrag/api/lightrag-api
85
+ ```
86
 
87
+ Modify your service startup script: `lightrag-api`. Change you python virtual environment activation command as needed:
88
 
89
+ ```shell
90
+ #!/bin/bash
91
+
92
+ # your python virtual environment activation
93
+ source /home/netman/lightrag-xyj/venv/bin/activate
94
+ # start lightrag api server
95
+ lightrag-server
96
  ```
97
 
98
+ Install LightRAG service. If your system is Ubuntu, the following commands will work:
99
 
100
+ ```shell
101
+ sudo cp lightrag.service /etc/systemd/system/
102
+ sudo systemctl daemon-reload
103
+ sudo systemctl start lightrag.service
104
+ sudo systemctl status lightrag.service
105
+ sudo systemctl enable lightrag.service
106
+ ```
107
 
 
108
 
 
109
 
110
  ## Configuration
111
 
 
387
 
388
  #### GET /api/version
389
 
390
+ Get Ollama version information.
391
 
392
  ```bash
393
  curl http://localhost:9621/api/version
 
395
 
396
  #### GET /api/tags
397
 
398
+ Get Ollama available models.
399
 
400
  ```bash
401
  curl http://localhost:9621/api/tags
 
403
 
404
  #### POST /api/chat
405
 
406
+ Handle chat completion requests. Routes user queries through LightRAG by selecting query mode based on query prefix. Detects and forwards OpenWebUI session-related requests (for meta data generation task) directly to underlying LLM.
407
 
408
  ```shell
409
  curl -N -X POST http://localhost:9621/api/chat -H "Content-Type: application/json" -d \
 
412
 
413
  > For more information about Ollama API pls. visit : [Ollama API documentation](https://github.com/ollama/ollama/blob/main/docs/api.md)
414
 
415
+ #### POST /api/generate
416
+
417
+ Handle generate completion requests. For compatibility purpose, the request is not processed by LightRAG, and will be handled by underlying LLM model.
418
+
419
  ### Utility Endpoints
420
 
421
  #### GET /health
 
425
  curl "http://localhost:9621/health"
426
  ```
427
 
428
+ ## Ollama Emulation
429
+
430
+ We provide an Ollama-compatible interfaces for LightRAG, aiming to emulate LightRAG as an Ollama chat model. This allows AI chat frontends supporting Ollama, such as Open WebUI, to access LightRAG easily.
431
+
432
+ ### Connect Open WebUI to LightRAG
433
+
434
+ After starting the lightrag-server, you can add an Ollama-type connection in the Open WebUI admin pannel. And then a model named lightrag:latest will appear in Open WebUI's model management interface. Users can then send queries to LightRAG through the chat interface. You'd better install LightRAG as service for this use case.
435
+
436
+ Open WebUI's use LLM to do the session title and session keyword generation task. So the Ollama chat chat completion API detects and forwards OpenWebUI session-related requests directly to underlying LLM.
437
+
438
+ ### Choose Query mode in chat
439
+
440
+ A query prefix in the query string can determines which LightRAG query mode is used to generate the respond for the query. The supported prefixes include:
441
+
442
+ ```
443
+ /local
444
+ /global
445
+ /hybrid
446
+ /naive
447
+ /mix
448
+ /bypass
449
+ ```
450
+
451
+ For example, chat message "/mix 唐僧有几个徒弟" will trigger a mix mode query for LighRAG. A chat message without query prefix will trigger a hybrid mode query by default。
452
+
453
+ "/bypass" is not a LightRAG query mode, it will tell API Server to pass the query directly to the underlying LLM with chat history. So user can use LLM to answer question base on the chat history. If you are using Open WebUI as front end, you can just switch the model to a normal LLM instead of using /bypass prefix.
454
+
455
  ## Development
456
+
457
  Contribute to the project: [Guide](contributor-readme.MD)
458
 
459
  ### Running in Development Mode
 
511
  - Only new documents in the input directory will be processed
512
  - This optimization significantly reduces startup time for subsequent runs
513
  - The working directory (`--working-dir`) stores the vectorized documents database
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lightrag/api/lightrag_server.py CHANGED
@@ -159,8 +159,12 @@ def display_splash_screen(args: argparse.Namespace) -> None:
159
  ASCIIColors.yellow(f"{args.host}")
160
  ASCIIColors.white(" ├─ Port: ", end="")
161
  ASCIIColors.yellow(f"{args.port}")
162
- ASCIIColors.white(" └─ SSL Enabled: ", end="")
 
 
163
  ASCIIColors.yellow(f"{args.ssl}")
 
 
164
  if args.ssl:
165
  ASCIIColors.white(" ├─ SSL Cert: ", end="")
166
  ASCIIColors.yellow(f"{args.ssl_certfile}")
@@ -229,10 +233,8 @@ def display_splash_screen(args: argparse.Namespace) -> None:
229
  ASCIIColors.yellow(f"{ollama_server_infos.LIGHTRAG_MODEL}")
230
  ASCIIColors.white(" ├─ Log Level: ", end="")
231
  ASCIIColors.yellow(f"{args.log_level}")
232
- ASCIIColors.white(" ├─ Timeout: ", end="")
233
  ASCIIColors.yellow(f"{args.timeout if args.timeout else 'None (infinite)'}")
234
- ASCIIColors.white(" └─ API Key: ", end="")
235
- ASCIIColors.yellow("Set" if args.key else "Not Set")
236
 
237
  # Server Status
238
  ASCIIColors.green("\n✨ Server starting up...\n")
@@ -564,6 +566,10 @@ def parse_args() -> argparse.Namespace:
564
 
565
  args = parser.parse_args()
566
 
 
 
 
 
567
  ollama_server_infos.LIGHTRAG_MODEL = args.simulated_model_name
568
 
569
  return args
@@ -595,6 +601,7 @@ class DocumentManager:
595
  """Scan input directory for new files"""
596
  new_files = []
597
  for ext in self.supported_extensions:
 
598
  for file_path in self.input_dir.rglob(f"*{ext}"):
599
  if file_path not in self.indexed_files:
600
  new_files.append(file_path)
@@ -842,10 +849,19 @@ def create_app(args):
842
  lifespan=lifespan,
843
  )
844
 
 
 
 
 
 
 
 
 
 
845
  # Add CORS middleware
846
  app.add_middleware(
847
  CORSMiddleware,
848
- allow_origins=["*"],
849
  allow_credentials=True,
850
  allow_methods=["*"],
851
  allow_headers=["*"],
@@ -1198,6 +1214,7 @@ def create_app(args):
1198
  new_files = doc_manager.scan_directory_for_new_files()
1199
  scan_progress["total_files"] = len(new_files)
1200
 
 
1201
  for file_path in new_files:
1202
  try:
1203
  with progress_lock:
@@ -1371,10 +1388,7 @@ def create_app(args):
1371
  "Cache-Control": "no-cache",
1372
  "Connection": "keep-alive",
1373
  "Content-Type": "application/x-ndjson",
1374
- "Access-Control-Allow-Origin": "*",
1375
- "Access-Control-Allow-Methods": "POST, OPTIONS",
1376
- "Access-Control-Allow-Headers": "Content-Type",
1377
- "X-Accel-Buffering": "no", # Disable Nginx buffering
1378
  },
1379
  )
1380
  except Exception as e:
 
159
  ASCIIColors.yellow(f"{args.host}")
160
  ASCIIColors.white(" ├─ Port: ", end="")
161
  ASCIIColors.yellow(f"{args.port}")
162
+ ASCIIColors.white(" ├─ CORS Origins: ", end="")
163
+ ASCIIColors.yellow(f"{os.getenv('CORS_ORIGINS', '*')}")
164
+ ASCIIColors.white(" ├─ SSL Enabled: ", end="")
165
  ASCIIColors.yellow(f"{args.ssl}")
166
+ ASCIIColors.white(" └─ API Key: ", end="")
167
+ ASCIIColors.yellow("Set" if args.key else "Not Set")
168
  if args.ssl:
169
  ASCIIColors.white(" ├─ SSL Cert: ", end="")
170
  ASCIIColors.yellow(f"{args.ssl_certfile}")
 
233
  ASCIIColors.yellow(f"{ollama_server_infos.LIGHTRAG_MODEL}")
234
  ASCIIColors.white(" ├─ Log Level: ", end="")
235
  ASCIIColors.yellow(f"{args.log_level}")
236
+ ASCIIColors.white(" └─ Timeout: ", end="")
237
  ASCIIColors.yellow(f"{args.timeout if args.timeout else 'None (infinite)'}")
 
 
238
 
239
  # Server Status
240
  ASCIIColors.green("\n✨ Server starting up...\n")
 
566
 
567
  args = parser.parse_args()
568
 
569
+ # conver relative path to absolute path
570
+ args.working_dir = os.path.abspath(args.working_dir)
571
+ args.input_dir = os.path.abspath(args.input_dir)
572
+
573
  ollama_server_infos.LIGHTRAG_MODEL = args.simulated_model_name
574
 
575
  return args
 
601
  """Scan input directory for new files"""
602
  new_files = []
603
  for ext in self.supported_extensions:
604
+ logger.info(f"Scanning for {ext} files in {self.input_dir}")
605
  for file_path in self.input_dir.rglob(f"*{ext}"):
606
  if file_path not in self.indexed_files:
607
  new_files.append(file_path)
 
849
  lifespan=lifespan,
850
  )
851
 
852
+ def get_cors_origins():
853
+ """Get allowed origins from environment variable
854
+ Returns a list of allowed origins, defaults to ["*"] if not set
855
+ """
856
+ origins_str = os.getenv("CORS_ORIGINS", "*")
857
+ if origins_str == "*":
858
+ return ["*"]
859
+ return [origin.strip() for origin in origins_str.split(",")]
860
+
861
  # Add CORS middleware
862
  app.add_middleware(
863
  CORSMiddleware,
864
+ allow_origins=get_cors_origins(),
865
  allow_credentials=True,
866
  allow_methods=["*"],
867
  allow_headers=["*"],
 
1214
  new_files = doc_manager.scan_directory_for_new_files()
1215
  scan_progress["total_files"] = len(new_files)
1216
 
1217
+ logger.info(f"Found {len(new_files)} new files to index.")
1218
  for file_path in new_files:
1219
  try:
1220
  with progress_lock:
 
1388
  "Cache-Control": "no-cache",
1389
  "Connection": "keep-alive",
1390
  "Content-Type": "application/x-ndjson",
1391
+ "X-Accel-Buffering": "no", # 确保在Nginx代理时正确处理流式响应
 
 
 
1392
  },
1393
  )
1394
  except Exception as e:
lightrag/api/ollama_api.py CHANGED
@@ -316,9 +316,7 @@ class OllamaAPI:
316
  "Cache-Control": "no-cache",
317
  "Connection": "keep-alive",
318
  "Content-Type": "application/x-ndjson",
319
- "Access-Control-Allow-Origin": "*",
320
- "Access-Control-Allow-Methods": "POST, OPTIONS",
321
- "Access-Control-Allow-Headers": "Content-Type",
322
  },
323
  )
324
  else:
@@ -534,9 +532,7 @@ class OllamaAPI:
534
  "Cache-Control": "no-cache",
535
  "Connection": "keep-alive",
536
  "Content-Type": "application/x-ndjson",
537
- "Access-Control-Allow-Origin": "*",
538
- "Access-Control-Allow-Methods": "POST, OPTIONS",
539
- "Access-Control-Allow-Headers": "Content-Type",
540
  },
541
  )
542
  else:
 
316
  "Cache-Control": "no-cache",
317
  "Connection": "keep-alive",
318
  "Content-Type": "application/x-ndjson",
319
+ "X-Accel-Buffering": "no", # 确保在Nginx代理时正确处理流式响应
 
 
320
  },
321
  )
322
  else:
 
532
  "Cache-Control": "no-cache",
533
  "Connection": "keep-alive",
534
  "Content-Type": "application/x-ndjson",
535
+ "X-Accel-Buffering": "no", # 确保在Nginx代理时正确处理流式响应
 
 
536
  },
537
  )
538
  else:
lightrag/kg/faiss_impl.py CHANGED
@@ -27,8 +27,8 @@ class FaissVectorDBStorage(BaseVectorStorage):
27
 
28
  def __post_init__(self):
29
  # Grab config values if available
30
- config = self.global_config.get("vector_db_storage_cls_kwargs", {})
31
- cosine_threshold = config.get("cosine_better_than_threshold")
32
  if cosine_threshold is None:
33
  raise ValueError(
34
  "cosine_better_than_threshold must be specified in vector_db_storage_cls_kwargs"
 
27
 
28
  def __post_init__(self):
29
  # Grab config values if available
30
+ kwargs = self.global_config.get("vector_db_storage_cls_kwargs", {})
31
+ cosine_threshold = kwargs.get("cosine_better_than_threshold")
32
  if cosine_threshold is None:
33
  raise ValueError(
34
  "cosine_better_than_threshold must be specified in vector_db_storage_cls_kwargs"
lightrag/kg/nano_vector_db_impl.py CHANGED
@@ -79,8 +79,8 @@ class NanoVectorDBStorage(BaseVectorStorage):
79
  # Initialize lock only for file operations
80
  self._save_lock = asyncio.Lock()
81
  # Use global config value if specified, otherwise use default
82
- config = self.global_config.get("vector_db_storage_cls_kwargs", {})
83
- cosine_threshold = config.get("cosine_better_than_threshold")
84
  if cosine_threshold is None:
85
  raise ValueError(
86
  "cosine_better_than_threshold must be specified in vector_db_storage_cls_kwargs"
 
79
  # Initialize lock only for file operations
80
  self._save_lock = asyncio.Lock()
81
  # Use global config value if specified, otherwise use default
82
+ kwargs = self.global_config.get("vector_db_storage_cls_kwargs", {})
83
+ cosine_threshold = kwargs.get("cosine_better_than_threshold")
84
  if cosine_threshold is None:
85
  raise ValueError(
86
  "cosine_better_than_threshold must be specified in vector_db_storage_cls_kwargs"