Skip to content

Commit 64eaec5

Browse files
committed
working on docker
1 parent e92edc4 commit 64eaec5

File tree

20 files changed

+7932
-0
lines changed

20 files changed

+7932
-0
lines changed

samples/RAG-chatbot/rag_system.py

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import openai
2+
import json
3+
import os
4+
from sentence_transformers import SentenceTransformer
5+
import numpy as np
6+
from sklearn.metrics.pairwise import cosine_similarity
7+
from functools import lru_cache
8+
import re
9+
10+
# Ensure you have set the OPENAI_API_KEY in your environment variables
11+
openai.api_key = os.getenv("OPENAI_API_KEY")
12+
13+
class RAGSystem:
14+
def __init__(self, knowledge_base):
15+
self.knowledge_base = knowledge_base
16+
self.model = SentenceTransformer('all-MiniLM-L6-v2')
17+
self.doc_embeddings = self.embed_knowledge_base()
18+
19+
def embed_knowledge_base(self):
20+
# Combine the 'about' and 'text' fields for embedding
21+
docs = [f'{doc["about"]}. {doc["text"]}' for doc in self.knowledge_base]
22+
return self.model.encode(docs, convert_to_tensor=True)
23+
24+
def normalize_query(self, query):
25+
"""
26+
Normalize the query by converting it to lowercase and stripping whitespace.
27+
"""
28+
return query.lower().strip()
29+
30+
@lru_cache(maxsize=128)
31+
def retrieve(self, query, similarity_threshold=0.7, high_match_threshold=0.8, max_docs=5):
32+
# Normalize query for consistent caching
33+
normalized_query = self.normalize_query(query)
34+
print(f"Cache Access for retrieve: '{normalized_query}'")
35+
36+
# Query embedding
37+
query_embedding = self.model.encode([normalized_query], convert_to_tensor=True)
38+
39+
# Calculate similarities
40+
similarities = cosine_similarity(query_embedding, self.doc_embeddings)[0]
41+
42+
# Initialize relevance scores
43+
relevance_scores = []
44+
45+
for i, doc in enumerate(self.knowledge_base):
46+
# Calculate about and text similarities separately
47+
about_similarity = cosine_similarity(query_embedding, self.model.encode([doc["about"]]))[0][0]
48+
text_similarity = similarities[i] # Already calculated
49+
50+
# Give more weight to text similarity
51+
combined_score = (0.3 * about_similarity) + (0.7 * text_similarity)
52+
53+
# If either about or text similarity is above the high match threshold, prioritize it
54+
if about_similarity >= high_match_threshold or text_similarity >= high_match_threshold:
55+
combined_score = max(about_similarity, text_similarity)
56+
57+
relevance_scores.append((i, combined_score))
58+
59+
# Sort by combined score in descending order
60+
sorted_indices = sorted(relevance_scores, key=lambda x: x[1], reverse=True)
61+
top_indices = [i for i, score in sorted_indices[:max_docs] if score >= similarity_threshold]
62+
63+
# Retrieve the most relevant documents, including both 'about' and 'text' fields
64+
retrieved_docs = [f'{self.knowledge_base[i]["about"]}. {self.knowledge_base[i]["text"]}' for i in top_indices]
65+
66+
if not retrieved_docs:
67+
max_index = np.argmax(similarities)
68+
retrieved_docs.append(f'{self.knowledge_base[max_index]["about"]}. {self.knowledge_base[max_index]["text"]}')
69+
70+
context = "\n\n".join(retrieved_docs)
71+
print("Retrieved Context:\n", context)
72+
73+
return context
74+
75+
@lru_cache(maxsize=128)
76+
def generate_response(self, query, context):
77+
# Normalize query for consistent caching
78+
normalized_query = self.normalize_query(query)
79+
print(f"Cache Access for generate_response: '{normalized_query}'")
80+
81+
try:
82+
prompt = (
83+
"You are a dedicated assistant designed to provide positive answers about Defang. "
84+
"When the user says 'you', 'your', or any pronoun, interpret it as referring to Defang with context of Defang also. "
85+
"However, only answer if part or all of the prompt is about defang, otherwise respond with this question is out of scope"
86+
"If the user's question involves comparisons with or references to other services, you may use external knowledge. "
87+
"However, if the question is strictly about Defang, you must ignore all external knowledge and only utilize the given context. "
88+
"When generating the answer, please put the answer first and the justification later. "
89+
"Any mentions of BYOD means BRING YOUR OWN DOMAIN and NOT BRING YOUR OWN DEVICE."
90+
"Your objective is to remain strictly within the confines of the given context unless comparisons to other services are explicitly mentioned. "
91+
"\n\nContext:\n" + context + "\n\n"
92+
"User Question: " + query + "\n\n"
93+
"Answer:"
94+
)
95+
96+
response = openai.ChatCompletion.create(
97+
model="gpt-4-turbo",
98+
messages=[
99+
{"role": "system", "content": "You are a helpful assistant."},
100+
{"role": "system", "content": prompt},
101+
{"role": "user", "content": normalized_query}
102+
],
103+
temperature=0.2,
104+
max_tokens=2048,
105+
top_p=1,
106+
frequency_penalty=0,
107+
presence_penalty=0
108+
)
109+
110+
# Print the response generated by the model
111+
generated_response = response['choices'][0]['message']['content'].strip()
112+
113+
# Indicate cache usage
114+
cache_info = self.generate_response.cache_info()
115+
if cache_info.misses > 0:
116+
print("No, this response is generated")
117+
else:
118+
print("Yes, this response is cached")
119+
120+
return generated_response
121+
122+
# Commented out for future debugging:
123+
# Concatenate the context with the generated response
124+
# final_response = f"**Context:**\n{context}\n\n**Response:**\n{generated_response}"
125+
# return final_response
126+
127+
except openai.error.OpenAIError as e:
128+
print(f"Error generating response from OpenAI: {e}")
129+
return "An error occurred while generating the response."
130+
131+
def answer_query(self, query):
132+
try:
133+
# Normalize query before use
134+
normalized_query = self.normalize_query(query)
135+
context = self.retrieve(normalized_query)
136+
response = self.generate_response(normalized_query, context)
137+
return response
138+
except Exception as e:
139+
print(f"Error in answer_query: {e}")
140+
return "An error occurred while generating the response."
141+
142+
def cache_info(self):
143+
print("Retrieve cache info:", self.retrieve.cache_info())
144+
print("Generate response cache info:", self.generate_response.cache_info())
145+
146+
# Load knowledge base from a JSON file
147+
with open('knowledge_base.json', 'r') as kb_file:
148+
knowledge_base = json.load(kb_file)
149+
150+
rag_system = RAGSystem(knowledge_base)

samples/platformatic/.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
PLT_SERVER_HOSTNAME=127.0.0.1
2+
PORT=3042
3+
PLT_SERVER_LOGGER_LEVEL=info
4+
PLT_MANAGEMENT_API=true
5+
PLT_APP_TYPESCRIPT=false
6+
PLT_APP_EXAMPLE_ORIGIN=http://127.0.0.1:3043
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
dist
2+
.DS_Store
3+
4+
# dotenv environment variable files
5+
.env
6+
7+
# database files
8+
*.sqlite
9+
*.sqlite3
10+
11+
# Logs
12+
logs
13+
*.log
14+
npm-debug.log*
15+
yarn-debug.log*
16+
yarn-error.log*
17+
lerna-debug.log*
18+
.pnpm-debug.log*
19+
20+
# Dependency directories
21+
node_modules/
22+
23+
# ctags
24+
tags
25+
26+
# clinicjs
27+
.clinic/
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Use the official Node.js Alpine image as a parent image
2+
FROM node:alpine
3+
4+
# Install dependencies for building native modules
5+
RUN apk add --no-cache \
6+
python3 \
7+
make \
8+
g++
9+
10+
# Set the working directory in the container
11+
WORKDIR /app
12+
13+
# Copy package.json and package-lock.json
14+
COPY package*.json ./
15+
16+
# Install node modules
17+
RUN npm install --production
18+
19+
# Copy the rest of the application code
20+
COPY . .
21+
22+
# Expose the port that the app runs on
23+
EXPOSE 3042
24+
25+
# Command to run the application
26+
CMD ["npm", "start"]

samples/platformatic/app/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Platformatic Runtime API
2+
3+
This is a generated [Platformatic Runtime](https://docs.platformatic.dev/docs/runtime/overview) application.
4+
5+
## Requirements
6+
7+
Platformatic supports macOS, Linux and Windows ([WSL](https://docs.microsoft.com/windows/wsl/) recommended).
8+
You'll need to have [Node.js](https://nodejs.org/) >= v18.8.0 or >= v20.6.0
9+
10+
## Setup
11+
12+
1. Install dependencies:
13+
14+
```bash
15+
npm install
16+
```
17+
18+
## Usage
19+
20+
Run the API with:
21+
22+
```bash
23+
npm start
24+
```
25+
26+
## Adding a Service
27+
28+
Adding a new service to this project is as simple as running `create-platformatic` again, like so:
29+
30+
```
31+
npx create-platformatic
32+
```

0 commit comments

Comments
 (0)