sravan commited on
Commit
8e70769
·
1 Parent(s): 39ecd8e
app/.DS_Store → .DS_Store RENAMED
Binary files a/app/.DS_Store and b/.DS_Store differ
 
.gitignore CHANGED
@@ -1 +1,4 @@
1
- myenv
 
 
 
 
1
+ myenv
2
+ *pycache*
3
+
4
+
Dockerfile DELETED
@@ -1,20 +0,0 @@
1
- FROM python:3.12
2
- # Create a new user named 'user' with user ID 1000 and create their home directory
3
- RUN useradd -m -u 1000 user
4
- # Switch to the newly created user
5
- USER user
6
- # Add the user's local bin directory to the PATH
7
- ENV PATH="/home/user/.local/bin:$PATH"
8
- # Set the working directory in the container to /app
9
- WORKDIR /app
10
- # Copy the requirements.txt file from the host to the container
11
- # The --chown=user ensures the copied file is owned by our 'user'
12
- # RUN --mount=type=secret,id=HF_TOKEN,mode=0444,required=true
13
- COPY --chown=user ./requirements.txt requirements.txt
14
- # Install the Python dependencies listed in requirements.txt
15
- RUN pip install --no-cache-dir --upgrade -r requirements.txt
16
- # Copy the rest of the application code from the host to the container
17
- # Again, ensure the copied files are owned by 'user'
18
- COPY --chown=user . /app
19
- # Specify the command to run when the container starts
20
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,9 +1,5 @@
1
  from fastapi import FastAPI
2
-
3
  app = FastAPI()
4
-
5
  @app.get("/")
6
- def api_get():
7
- return {"Hello": "World"}
8
-
9
-
 
1
  from fastapi import FastAPI
 
2
  app = FastAPI()
 
3
  @app.get("/")
4
+ def greet_json():
5
+ return {"Hello": "World!"}
 
 
app/Backend/Dockerfile DELETED
@@ -1,20 +0,0 @@
1
- FROM python:3.12
2
- # Create a new user named 'user' with user ID 1000 and create their home directory
3
- RUN useradd -m -u 1000 user
4
- # Switch to the newly created user
5
- USER user
6
- # Add the user's local bin directory to the PATH
7
- ENV PATH="/home/user/.local/bin:$PATH"
8
- # Set the working directory in the container to /app
9
- WORKDIR /app
10
- # Copy the requirements.txt file from the host to the container
11
- # The --chown=user ensures the copied file is owned by our 'user'
12
- RUN --mount=type=secret,id=HF_TOKEN,mode=0444,required=true
13
- COPY --chown=user ./requirements.txt requirements.txt
14
- # Install the Python dependencies listed in requirements.txt
15
- RUN pip install --no-cache-dir --upgrade -r requirements.txt
16
- # Copy the rest of the application code from the host to the container
17
- # Again, ensure the copied files are owned by 'user'
18
- COPY --chown=user . /app
19
- # Specify the command to run when the container starts
20
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Backend/app.py DELETED
@@ -1,5 +0,0 @@
1
- from fastapi import FastAPI
2
- app = FastAPI()
3
- @app.get("/")
4
- def greet_json():
5
- return {"Hello": "World!"}
 
 
 
 
 
 
app/Backend/requirements.txt DELETED
@@ -1,9 +0,0 @@
1
- fastapi
2
- uvicorn[standard]
3
- sse-starlette
4
- langchain-core
5
- langserve
6
- sqlalchemy
7
- langchain-huggingface
8
- transformers
9
-
 
 
 
 
 
 
 
 
 
 
app/Frontend/README.md DELETED
@@ -1,12 +0,0 @@
1
- ---
2
- title: Frontend
3
- emoji: 🚀
4
- colorFrom: indigo
5
- colorTo: purple
6
- sdk: streamlit
7
- sdk_version: 1.37.1
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Frontend/app.py DELETED
@@ -1,12 +0,0 @@
1
- import streamlit as st
2
-
3
- pg = st.navigation([
4
- st.Page("pages/simple_page.py"),
5
- st.Page("pages/formatted_page.py"),
6
- st.Page("pages/history_page.py"),
7
- st.Page("pages/rag_page.py"),
8
- st.Page("pages/filtered_rag_page.py"),
9
- ])
10
- pg.run()
11
-
12
-
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Frontend/pages/__pycache__/page_base.cpython-310.pyc DELETED
Binary file (1.35 kB)
 
app/Frontend/pages/filtered_rag_page.py DELETED
@@ -1,9 +0,0 @@
1
- from streamlit.runtime.scriptrunner import get_script_run_ctx
2
- from pages.page_base import chat_interface
3
-
4
-
5
- chat_title = "Filtered RAG Chat App"
6
- url = "[YOUR FILTERED RAG URL]"
7
- page_hash = get_script_run_ctx().page_script_hash
8
-
9
- chat_interface(chat_title, page_hash, url)
 
 
 
 
 
 
 
 
 
 
app/Frontend/pages/formatted_page.py DELETED
@@ -1,9 +0,0 @@
1
- from streamlit.runtime.scriptrunner import get_script_run_ctx
2
- from pages.page_base import chat_interface
3
-
4
-
5
- chat_title = "Formatted Chat App"
6
- url = "[YOUR FORMATTED CHAT URL]"
7
- page_hash = get_script_run_ctx().page_script_hash
8
-
9
- chat_interface(chat_title, page_hash, url)
 
 
 
 
 
 
 
 
 
 
app/Frontend/pages/history_page.py DELETED
@@ -1,9 +0,0 @@
1
- from streamlit.runtime.scriptrunner import get_script_run_ctx
2
- from pages.page_base import chat_interface
3
-
4
-
5
- chat_title = "History Chat App"
6
- url = "[YOUR HISTORY CHAT URL]"
7
- page_hash = get_script_run_ctx().page_script_hash
8
-
9
- chat_interface(chat_title, page_hash, url)
 
 
 
 
 
 
 
 
 
 
app/Frontend/pages/page_base.py DELETED
@@ -1,48 +0,0 @@
1
- import streamlit as st
2
- from langserve.client import RemoteRunnable
3
-
4
- def get_response(user_input, url, username):
5
- response_placeholder = st.empty()
6
- full_response = ""
7
- chain = RemoteRunnable(url)
8
- stream = chain.stream(input={'question': user_input, 'username': username})
9
- for chunk in stream:
10
- full_response += chunk
11
- response_placeholder.markdown(full_response)
12
-
13
- return full_response
14
-
15
- def chat_interface(chat_title, page_hash ,url):
16
- st.title(chat_title)
17
-
18
- # Add username input at the top of the page
19
- username = st.text_input("Enter your username:", key="username_input", value="Guest")
20
-
21
- # Initialize page-specific chat history
22
- if "chat_histories" not in st.session_state:
23
- st.session_state.chat_histories = {}
24
-
25
- if page_hash not in st.session_state.chat_histories:
26
- st.session_state.chat_histories[page_hash] = []
27
-
28
- # Display chat messages from history for the current page
29
- for message in st.session_state.chat_histories[page_hash]:
30
- with st.chat_message(message["role"]):
31
- st.markdown(message["content"])
32
-
33
- # React to user input
34
- if prompt := st.chat_input("What is your message?"):
35
- # Display user message in chat message container
36
- st.chat_message("user").markdown(prompt)
37
- # Add user message to chat history
38
- st.session_state.chat_histories[page_hash].append({"role": "user", "content": prompt})
39
-
40
- # Get streaming response
41
- with st.chat_message("assistant"):
42
- full_response = get_response(prompt, url, username)
43
-
44
- # Add assistant response to chat history
45
- st.session_state.chat_histories[page_hash].append({"role": "assistant", "content": full_response})
46
-
47
- if __name__ == "__main__":
48
- chat_interface()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Frontend/pages/rag_page.py DELETED
@@ -1,9 +0,0 @@
1
- from streamlit.runtime.scriptrunner import get_script_run_ctx
2
- from pages.page_base import chat_interface
3
-
4
-
5
- chat_title = "RAG Chat App"
6
- url = "[YOUR RAG CHAT URL]"
7
- page_hash = get_script_run_ctx().page_script_hash
8
-
9
- chat_interface(chat_title, page_hash, url)
 
 
 
 
 
 
 
 
 
 
app/Frontend/pages/simple_page.py DELETED
@@ -1,12 +0,0 @@
1
- # import streamlit as st
2
- # import time
3
- # from langserve import RemoteRunnable
4
- from streamlit.runtime.scriptrunner import get_script_run_ctx
5
- import streamlit as st
6
- from pages.page_base import chat_interface
7
-
8
- chat_title = "Simple Chat App"
9
- url = "https://damienbenveniste-backend.hf.space/simple"
10
- page_hash = get_script_run_ctx().page_script_hash
11
-
12
- chat_interface(chat_title, page_hash, url)
 
 
 
 
 
 
 
 
 
 
 
 
 
app/Frontend/requirements.txt DELETED
@@ -1 +0,0 @@
1
- langserve[client]
 
 
app/Backend/app/callbacks.py → callbacks.py RENAMED
@@ -15,7 +15,19 @@ class LogResponseCallback(BaseCallbackHandler):
15
  """Run when llm ends running."""
16
  # TODO: The function on_llm_end is going to be called when the LLM stops sending
17
  # the response. Use the crud.add_message function to capture that response.
18
- raise NotImplemented
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  def on_llm_start(
21
  self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
 
15
  """Run when llm ends running."""
16
  # TODO: The function on_llm_end is going to be called when the LLM stops sending
17
  # the response. Use the crud.add_message function to capture that response.
18
+ type = 'AI'
19
+ user_data = crud.get_or_create(db, self.user_request.username)
20
+ user_id = user_data.user_id
21
+ timestamp = datetime.now()
22
+ message = outputs.generations[0][0].text # answer from the prompt message
23
+ message_to_add = schemas.MessageBase(
24
+ user_id = user_id,
25
+ message = message,
26
+ type = type,
27
+ timestamp = timestamp
28
+ )
29
+ _ = crud.add_message(self.db, message_to_add, self.user_request.username )
30
+ # raise NotImplemented
31
 
32
  def on_llm_start(
33
  self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
app/Backend/app/chains.py → chains.py RENAMED
@@ -1,50 +1,66 @@
1
  import os
2
  from langchain_huggingface import HuggingFaceEndpoint
3
  from langchain_core.runnables import RunnablePassthrough
 
4
  import schemas
 
5
  from prompts import (
6
  raw_prompt,
7
  raw_prompt_formatted,
8
  format_context,
9
- tokenizer
 
 
10
  )
11
  from data_indexing import DataIndexer
 
12
 
13
  data_indexer = DataIndexer()
14
 
 
 
15
  llm = HuggingFaceEndpoint(
16
  repo_id="meta-llama/Meta-Llama-3-8B-Instruct",
 
17
  huggingfacehub_api_token=os.environ['HF_TOKEN'],
18
  max_new_tokens=512,
19
  stop_sequences=[tokenizer.eos_token],
20
  streaming=True,
 
 
21
  )
22
 
23
  simple_chain = (raw_prompt | llm).with_types(input_type=schemas.UserQuestion)
24
 
25
  # TODO: create formatted_chain by piping raw_prompt_formatted and the LLM endpoint.
26
- formatted_chain = (raw_prompt_formatted | llm).with_types(input_types=schemas.UserQuestion)
27
 
28
  # TODO: use history_prompt_formatted and HistoryInput to create the history_chain
29
- history_chain = None
30
 
31
  # TODO: Let's construct the standalone_chain by piping standalone_prompt_formatted with the LLM
32
- standalone_chain = None
33
 
34
  input_1 = RunnablePassthrough.assign(new_question=standalone_chain)
35
  input_2 = {
36
  'context': lambda x: format_context(data_indexer.search(x['new_question'])),
37
- 'standalone_question': lambda x: x['new_question']
38
  }
39
  input_to_rag_chain = input_1 | input_2
40
 
41
  # TODO: use input_to_rag_chain, rag_prompt_formatted,
42
  # HistoryInput and the LLM to build the rag_chain.
43
- rag_chain = None
44
 
45
  # TODO: Implement the filtered_rag_chain. It should be the
46
  # same as the rag_chain but with hybrid_search = True.
47
- filtered_rag_chain = None
 
 
 
 
 
 
48
 
49
 
50
 
 
1
  import os
2
  from langchain_huggingface import HuggingFaceEndpoint
3
  from langchain_core.runnables import RunnablePassthrough
4
+
5
  import schemas
6
+ import prompts
7
  from prompts import (
8
  raw_prompt,
9
  raw_prompt_formatted,
10
  format_context,
11
+ history_prompt_formatted,
12
+ standalone_prompt_formatted,
13
+ rag_prompt_formatted
14
  )
15
  from data_indexing import DataIndexer
16
+ from transformers import AutoTokenizer
17
 
18
  data_indexer = DataIndexer()
19
 
20
+ tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")
21
+
22
  llm = HuggingFaceEndpoint(
23
  repo_id="meta-llama/Meta-Llama-3-8B-Instruct",
24
+
25
  huggingfacehub_api_token=os.environ['HF_TOKEN'],
26
  max_new_tokens=512,
27
  stop_sequences=[tokenizer.eos_token],
28
  streaming=True,
29
+ # task="conversational",
30
+ task="text-generation",
31
  )
32
 
33
  simple_chain = (raw_prompt | llm).with_types(input_type=schemas.UserQuestion)
34
 
35
  # TODO: create formatted_chain by piping raw_prompt_formatted and the LLM endpoint.
36
+ formatted_chain = (raw_prompt_formatted | llm).with_types(input_type=schemas.UserQuestion)
37
 
38
  # TODO: use history_prompt_formatted and HistoryInput to create the history_chain
39
+ history_chain = (history_prompt_formatted | llm).with_types(input_type=schemas.HistoryInput)
40
 
41
  # TODO: Let's construct the standalone_chain by piping standalone_prompt_formatted with the LLM
42
+ standalone_chain = (standalone_prompt_formatted | llm).with_types(input_type=schemas.HistoryInput)
43
 
44
  input_1 = RunnablePassthrough.assign(new_question=standalone_chain)
45
  input_2 = {
46
  'context': lambda x: format_context(data_indexer.search(x['new_question'])),
47
+ 'standalone_question': lambda x: x['new_question'] # new question was the parameter in input1
48
  }
49
  input_to_rag_chain = input_1 | input_2
50
 
51
  # TODO: use input_to_rag_chain, rag_prompt_formatted,
52
  # HistoryInput and the LLM to build the rag_chain.
53
+ rag_chain = (input_to_rag_chain | rag_prompt_formatted | llm).with_types(input_type=schemas.RagInput)
54
 
55
  # TODO: Implement the filtered_rag_chain. It should be the
56
  # same as the rag_chain but with hybrid_search = True.
57
+
58
+ input_2_hybrid_search = {
59
+ 'context': lambda x: format_context(data_indexer.search(x['new_question'], hybrid_search=True)),
60
+ 'standalone_question': lambda x: x['new_question']
61
+ }
62
+
63
+ filtered_rag_chain = (input_1 | input_2_hybrid_search | rag_prompt_formatted | llm ).with_types(input_type=schemas.RagInput)
64
 
65
 
66
 
app/Backend/app/crud.py → crud.py RENAMED
@@ -17,7 +17,28 @@ def add_message(db: Session, message: schemas.MessageBase, username: str):
17
  # - create a models.Message instance
18
  # - pass the retrieved user to the message instance
19
  # - save the message instance to the database
20
- raise NotImplemented
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  def get_user_chat_history(db: Session, username: str):
23
- raise NotImplemented
 
 
 
 
 
 
 
 
 
 
 
17
  # - create a models.Message instance
18
  # - pass the retrieved user to the message instance
19
  # - save the message instance to the database
20
+ user_data = get_or_create_user(db, username)
21
+ db_message = models.Message(
22
+ message=message.message,
23
+ type=message.type,
24
+ timestamp=message.timestamp,
25
+ user_id=user_data.id
26
+ )
27
+ db.add(db_message)
28
+ db.commit()
29
+ db.refresh(db_message)
30
+ # raise NotImplemented
31
+ return message
32
 
33
  def get_user_chat_history(db: Session, username: str):
34
+ # chat_history = db.
35
+ user_data = get_or_create_user(db, username)
36
+ messages = db.query(models.Message.message,
37
+ models.Message.type,
38
+ models.Message.timestamp
39
+ ).filter(models.Message.user_id==user_data.id).all()
40
+
41
+ if not messages:
42
+ return []
43
+ return messages
44
+ # raise NotImplemented
app/Backend/app/data_indexing.py → data_indexing.py RENAMED
@@ -5,6 +5,7 @@ from pinecone.grpc import PineconeGRPC as Pinecone
5
  from pinecone import ServerlessSpec
6
  from langchain_community.vectorstores import Chroma
7
  from langchain_openai import OpenAIEmbeddings
 
8
 
9
  current_dir = Path(__file__).resolve().parent
10
 
@@ -16,22 +17,31 @@ class DataIndexer:
16
  def __init__(self, index_name='langchain-repo') -> None:
17
 
18
  # TODO: choose your embedding model
19
- # self.embedding_client = InferenceClient(
20
- # "dunzhang/stella_en_1.5B_v5",
21
- # token=os.environ['HF_TOKEN'],
22
- # )
23
- self.embedding_client = OpenAIEmbeddings()
 
 
 
 
24
  self.index_name = index_name
25
  self.pinecone_client = Pinecone(api_key=os.environ.get('PINECONE_API_KEY'))
26
 
27
  if index_name not in self.pinecone_client.list_indexes().names():
28
  # TODO: create your index if it doesn't exist. Use the create_index function.
29
  # Make sure to choose the dimension that corresponds to your embedding model
30
- pass
31
-
 
 
 
 
 
32
  self.index = self.pinecone_client.Index(self.index_name)
33
  # TODO: make sure to build the index.
34
- self.source_index = None
35
 
36
  def get_source_index(self):
37
  if not os.path.isfile(self.source_file):
@@ -60,21 +70,23 @@ class DataIndexer:
60
 
61
  # TODO: create a list of the vector representations of each text data in the batch
62
  # TODO: choose your embedding model
63
- # values = self.embedding_client.embed_documents([
64
- # doc.page_content for doc in batch
65
- # ])
66
 
67
  # values = self.embedding_client.feature_extraction([
68
  # doc.page_content for doc in batch
69
  # ])
70
- values = None
71
 
72
  # TODO: create a list of unique identifiers for each element in the batch with the uuid package.
73
- vector_ids = None
74
 
75
  # TODO: create a list of dictionaries representing the metadata. Capture the text data
76
  # with the "text" key, and make sure to capture the rest of the doc.metadata.
77
- metadatas = None
 
 
78
 
79
  # create a list of dictionaries with keys "id" (the unique identifiers), "values"
80
  # (the vector representation), and "metadata" (the metadata).
@@ -86,8 +98,8 @@ class DataIndexer:
86
 
87
  try:
88
  # TODO: Use the function upsert to upload the data to the database.
89
- upsert_response = None
90
- print(upsert_response)
91
  except Exception as e:
92
  print(e)
93
 
@@ -103,17 +115,22 @@ class DataIndexer:
103
  # TODO: embed the text_query by using the embedding model
104
  # TODO: choose your embedding model
105
  # vector = self.embedding_client.feature_extraction(text_query)
106
- # vector = self.embedding_client.embed_query(text_query)
107
- vector = None
108
 
109
  # TODO: use the vector representation of the text_query to
110
  # search the database by using the query function.
111
- result = None
 
 
 
 
112
 
113
  docs = []
114
  for res in result["matches"]:
115
  # TODO: From the result's metadata, extract the "text" element.
116
- pass
 
117
 
118
  return docs
119
 
 
5
  from pinecone import ServerlessSpec
6
  from langchain_community.vectorstores import Chroma
7
  from langchain_openai import OpenAIEmbeddings
8
+ from huggingface_hub import InferenceClient
9
 
10
  current_dir = Path(__file__).resolve().parent
11
 
 
17
  def __init__(self, index_name='langchain-repo') -> None:
18
 
19
  # TODO: choose your embedding model
20
+ self.embedding_client = InferenceClient(
21
+ "dunzhang/stella_en_1.5B_v5",
22
+ token=os.environ['HF_TOKEN'],
23
+ )
24
+ self.spec = ServerlessSpec(
25
+ cloud = 'aws',
26
+ region='us-east-1'
27
+ )
28
+ # self.embedding_client = OpenAIEmbeddings()
29
  self.index_name = index_name
30
  self.pinecone_client = Pinecone(api_key=os.environ.get('PINECONE_API_KEY'))
31
 
32
  if index_name not in self.pinecone_client.list_indexes().names():
33
  # TODO: create your index if it doesn't exist. Use the create_index function.
34
  # Make sure to choose the dimension that corresponds to your embedding model
35
+ self.pinecone_client.create_index(
36
+ name=index_name,
37
+ dimension=1024,
38
+ metric='cosine',
39
+ spec=self.spec
40
+ )
41
+
42
  self.index = self.pinecone_client.Index(self.index_name)
43
  # TODO: make sure to build the index.
44
+ self.source_index = self.get_source_index()
45
 
46
  def get_source_index(self):
47
  if not os.path.isfile(self.source_file):
 
70
 
71
  # TODO: create a list of the vector representations of each text data in the batch
72
  # TODO: choose your embedding model
73
+ values = self.embedding_client.embed_documents([
74
+ doc.page_content for doc in batch
75
+ ])
76
 
77
  # values = self.embedding_client.feature_extraction([
78
  # doc.page_content for doc in batch
79
  # ])
80
+ # values = None
81
 
82
  # TODO: create a list of unique identifiers for each element in the batch with the uuid package.
83
+ vector_ids = [uuid.uuid4() for _ in batch]
84
 
85
  # TODO: create a list of dictionaries representing the metadata. Capture the text data
86
  # with the "text" key, and make sure to capture the rest of the doc.metadata.
87
+ metadatas = [{"text": doc.page_content,
88
+ **doc.metadata
89
+ } for doc in batch]
90
 
91
  # create a list of dictionaries with keys "id" (the unique identifiers), "values"
92
  # (the vector representation), and "metadata" (the metadata).
 
98
 
99
  try:
100
  # TODO: Use the function upsert to upload the data to the database.
101
+ upsert_response = self.index.upsert(vectors)
102
+ print(f"successfully indexed batch {upsert_response}")
103
  except Exception as e:
104
  print(e)
105
 
 
115
  # TODO: embed the text_query by using the embedding model
116
  # TODO: choose your embedding model
117
  # vector = self.embedding_client.feature_extraction(text_query)
118
+ vector = self.embedding_client.embed_query(text_query)
119
+ # vector = None
120
 
121
  # TODO: use the vector representation of the text_query to
122
  # search the database by using the query function.
123
+ result = self.index.query(vector,
124
+ filter=filter,
125
+ top_k=top_k,
126
+ include_values=True
127
+ )
128
 
129
  docs = []
130
  for res in result["matches"]:
131
  # TODO: From the result's metadata, extract the "text" element.
132
+ docs.append(res['metadata']['text'])
133
+ # pass
134
 
135
  return docs
136
 
app/Backend/app/database.py → database.py RENAMED
File without changes
app/Backend/app/main.py → main.py RENAMED
@@ -5,13 +5,24 @@ from sse_starlette.sse import EventSourceResponse
5
  from langserve.serialization import WellKnownLCSerializer
6
  from typing import List
7
  from sqlalchemy.orm import Session
 
8
 
9
  import schemas
10
- from chains import simple_chain, formatted_chain
 
 
11
  import crud, models, schemas
12
  from database import SessionLocal, engine
13
  from callbacks import LogResponseCallback
14
 
 
 
 
 
 
 
 
 
15
 
16
  models.Base.metadata.create_all(bind=engine)
17
 
@@ -42,9 +53,18 @@ async def simple_stream(request: Request):
42
  @app.post("/formatted/stream")
43
  async def formatted_stream(request: Request):
44
  # TODO: use the formatted_chain to implement the "/formatted/stream" endpoint.
45
- data = await request.json()
46
- user_question = schemas.UserQuestion(**data['input'])
47
- return EventSourceResponse(generate_stream(user_question,formatted_chain))
 
 
 
 
 
 
 
 
 
48
  # raise NotImplemented
49
 
50
 
@@ -57,7 +77,34 @@ async def history_stream(request: Request, db: Session = Depends(get_db)):
57
  # - We add as part of the user history the current question by using add_message.
58
  # - We create an instance of HistoryInput by using format_chat_history.
59
  # - We use the history input within the history chain.
60
- raise NotImplemented
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
 
63
  @app.post("/rag/stream")
@@ -69,7 +116,27 @@ async def rag_stream(request: Request, db: Session = Depends(get_db)):
69
  # - We add as part of the user history the current question by using add_message.
70
  # - We create an instance of HistoryInput by using format_chat_history.
71
  # - We use the history input within the rag chain.
72
- raise NotImplemented
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
 
75
  @app.post("/filtered_rag/stream")
@@ -81,7 +148,36 @@ async def filtered_rag_stream(request: Request, db: Session = Depends(get_db)):
81
  # - We add as part of the user history the current question by using add_message.
82
  # - We create an instance of HistoryInput by using format_chat_history.
83
  # - We use the history input within the filtered rag chain.
84
- raise NotImplemented
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
 
87
 
 
5
  from langserve.serialization import WellKnownLCSerializer
6
  from typing import List
7
  from sqlalchemy.orm import Session
8
+ from datetime import datetime
9
 
10
  import schemas
11
+ from models import Message
12
+ from chains import simple_chain, formatted_chain, history_chain, rag_chain
13
+ from prompts import format_chat_history
14
  import crud, models, schemas
15
  from database import SessionLocal, engine
16
  from callbacks import LogResponseCallback
17
 
18
+ # temporary
19
+ from database import engine
20
+ import models
21
+
22
+ # drop all tables and recreate
23
+ models.Base.metadata.drop_all(bind=engine)
24
+ models.Base.metadata.create_all(bind=engine)
25
+
26
 
27
  models.Base.metadata.create_all(bind=engine)
28
 
 
53
  @app.post("/formatted/stream")
54
  async def formatted_stream(request: Request):
55
  # TODO: use the formatted_chain to implement the "/formatted/stream" endpoint.
56
+ try:
57
+ data = await request.json()
58
+ user_question = schemas.UserQuestion(**data['input'])
59
+ return EventSourceResponse(
60
+ generate_stream(
61
+ input_data = user_question,
62
+ runnable = formatted_chain )
63
+ )
64
+ except ValueError as e:
65
+ raise HTTPException(status_code=400, detail=str(e))
66
+ except Exception as e:
67
+ raise HTTPException(status_code=500, detail=str(e))
68
  # raise NotImplemented
69
 
70
 
 
77
  # - We add as part of the user history the current question by using add_message.
78
  # - We create an instance of HistoryInput by using format_chat_history.
79
  # - We use the history input within the history chain.
80
+ data = await request.json()
81
+ user_request = schemas.UserRequest(**data['input'])
82
+ # user_data = await crud.get_or_create(db, user_request.username)
83
+ # since history stream means
84
+ # we have existing user's no need to check for a user
85
+ chat_history = crud.get_user_chat_history(db, user_request.username)
86
+ history_input = schemas.HistoryInput(
87
+ chat_history = format_chat_history(chat_history),
88
+ question=user_request.question
89
+ )
90
+
91
+ ## adding messgae to message database
92
+ type = 'Human'
93
+ user_data = crud.get_or_create_user(db, user_request.username)
94
+ user_id = user_data.id
95
+ timestamp = str(datetime.now())
96
+ add_message = schemas.MessageBase(
97
+ user_id = user_id,
98
+ message = user_request.question,
99
+ type = type,
100
+ timestamp = timestamp,
101
+ user=user_request.username,
102
+ )
103
+
104
+ _ = crud.add_message(db,add_message, username = user_request.username)
105
+ # chat history contains: [{ message, type, timestamp}]
106
+ return EventSourceResponse(generate_stream(history_input, history_chain))
107
+ # raise NotImplemented
108
 
109
 
110
  @app.post("/rag/stream")
 
116
  # - We add as part of the user history the current question by using add_message.
117
  # - We create an instance of HistoryInput by using format_chat_history.
118
  # - We use the history input within the rag chain.
119
+ data = await request.json()
120
+ user_request = schemas.UserRequest(**data['input'])
121
+ messages = crud.get_user_chat_history(db, user_request.username)
122
+ chat_history = format_chat_history(messages)
123
+
124
+ history_input = schemas.HistoryInput( chat_history = format_chat_history(chat_history), question=user_request.question)
125
+ ## adding messgae to message database
126
+ type = 'Human'
127
+ user_data = crud.get_or_create_user(db, user_request.username)
128
+ user_id = user_data.id
129
+ timestamp = str(datetime.now())
130
+ add_message = schemas.MessageBase(
131
+ user_id = user_id,
132
+ message = user_request.question,
133
+ type = type,
134
+ timestamp = timestamp
135
+ )
136
+
137
+ _ = crud.add_message(db,add_message, username = user_request.username)
138
+ return EventSourceResponse(generate_stream(history_input, rag_chain))
139
+ # raise NotImplemented
140
 
141
 
142
  @app.post("/filtered_rag/stream")
 
148
  # - We add as part of the user history the current question by using add_message.
149
  # - We create an instance of HistoryInput by using format_chat_history.
150
  # - We use the history input within the filtered rag chain.
151
+ data = await request.json()
152
+ user_request = models.UserRequest(data)
153
+
154
+ messages = db.Query(
155
+ Message.message,
156
+ Message.type,
157
+ Message.timestamp
158
+ ).filter(Message.user_id == user_request.username)
159
+ chat_history = format_chat_history(messages)
160
+
161
+ history_input = schemas.HistoryInput(
162
+ chat_history = format_chat_history(chat_history),
163
+ question=user_request.question
164
+ )
165
+ ## adding messgae to message database
166
+ type = 'Human'
167
+ user_data = crud.get_or_create_user(db, user_request.username)
168
+ user_id = user_data.id
169
+ timestamp = str(datetime.now())
170
+ add_message = schemas.MessageBase(
171
+ user_id = user_id,
172
+ message = user_request.question,
173
+ type = type,
174
+ timestamp = timestamp
175
+ )
176
+
177
+ _ = crud.add_message(db,add_message, username = user_request.username)
178
+
179
+ return EventSourceResponse(generate_stream(history_input, filtered_rag_chain))
180
+ # raise NotImplemented
181
 
182
 
183
 
app/Backend/app/models.py → models.py RENAMED
@@ -3,6 +3,7 @@ from sqlalchemy.orm import relationship
3
 
4
  from database import Base
5
 
 
6
  class User(Base):
7
  __tablename__ = "users"
8
 
@@ -18,4 +19,11 @@ class User(Base):
18
  # attribute as a foreign key.
19
  class Message(Base):
20
  __tablename__ = "messages"
21
- pass
 
 
 
 
 
 
 
 
3
 
4
  from database import Base
5
 
6
+
7
  class User(Base):
8
  __tablename__ = "users"
9
 
 
19
  # attribute as a foreign key.
20
  class Message(Base):
21
  __tablename__ = "messages"
22
+
23
+ id = Column(Integer, primary_key=True, index=True)
24
+ message = Column(String)
25
+ type = Column(String)
26
+ timestamp = Column(DateTime)
27
+ user_id = Column(Integer, ForeignKey('users.id'))
28
+ user = relationship("User",back_populates="messages")
29
+
app/Backend/app/prompts.py → prompts.py RENAMED
@@ -6,15 +6,15 @@ import models
6
  def format_prompt(prompt) -> PromptTemplate:
7
  # TODO: format the input prompt by using the model specific instruction template
8
  template = f"""
9
- <|begin_of_text|><|start_header_id|>system<end_header_id>
10
  You are a helpful assistant.<|eot_id|>
11
  <|start_header_id|>user<|end_header_id|>
12
  {prompt}<|eot_id|>
13
  <|start_header_id|>assistant<|end_header_id|>
14
-
15
  """
 
16
  prompt_template = PromptTemplate(
17
- input_variables=["question"],
18
  template = template
19
  )
20
  # TODO: return a langchain PromptTemplate
@@ -24,39 +24,73 @@ def format_prompt(prompt) -> PromptTemplate:
24
  def format_chat_history(messages: List[models.Message]):
25
  # TODO: implement format_chat_history to format
26
  # the list of Message into a text of chat history.
27
- raise NotImplemented
 
 
 
 
 
 
28
 
29
  def format_context(docs: List[str]):
30
  # TODO: the output of the DataIndexer.search is a list of text,
31
  # so we need to concatenate that list into a text that can fit into
32
  # the rag_prompt_formatted. Implement format_context that takes a
33
  # like of strings and returns the context as one string.
34
- raise NotImplemented
 
 
 
 
 
 
 
35
 
36
  raw_prompt = "{question}"
37
 
38
  # TODO: Create the history_prompt prompt that will capture the question and the conversation history.
39
  # The history_prompt needs a {chat_history} placeholder and a {question} placeholder.
40
- history_prompt: str = None
 
 
 
 
 
 
 
 
 
 
41
 
42
  # TODO: Create the standalone_prompt prompt that will capture the question and the chat history
43
  # to generate a standalone question. It needs a {chat_history} placeholder and a {question} placeholder,
44
- standalone_prompt: str = None
 
 
 
 
 
 
 
45
 
46
  # TODO: Create the rag_prompt that will capture the context and the standalone question to generate
47
  # a final answer to the question.
48
- rag_prompt: str = None
 
 
 
 
49
 
50
  # TODO: create raw_prompt_formatted by using format_prompt
51
  raw_prompt_formatted = format_prompt(raw_prompt)
52
  raw_prompt = PromptTemplate.from_template(raw_prompt)
53
 
54
  # TODO: use format_prompt to create history_prompt_formatted
55
- history_prompt_formatted: PromptTemplate = None
56
  # TODO: use format_prompt to create standalone_prompt_formatted
57
- standalone_prompt_formatted: PromptTemplate = None
58
  # TODO: use format_prompt to create rag_prompt_formatted
59
- rag_prompt_formatted: PromptTemplate = None
60
 
61
 
62
 
 
6
  def format_prompt(prompt) -> PromptTemplate:
7
  # TODO: format the input prompt by using the model specific instruction template
8
  template = f"""
9
+ <|begin_of_text|><|start_header_id|>system<|end_header_id|>
10
  You are a helpful assistant.<|eot_id|>
11
  <|start_header_id|>user<|end_header_id|>
12
  {prompt}<|eot_id|>
13
  <|start_header_id|>assistant<|end_header_id|>
 
14
  """
15
+
16
  prompt_template = PromptTemplate(
17
+ # input_variables=["question"], the variables will be auto detected by langchain package
18
  template = template
19
  )
20
  # TODO: return a langchain PromptTemplate
 
24
  def format_chat_history(messages: List[models.Message]):
25
  # TODO: implement format_chat_history to format
26
  # the list of Message into a text of chat history.
27
+ chat_history = ""
28
+ for msg in messages:
29
+ chat_history += msg['message']
30
+ chat_history += "\n---\n"
31
+ # combined all messages from the list for sending it to the model prompt.
32
+ return chat_history
33
+ # raise NotImplemented
34
 
35
  def format_context(docs: List[str]):
36
  # TODO: the output of the DataIndexer.search is a list of text,
37
  # so we need to concatenate that list into a text that can fit into
38
  # the rag_prompt_formatted. Implement format_context that takes a
39
  # like of strings and returns the context as one string.
40
+ if not docs:
41
+ return ""
42
+ combined_text = ""
43
+ combined_text = "\n\n---\n\n".join(
44
+ doc.strip() for doc in docs if doc.strip()
45
+ )
46
+ # raise NotImplemented
47
+ return combined_text
48
 
49
  raw_prompt = "{question}"
50
 
51
  # TODO: Create the history_prompt prompt that will capture the question and the conversation history.
52
  # The history_prompt needs a {chat_history} placeholder and a {question} placeholder.
53
+ history_prompt: str = """
54
+ Given the following conversation provide a helpful answer to the following up question.
55
+
56
+ Chat History:
57
+
58
+ {chat_history}
59
+
60
+ Follow Up Question: {question}
61
+
62
+ helpful answer:
63
+ """
64
 
65
  # TODO: Create the standalone_prompt prompt that will capture the question and the chat history
66
  # to generate a standalone question. It needs a {chat_history} placeholder and a {question} placeholder,
67
+ standalone_prompt: str = """
68
+ Given the following conversation and a follow up question, rephrase the
69
+ follow up question to be a standalone question, in its original language.
70
+ Chat History:
71
+ {chat_history}
72
+ Follow Up Input: {question}
73
+ Standalone question:
74
+ """
75
 
76
  # TODO: Create the rag_prompt that will capture the context and the standalone question to generate
77
  # a final answer to the question.
78
+ rag_prompt: str = """
79
+ Answer the question based only on the following context:
80
+ {context}
81
+ Question: {standalone_question}
82
+ """
83
 
84
  # TODO: create raw_prompt_formatted by using format_prompt
85
  raw_prompt_formatted = format_prompt(raw_prompt)
86
  raw_prompt = PromptTemplate.from_template(raw_prompt)
87
 
88
  # TODO: use format_prompt to create history_prompt_formatted
89
+ history_prompt_formatted: PromptTemplate = format_prompt(history_prompt)
90
  # TODO: use format_prompt to create standalone_prompt_formatted
91
+ standalone_prompt_formatted: PromptTemplate = format_prompt(standalone_prompt)
92
  # TODO: use format_prompt to create rag_prompt_formatted
93
+ rag_prompt_formatted: PromptTemplate = format_prompt(rag_prompt)
94
 
95
 
96
 
requirements.txt CHANGED
@@ -1,2 +1,109 @@
1
- fastapi
2
- uvicorn[standard]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiohappyeyeballs==2.6.1
2
+ aiohttp==3.12.15
3
+ aiosignal==1.4.0
4
+ altair==5.5.0
5
+ annotated-types==0.7.0
6
+ anyio==4.10.0
7
+ appier==1.34.6
8
+ async-timeout==4.0.3
9
+ attrs==25.3.0
10
+ blinker==1.9.0
11
+ cachetools==5.5.2
12
+ certifi==2025.8.3
13
+ charset-normalizer==3.4.2
14
+ click==8.2.1
15
+ dataclasses-json==0.6.7
16
+ distro==1.9.0
17
+ exceptiongroup==1.3.0
18
+ fastapi==0.116.1
19
+ filelock==3.18.0
20
+ frozenlist==1.7.0
21
+ fsspec==2025.7.0
22
+ gitdb==4.0.12
23
+ GitPython==3.1.45
24
+ google-api==0.1.12
25
+ google-api-core==2.25.1
26
+ google-auth==2.40.3
27
+ google-cloud-core==2.4.3
28
+ googleapis-common-protos==1.70.0
29
+ grpcio==1.74.0
30
+ grpcio-tools==1.74.0
31
+ h11==0.16.0
32
+ hf-xet==1.1.5
33
+ httpcore==1.0.9
34
+ httpx==0.28.1
35
+ httpx-sse==0.4.1
36
+ huggingface-hub==0.34.3
37
+ idna==3.10
38
+ Jinja2==3.1.6
39
+ jiter==0.10.0
40
+ jsonpatch==1.33
41
+ jsonpointer==3.0.0
42
+ jsonschema==4.25.0
43
+ jsonschema-specifications==2025.4.1
44
+ langchain==0.3.27
45
+ langchain-community==0.3.27
46
+ langchain-core==0.3.72
47
+ langchain-huggingface==0.3.1
48
+ langchain-openai==0.3.28
49
+ langchain-text-splitters==0.3.9
50
+ langserve==0.3.1
51
+ langsmith==0.4.11
52
+ MarkupSafe==3.0.2
53
+ marshmallow==3.26.1
54
+ multidict==6.6.3
55
+ mypy_extensions==1.1.0
56
+ narwhals==2.0.1
57
+ numpy==2.2.6
58
+ openai==1.98.0
59
+ orjson==3.11.1
60
+ packaging==24.2
61
+ pandas==2.3.1
62
+ pathlib==1.0.1
63
+ pillow==11.3.0
64
+ pinecone==7.3.0
65
+ pinecone-plugin-assistant==1.7.0
66
+ pinecone-plugin-interface==0.0.7
67
+ propcache==0.3.2
68
+ proto-plus==1.26.1
69
+ protobuf==6.31.1
70
+ pyarrow==21.0.0
71
+ pyasn1==0.6.1
72
+ pyasn1_modules==0.4.2
73
+ pydantic==2.11.7
74
+ pydantic-settings==2.10.1
75
+ pydantic_core==2.33.2
76
+ pydeck==0.9.1
77
+ python-dateutil==2.9.0.post0
78
+ python-dotenv==1.1.1
79
+ pytz==2025.2
80
+ PyYAML==6.0.2
81
+ referencing==0.36.2
82
+ regex==2025.7.34
83
+ requests==2.32.4
84
+ requests-toolbelt==1.0.0
85
+ rpds-py==0.26.0
86
+ rsa==4.9.1
87
+ safetensors==0.5.3
88
+ six==1.17.0
89
+ smmap==5.0.2
90
+ sniffio==1.3.1
91
+ SQLAlchemy==2.0.42
92
+ sse-starlette==3.0.2
93
+ starlette==0.47.2
94
+ streamlit==1.47.1
95
+ tenacity==9.1.2
96
+ tiktoken==0.9.0
97
+ tokenizers==0.21.4
98
+ toml==0.10.2
99
+ tornado==6.5.1
100
+ tqdm==4.67.1
101
+ transformers==4.54.1
102
+ typing-inspect==0.9.0
103
+ typing-inspection==0.4.1
104
+ typing_extensions==4.14.1
105
+ tzdata==2025.2
106
+ urllib3==2.5.0
107
+ uvicorn==0.35.0
108
+ yarl==1.20.1
109
+ zstandard==0.23.0
app/Backend/app/schemas.py → schemas.py RENAMED
@@ -1,4 +1,5 @@
1
  from pydantic.v1 import BaseModel
 
2
 
3
 
4
  class UserQuestion(BaseModel):
@@ -6,14 +7,27 @@ class UserQuestion(BaseModel):
6
 
7
  # TODO: create a HistoryInput data model with a chat_history and question attributes.
8
  class HistoryInput(BaseModel):
9
- pass
 
10
 
11
  # TODO: let's create a UserRequest data model with a question and username attribute.
12
  # This will be used to parse the input request.
13
  class UserRequest(BaseModel):
14
  username: str
 
 
15
 
16
  # TODO: implement MessageBase as a schema mapping from the database model to the
17
  # FastAPI data model. Basically MessageBase should have the same attributes as models.Message
18
  class MessageBase(BaseModel):
19
- pass
 
 
 
 
 
 
 
 
 
 
 
1
  from pydantic.v1 import BaseModel
2
+ from datetime import datetime
3
 
4
 
5
  class UserQuestion(BaseModel):
 
7
 
8
  # TODO: create a HistoryInput data model with a chat_history and question attributes.
9
  class HistoryInput(BaseModel):
10
+ question: str
11
+ chat_history: str
12
 
13
  # TODO: let's create a UserRequest data model with a question and username attribute.
14
  # This will be used to parse the input request.
15
  class UserRequest(BaseModel):
16
  username: str
17
+ question: str
18
+
19
 
20
  # TODO: implement MessageBase as a schema mapping from the database model to the
21
  # FastAPI data model. Basically MessageBase should have the same attributes as models.Message
22
  class MessageBase(BaseModel):
23
+ # id: int
24
+ message: str
25
+ timestamp: datetime
26
+ type: str
27
+ user_id: int
28
+ user: str
29
+
30
+ # created additional
31
+ class RagInput(BaseModel):
32
+ standalone_question: str
33
+ context: str
test.db ADDED
Binary file (24.6 kB). View file