NitinBot001 commited on
Commit
e49ea62
·
verified ·
1 Parent(s): 8a3e525

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -59
app.py CHANGED
@@ -55,13 +55,13 @@ is_initialized = False
55
 
56
  # Configuration
57
  class Config:
58
- # OpenAI Compatible API Configuration
59
- OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
60
- # REMOVED: OPENAI_BASE_URL = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
61
 
62
- # ADDED: Separate base URLs for LLM and Embeddings
63
- LLM_BASE_URL = os.getenv("LLM_BASE_URL", "https://api.openai.com/v1")
64
- EMBEDDING_BASE_URL = os.getenv("EMBEDDING_BASE_URL", "https://api.openai.com/v1")
65
 
66
  # Model Configuration
67
  LLM_MODEL = os.getenv("LLM_MODEL", "gpt-3.5-turbo")
@@ -104,18 +104,21 @@ class SystemStatus(BaseModel):
104
  is_initialized: bool
105
  model_name: str
106
  embedding_model: str
107
- # CHANGED: Use separate URLs
108
  llm_base_url: str
109
  embedding_base_url: str
110
  vector_store_ready: bool
111
  total_chunks: int = 0
112
- api_key_configured: bool
 
113
 
114
  class InitializeRequest(BaseModel):
115
- api_key: str = Field(..., min_length=1)
116
- # CHANGED: Accept separate URLs
117
- llm_base_url: Optional[str] = Field(default=None, description="LLM (text generation) API base URL")
118
- embedding_base_url: Optional[str] = Field(default=None, description="Embedding model API base URL")
 
 
 
119
  llm_model: Optional[str] = Field(default=None, description="LLM model name")
120
  embedding_model: Optional[str] = Field(default=None, description="Embedding model name")
121
 
@@ -133,7 +136,7 @@ def estimate_tokens(text: str) -> int:
133
  except:
134
  return len(text.split()) * 1.3 # Rough estimate
135
 
136
- # Rate limiting helper functions (No changes needed here)
137
  async def rate_limited_embedding_creation(chunks, embeddings):
138
  """Create embeddings with rate limiting to avoid API limits."""
139
  logger.info(f"Creating embeddings for {len(chunks)} chunks with rate limiting...")
@@ -196,7 +199,7 @@ async def rate_limited_embedding_creation(chunks, embeddings):
196
  logger.info("Successfully created and merged all embeddings")
197
  return final_vector_store
198
 
199
- # Custom Callback Handler for OpenAI (No changes needed here)
200
  class TokenUsageCallbackHandler(BaseCallbackHandler):
201
  """Callback handler to track token usage in OpenAI calls."""
202
 
@@ -247,29 +250,40 @@ class TokenUsageCallbackHandler(BaseCallbackHandler):
247
  }
248
 
249
  # RAG System Functions
250
- # CHANGED: Function signature to accept separate URLs
251
  async def initialize_rag_system(
252
- api_key: str = None,
 
 
253
  llm_base_url: str = None,
254
  embedding_base_url: str = None,
255
  llm_model: str = None,
256
  embedding_model: str = None
257
  ):
258
- """Initialize or reinitialize the RAG system with OpenAI compatible API."""
259
  global vector_store, qa_chain, token_callback_handler, is_initialized, config
260
 
261
  try:
262
- # Update configuration
263
- if api_key:
264
- config.OPENAI_API_KEY = api_key
265
- elif not config.OPENAI_API_KEY:
266
- raise ValueError("OpenAI API key not provided")
 
 
 
 
 
 
 
 
 
267
 
268
- # CHANGED: Update separate base URLs
269
  if llm_base_url:
270
- config.LLM_BASE_URL = llm_base_url
 
271
  if embedding_base_url:
272
- config.EMBEDDING_BASE_URL = embedding_base_url
273
 
274
  if llm_model:
275
  config.LLM_MODEL = llm_model
@@ -277,10 +291,11 @@ async def initialize_rag_system(
277
  if embedding_model:
278
  config.EMBEDDING_MODEL = embedding_model
279
 
280
- # CHANGED: Update logging
281
  logger.info(f"Initializing RAG system with:")
282
- logger.info(f" - LLM Base URL: {config.LLM_BASE_URL}")
283
- logger.info(f" - Embedding Base URL: {config.EMBEDDING_BASE_URL}")
 
 
284
  logger.info(f" - LLM Model: {config.LLM_MODEL}")
285
  logger.info(f" - Embedding Model: {config.EMBEDDING_MODEL}")
286
 
@@ -302,14 +317,15 @@ async def initialize_rag_system(
302
  chunks = text_splitter.split_documents(documents)
303
  logger.info(f"Document split into {len(chunks)} chunks")
304
 
 
305
  if len(chunks) > 200:
306
  logger.warning(f"Large number of chunks ({len(chunks)}). Consider increasing chunk_size to reduce API calls.")
307
 
308
- # CHANGED: Initialize OpenAI embeddings with its specific base URL
309
  embeddings = OpenAIEmbeddings(
310
  model=config.EMBEDDING_MODEL,
311
- openai_api_key=config.OPENAI_API_KEY,
312
- openai_api_base=config.EMBEDDING_BASE_URL,
313
  chunk_size=1000
314
  )
315
 
@@ -343,11 +359,11 @@ async def initialize_rag_system(
343
  vector_store.save_local(config.INDEX_PATH)
344
  logger.info(f"Created new FAISS index at '{config.INDEX_PATH}'")
345
 
346
- # CHANGED: Initialize OpenAI LLM with its specific base URL
347
  llm = ChatOpenAI(
348
  model_name=config.LLM_MODEL,
349
- openai_api_key=config.OPENAI_API_KEY,
350
- openai_api_base=config.LLM_BASE_URL,
351
  temperature=config.TEMPERATURE,
352
  max_tokens=config.MAX_OUTPUT_TOKENS,
353
  callbacks=[token_callback_handler],
@@ -356,9 +372,6 @@ async def initialize_rag_system(
356
 
357
  # Test LLM connection
358
  try:
359
- # Note: The os.environ is not strictly needed if passing params directly,
360
- # but setting it can be a good practice for other potential library uses.
361
- # We'll rely on direct parameter passing which is cleaner.
362
  test_response = llm.invoke("Test connection")
363
  logger.info("Successfully connected to LLM API")
364
  except Exception as e:
@@ -407,10 +420,9 @@ Answer:"""
407
  # API Endpoints
408
  @app.on_event("startup")
409
  async def startup_event():
410
- """Initialize the system on startup if API key is available."""
411
- if config.OPENAI_API_KEY:
412
  try:
413
- # This will use the URLs from environment variables by default
414
  await initialize_rag_system()
415
  except Exception as e:
416
  logger.warning(f"Could not initialize on startup: {str(e)}")
@@ -445,35 +457,37 @@ async def get_status():
445
  is_initialized=is_initialized,
446
  model_name=config.LLM_MODEL,
447
  embedding_model=config.EMBEDDING_MODEL,
448
- # CHANGED: Return separate URLs
449
- llm_base_url=config.LLM_BASE_URL,
450
- embedding_base_url=config.EMBEDDING_BASE_URL,
451
  vector_store_ready=vector_store is not None,
452
  total_chunks=len(vector_store.docstore._dict) if vector_store else 0,
453
- api_key_configured=bool(config.OPENAI_API_KEY)
 
454
  )
455
 
456
  @app.post("/api/initialize", response_model=Dict[str, Any])
457
  async def initialize_system(request: InitializeRequest):
458
- """Initialize the RAG system with provided API key and configuration."""
459
  try:
460
- # CHANGED: Pass separate URLs to the initialization function
461
  await initialize_rag_system(
 
 
462
  api_key=request.api_key,
463
  llm_base_url=request.llm_base_url,
464
  embedding_base_url=request.embedding_base_url,
465
  llm_model=request.llm_model,
466
  embedding_model=request.embedding_model
467
  )
468
- # CHANGED: Return separate URLs in the response
469
  return {
470
  "success": True,
471
  "message": "System initialized successfully",
472
  "config": {
473
- "llm_base_url": config.LLM_BASE_URL,
474
- "embedding_base_url": config.EMBEDDING_BASE_URL,
475
  "llm_model": config.LLM_MODEL,
476
- "embedding_model": config.EMBEDDING_MODEL
 
 
477
  }
478
  }
479
  except Exception as e:
@@ -485,7 +499,7 @@ async def process_query(request: QueryRequest):
485
  if not is_initialized:
486
  raise HTTPException(
487
  status_code=503,
488
- detail="System not initialized. Please provide API key and configuration."
489
  )
490
 
491
  try:
@@ -539,8 +553,6 @@ async def process_query(request: QueryRequest):
539
  logger.error(f"Error processing query: {str(e)}")
540
  raise HTTPException(status_code=500, detail=str(e))
541
 
542
- # (No changes needed in the remaining endpoints)
543
-
544
  @app.get("/api/token-stats", response_model=Dict[str, Any])
545
  async def get_token_stats():
546
  """Get token usage statistics."""
@@ -568,7 +580,7 @@ async def upload_document(file: UploadFile = File(...)):
568
  logger.info(f"Uploaded new document: {file.filename}")
569
 
570
  # Reinitialize the system with new data
571
- if config.OPENAI_API_KEY:
572
  # Remove old index to force recreation
573
  if os.path.exists(config.INDEX_PATH):
574
  import shutil
@@ -592,22 +604,23 @@ async def health_check():
592
  "status": "healthy",
593
  "timestamp": datetime.now().isoformat(),
594
  "system_initialized": is_initialized,
595
- "api_configured": bool(config.OPENAI_API_KEY)
 
596
  }
597
 
598
  # Configuration endpoint
599
  @app.get("/api/config")
600
  async def get_config():
601
  """Get current configuration."""
602
- # CHANGED: Return separate URLs
603
  return {
604
- "llm_base_url": config.LLM_BASE_URL,
605
- "embedding_base_url": config.EMBEDDING_BASE_URL,
606
  "llm_model": config.LLM_MODEL,
607
  "embedding_model": config.EMBEDDING_MODEL,
608
  "chunk_size": config.CHUNK_SIZE,
609
  "retriever_k": config.RETRIEVER_K,
610
- "api_key_configured": bool(config.OPENAI_API_KEY)
 
611
  }
612
 
613
  # Mount static files
 
55
 
56
  # Configuration
57
  class Config:
58
+ # API Keys - separate for each service
59
+ OPENAI_LLM_API_KEY = os.getenv("OPENAI_LLM_API_KEY", os.getenv("OPENAI_API_KEY", ""))
60
+ OPENAI_EMBEDDING_API_KEY = os.getenv("OPENAI_EMBEDDING_API_KEY", os.getenv("OPENAI_API_KEY", ""))
61
 
62
+ # Base URLs - separate for each service
63
+ OPENAI_LLM_BASE_URL = os.getenv("OPENAI_LLM_BASE_URL", os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"))
64
+ OPENAI_EMBEDDING_BASE_URL = os.getenv("OPENAI_EMBEDDING_BASE_URL", os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"))
65
 
66
  # Model Configuration
67
  LLM_MODEL = os.getenv("LLM_MODEL", "gpt-3.5-turbo")
 
104
  is_initialized: bool
105
  model_name: str
106
  embedding_model: str
 
107
  llm_base_url: str
108
  embedding_base_url: str
109
  vector_store_ready: bool
110
  total_chunks: int = 0
111
+ llm_api_key_configured: bool
112
+ embedding_api_key_configured: bool
113
 
114
  class InitializeRequest(BaseModel):
115
+ llm_api_key: Optional[str] = Field(default=None, description="API key for LLM service")
116
+ embedding_api_key: Optional[str] = Field(default=None, description="API key for embedding service")
117
+ # Backward compatibility - if provided, will be used for both services if individual keys not specified
118
+ api_key: Optional[str] = Field(default=None, description="Fallback API key for both services")
119
+
120
+ llm_base_url: Optional[str] = Field(default=None, description="Base URL for LLM/text generation API")
121
+ embedding_base_url: Optional[str] = Field(default=None, description="Base URL for embedding API")
122
  llm_model: Optional[str] = Field(default=None, description="LLM model name")
123
  embedding_model: Optional[str] = Field(default=None, description="Embedding model name")
124
 
 
136
  except:
137
  return len(text.split()) * 1.3 # Rough estimate
138
 
139
+ # Rate limiting helper functions
140
  async def rate_limited_embedding_creation(chunks, embeddings):
141
  """Create embeddings with rate limiting to avoid API limits."""
142
  logger.info(f"Creating embeddings for {len(chunks)} chunks with rate limiting...")
 
199
  logger.info("Successfully created and merged all embeddings")
200
  return final_vector_store
201
 
202
+ # Custom Callback Handler for OpenAI
203
  class TokenUsageCallbackHandler(BaseCallbackHandler):
204
  """Callback handler to track token usage in OpenAI calls."""
205
 
 
250
  }
251
 
252
  # RAG System Functions
 
253
  async def initialize_rag_system(
254
+ llm_api_key: str = None,
255
+ embedding_api_key: str = None,
256
+ api_key: str = None, # Fallback for backward compatibility
257
  llm_base_url: str = None,
258
  embedding_base_url: str = None,
259
  llm_model: str = None,
260
  embedding_model: str = None
261
  ):
262
+ """Initialize or reinitialize the RAG system with separate OpenAI compatible APIs and keys."""
263
  global vector_store, qa_chain, token_callback_handler, is_initialized, config
264
 
265
  try:
266
+ # Handle API key configuration with fallback logic
267
+ if llm_api_key:
268
+ config.OPENAI_LLM_API_KEY = llm_api_key
269
+ elif api_key:
270
+ config.OPENAI_LLM_API_KEY = api_key
271
+ elif not config.OPENAI_LLM_API_KEY:
272
+ raise ValueError("LLM API key not provided")
273
+
274
+ if embedding_api_key:
275
+ config.OPENAI_EMBEDDING_API_KEY = embedding_api_key
276
+ elif api_key:
277
+ config.OPENAI_EMBEDDING_API_KEY = api_key
278
+ elif not config.OPENAI_EMBEDDING_API_KEY:
279
+ raise ValueError("Embedding API key not provided")
280
 
281
+ # Update base URLs
282
  if llm_base_url:
283
+ config.OPENAI_LLM_BASE_URL = llm_base_url
284
+
285
  if embedding_base_url:
286
+ config.OPENAI_EMBEDDING_BASE_URL = embedding_base_url
287
 
288
  if llm_model:
289
  config.LLM_MODEL = llm_model
 
291
  if embedding_model:
292
  config.EMBEDDING_MODEL = embedding_model
293
 
 
294
  logger.info(f"Initializing RAG system with:")
295
+ logger.info(f" - LLM Base URL: {config.OPENAI_LLM_BASE_URL}")
296
+ logger.info(f" - LLM API Key: {'*' * (len(config.OPENAI_LLM_API_KEY) - 8) + config.OPENAI_LLM_API_KEY[-8:] if len(config.OPENAI_LLM_API_KEY) > 8 else '*' * len(config.OPENAI_LLM_API_KEY)}")
297
+ logger.info(f" - Embedding Base URL: {config.OPENAI_EMBEDDING_BASE_URL}")
298
+ logger.info(f" - Embedding API Key: {'*' * (len(config.OPENAI_EMBEDDING_API_KEY) - 8) + config.OPENAI_EMBEDDING_API_KEY[-8:] if len(config.OPENAI_EMBEDDING_API_KEY) > 8 else '*' * len(config.OPENAI_EMBEDDING_API_KEY)}")
299
  logger.info(f" - LLM Model: {config.LLM_MODEL}")
300
  logger.info(f" - Embedding Model: {config.EMBEDDING_MODEL}")
301
 
 
317
  chunks = text_splitter.split_documents(documents)
318
  logger.info(f"Document split into {len(chunks)} chunks")
319
 
320
+ # Check if we have too many chunks that might cause rate limiting
321
  if len(chunks) > 200:
322
  logger.warning(f"Large number of chunks ({len(chunks)}). Consider increasing chunk_size to reduce API calls.")
323
 
324
+ # Initialize OpenAI embeddings with separate API key and base URL
325
  embeddings = OpenAIEmbeddings(
326
  model=config.EMBEDDING_MODEL,
327
+ openai_api_key=config.OPENAI_EMBEDDING_API_KEY, # Use embedding-specific API key
328
+ openai_api_base=config.OPENAI_EMBEDDING_BASE_URL,
329
  chunk_size=1000
330
  )
331
 
 
359
  vector_store.save_local(config.INDEX_PATH)
360
  logger.info(f"Created new FAISS index at '{config.INDEX_PATH}'")
361
 
362
+ # Initialize OpenAI LLM with separate API key and base URL
363
  llm = ChatOpenAI(
364
  model_name=config.LLM_MODEL,
365
+ openai_api_key=config.OPENAI_LLM_API_KEY, # Use LLM-specific API key
366
+ openai_api_base=config.OPENAI_LLM_BASE_URL,
367
  temperature=config.TEMPERATURE,
368
  max_tokens=config.MAX_OUTPUT_TOKENS,
369
  callbacks=[token_callback_handler],
 
372
 
373
  # Test LLM connection
374
  try:
 
 
 
375
  test_response = llm.invoke("Test connection")
376
  logger.info("Successfully connected to LLM API")
377
  except Exception as e:
 
420
  # API Endpoints
421
  @app.on_event("startup")
422
  async def startup_event():
423
+ """Initialize the system on startup if API keys are available."""
424
+ if config.OPENAI_LLM_API_KEY and config.OPENAI_EMBEDDING_API_KEY:
425
  try:
 
426
  await initialize_rag_system()
427
  except Exception as e:
428
  logger.warning(f"Could not initialize on startup: {str(e)}")
 
457
  is_initialized=is_initialized,
458
  model_name=config.LLM_MODEL,
459
  embedding_model=config.EMBEDDING_MODEL,
460
+ llm_base_url=config.OPENAI_LLM_BASE_URL,
461
+ embedding_base_url=config.OPENAI_EMBEDDING_BASE_URL,
 
462
  vector_store_ready=vector_store is not None,
463
  total_chunks=len(vector_store.docstore._dict) if vector_store else 0,
464
+ llm_api_key_configured=bool(config.OPENAI_LLM_API_KEY),
465
+ embedding_api_key_configured=bool(config.OPENAI_EMBEDDING_API_KEY)
466
  )
467
 
468
  @app.post("/api/initialize", response_model=Dict[str, Any])
469
  async def initialize_system(request: InitializeRequest):
470
+ """Initialize the RAG system with provided API keys and configuration."""
471
  try:
 
472
  await initialize_rag_system(
473
+ llm_api_key=request.llm_api_key,
474
+ embedding_api_key=request.embedding_api_key,
475
  api_key=request.api_key,
476
  llm_base_url=request.llm_base_url,
477
  embedding_base_url=request.embedding_base_url,
478
  llm_model=request.llm_model,
479
  embedding_model=request.embedding_model
480
  )
 
481
  return {
482
  "success": True,
483
  "message": "System initialized successfully",
484
  "config": {
485
+ "llm_base_url": config.OPENAI_LLM_BASE_URL,
486
+ "embedding_base_url": config.OPENAI_EMBEDDING_BASE_URL,
487
  "llm_model": config.LLM_MODEL,
488
+ "embedding_model": config.EMBEDDING_MODEL,
489
+ "llm_api_key_configured": bool(config.OPENAI_LLM_API_KEY),
490
+ "embedding_api_key_configured": bool(config.OPENAI_EMBEDDING_API_KEY)
491
  }
492
  }
493
  except Exception as e:
 
499
  if not is_initialized:
500
  raise HTTPException(
501
  status_code=503,
502
+ detail="System not initialized. Please provide API keys and configuration."
503
  )
504
 
505
  try:
 
553
  logger.error(f"Error processing query: {str(e)}")
554
  raise HTTPException(status_code=500, detail=str(e))
555
 
 
 
556
  @app.get("/api/token-stats", response_model=Dict[str, Any])
557
  async def get_token_stats():
558
  """Get token usage statistics."""
 
580
  logger.info(f"Uploaded new document: {file.filename}")
581
 
582
  # Reinitialize the system with new data
583
+ if config.OPENAI_LLM_API_KEY and config.OPENAI_EMBEDDING_API_KEY:
584
  # Remove old index to force recreation
585
  if os.path.exists(config.INDEX_PATH):
586
  import shutil
 
604
  "status": "healthy",
605
  "timestamp": datetime.now().isoformat(),
606
  "system_initialized": is_initialized,
607
+ "llm_api_configured": bool(config.OPENAI_LLM_API_KEY),
608
+ "embedding_api_configured": bool(config.OPENAI_EMBEDDING_API_KEY)
609
  }
610
 
611
  # Configuration endpoint
612
  @app.get("/api/config")
613
  async def get_config():
614
  """Get current configuration."""
 
615
  return {
616
+ "llm_base_url": config.OPENAI_LLM_BASE_URL,
617
+ "embedding_base_url": config.OPENAI_EMBEDDING_BASE_URL,
618
  "llm_model": config.LLM_MODEL,
619
  "embedding_model": config.EMBEDDING_MODEL,
620
  "chunk_size": config.CHUNK_SIZE,
621
  "retriever_k": config.RETRIEVER_K,
622
+ "llm_api_key_configured": bool(config.OPENAI_LLM_API_KEY),
623
+ "embedding_api_key_configured": bool(config.OPENAI_EMBEDDING_API_KEY)
624
  }
625
 
626
  # Mount static files