Skip to content

Commit 2f305d7

Browse files
addressed PR comments
Signed-off-by: gopal-raj-suresh <gopal.raj.dummugudupu@cloud2labs.com>
1 parent 0efa206 commit 2f305d7

6 files changed

Lines changed: 38 additions & 156 deletions

File tree

sample_solutions/RAGChatbot/api/.env.example

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
11
# Inference API Configuration
22
# INFERENCE_API_ENDPOINT: URL to your inference service (without /v1 suffix)
3-
# - For GenAI Gateway: https://genai-gateway.example.com
4-
# - For APISIX Gateway: https://apisix-gateway.example.com/Llama-3.1-8B-Instruct
5-
# Note: APISIX Gateway requires the model name in the URL path
3+
#
4+
# **GenAI Gateway**: Provide your GenAI Gateway URL and API key
5+
# - URL format: https://genai-gateway.example.com
6+
# - To generate the GenAI Gateway API key, use the [generate-vault-secrets.sh](https://github.com/opea-project/Enterprise-Inference/blob/main/core/scripts/generate-vault-secrets.sh) script
7+
# - The API key is the litellm_master_key value from the generated vault.yml file
8+
#
9+
# **APISIX Gateway**: Provide your APISIX Gateway URL and authentication token
10+
# - For embedding: https://apisix-gateway.example.com/bge-base-en-v1.5
11+
# - For inference: https://apisix-gateway.example.com/Llama-3.1-8B-Instruct
12+
# - Note: APISIX requires the model name in the URL path
13+
# - To generate the APISIX authentication token, use the [generate-token.sh](https://github.com/opea-project/Enterprise-Inference/blob/main/core/scripts/generate-token.sh) script
14+
# - The token is generated using Keycloak client credentials
15+
# - Set EMBEDDING_API_ENDPOINT and INFERENCE_MODEL_ENDPOINT when using APISIX
616
#
717
# INFERENCE_API_TOKEN: Authentication token/API key for the inference service
8-
# - For GenAI Gateway: Your GenAI Gateway API key
9-
# - For APISIX Gateway: Your APISIX authentication token
1018
INFERENCE_API_ENDPOINT=https://api.example.com
1119
INFERENCE_API_TOKEN=your-pre-generated-token-here
1220

1321
# Model Configuration
14-
# IMPORTANT: Use the full model names as they appear in your inference service
15-
# Check available models: curl https://your-api-endpoint.com/v1/models -H "Authorization: Bearer your-token"
16-
#
17-
# EMBEDDING_ENDPOINT: For APISIX/Keycloak, you need a separate endpoint for embeddings
18-
# Example: EMBEDDING_ENDPOINT=https://apisix-gateway.example.com/bge-base-en-v1.5
1922
EMBEDDING_MODEL_NAME=BAAI/bge-base-en-v1.5
2023
INFERENCE_MODEL_NAME=meta-llama/Llama-3.1-8B-Instruct
2124

25+
# APISIX Gateway Endpoints
26+
# Uncomment and set these when using APISIX Gateway:
27+
# EMBEDDING_API_ENDPOINT=https://api.example.com/bge-base-en-v1.5
28+
# INFERENCE_MODEL_ENDPOINT=https://api.example.com/Llama-3.1-8B-Instruct
29+
2230
# Local URL Endpoint (only needed for non-public domains)
2331
# If using a local domain like api.example.com mapped to localhost:
2432
# Set this to: api.example.com (domain without https://)

sample_solutions/RAGChatbot/api/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ COPY requirements.txt .
1010
RUN pip install --no-cache-dir -r requirements.txt
1111

1212
# Copy the rest of the application files into the container
13-
COPY server.py .
13+
COPY . .
1414

1515
# Expose the port the service runs on
1616
EXPOSE 5001

sample_solutions/RAGChatbot/api/config.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,21 @@
1515
INFERENCE_API_ENDPOINT = os.getenv("INFERENCE_API_ENDPOINT", "https://api.example.com")
1616
INFERENCE_API_TOKEN = os.getenv("INFERENCE_API_TOKEN")
1717

18+
EMBEDDING_API_ENDPOINT = os.getenv("EMBEDDING_API_ENDPOINT")
19+
INFERENCE_MODEL_ENDPOINT = os.getenv("INFERENCE_MODEL_ENDPOINT")
20+
21+
if not EMBEDDING_API_ENDPOINT:
22+
EMBEDDING_API_ENDPOINT = INFERENCE_API_ENDPOINT
23+
if not INFERENCE_MODEL_ENDPOINT:
24+
INFERENCE_MODEL_ENDPOINT = INFERENCE_API_ENDPOINT
25+
1826
# Model Configuration
1927
EMBEDDING_MODEL_NAME = os.getenv("EMBEDDING_MODEL_NAME", "bge-base-en-v1.5")
2028
INFERENCE_MODEL_NAME = os.getenv("INFERENCE_MODEL_NAME", "meta-llama/Llama-3.1-8B-Instruct")
2129

2230
# Validate required configuration
23-
if not INFERENCE_API_ENDPOINT or not INFERENCE_API_TOKEN:
24-
raise ValueError("INFERENCE_API_ENDPOINT and INFERENCE_API_TOKEN must be set in environment variables")
31+
if not INFERENCE_API_TOKEN:
32+
raise ValueError("INFERENCE_API_TOKEN must be set in environment variables")
2533

2634
# Application Settings
2735
APP_TITLE = "RAG QnA Chatbot"

sample_solutions/RAGChatbot/api/services/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from .pdf_service import load_and_split_pdf, validate_pdf_file
66
from .vector_service import store_in_vector_storage, load_vector_store, delete_vector_store
7-
from .retrieval_service import build_retrieval_chain, query_documents
7+
from .retrieval_service import query_documents
88
from .api_client import APIClient, get_api_client
99

1010
__all__ = [
@@ -13,7 +13,6 @@
1313
'store_in_vector_storage',
1414
'load_vector_store',
1515
'delete_vector_store',
16-
'build_retrieval_chain',
1716
'query_documents',
1817
'APIClient',
1918
'get_api_client'

sample_solutions/RAGChatbot/api/services/api_client.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ class APIClient:
1818
"""
1919

2020
def __init__(self):
21-
self.base_url = config.INFERENCE_API_ENDPOINT
21+
self.embedding_base_url = config.EMBEDDING_API_ENDPOINT
22+
self.inference_base_url = config.INFERENCE_MODEL_ENDPOINT
2223
self.token = config.INFERENCE_API_TOKEN
2324
self.http_client = httpx.Client(verify=False)
24-
logger.info(f"✓ API Client initialized with endpoint: {self.base_url}")
25-
25+
logger.info(f"✓ API Client initialized - Embedding: {self.embedding_base_url}, Inference: {self.inference_base_url}")
26+
2627
def get_embedding_client(self):
2728
"""
2829
Get OpenAI-style client for embeddings
@@ -32,10 +33,10 @@ def get_embedding_client(self):
3233

3334
return OpenAI(
3435
api_key=self.token,
35-
base_url=f"{self.base_url}/v1",
36+
base_url=f"{self.embedding_base_url}/v1",
3637
http_client=self.http_client
3738
)
38-
39+
3940
def get_inference_client(self):
4041
"""
4142
Get OpenAI-style client for inference/completions
@@ -45,7 +46,7 @@ def get_inference_client(self):
4546

4647
return OpenAI(
4748
api_key=self.token,
48-
base_url=f"{self.base_url}/v1",
49+
base_url=f"{self.inference_base_url}/v1",
4950
http_client=self.http_client
5051
)
5152

sample_solutions/RAGChatbot/api/services/retrieval_service.py

Lines changed: 1 addition & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,15 @@
11
"""
22
Retrieval service
3-
Handles query processing and retrieval chain operations
3+
Handles query processing and retrieval operations
44
"""
55

66
import logging
7-
from langchain_openai import ChatOpenAI
87
from langchain_community.vectorstores import FAISS
9-
from langchain.chains.retrieval import create_retrieval_chain
10-
from langchain.chains.combine_documents import create_stuff_documents_chain
11-
from langchain import hub
12-
from langchain_core.language_models.chat_models import BaseChatModel
13-
from langchain_core.language_models.llms import LLM
14-
from langchain_core.outputs import LLMResult, Generation
15-
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage, BaseMessage
16-
from typing import List, Optional, Any
178
import config
189

1910
logger = logging.getLogger(__name__)
2011

2112

22-
class CustomLLM(LLM):
23-
"""
24-
Custom LLM class that uses the Llama-3.1-8B-Instruct endpoint
25-
"""
26-
27-
@property
28-
def _llm_type(self) -> str:
29-
"""Return type of LLM."""
30-
return "custom_llm"
31-
32-
def _call(
33-
self,
34-
prompt: str,
35-
stop: Optional[List[str]] = None,
36-
run_manager: Optional[Any] = None,
37-
**kwargs: Any,
38-
) -> str:
39-
"""Call the LLM on the given prompt."""
40-
from .api_client import get_api_client
41-
api_client = get_api_client()
42-
return api_client.complete(prompt, max_tokens=kwargs.get('max_tokens', 150), temperature=kwargs.get('temperature', 0))
43-
44-
45-
class CustomChatModel(BaseChatModel):
46-
"""
47-
Custom Chat Model that uses the Llama-3.1-8B-Instruct endpoint
48-
"""
49-
50-
@property
51-
def _llm_type(self) -> str:
52-
"""Return type of LLM."""
53-
return "custom_chat"
54-
55-
def _generate(
56-
self,
57-
messages: List[BaseMessage],
58-
stop: Optional[List[str]] = None,
59-
run_manager: Optional[Any] = None,
60-
**kwargs: Any,
61-
) -> LLMResult:
62-
"""Generate response from messages."""
63-
from .api_client import get_api_client
64-
api_client = get_api_client()
65-
66-
# Convert messages to a prompt string
67-
# Build the prompt from all messages
68-
prompt_parts = []
69-
70-
for msg in messages:
71-
if isinstance(msg, SystemMessage):
72-
prompt_parts.append(f"System: {msg.content}")
73-
elif isinstance(msg, HumanMessage):
74-
prompt_parts.append(f"User: {msg.content}")
75-
elif isinstance(msg, AIMessage):
76-
prompt_parts.append(f"Assistant: {msg.content}")
77-
78-
# Join all parts and add assistant prompt suffix
79-
full_prompt = "\n\n".join(prompt_parts)
80-
if not full_prompt.endswith("Assistant:"):
81-
full_prompt += "\n\nAssistant:"
82-
83-
logger.info(f"Sending prompt to LLM (length: {len(full_prompt)} chars)")
84-
85-
# Use the complete method which directly sends the prompt
86-
# This calls: Llama-3.1-8B-Instruct/v1/completions with prompt
87-
response_text = api_client.complete(
88-
full_prompt,
89-
max_tokens=kwargs.get('max_tokens', 150),
90-
temperature=kwargs.get('temperature', 0)
91-
)
92-
93-
generations = [Generation(text=response_text)]
94-
return LLMResult(generations=[generations])
95-
96-
97-
def get_llm(api_key: str) -> BaseChatModel:
98-
"""
99-
Get LLM instance (ChatOpenAI or CustomChatModel based on config)
100-
101-
Args:
102-
api_key: API key
103-
104-
Returns:
105-
LLM instance
106-
"""
107-
# Check if using custom inference endpoint
108-
if hasattr(config, 'INFERENCE_API_TOKEN') and config.INFERENCE_API_TOKEN:
109-
return CustomChatModel()
110-
else:
111-
# Fallback to OpenAI ChatOpenAI
112-
return ChatOpenAI(
113-
model="gpt-3.5-turbo",
114-
temperature=0,
115-
openai_api_key=api_key
116-
)
117-
118-
119-
def build_retrieval_chain(vectorstore: FAISS, api_key: str):
120-
"""
121-
Build retrieval chain with LLM (ChatOpenAI or CustomChatModel)
122-
123-
Args:
124-
vectorstore: FAISS vectorstore instance
125-
api_key: API key
126-
127-
Returns:
128-
Configured retrieval chain
129-
130-
Raises:
131-
Exception: If chain building fails
132-
"""
133-
try:
134-
retrieval_qa_chat_prompt = hub.pull("langchain-ai/retrieval-qa-chat")
135-
llm = get_llm(api_key)
136-
combine_docs_chain = create_stuff_documents_chain(llm, retrieval_qa_chat_prompt)
137-
retrieval_chain = create_retrieval_chain(
138-
vectorstore.as_retriever(search_kwargs={"k": 4}),
139-
combine_docs_chain
140-
)
141-
return retrieval_chain
142-
except Exception as e:
143-
logger.error(f"Error building retrieval chain: {str(e)}")
144-
raise
145-
146-
14713
def query_documents(query: str, vectorstore: FAISS, api_key: str) -> dict:
14814
"""
14915
Query the documents using RAG with custom embedding and inference

0 commit comments

Comments
 (0)