Spaces:
Runtime error
Runtime error
Commit
·
617c511
1
Parent(s):
90c9f68
Upload 5 files
Browse files- app.py +21 -27
- llm_client.py +31 -27
- pinecone_index.py +23 -28
app.py
CHANGED
@@ -4,19 +4,20 @@ import gradio as gr
|
|
4 |
|
5 |
from typing import List
|
6 |
|
7 |
-
from llm_client import
|
8 |
from pinecone_index import PinceconeIndex
|
9 |
|
10 |
-
SYSTEM_MESSAGE =
|
11 |
-
context and evidence and do not be verbose.
|
12 |
-
TOP_K =
|
13 |
|
14 |
|
15 |
def format_prompt(question: str, evidence: List[str]):
|
16 |
-
evidence_string =
|
17 |
for i, ev in enumerate(evidence):
|
18 |
-
evidence_string.join(f
|
19 |
|
|
|
20 |
content = f"{SYSTEM_MESSAGE} \
|
21 |
\n ### Question:{question} \
|
22 |
\n ### Evidence: {evidence_string} \
|
@@ -25,39 +26,36 @@ def format_prompt(question: str, evidence: List[str]):
|
|
25 |
return content
|
26 |
|
27 |
|
28 |
-
if __name__ ==
|
29 |
-
|
30 |
-
|
31 |
-
with open('config.yml', 'r') as file:
|
32 |
config = yaml.safe_load(file)
|
33 |
|
34 |
print(config)
|
35 |
|
36 |
-
data_path = config[
|
37 |
-
project = config[
|
38 |
|
39 |
-
index_name = config[
|
40 |
-
embedding_model = config[
|
41 |
-
embedding_dimension = config[
|
42 |
-
'embedding-dimension']
|
43 |
|
44 |
index = PinceconeIndex(index_name, embedding_model)
|
45 |
index.connect_index(embedding_dimension, False)
|
46 |
|
47 |
-
|
48 |
|
49 |
def get_answer(question: str):
|
50 |
evidence = index.query(question, top_k=TOP_K)
|
51 |
prompt_with_evidence = format_prompt(question, evidence)
|
52 |
print(prompt_with_evidence)
|
53 |
-
response =
|
54 |
final_output = [response] + evidence
|
55 |
|
56 |
return final_output
|
57 |
|
58 |
-
context_outputs = [gr.Textbox(label=f
|
59 |
-
|
60 |
-
result_output = [gr.Textbox(label='Answer')]
|
61 |
|
62 |
gradio_outputs = result_output + context_outputs
|
63 |
gradio_inputs = gr.Textbox(placeholder="Enter your question...")
|
@@ -69,12 +67,8 @@ if __name__ == '__main__':
|
|
69 |
outputs=gradio_outputs,
|
70 |
title="GT Student Code of Conduct Bot",
|
71 |
description="Get LLM-powered answers to questions about the \
|
72 |
-
|
73 |
-
from the Code of Conduct.
|
74 |
-
and this is an experimental setup. Please do not consider the \
|
75 |
-
answers as legal advice. We recommend you to consult the \
|
76 |
-
actual Student Code of Conduct online for authoritative \
|
77 |
-
information."
|
78 |
)
|
79 |
|
80 |
demo.launch()
|
|
|
4 |
|
5 |
from typing import List
|
6 |
|
7 |
+
from llm_client import GeminiClient
|
8 |
from pinecone_index import PinceconeIndex
|
9 |
|
10 |
+
SYSTEM_MESSAGE = "Give a precise answer to the question based on only the \
|
11 |
+
context and evidence and do not be verbose."
|
12 |
+
TOP_K = 1
|
13 |
|
14 |
|
15 |
def format_prompt(question: str, evidence: List[str]):
|
16 |
+
evidence_string = ""
|
17 |
for i, ev in enumerate(evidence):
|
18 |
+
evidence_string = evidence_string.join(f"\n Evidence {i+1}: {ev}")
|
19 |
|
20 |
+
print(f"evidence string - {evidence_string}")
|
21 |
content = f"{SYSTEM_MESSAGE} \
|
22 |
\n ### Question:{question} \
|
23 |
\n ### Evidence: {evidence_string} \
|
|
|
26 |
return content
|
27 |
|
28 |
|
29 |
+
if __name__ == "__main__":
|
30 |
+
config_path = "config.yml"
|
31 |
+
with open("config.yml", "r") as file:
|
|
|
32 |
config = yaml.safe_load(file)
|
33 |
|
34 |
print(config)
|
35 |
|
36 |
+
data_path = config["paths"]["data_path"]
|
37 |
+
project = config["paths"]["project"]
|
38 |
|
39 |
+
index_name = config["pinecone"]["index-name"]
|
40 |
+
embedding_model = config["sentence-transformers"]["model-name"]
|
41 |
+
embedding_dimension = config["sentence-transformers"]["embedding-dimension"]
|
|
|
42 |
|
43 |
index = PinceconeIndex(index_name, embedding_model)
|
44 |
index.connect_index(embedding_dimension, False)
|
45 |
|
46 |
+
gemini_client = GeminiClient()
|
47 |
|
48 |
def get_answer(question: str):
|
49 |
evidence = index.query(question, top_k=TOP_K)
|
50 |
prompt_with_evidence = format_prompt(question, evidence)
|
51 |
print(prompt_with_evidence)
|
52 |
+
response = gemini_client.generate_text(prompt_with_evidence)
|
53 |
final_output = [response] + evidence
|
54 |
|
55 |
return final_output
|
56 |
|
57 |
+
context_outputs = [gr.Textbox(label=f"Evidence {i+1}") for i in range(TOP_K)]
|
58 |
+
result_output = [gr.Textbox(label="Answer")]
|
|
|
59 |
|
60 |
gradio_outputs = result_output + context_outputs
|
61 |
gradio_inputs = gr.Textbox(placeholder="Enter your question...")
|
|
|
67 |
outputs=gradio_outputs,
|
68 |
title="GT Student Code of Conduct Bot",
|
69 |
description="Get LLM-powered answers to questions about the \
|
70 |
+
Georgia Tech Student Code of Conduct. The evidences are exerpts\
|
71 |
+
from the Code of Conduct.",
|
|
|
|
|
|
|
|
|
72 |
)
|
73 |
|
74 |
demo.launch()
|
llm_client.py
CHANGED
@@ -1,41 +1,45 @@
|
|
1 |
import os
|
2 |
|
3 |
-
import google.generativeai as
|
4 |
|
5 |
|
6 |
-
class
|
7 |
def __init__(self):
|
8 |
self.connect_client()
|
9 |
|
10 |
def connect_client(self):
|
11 |
-
if
|
12 |
-
raise Exception(
|
13 |
-
|
14 |
-
api_key = os.getenv(
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
{"category": "
|
19 |
-
{"category": "
|
20 |
-
{
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
25 |
|
26 |
defaults = {
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
'top_p': 0.95,
|
32 |
-
'max_output_tokens': 1024,
|
33 |
-
'stop_sequences': [],
|
34 |
-
'safety_settings': safety_overrides,
|
35 |
}
|
36 |
|
37 |
-
self.
|
|
|
|
|
|
|
|
|
38 |
|
39 |
def generate_text(self, prompt: str) -> str:
|
40 |
-
response =
|
41 |
-
return response.
|
|
|
1 |
import os
|
2 |
|
3 |
+
import google.generativeai as genai
|
4 |
|
5 |
|
6 |
+
class GeminiClient:
|
7 |
def __init__(self):
|
8 |
self.connect_client()
|
9 |
|
10 |
def connect_client(self):
|
11 |
+
if not os.getenv("GOOGLE_PALM_KEY"):
|
12 |
+
raise Exception("Please set your Google AI Studio key")
|
13 |
+
|
14 |
+
api_key = os.getenv("GOOGLE_PALM_KEY")
|
15 |
+
genai.configure(api_key=api_key)
|
16 |
+
|
17 |
+
safety_settings = [
|
18 |
+
{"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_ONLY_HIGH"},
|
19 |
+
{"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_ONLY_HIGH"},
|
20 |
+
{
|
21 |
+
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
|
22 |
+
"threshold": "BLOCK_ONLY_HIGH",
|
23 |
+
},
|
24 |
+
{
|
25 |
+
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
|
26 |
+
"threshold": "BLOCK_ONLY_HIGH",
|
27 |
+
},
|
28 |
+
]
|
29 |
|
30 |
defaults = {
|
31 |
+
"temperature": 0.7,
|
32 |
+
"top_k": 40,
|
33 |
+
"top_p": 0.95,
|
34 |
+
"max_output_tokens": 1024,
|
|
|
|
|
|
|
|
|
35 |
}
|
36 |
|
37 |
+
self.model = genai.GenerativeModel(
|
38 |
+
model_name="gemini-pro",
|
39 |
+
generation_config=defaults,
|
40 |
+
safety_settings=safety_settings,
|
41 |
+
)
|
42 |
|
43 |
def generate_text(self, prompt: str) -> str:
|
44 |
+
response = self.model.generate_content(prompt)
|
45 |
+
return response.text
|
pinecone_index.py
CHANGED
@@ -19,18 +19,17 @@ class PinceconeIndex:
|
|
19 |
self.index_name = index_name
|
20 |
self._embeddingModel = HuggingFaceEmbeddings(model_name=model_name)
|
21 |
|
22 |
-
def connect_index(self, embedding_dimension: int,
|
23 |
-
delete_existing: bool = False):
|
24 |
index_name = self.index_name
|
25 |
|
26 |
# load pinecone env variables within Google Colab
|
27 |
-
if (not os.getenv(
|
28 |
-
dotenv_path = Path(
|
29 |
load_dotenv(dotenv_path=dotenv_path)
|
30 |
|
31 |
pinecone.init(
|
32 |
-
api_key=os.getenv(
|
33 |
-
environment=os.getenv(
|
34 |
)
|
35 |
|
36 |
if index_name in pinecone.list_indexes() and delete_existing:
|
@@ -47,9 +46,8 @@ class PinceconeIndex:
|
|
47 |
def upsert_docs(self, df: pd.DataFrame, text_col: str):
|
48 |
loader = DataFrameLoader(df, page_content_column=text_col)
|
49 |
docs = loader.load()
|
50 |
-
Pinecone.from_documents(docs, self._embeddingModel,
|
51 |
-
|
52 |
-
|
53 |
def get_embedding_model(self):
|
54 |
return self._embeddingModel
|
55 |
|
@@ -57,47 +55,44 @@ class PinceconeIndex:
|
|
57 |
return self.index_name
|
58 |
|
59 |
def query(self, query: str, top_k: int = 5) -> List[str]:
|
60 |
-
docsearch = Pinecone.from_existing_index(self.index_name,
|
61 |
-
self._embeddingModel)
|
62 |
res = docsearch.similarity_search(query, k=top_k)
|
63 |
|
64 |
return [doc.page_content for doc in res]
|
65 |
|
66 |
|
67 |
-
if __name__ ==
|
68 |
-
config_path =
|
69 |
-
with open(
|
70 |
config = yaml.safe_load(file)
|
71 |
|
72 |
print(config)
|
73 |
|
74 |
-
data_path = config[
|
75 |
-
project = config[
|
76 |
-
format =
|
77 |
|
78 |
-
index_name = config[
|
79 |
-
embedding_model = config[
|
80 |
-
|
81 |
-
embedding_dimension = config['sentence-transformers'][
|
82 |
-
'embedding-dimension']
|
83 |
delete_existing = True
|
84 |
|
85 |
-
if config[
|
86 |
print("Using manual chunking")
|
87 |
-
file_path_embedding = config[
|
88 |
-
df = pd.read_csv(file_path_embedding, header=None, names=[
|
89 |
else:
|
90 |
print("Using automatic chunking")
|
91 |
-
file_path_embedding = config[
|
92 |
df = pd.read_csv(file_path_embedding, index_col=0)
|
93 |
|
94 |
print(df)
|
95 |
start_time = time.time()
|
96 |
index = PinceconeIndex(index_name, embedding_model)
|
97 |
index.connect_index(embedding_dimension, delete_existing)
|
98 |
-
index.upsert_docs(df,
|
99 |
end_time = time.time()
|
100 |
-
print(f
|
101 |
|
102 |
index = PinceconeIndex(index_name, embedding_model)
|
103 |
index.connect_index(embedding_dimension, delete_existing=False)
|
|
|
19 |
self.index_name = index_name
|
20 |
self._embeddingModel = HuggingFaceEmbeddings(model_name=model_name)
|
21 |
|
22 |
+
def connect_index(self, embedding_dimension: int, delete_existing: bool = False):
|
|
|
23 |
index_name = self.index_name
|
24 |
|
25 |
# load pinecone env variables within Google Colab
|
26 |
+
if (not os.getenv("PINECONE_KEY")) or (not os.getenv("PINECONE_ENV")):
|
27 |
+
dotenv_path = Path("/content/gt-policy-bot/config.env")
|
28 |
load_dotenv(dotenv_path=dotenv_path)
|
29 |
|
30 |
pinecone.init(
|
31 |
+
api_key=os.getenv("PINECONE_KEY"),
|
32 |
+
environment=os.getenv("PINECONE_ENV"),
|
33 |
)
|
34 |
|
35 |
if index_name in pinecone.list_indexes() and delete_existing:
|
|
|
46 |
def upsert_docs(self, df: pd.DataFrame, text_col: str):
|
47 |
loader = DataFrameLoader(df, page_content_column=text_col)
|
48 |
docs = loader.load()
|
49 |
+
Pinecone.from_documents(docs, self._embeddingModel, index_name=self.index_name)
|
50 |
+
|
|
|
51 |
def get_embedding_model(self):
|
52 |
return self._embeddingModel
|
53 |
|
|
|
55 |
return self.index_name
|
56 |
|
57 |
def query(self, query: str, top_k: int = 5) -> List[str]:
|
58 |
+
docsearch = Pinecone.from_existing_index(self.index_name, self._embeddingModel)
|
|
|
59 |
res = docsearch.similarity_search(query, k=top_k)
|
60 |
|
61 |
return [doc.page_content for doc in res]
|
62 |
|
63 |
|
64 |
+
if __name__ == "__main__":
|
65 |
+
config_path = "config.yml"
|
66 |
+
with open("config.yml", "r") as file:
|
67 |
config = yaml.safe_load(file)
|
68 |
|
69 |
print(config)
|
70 |
|
71 |
+
data_path = config["paths"]["data_path"]
|
72 |
+
project = config["paths"]["project"]
|
73 |
+
format = ".csv"
|
74 |
|
75 |
+
index_name = config["pinecone"]["index-name"]
|
76 |
+
embedding_model = config["sentence-transformers"]["model-name"]
|
77 |
+
embedding_dimension = config["sentence-transformers"]["embedding-dimension"]
|
|
|
|
|
78 |
delete_existing = True
|
79 |
|
80 |
+
if config["paths"]["chunking"] == "manual":
|
81 |
print("Using manual chunking")
|
82 |
+
file_path_embedding = config["paths"]["manual_chunk_file"]
|
83 |
+
df = pd.read_csv(file_path_embedding, header=None, names=["chunks"])
|
84 |
else:
|
85 |
print("Using automatic chunking")
|
86 |
+
file_path_embedding = config["paths"]["auto_chunk_file"]
|
87 |
df = pd.read_csv(file_path_embedding, index_col=0)
|
88 |
|
89 |
print(df)
|
90 |
start_time = time.time()
|
91 |
index = PinceconeIndex(index_name, embedding_model)
|
92 |
index.connect_index(embedding_dimension, delete_existing)
|
93 |
+
index.upsert_docs(df, "chunks")
|
94 |
end_time = time.time()
|
95 |
+
print(f"Indexing took {end_time - start_time} seconds")
|
96 |
|
97 |
index = PinceconeIndex(index_name, embedding_model)
|
98 |
index.connect_index(embedding_dimension, delete_existing=False)
|