From caec526d75b821efffc7987d4c12d831ca0498b2 Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Tue, 5 Nov 2024 14:26:39 +0700 Subject: [PATCH 1/6] Add support for more LLM models (#186) --- chains.py | 20 ++++++++++++++++++-- env.example | 2 +- pull_model.Dockerfile | 10 +++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/chains.py b/chains.py index 138ced667..926ced7ee 100644 --- a/chains.py +++ b/chains.py @@ -23,6 +23,14 @@ from utils import BaseLogger, extract_title_and_question from langchain_google_genai import GoogleGenerativeAIEmbeddings +AWS_MODELS = ( + "ai21.jamba-instruct-v1:0", + "amazon.titan", + "anthropic.claude", + "cohere.command", + "meta.llama", + "mistral.mi", +) def load_embedding_model(embedding_model_name: str, logger=BaseLogger(), config={}): if embedding_model_name == "ollama": @@ -55,9 +63,9 @@ def load_embedding_model(embedding_model_name: str, logger=BaseLogger(), config= def load_llm(llm_name: str, logger=BaseLogger(), config={}): - if llm_name == "gpt-4": + if llm_name in ["gpt-4", "gpt-4o", "gpt-4-turbo"]: logger.info("LLM: Using GPT-4") - return ChatOpenAI(temperature=0, model_name="gpt-4", streaming=True) + return ChatOpenAI(temperature=0, model_name=llm_name, streaming=True) elif llm_name == "gpt-3.5": logger.info("LLM: Using GPT-3.5") return ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo", streaming=True) @@ -68,6 +76,14 @@ def load_llm(llm_name: str, logger=BaseLogger(), config={}): model_kwargs={"temperature": 0.0, "max_tokens_to_sample": 1024}, streaming=True, ) + elif llm_name.startswith(AWS_MODELS): + logger.info(f"LLM: {llm_name}") + return ChatBedrock( + model_id=llm_name, + model_kwargs={"temperature": 0.0, "max_tokens_to_sample": 1024}, + streaming=True, + ) + elif len(llm_name): logger.info(f"LLM: Using Ollama: {llm_name}") return ChatOllama( diff --git a/env.example b/env.example index 88e33cc33..7d9574f38 100644 --- a/env.example +++ b/env.example @@ -1,7 +1,7 @@ #***************************************************************** # LLM and Embedding Model #***************************************************************** -LLM=llama2 #or any Ollama model tag, gpt-4, gpt-3.5, or claudev2 +LLM=llama2 #or any Ollama model tag, gpt-4 (o or turbo), gpt-3.5, or any bedrock model EMBEDDING_MODEL=sentence_transformer #or google-genai-embedding-001 openai, ollama, or aws #***************************************************************** diff --git a/pull_model.Dockerfile b/pull_model.Dockerfile index e59398f75..b06625f7d 100644 --- a/pull_model.Dockerfile +++ b/pull_model.Dockerfile @@ -15,7 +15,15 @@ COPY < Date: Tue, 11 Mar 2025 15:16:19 +0100 Subject: [PATCH 2/6] Update dependencies (#197) --- api.py | 2 +- bot.py | 2 +- chains.py | 2 +- docker-compose.yml | 2 +- loader.py | 4 +--- pdf_bot.py | 2 +- requirements.txt | 13 +++++++------ 7 files changed, 13 insertions(+), 14 deletions(-) diff --git a/api.py b/api.py index b7e8c9969..854070cf7 100644 --- a/api.py +++ b/api.py @@ -1,6 +1,6 @@ import os -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph from dotenv import load_dotenv from utils import ( create_vector_index, diff --git a/bot.py b/bot.py index 970a1a446..a054b7526 100644 --- a/bot.py +++ b/bot.py @@ -3,7 +3,7 @@ import streamlit as st from streamlit.logger import get_logger from langchain.callbacks.base import BaseCallbackHandler -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph from dotenv import load_dotenv from utils import ( create_vector_index, diff --git a/chains.py b/chains.py index 926ced7ee..5a71d1e5e 100644 --- a/chains.py +++ b/chains.py @@ -8,7 +8,7 @@ from langchain_ollama import ChatOllama from langchain_aws import ChatBedrock -from langchain_community.vectorstores import Neo4jVector +from langchain_neo4j import Neo4jVector from langchain.chains import RetrievalQAWithSourcesChain from langchain.chains.qa_with_sources import load_qa_with_sources_chain diff --git a/docker-compose.yml b/docker-compose.yml index 7dacfd59c..3a1bbc084 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: database: user: neo4j:neo4j - image: neo4j:5.23 + image: neo4j:5.26 ports: - 7687:7687 - 7474:7474 diff --git a/loader.py b/loader.py index a02027996..cf06a7367 100644 --- a/loader.py +++ b/loader.py @@ -1,7 +1,7 @@ import os import requests from dotenv import load_dotenv -from langchain_community.graphs import Neo4jGraph +from langchain_neo4j import Neo4jGraph import streamlit as st from streamlit.logger import get_logger from chains import load_embedding_model @@ -15,8 +15,6 @@ password = os.getenv("NEO4J_PASSWORD") ollama_base_url = os.getenv("OLLAMA_BASE_URL") embedding_model_name = os.getenv("EMBEDDING_MODEL") -# Remapping for Langchain Neo4j integration -os.environ["NEO4J_URL"] = url logger = get_logger(__name__) diff --git a/pdf_bot.py b/pdf_bot.py index fb8f4d461..fbb0a38d8 100644 --- a/pdf_bot.py +++ b/pdf_bot.py @@ -5,7 +5,7 @@ from PyPDF2 import PdfReader from langchain.callbacks.base import BaseCallbackHandler from langchain.text_splitter import RecursiveCharacterTextSplitter -from langchain_community.vectorstores import Neo4jVector +from langchain_neo4j import Neo4jVector from streamlit.logger import get_logger from chains import ( load_embedding_model, diff --git a/requirements.txt b/requirements.txt index 2670d2535..b600754d1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,9 +12,10 @@ sse-starlette boto3 streamlit==1.32.1 # missing from the langchain base image? -langchain-openai==0.2.4 -langchain-community==0.3.3 -langchain-google-genai==2.0.3 -langchain-ollama==0.2.0 -langchain-huggingface==0.1.1 -langchain-aws==0.2.4 +langchain-openai==0.3.8 +langchain-community==0.3.19 +langchain-google-genai==2.0.11 +langchain-ollama==0.2.3 +langchain-huggingface==0.1.2 +langchain-aws==0.2.15 +langchain-neo4j==0.4.0 From 0444f467c600658841580866c4913eaab327b8ec Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Tue, 11 Mar 2025 17:44:17 +0100 Subject: [PATCH 3/6] Update deprecated chains to LCEL (#198) * update chains * Format --- api.py | 9 ++------- bot.py | 8 ++++---- chains.py | 51 +++++++++++++++++++-------------------------------- pdf_bot.py | 28 ++++++++++++++++++++++++---- utils.py | 8 +++++++- 5 files changed, 56 insertions(+), 48 deletions(-) diff --git a/api.py b/api.py index 854070cf7..d05b7d00d 100644 --- a/api.py +++ b/api.py @@ -128,10 +128,7 @@ def qstream(question: Question = Depends()): q = Queue() def cb(): - output_function( - {"question": question.text, "chat_history": []}, - callbacks=[QueueCallback(q)], - ) + output_function.invoke(question.text, config={"callbacks": [QueueCallback(q)]}) def generate(): yield json.dumps({"init": True, "model": llm_name}) @@ -146,9 +143,7 @@ async def ask(question: Question = Depends()): output_function = llm_chain if question.rag: output_function = rag_chain - result = output_function( - {"question": question.text, "chat_history": []}, callbacks=[] - ) + result = output_function.invoke(question.text) return {"result": result["answer"], "model": llm_name} diff --git a/bot.py b/bot.py index a054b7526..4f3cf7fe5 100644 --- a/bot.py +++ b/bot.py @@ -92,10 +92,10 @@ def chat_input(): with st.chat_message("assistant"): st.caption(f"RAG: {name}") stream_handler = StreamHandler(st.empty()) - result = output_function( - {"question": user_input, "chat_history": []}, callbacks=[stream_handler] - )["answer"] - output = result + output = output_function.invoke( + user_input, config={"callbacks": [stream_handler]} + ) + st.session_state[f"user_input"].append(user_input) st.session_state[f"generated"].append(output) st.session_state[f"rag_mode"].append(name) diff --git a/chains.py b/chains.py index 5a71d1e5e..584988224 100644 --- a/chains.py +++ b/chains.py @@ -1,4 +1,3 @@ - from langchain_openai import OpenAIEmbeddings from langchain_ollama import OllamaEmbeddings from langchain_aws import BedrockEmbeddings @@ -10,17 +9,17 @@ from langchain_neo4j import Neo4jVector -from langchain.chains import RetrievalQAWithSourcesChain -from langchain.chains.qa_with_sources import load_qa_with_sources_chain +from langchain_core.runnables import RunnableParallel, RunnablePassthrough +from langchain_core.output_parsers import StrOutputParser from langchain.prompts import ( ChatPromptTemplate, HumanMessagePromptTemplate, - SystemMessagePromptTemplate + SystemMessagePromptTemplate, ) from typing import List, Any -from utils import BaseLogger, extract_title_and_question +from utils import BaseLogger, extract_title_and_question, format_docs from langchain_google_genai import GoogleGenerativeAIEmbeddings AWS_MODELS = ( @@ -32,6 +31,7 @@ "mistral.mi", ) + def load_embedding_model(embedding_model_name: str, logger=BaseLogger(), config={}): if embedding_model_name == "ollama": embeddings = OllamaEmbeddings( @@ -47,10 +47,8 @@ def load_embedding_model(embedding_model_name: str, logger=BaseLogger(), config= embeddings = BedrockEmbeddings() dimension = 1536 logger.info("Embedding: Using AWS") - elif embedding_model_name == "google-genai-embedding-001": - embeddings = GoogleGenerativeAIEmbeddings( - model="models/embedding-001" - ) + elif embedding_model_name == "google-genai-embedding-001": + embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001") dimension = 768 logger.info("Embedding: Using Google Generative AI Embeddings") else: @@ -112,17 +110,8 @@ def configure_llm_only_chain(llm): chat_prompt = ChatPromptTemplate.from_messages( [system_message_prompt, human_message_prompt] ) - - def generate_llm_output( - user_input: str, callbacks: List[Any], prompt=chat_prompt - ) -> str: - chain = prompt | llm - answer = chain.invoke( - {"question": user_input}, config={"callbacks": callbacks} - ).content - return {"answer": answer} - - return generate_llm_output + chain = chat_prompt | llm | StrOutputParser() + return chain def configure_qa_rag_chain(llm, embeddings, embeddings_store_url, username, password): @@ -152,12 +141,6 @@ def configure_qa_rag_chain(llm, embeddings, embeddings_store_url, username, pass ] qa_prompt = ChatPromptTemplate.from_messages(messages) - qa_chain = load_qa_with_sources_chain( - llm, - chain_type="stuff", - prompt=qa_prompt, - ) - # Vector + Knowledge Graph response kg = Neo4jVector.from_existing_index( embedding=embeddings, @@ -183,12 +166,16 @@ def configure_qa_rag_chain(llm, embeddings, embeddings_store_url, username, pass ORDER BY similarity ASC // so that best answers are the last """, ) - - kg_qa = RetrievalQAWithSourcesChain( - combine_documents_chain=qa_chain, - retriever=kg.as_retriever(search_kwargs={"k": 2}), - reduce_k_below_max_tokens=False, - max_tokens_limit=3375, + kg_qa = ( + RunnableParallel( + { + "summaries": kg.as_retriever(search_kwargs={"k": 2}) | format_docs, + "question": RunnablePassthrough(), + } + ) + | qa_prompt + | llm + | StrOutputParser() ) return kg_qa diff --git a/pdf_bot.py b/pdf_bot.py index fbb0a38d8..96acee2cf 100644 --- a/pdf_bot.py +++ b/pdf_bot.py @@ -1,16 +1,19 @@ import os import streamlit as st -from langchain.chains import RetrievalQA from PyPDF2 import PdfReader from langchain.callbacks.base import BaseCallbackHandler from langchain.text_splitter import RecursiveCharacterTextSplitter +from langchain.prompts import ChatPromptTemplate from langchain_neo4j import Neo4jVector from streamlit.logger import get_logger from chains import ( load_embedding_model, load_llm, ) +from langchain_core.runnables import RunnableParallel, RunnablePassthrough +from langchain_core.output_parsers import StrOutputParser +from utils import format_docs # load api key lib from dotenv import load_dotenv @@ -67,6 +70,14 @@ def main(): ) chunks = text_splitter.split_text(text=text) + qa_prompt = ChatPromptTemplate.from_messages( + [ + ( + "human", + "Based on the provided summary: {summaries} \n Answer the following question:{question}", + ) + ] + ) # Store the chunks part in db (vector) vectorstore = Neo4jVector.from_texts( @@ -79,8 +90,17 @@ def main(): node_label="PdfBotChunk", pre_delete_collection=True, # Delete existing PDF data ) - qa = RetrievalQA.from_chain_type( - llm=llm, chain_type="stuff", retriever=vectorstore.as_retriever() + qa = ( + RunnableParallel( + { + "summaries": vectorstore.as_retriever(search_kwargs={"k": 2}) + | format_docs, + "question": RunnablePassthrough(), + } + ) + | qa_prompt + | llm + | StrOutputParser() ) # Accept user questions/query @@ -88,7 +108,7 @@ def main(): if query: stream_handler = StreamHandler(st.empty()) - qa.run(query, callbacks=[stream_handler]) + qa.invoke(query, {"callbacks": [stream_handler]}) if __name__ == "__main__": diff --git a/utils.py b/utils.py index 23ad5b63d..4cd2074f4 100644 --- a/utils.py +++ b/utils.py @@ -32,7 +32,9 @@ def create_vector_index(driver) -> None: driver.query(index_query) except: # Already exists pass - index_query = "CREATE VECTOR INDEX top_answers IF NOT EXISTS FOR (m:Answer) ON m.embedding" + index_query = ( + "CREATE VECTOR INDEX top_answers IF NOT EXISTS FOR (m:Answer) ON m.embedding" + ) try: driver.query(index_query) except: # Already exists @@ -52,3 +54,7 @@ def create_constraints(driver): driver.query( "CREATE CONSTRAINT tag_name IF NOT EXISTS FOR (t:Tag) REQUIRE (t.name) IS UNIQUE" ) + + +def format_docs(docs): + return "\n\n".join(doc.page_content for doc in docs) From 945bb1e5ed5d57597acf51b2e284a0c6d77a5e08 Mon Sep 17 00:00:00 2001 From: Sasha Smith Date: Fri, 27 Jun 2025 00:08:01 +0200 Subject: [PATCH 4/6] Update extensions.json --- front-end/.vscode/extensions.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/front-end/.vscode/extensions.json b/front-end/.vscode/extensions.json index bdef82015..9de591fce 100644 --- a/front-end/.vscode/extensions.json +++ b/front-end/.vscode/extensions.json @@ -1,3 +1,5 @@ + { + "recommendations": ["svelte.svelte-vscode"] } From 6b9f6cfa01d1cd5f48a85b5d7c6b452d17b76e0b Mon Sep 17 00:00:00 2001 From: Sasha Smith Date: Sun, 7 Sep 2025 21:55:36 +0200 Subject: [PATCH 5/6] Add initial IntelliJ IDEA project configuration Added .idea directory files including .gitignore, device streaming cache, module, misc, modules, and VCS configuration to set up the project for development in IntelliJ IDEA. --- .idea/.gitignore | 3 + .idea/caches/deviceStreaming.xml | 848 +++++++++++++++++++++++++++++++ .idea/genai-stack.iml | 9 + .idea/misc.xml | 5 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + 6 files changed, 879 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/caches/deviceStreaming.xml create mode 100644 .idea/genai-stack.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..26d33521a --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml new file mode 100644 index 000000000..528f19ece --- /dev/null +++ b/.idea/caches/deviceStreaming.xml @@ -0,0 +1,848 @@ + + + + + + \ No newline at end of file diff --git a/.idea/genai-stack.iml b/.idea/genai-stack.iml new file mode 100644 index 000000000..d6ebd4805 --- /dev/null +++ b/.idea/genai-stack.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..6e8667213 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..7ba5e54d4 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 2cb4ca321eace246f34eb3eac6c82774436f2c52 Mon Sep 17 00:00:00 2001 From: Sasha Smith Date: Fri, 26 Sep 2025 23:03:06 +0200 Subject: [PATCH 6/6] Update deviceStreaming.xml --- .idea/caches/deviceStreaming.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml index 528f19ece..17b82fc87 100644 --- a/.idea/caches/deviceStreaming.xml +++ b/.idea/caches/deviceStreaming.xml @@ -51,6 +51,18 @@