Spaces:
Running
Running
Commit
·
ffbd97d
1
Parent(s):
ce282d0
Update app.py
Browse files
README.md
CHANGED
@@ -1,12 +1,15 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
1 |
+
## <h1 align="center" id="heading">An Agentic Bible Study Tool Built with LangChain and LangGraph</h1>
|
2 |
+
|
3 |
+
Create an intelligent Bible study assistant that utilizes LLMs to enhance contextual understanding of scripture. This tool will enable users to pose questions, and the AI will provide answers grounded in the Bible, by accurately identifying and synthesizing information from relevant verses, chapters, and cross-references, promoting deeper comprehension and reducing misinterpretations.
|
4 |
+
|
5 |
+
|
6 |
+
### Phase I
|
7 |
+
- Book of Genesis
|
8 |
+
- Examples of questions:
|
9 |
+
- How did GOD create the whole universe based on Genesis?
|
10 |
+
- Why LORD God make man leave garden?
|
11 |
+
- How did the Israelites, led by Jacob, end up in Egypt, and what role did Joseph play in their settlement there?
|
12 |
+
|
13 |
+
|
14 |
+
## Ship 🚢
|
15 |
+
Check out the prototype at https://huggingface.co/spaces/kcheng0816/BibleStudy
|
app.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
import os
|
2 |
from dotenv import load_dotenv
|
3 |
-
from chainlit.types import AskFileResponse
|
4 |
import chainlit as cl
|
5 |
|
6 |
import pandas as pd
|
7 |
from langchain_community.vectorstores import FAISS
|
|
|
8 |
from langchain_core.documents import Document
|
9 |
from langchain_community.document_loaders import DirectoryLoader
|
10 |
from langchain_community.document_loaders import BSHTMLLoader
|
@@ -25,7 +25,10 @@ from langchain_core.documents import Document
|
|
25 |
from langchain_core.messages import HumanMessage
|
26 |
from langchain_core.tools import tool
|
27 |
from langgraph.prebuilt import ToolNode
|
28 |
-
|
|
|
|
|
|
|
29 |
|
30 |
#Load API Keys
|
31 |
load_dotenv()
|
@@ -35,7 +38,7 @@ path = "data/"
|
|
35 |
loader = DirectoryLoader(path, glob="*.html")
|
36 |
docs = loader.load()
|
37 |
|
38 |
-
#
|
39 |
text_splitter = RecursiveCharacterTextSplitter(
|
40 |
chunk_size = 750,
|
41 |
chunk_overlap = 100
|
@@ -43,9 +46,11 @@ text_splitter = RecursiveCharacterTextSplitter(
|
|
43 |
|
44 |
split_documents = text_splitter.split_documents(docs)
|
45 |
len(split_documents)
|
|
|
46 |
#fine tuned embedding model
|
47 |
huggingface_embeddings = HuggingFaceEmbeddings(model_name="kcheng0816/finetuned_arctic_genesis")
|
48 |
|
|
|
49 |
client = QdrantClient(":memory:")
|
50 |
client.create_collection(
|
51 |
collection_name="genesis_bible",
|
@@ -59,6 +64,7 @@ vector_store = QdrantVectorStore(
|
|
59 |
)
|
60 |
|
61 |
_ = vector_store.add_documents(documents=split_documents)
|
|
|
62 |
#Retrieve
|
63 |
retriever = vector_store.as_retriever(search_kwargs={"k": 5})
|
64 |
|
@@ -71,7 +77,7 @@ def retrieve_adjusted(state):
|
|
71 |
retrieved_docs = compression_retriever.invoke(state["question"])
|
72 |
return {"context" : retrieved_docs}
|
73 |
|
74 |
-
|
75 |
RAG_PROMPT = """\
|
76 |
You are a helpful assistant who answers questions based on provided context. You must only use the provided context, and cannot use your own knowledge.
|
77 |
|
@@ -84,7 +90,7 @@ You are a helpful assistant who answers questions based on provided context. You
|
|
84 |
rag_prompt = ChatPromptTemplate.from_template(RAG_PROMPT)
|
85 |
|
86 |
|
87 |
-
#llm
|
88 |
rate_limiter = InMemoryRateLimiter(
|
89 |
requests_per_second=1, # <-- make a request once every 1 seconds!!
|
90 |
check_every_n_seconds=0.1, # Wake up every 100 ms to check whether allowed to make a request,
|
@@ -99,9 +105,7 @@ def generate(state):
|
|
99 |
response = llm.invoke(messages)
|
100 |
return {"response" : response.content}
|
101 |
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
class State(TypedDict):
|
106 |
question: str
|
107 |
context: List[Document]
|
@@ -112,8 +116,6 @@ graph_builder.add_edge(START, "retrieve_adjusted")
|
|
112 |
graph = graph_builder.compile()
|
113 |
|
114 |
|
115 |
-
|
116 |
-
|
117 |
@tool
|
118 |
def ai_rag_tool(question: str) -> str:
|
119 |
"""Useful for when you need to answer questions about Bible """
|
@@ -127,24 +129,18 @@ tool_belt = [
|
|
127 |
ai_rag_tool
|
128 |
]
|
129 |
|
130 |
-
|
131 |
llm = init_chat_model("gpt-4o", temperature=0, rate_limiter=rate_limiter)
|
132 |
llm_with_tools = llm.bind_tools(tool_belt)
|
133 |
|
134 |
|
135 |
-
from langgraph.graph import END
|
136 |
-
from langchain_core.messages import AnyMessage
|
137 |
-
from langgraph.graph.message import add_messages
|
138 |
-
from typing import TypedDict, Annotated
|
139 |
-
from langchain_core.documents import Document
|
140 |
-
|
141 |
|
|
|
142 |
class AgentState(TypedDict):
|
143 |
messages: Annotated[list[AnyMessage], add_messages]
|
144 |
context:List[Document]
|
145 |
|
146 |
|
147 |
-
|
148 |
def call_mode(state):
|
149 |
messages = state["messages"]
|
150 |
response = llm_with_tools.invoke(messages)
|
@@ -164,7 +160,6 @@ def should_continue(state):
|
|
164 |
return END
|
165 |
|
166 |
|
167 |
-
#
|
168 |
uncompiled_graph = StateGraph(AgentState)
|
169 |
|
170 |
uncompiled_graph.add_node("agent", call_mode)
|
@@ -179,13 +174,11 @@ uncompiled_graph.add_conditional_edges(
|
|
179 |
|
180 |
uncompiled_graph.add_edge("action", "agent")
|
181 |
|
182 |
-
# Compile
|
183 |
compiled_graph = uncompiled_graph.compile()
|
184 |
|
185 |
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
@cl.on_chat_start
|
190 |
async def on_chat_start():
|
191 |
cl.user_session.set("graph", compiled_graph)
|
|
|
1 |
import os
|
2 |
from dotenv import load_dotenv
|
|
|
3 |
import chainlit as cl
|
4 |
|
5 |
import pandas as pd
|
6 |
from langchain_community.vectorstores import FAISS
|
7 |
+
from langchain_openai.embeddings import OpenAIEmbeddings
|
8 |
from langchain_core.documents import Document
|
9 |
from langchain_community.document_loaders import DirectoryLoader
|
10 |
from langchain_community.document_loaders import BSHTMLLoader
|
|
|
25 |
from langchain_core.messages import HumanMessage
|
26 |
from langchain_core.tools import tool
|
27 |
from langgraph.prebuilt import ToolNode
|
28 |
+
from langchain_core.messages import AnyMessage
|
29 |
+
from langgraph.graph.message import add_messages
|
30 |
+
from typing import TypedDict, Annotated
|
31 |
+
from langchain_core.documents import Document
|
32 |
|
33 |
#Load API Keys
|
34 |
load_dotenv()
|
|
|
38 |
loader = DirectoryLoader(path, glob="*.html")
|
39 |
docs = loader.load()
|
40 |
|
41 |
+
#Text Splitter
|
42 |
text_splitter = RecursiveCharacterTextSplitter(
|
43 |
chunk_size = 750,
|
44 |
chunk_overlap = 100
|
|
|
46 |
|
47 |
split_documents = text_splitter.split_documents(docs)
|
48 |
len(split_documents)
|
49 |
+
|
50 |
#fine tuned embedding model
|
51 |
huggingface_embeddings = HuggingFaceEmbeddings(model_name="kcheng0816/finetuned_arctic_genesis")
|
52 |
|
53 |
+
#vector datastore
|
54 |
client = QdrantClient(":memory:")
|
55 |
client.create_collection(
|
56 |
collection_name="genesis_bible",
|
|
|
64 |
)
|
65 |
|
66 |
_ = vector_store.add_documents(documents=split_documents)
|
67 |
+
|
68 |
#Retrieve
|
69 |
retriever = vector_store.as_retriever(search_kwargs={"k": 5})
|
70 |
|
|
|
77 |
retrieved_docs = compression_retriever.invoke(state["question"])
|
78 |
return {"context" : retrieved_docs}
|
79 |
|
80 |
+
#RAG prompt
|
81 |
RAG_PROMPT = """\
|
82 |
You are a helpful assistant who answers questions based on provided context. You must only use the provided context, and cannot use your own knowledge.
|
83 |
|
|
|
90 |
rag_prompt = ChatPromptTemplate.from_template(RAG_PROMPT)
|
91 |
|
92 |
|
93 |
+
#llm for RAG
|
94 |
rate_limiter = InMemoryRateLimiter(
|
95 |
requests_per_second=1, # <-- make a request once every 1 seconds!!
|
96 |
check_every_n_seconds=0.1, # Wake up every 100 ms to check whether allowed to make a request,
|
|
|
105 |
response = llm.invoke(messages)
|
106 |
return {"response" : response.content}
|
107 |
|
108 |
+
#Build RAG graph
|
|
|
|
|
109 |
class State(TypedDict):
|
110 |
question: str
|
111 |
context: List[Document]
|
|
|
116 |
graph = graph_builder.compile()
|
117 |
|
118 |
|
|
|
|
|
119 |
@tool
|
120 |
def ai_rag_tool(question: str) -> str:
|
121 |
"""Useful for when you need to answer questions about Bible """
|
|
|
129 |
ai_rag_tool
|
130 |
]
|
131 |
|
132 |
+
#llm for agent reasoning
|
133 |
llm = init_chat_model("gpt-4o", temperature=0, rate_limiter=rate_limiter)
|
134 |
llm_with_tools = llm.bind_tools(tool_belt)
|
135 |
|
136 |
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
|
138 |
+
#Build an agent graph
|
139 |
class AgentState(TypedDict):
|
140 |
messages: Annotated[list[AnyMessage], add_messages]
|
141 |
context:List[Document]
|
142 |
|
143 |
|
|
|
144 |
def call_mode(state):
|
145 |
messages = state["messages"]
|
146 |
response = llm_with_tools.invoke(messages)
|
|
|
160 |
return END
|
161 |
|
162 |
|
|
|
163 |
uncompiled_graph = StateGraph(AgentState)
|
164 |
|
165 |
uncompiled_graph.add_node("agent", call_mode)
|
|
|
174 |
|
175 |
uncompiled_graph.add_edge("action", "agent")
|
176 |
|
177 |
+
# Compile the graph.
|
178 |
compiled_graph = uncompiled_graph.compile()
|
179 |
|
180 |
|
181 |
+
#user interface
|
|
|
|
|
182 |
@cl.on_chat_start
|
183 |
async def on_chat_start():
|
184 |
cl.user_session.set("graph", compiled_graph)
|