Spaces:
Sleeping
Sleeping
Commit ·
14d48df
1
Parent(s): 9c7476c
implement history stream
Browse files- app/callbacks.py +3 -1
- app/chains.py +2 -1
- app/main.py +42 -13
- app/prompts.py +30 -6
app/callbacks.py
CHANGED
|
@@ -15,7 +15,9 @@ 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 |
-
|
|
|
|
|
|
|
| 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 |
+
print(outputs)
|
| 19 |
+
message = schemas.MessageBase(message=outputs.get('text'), type='AI')
|
| 20 |
+
crud.add_message(self.db, message=message, username=self.user_request.username)
|
| 21 |
|
| 22 |
def on_llm_start(
|
| 23 |
self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
|
app/chains.py
CHANGED
|
@@ -9,6 +9,7 @@ import schemas
|
|
| 9 |
from prompts import (
|
| 10 |
raw_prompt,
|
| 11 |
raw_prompt_formatted,
|
|
|
|
| 12 |
format_context,
|
| 13 |
tokenizer
|
| 14 |
)
|
|
@@ -34,7 +35,7 @@ simple_chain = (raw_prompt | llm).with_types(input_type=schemas.UserQuestion)
|
|
| 34 |
formatted_chain = (raw_prompt_formatted | llm).with_types(input_type=schemas.UserQuestion)
|
| 35 |
|
| 36 |
# # TODO: use history_prompt_formatted and HistoryInput to create the history_chain
|
| 37 |
-
|
| 38 |
|
| 39 |
# # TODO: Let's construct the standalone_chain by piping standalone_prompt_formatted with the LLM
|
| 40 |
# standalone_chain = None
|
|
|
|
| 9 |
from prompts import (
|
| 10 |
raw_prompt,
|
| 11 |
raw_prompt_formatted,
|
| 12 |
+
history_prompt_formatted,
|
| 13 |
format_context,
|
| 14 |
tokenizer
|
| 15 |
)
|
|
|
|
| 35 |
formatted_chain = (raw_prompt_formatted | llm).with_types(input_type=schemas.UserQuestion)
|
| 36 |
|
| 37 |
# # TODO: use history_prompt_formatted and HistoryInput to create the history_chain
|
| 38 |
+
history_chain = (history_prompt_formatted | llm).with_types(input_type=schemas.HistoryInput)
|
| 39 |
|
| 40 |
# # TODO: Let's construct the standalone_chain by piping standalone_prompt_formatted with the LLM
|
| 41 |
# standalone_chain = None
|
app/main.py
CHANGED
|
@@ -10,18 +10,32 @@ from typing import List
|
|
| 10 |
from sqlalchemy.orm import Session
|
| 11 |
|
| 12 |
import schemas
|
| 13 |
-
from chains import simple_chain, formatted_chain
|
| 14 |
-
import crud, models, schemas
|
| 15 |
from database import SessionLocal, engine
|
| 16 |
from callbacks import LogResponseCallback
|
| 17 |
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
models.Base.metadata.create_all(bind=engine)
|
| 20 |
|
| 21 |
app = FastAPI()
|
| 22 |
|
| 23 |
def get_db():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
db = SessionLocal()
|
|
|
|
|
|
|
|
|
|
| 25 |
try:
|
| 26 |
yield db
|
| 27 |
finally:
|
|
@@ -71,16 +85,31 @@ async def formatted_stream(request: Request):
|
|
| 71 |
return EventSourceResponse(generate_stream(user_question, formatted_chain))
|
| 72 |
|
| 73 |
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
#
|
| 77 |
-
#
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
#
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
|
| 86 |
# @app.post("/rag/stream")
|
|
|
|
| 10 |
from sqlalchemy.orm import Session
|
| 11 |
|
| 12 |
import schemas
|
| 13 |
+
from chains import simple_chain, formatted_chain, history_chain
|
| 14 |
+
import crud, models, schemas, prompts
|
| 15 |
from database import SessionLocal, engine
|
| 16 |
from callbacks import LogResponseCallback
|
| 17 |
|
| 18 |
+
# models.Base comes from SQLAlchemy’s declarative_base() in database.py.
|
| 19 |
+
# It acts as the base class for all ORM models (defined in models.py).
|
| 20 |
+
# .metadata.create_all(): Tells SQLAlchemy to create all the tables defined
|
| 21 |
+
# in the models module if they don’t already exist in the database.
|
| 22 |
+
# -> metadata is a catalog of all the tables and other schema constructs in your database.
|
| 23 |
+
# -> create_all() method creates all the tables that don't exist yet in the database.
|
| 24 |
+
# -> bind=engine specifies which database engine to use for this operation.
|
| 25 |
models.Base.metadata.create_all(bind=engine)
|
| 26 |
|
| 27 |
app = FastAPI()
|
| 28 |
|
| 29 |
def get_db():
|
| 30 |
+
"""This is a dependency function used to create and provide a
|
| 31 |
+
database session to various endpoints in the FastAPI app.
|
| 32 |
+
"""
|
| 33 |
+
# A new SQLAlchemy session is created using the SessionLocal session factory.
|
| 34 |
+
# This session will be used for database transactions.
|
| 35 |
db = SessionLocal()
|
| 36 |
+
|
| 37 |
+
# This pattern ensures that each request gets its own database session and that
|
| 38 |
+
# the session is properly closed when the request is finished, preventing resource leaks.
|
| 39 |
try:
|
| 40 |
yield db
|
| 41 |
finally:
|
|
|
|
| 85 |
return EventSourceResponse(generate_stream(user_question, formatted_chain))
|
| 86 |
|
| 87 |
|
| 88 |
+
@app.post("/history/stream")
|
| 89 |
+
async def history_stream(request: Request, db: Session = Depends(get_db)):
|
| 90 |
+
# TODO: Let's implement the "/history/stream" endpoint. The endpoint should follow those steps:
|
| 91 |
+
# - The endpoint receives the request
|
| 92 |
+
data = await request.json()
|
| 93 |
+
|
| 94 |
+
# - The request is parsed into a user request
|
| 95 |
+
user_request = schemas.UserRequest(**data['input'])
|
| 96 |
+
|
| 97 |
+
# - The user request is used to pull the chat history of the user
|
| 98 |
+
chat_history = crud.get_user_chat_history(db=db, username=user_request.username)
|
| 99 |
+
|
| 100 |
+
# - We add as part of the user history the current question by using add_message.
|
| 101 |
+
message = schemas.MessageBase(message=user_request.question, type='User')
|
| 102 |
+
crud.add_message(db, message=message, username=user_request.username)
|
| 103 |
+
|
| 104 |
+
# - We create an instance of HistoryInput by using format_chat_history.
|
| 105 |
+
history_input = schemas.HistoryInput(question=user_request.username, chat_history=chat_history)
|
| 106 |
+
|
| 107 |
+
# - We use the history input within the history chain.
|
| 108 |
+
return EventSourceResponse(generate_stream(
|
| 109 |
+
history_input, history_chain, [LogResponseCallback(user_request, db)]
|
| 110 |
+
))
|
| 111 |
+
|
| 112 |
+
|
| 113 |
|
| 114 |
|
| 115 |
# @app.post("/rag/stream")
|
app/prompts.py
CHANGED
|
@@ -36,7 +36,14 @@ def format_prompt(prompt) -> PromptTemplate:
|
|
| 36 |
def format_chat_history(messages: List[models.Message]):
|
| 37 |
# TODO: implement format_chat_history to format
|
| 38 |
# the list of Message into a text of chat history.
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
|
| 42 |
def format_context(docs: List[str]):
|
|
@@ -46,11 +53,20 @@ def format_context(docs: List[str]):
|
|
| 46 |
# like of strings and returns the context as one string.
|
| 47 |
raise NotImplemented
|
| 48 |
|
| 49 |
-
|
| 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 |
|
| 55 |
# TODO: Create the standalone_prompt prompt that will capture the question and the chat history
|
| 56 |
# to generate a standalone question. It needs a {chat_history} placeholder and a {question} placeholder,
|
|
@@ -61,11 +77,19 @@ standalone_prompt: str = None
|
|
| 61 |
rag_prompt: str = None
|
| 62 |
|
| 63 |
# TODO: create raw_prompt_formatted by using format_prompt
|
| 64 |
-
raw_prompt_formatted = format_prompt(raw_prompt)
|
| 65 |
-
raw_prompt = PromptTemplate.from_template(raw_prompt)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
# TODO: use format_prompt to create history_prompt_formatted
|
| 68 |
-
history_prompt_formatted
|
|
|
|
| 69 |
# TODO: use format_prompt to create standalone_prompt_formatted
|
| 70 |
standalone_prompt_formatted: PromptTemplate = None
|
| 71 |
# TODO: use format_prompt to create rag_prompt_formatted
|
|
|
|
| 36 |
def format_chat_history(messages: List[models.Message]):
|
| 37 |
# TODO: implement format_chat_history to format
|
| 38 |
# the list of Message into a text of chat history.
|
| 39 |
+
|
| 40 |
+
return '\n'.join([
|
| 41 |
+
'[{}] {}: {}'.format(
|
| 42 |
+
message.timestamp.strftime("%Y-%m-%d %H:%M:%S"),
|
| 43 |
+
message.type,
|
| 44 |
+
message.message
|
| 45 |
+
) for message in messages
|
| 46 |
+
])
|
| 47 |
|
| 48 |
|
| 49 |
def format_context(docs: List[str]):
|
|
|
|
| 53 |
# like of strings and returns the context as one string.
|
| 54 |
raise NotImplemented
|
| 55 |
|
| 56 |
+
prompt = "{question}"
|
| 57 |
|
| 58 |
# TODO: Create the history_prompt prompt that will capture the question and the conversation history.
|
| 59 |
# The history_prompt needs a {chat_history} placeholder and a {question} placeholder.
|
| 60 |
+
history_prompt: str = """
|
| 61 |
+
Given the follwoing conversation provide a helpful answer to the follow up question.
|
| 62 |
+
|
| 63 |
+
Chat History:
|
| 64 |
+
{chat_history}
|
| 65 |
+
|
| 66 |
+
Follow Up Question: {question}
|
| 67 |
+
|
| 68 |
+
helpful answer:
|
| 69 |
+
"""
|
| 70 |
|
| 71 |
# TODO: Create the standalone_prompt prompt that will capture the question and the chat history
|
| 72 |
# to generate a standalone question. It needs a {chat_history} placeholder and a {question} placeholder,
|
|
|
|
| 77 |
rag_prompt: str = None
|
| 78 |
|
| 79 |
# TODO: create raw_prompt_formatted by using format_prompt
|
| 80 |
+
#raw_prompt_formatted = format_prompt(raw_prompt)
|
| 81 |
+
#raw_prompt = PromptTemplate.from_template(raw_prompt)
|
| 82 |
+
|
| 83 |
+
# i) raw prompt
|
| 84 |
+
raw_prompt = PromptTemplate.from_template(prompt)
|
| 85 |
+
|
| 86 |
+
# ii) formatted prompt
|
| 87 |
+
raw_prompt_formatted = format_prompt(prompt)
|
| 88 |
+
|
| 89 |
|
| 90 |
# TODO: use format_prompt to create history_prompt_formatted
|
| 91 |
+
history_prompt_formatted = format_prompt(history_prompt)
|
| 92 |
+
|
| 93 |
# TODO: use format_prompt to create standalone_prompt_formatted
|
| 94 |
standalone_prompt_formatted: PromptTemplate = None
|
| 95 |
# TODO: use format_prompt to create rag_prompt_formatted
|