Spaces:
Runtime error
Runtime error
feat: :sparkles: qa gradio ui and coding problem chain (#11)
Browse files- README.md +4 -1
- edu_assistant/learning_cases/__init__.py +0 -0
- edu_assistant/learning_cases/base.py +0 -0
- edu_assistant/learning_cases/context.py +0 -0
- edu_assistant/learning_tasks/qa.py +51 -9
- edu_assistant/utils/langchain_utils.py +33 -10
- edu_assistant/utils/qdrant_utils.py +13 -0
- examples/docs/1. cpp_intro.txt +26 -0
- examples/docs/2. cpp_getting_started.txt +61 -0
- examples/qa.py +2 -1
- examples/qdrant_vs.py +61 -0
- poetry.lock +0 -0
- pyproject.toml +4 -1
- webui/coding_problem.py +4 -0
- webui/qa.py +63 -0
- webui/ui.py +18 -0
README.md
CHANGED
|
@@ -18,9 +18,12 @@
|
|
| 18 |
| AZURE_OPENAI_API_BASE | No | | azure openai api base |
|
| 19 |
| AZURE_OPENAI_DEPLOYMENT_ID | No | | azure openai deployment id for gpt 3.5 |
|
| 20 |
| AZURE_OPENAI_EMBEDDING_DEP_ID | No | | azure openai deployment id for embedding |
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
## setup
|
| 23 |
|
| 24 |
- install python 3.10+
|
| 25 |
- install poetry 1.5.1+
|
| 26 |
-
- run: `poetry install`
|
|
|
|
| 18 |
| AZURE_OPENAI_API_BASE | No | | azure openai api base |
|
| 19 |
| AZURE_OPENAI_DEPLOYMENT_ID | No | | azure openai deployment id for gpt 3.5 |
|
| 20 |
| AZURE_OPENAI_EMBEDDING_DEP_ID | No | | azure openai deployment id for embedding |
|
| 21 |
+
| QDRANT_API | No | | use qdrant api if not blank |
|
| 22 |
+
| QDRANT_API_KEY | No | | qdrant api key |
|
| 23 |
+
| QDRANT_API_BASE | No | | qdrant api base |
|
| 24 |
|
| 25 |
## setup
|
| 26 |
|
| 27 |
- install python 3.10+
|
| 28 |
- install poetry 1.5.1+
|
| 29 |
+
- run: `poetry install --with dev`
|
edu_assistant/learning_cases/__init__.py
DELETED
|
File without changes
|
edu_assistant/learning_cases/base.py
DELETED
|
File without changes
|
edu_assistant/learning_cases/context.py
DELETED
|
File without changes
|
edu_assistant/learning_tasks/qa.py
CHANGED
|
@@ -19,11 +19,29 @@ The ai act following below instructions:
|
|
| 19 |
{instruction}
|
| 20 |
---
|
| 21 |
|
|
|
|
| 22 |
Current conversation:
|
| 23 |
-
{{
|
| 24 |
Human: {{input}}
|
| 25 |
AI:"""
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
TEMPLATE_ONCE = """The following is a friendly conversation between a human and an ai.
|
| 28 |
The ai is talkative and provides lots of specific details from its context.
|
| 29 |
If the ai does not know the answer to a question, it truthfully says it does not know.
|
|
@@ -35,12 +53,29 @@ The ai act following below instructions:
|
|
| 35 |
{{input}}
|
| 36 |
"""
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
class QaTask(BaseTask):
|
| 40 |
_session_store: dict
|
| 41 |
_knowledge: BaseRetriever | None
|
| 42 |
_qa_once: Chain
|
| 43 |
|
|
|
|
|
|
|
| 44 |
def __init__(self, instruction: str = "", knowledge: BaseRetriever = None):
|
| 45 |
"""Create a new QaTask service.
|
| 46 |
|
|
@@ -53,8 +88,16 @@ class QaTask(BaseTask):
|
|
| 53 |
If not set, will use internal memory to store chat history. Which will be lost after restart and might
|
| 54 |
cost huge memory.
|
| 55 |
"""
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
self._session_store = {}
|
| 60 |
self._knowledge = knowledge
|
|
@@ -66,7 +109,6 @@ class QaTask(BaseTask):
|
|
| 66 |
return LLMChain(
|
| 67 |
llm=load_llm(),
|
| 68 |
prompt=self._once_prompt,
|
| 69 |
-
memory=ConversationBufferMemory(),
|
| 70 |
)
|
| 71 |
else:
|
| 72 |
return RetrievalQA.from_llm(
|
|
@@ -80,7 +122,7 @@ class QaTask(BaseTask):
|
|
| 80 |
if not self._knowledge:
|
| 81 |
return ConversationChain(
|
| 82 |
llm=load_llm(),
|
| 83 |
-
memory=ConversationBufferMemory(),
|
| 84 |
prompt=self._chat_prompt,
|
| 85 |
)
|
| 86 |
else:
|
|
@@ -89,8 +131,8 @@ class QaTask(BaseTask):
|
|
| 89 |
retriever=self._knowledge,
|
| 90 |
condense_question_llm=load_llm(),
|
| 91 |
return_source_documents=True,
|
| 92 |
-
combine_docs_chain_kwargs={"prompt":
|
| 93 |
-
memory=ConversationBufferMemory(),
|
| 94 |
)
|
| 95 |
|
| 96 |
def ask(
|
|
@@ -117,14 +159,14 @@ class QaTask(BaseTask):
|
|
| 117 |
"""
|
| 118 |
|
| 119 |
if session:
|
| 120 |
-
args = {
|
| 121 |
if session_id and session_id in self._session_store:
|
| 122 |
chain = self._session_store[session_id]
|
| 123 |
else:
|
| 124 |
session_id = self._create_session_id()
|
| 125 |
chain = self._create_session_chain(session_id)
|
| 126 |
else:
|
| 127 |
-
args = {
|
| 128 |
chain = self._qa_once
|
| 129 |
|
| 130 |
if session_mem:
|
|
|
|
| 19 |
{instruction}
|
| 20 |
---
|
| 21 |
|
| 22 |
+
|
| 23 |
Current conversation:
|
| 24 |
+
{{chat_history}}
|
| 25 |
Human: {{input}}
|
| 26 |
AI:"""
|
| 27 |
|
| 28 |
+
TEMPLATE_CHAT_CONTEXT = """The following is a friendly conversation between a human and an ai.
|
| 29 |
+
The ai is talkative and provides lots of specific details from its context.
|
| 30 |
+
If the ai does not know the answer to a question, it truthfully says it does not know.
|
| 31 |
+
The ai act following below instructions:
|
| 32 |
+
---
|
| 33 |
+
{instruction}
|
| 34 |
+
---
|
| 35 |
+
Useful context for you to answer the question:
|
| 36 |
+
---
|
| 37 |
+
{{context}}
|
| 38 |
+
---
|
| 39 |
+
|
| 40 |
+
Current conversation:
|
| 41 |
+
{{chat_history}}
|
| 42 |
+
Human: {{question}}
|
| 43 |
+
AI:"""
|
| 44 |
+
|
| 45 |
TEMPLATE_ONCE = """The following is a friendly conversation between a human and an ai.
|
| 46 |
The ai is talkative and provides lots of specific details from its context.
|
| 47 |
If the ai does not know the answer to a question, it truthfully says it does not know.
|
|
|
|
| 53 |
{{input}}
|
| 54 |
"""
|
| 55 |
|
| 56 |
+
TEMPLATE_ONCE_CONTEXT = """The following is a friendly conversation between a human and an ai.
|
| 57 |
+
The ai is talkative and provides lots of specific details from its context.
|
| 58 |
+
If the ai does not know the answer to a question, it truthfully says it does not know.
|
| 59 |
+
The ai act following below instructions:
|
| 60 |
+
---
|
| 61 |
+
{instruction}
|
| 62 |
+
---
|
| 63 |
+
Useful context for you to answer the question:
|
| 64 |
+
---
|
| 65 |
+
{{context}}
|
| 66 |
+
---
|
| 67 |
+
|
| 68 |
+
{{input}}
|
| 69 |
+
"""
|
| 70 |
+
|
| 71 |
|
| 72 |
class QaTask(BaseTask):
|
| 73 |
_session_store: dict
|
| 74 |
_knowledge: BaseRetriever | None
|
| 75 |
_qa_once: Chain
|
| 76 |
|
| 77 |
+
HISTORY_KEY = "chat_history"
|
| 78 |
+
|
| 79 |
def __init__(self, instruction: str = "", knowledge: BaseRetriever = None):
|
| 80 |
"""Create a new QaTask service.
|
| 81 |
|
|
|
|
| 88 |
If not set, will use internal memory to store chat history. Which will be lost after restart and might
|
| 89 |
cost huge memory.
|
| 90 |
"""
|
| 91 |
+
if knowledge:
|
| 92 |
+
self._chat_prompt = PromptTemplate.from_template(TEMPLATE_CHAT_CONTEXT.format(instruction=instruction))
|
| 93 |
+
self._once_prompt = PromptTemplate.from_template(TEMPLATE_ONCE_CONTEXT.format(instruction=instruction))
|
| 94 |
+
self._input_key = "question"
|
| 95 |
+
self._output_key = "answer"
|
| 96 |
+
else:
|
| 97 |
+
self._chat_prompt = PromptTemplate.from_template(TEMPLATE_CHAT.format(instruction=instruction))
|
| 98 |
+
self._once_prompt = PromptTemplate.from_template(TEMPLATE_ONCE.format(instruction=instruction))
|
| 99 |
+
self._input_key = "input"
|
| 100 |
+
self._output_key = "response"
|
| 101 |
|
| 102 |
self._session_store = {}
|
| 103 |
self._knowledge = knowledge
|
|
|
|
| 109 |
return LLMChain(
|
| 110 |
llm=load_llm(),
|
| 111 |
prompt=self._once_prompt,
|
|
|
|
| 112 |
)
|
| 113 |
else:
|
| 114 |
return RetrievalQA.from_llm(
|
|
|
|
| 122 |
if not self._knowledge:
|
| 123 |
return ConversationChain(
|
| 124 |
llm=load_llm(),
|
| 125 |
+
memory=ConversationBufferMemory(memory_key=QaTask.HISTORY_KEY, output_key=self._output_key),
|
| 126 |
prompt=self._chat_prompt,
|
| 127 |
)
|
| 128 |
else:
|
|
|
|
| 131 |
retriever=self._knowledge,
|
| 132 |
condense_question_llm=load_llm(),
|
| 133 |
return_source_documents=True,
|
| 134 |
+
combine_docs_chain_kwargs={"prompt": self._chat_prompt},
|
| 135 |
+
memory=ConversationBufferMemory(memory_key=QaTask.HISTORY_KEY, output_key=self._output_key),
|
| 136 |
)
|
| 137 |
|
| 138 |
def ask(
|
|
|
|
| 159 |
"""
|
| 160 |
|
| 161 |
if session:
|
| 162 |
+
args = {self._input_key: question}
|
| 163 |
if session_id and session_id in self._session_store:
|
| 164 |
chain = self._session_store[session_id]
|
| 165 |
else:
|
| 166 |
session_id = self._create_session_id()
|
| 167 |
chain = self._create_session_chain(session_id)
|
| 168 |
else:
|
| 169 |
+
args = {self._input_key: question, QaTask.HISTORY_KEY: ""}
|
| 170 |
chain = self._qa_once
|
| 171 |
|
| 172 |
if session_mem:
|
edu_assistant/utils/langchain_utils.py
CHANGED
|
@@ -3,7 +3,10 @@ from functools import lru_cache
|
|
| 3 |
|
| 4 |
from langchain.chat_models import AzureChatOpenAI, ChatOpenAI
|
| 5 |
from langchain.chat_models.base import BaseChatModel
|
| 6 |
-
from langchain.
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
|
| 9 |
@lru_cache(maxsize=1)
|
|
@@ -28,6 +31,7 @@ def load_llm() -> BaseChatModel:
|
|
| 28 |
return llm
|
| 29 |
|
| 30 |
|
|
|
|
| 31 |
def load_gpt4_llm() -> BaseChatModel:
|
| 32 |
llm = ChatOpenAI(
|
| 33 |
openai_api_key=os.environ.get("OPENAI_API_KEY"),
|
|
@@ -38,13 +42,32 @@ def load_gpt4_llm() -> BaseChatModel:
|
|
| 38 |
return llm
|
| 39 |
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
-
|
| 45 |
-
memory (BaseChatMemory): chat history memory
|
| 46 |
-
question (str): qa question str
|
| 47 |
-
result (str): chain answer result
|
| 48 |
-
"""
|
| 49 |
-
memory.chat_memory.add_user_message(user_text)
|
| 50 |
-
memory.chat_memory.add_ai_message(ai_text)
|
|
|
|
| 3 |
|
| 4 |
from langchain.chat_models import AzureChatOpenAI, ChatOpenAI
|
| 5 |
from langchain.chat_models.base import BaseChatModel
|
| 6 |
+
from langchain.embeddings import OpenAIEmbeddings
|
| 7 |
+
from langchain.vectorstores import Qdrant, VectorStore
|
| 8 |
+
|
| 9 |
+
from edu_assistant.utils.qdrant_utils import load_qdrant_client
|
| 10 |
|
| 11 |
|
| 12 |
@lru_cache(maxsize=1)
|
|
|
|
| 31 |
return llm
|
| 32 |
|
| 33 |
|
| 34 |
+
@lru_cache(maxsize=1)
|
| 35 |
def load_gpt4_llm() -> BaseChatModel:
|
| 36 |
llm = ChatOpenAI(
|
| 37 |
openai_api_key=os.environ.get("OPENAI_API_KEY"),
|
|
|
|
| 42 |
return llm
|
| 43 |
|
| 44 |
|
| 45 |
+
@lru_cache(maxsize=1)
|
| 46 |
+
def load_embeddings():
|
| 47 |
+
if os.environ.get("AZURE_OPENAI"):
|
| 48 |
+
embeddings = OpenAIEmbeddings(
|
| 49 |
+
openai_api_type="azure",
|
| 50 |
+
openai_api_key=os.environ.get("AZURE_OPENAI_API_KEY"),
|
| 51 |
+
openai_api_base=os.environ.get("AZURE_OPENAI_API_BASE"),
|
| 52 |
+
openai_api_version="2023-05-15",
|
| 53 |
+
deployment=os.environ.get("AZURE_OPENAI_EMBEDDING_DEP_ID", ""),
|
| 54 |
+
)
|
| 55 |
+
else:
|
| 56 |
+
embeddings = OpenAIEmbeddings(
|
| 57 |
+
openai_api_key=os.environ.get("OPENAI_API_KEY"),
|
| 58 |
+
openai_proxy=os.environ.get("OPENAI_PROXY", ""),
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
return embeddings
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
@lru_cache(maxsize=10)
|
| 65 |
+
def load_vectorstore(collection_name: str = "default") -> VectorStore:
|
| 66 |
+
if os.environ.get("QDRANT_API"):
|
| 67 |
+
client = load_qdrant_client()
|
| 68 |
+
embeddings = load_embeddings()
|
| 69 |
+
doc_store = Qdrant(client=client, collection_name=collection_name, embeddings=embeddings)
|
| 70 |
+
|
| 71 |
+
return doc_store
|
| 72 |
|
| 73 |
+
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
edu_assistant/utils/qdrant_utils.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from functools import lru_cache
|
| 3 |
+
|
| 4 |
+
from qdrant_client import QdrantClient
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
@lru_cache(maxsize=1)
|
| 8 |
+
def load_qdrant_client():
|
| 9 |
+
qdrant_url = os.environ.get("QDRANT_API_BASE", "")
|
| 10 |
+
qdrant_apikey = os.environ.get("QDRANT_API_KEY", "")
|
| 11 |
+
client = QdrantClient(url=qdrant_url, api_key=qdrant_apikey)
|
| 12 |
+
|
| 13 |
+
return client
|
examples/docs/1. cpp_intro.txt
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
What is C++?
|
| 2 |
+
C++ is a cross-platform language that can be used to create high-performance applications.
|
| 3 |
+
|
| 4 |
+
C++ was developed by Bjarne Stroustrup, as an extension to the C language.
|
| 5 |
+
|
| 6 |
+
C++ gives programmers a high level of control over system resources and memory.
|
| 7 |
+
|
| 8 |
+
The language was updated 4 major times in 2011, 2014, 2017, and 2020 to C++11, C++14, C++17, C++20.
|
| 9 |
+
|
| 10 |
+
Why Use C++
|
| 11 |
+
C++ is one of the world's most popular programming languages.
|
| 12 |
+
|
| 13 |
+
C++ can be found in today's operating systems, Graphical User Interfaces, and embedded systems.
|
| 14 |
+
|
| 15 |
+
C++ is an object-oriented programming language which gives a clear structure to programs and allows code to be reused, lowering development costs.
|
| 16 |
+
|
| 17 |
+
C++ is portable and can be used to develop applications that can be adapted to multiple platforms.
|
| 18 |
+
|
| 19 |
+
C++ is fun and easy to learn!
|
| 20 |
+
|
| 21 |
+
As C++ is close to C, C# and Java, it makes it easy for programmers to switch to C++ or vice versa.
|
| 22 |
+
|
| 23 |
+
Difference between C and C++
|
| 24 |
+
C++ was developed as an extension of C, and both languages have almost the same syntax.
|
| 25 |
+
|
| 26 |
+
The main difference between C and C++ is that C++ support classes and objects, while C does not.
|
examples/docs/2. cpp_getting_started.txt
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
C++ Get Started
|
| 2 |
+
To start using C++, you need two things:
|
| 3 |
+
|
| 4 |
+
A text editor, like Notepad, to write C++ code
|
| 5 |
+
A compiler, like GCC, to translate the C++ code into a language that the computer will understand
|
| 6 |
+
There are many text editors and compilers to choose from. In this tutorial, we will use an IDE (see below).
|
| 7 |
+
|
| 8 |
+
C++ Install IDE
|
| 9 |
+
An IDE (Integrated Development Environment) is used to edit AND compile the code.
|
| 10 |
+
|
| 11 |
+
Popular IDE's include Code::Blocks, Eclipse, and Visual Studio. These are all free, and they can be used to both edit and debug C++ code.
|
| 12 |
+
|
| 13 |
+
Note: Web-based IDE's can work as well, but functionality is limited.
|
| 14 |
+
|
| 15 |
+
We will use Code::Blocks in our tutorial, which we believe is a good place to start.
|
| 16 |
+
|
| 17 |
+
You can find the latest version of Codeblocks at http://www.codeblocks.org/. Download the mingw-setup.exe file, which will install the text editor with a compiler.
|
| 18 |
+
|
| 19 |
+
C++ Quickstart
|
| 20 |
+
Let's create our first C++ file.
|
| 21 |
+
|
| 22 |
+
Open Codeblocks and go to File > New > Empty File.
|
| 23 |
+
|
| 24 |
+
Write the following C++ code and save the file as myfirstprogram.cpp (File > Save File as):
|
| 25 |
+
|
| 26 |
+
myfirstprogram.cpp
|
| 27 |
+
#include <iostream>
|
| 28 |
+
using namespace std;
|
| 29 |
+
|
| 30 |
+
int main() {
|
| 31 |
+
cout << "Hello World!";
|
| 32 |
+
return 0;
|
| 33 |
+
}
|
| 34 |
+
Don't worry if you don't understand the code above - we will discuss it in detail in later chapters. For now, focus on how to run the code.
|
| 35 |
+
|
| 36 |
+
In Codeblocks, it should look like this:
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
Then, go to Build > Build and Run to run (execute) the program. The result will look something to this:
|
| 40 |
+
|
| 41 |
+
Hello World!
|
| 42 |
+
Process returned 0 (0x0) execution time : 0.011 s
|
| 43 |
+
Press any key to continue.
|
| 44 |
+
Congratulations! You have now written and executed your first C++ program.
|
| 45 |
+
|
| 46 |
+
Learning C++ At W3Schools
|
| 47 |
+
When learning C++ at W3Schools.com, you can use our "Try it Yourself" tool, which shows both the code and the result. This will make it easier for you to understand every part as we move forward:
|
| 48 |
+
|
| 49 |
+
myfirstprogram.cpp
|
| 50 |
+
Code:
|
| 51 |
+
|
| 52 |
+
#include <iostream>
|
| 53 |
+
using namespace std;
|
| 54 |
+
|
| 55 |
+
int main() {
|
| 56 |
+
cout << "Hello World!";
|
| 57 |
+
return 0;
|
| 58 |
+
}
|
| 59 |
+
Result:
|
| 60 |
+
|
| 61 |
+
Hello World!
|
examples/qa.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
| 1 |
import json
|
|
|
|
| 2 |
|
| 3 |
from edu_assistant.learning_tasks import QaTask
|
| 4 |
from edu_assistant.utils.common_utils import init_local_logging
|
| 5 |
|
| 6 |
-
init_local_logging()
|
| 7 |
|
| 8 |
|
| 9 |
instruction = """
|
|
|
|
| 1 |
import json
|
| 2 |
+
import logging
|
| 3 |
|
| 4 |
from edu_assistant.learning_tasks import QaTask
|
| 5 |
from edu_assistant.utils.common_utils import init_local_logging
|
| 6 |
|
| 7 |
+
init_local_logging(logging.DEBUG)
|
| 8 |
|
| 9 |
|
| 10 |
instruction = """
|
examples/qdrant_vs.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import logging
|
| 3 |
+
|
| 4 |
+
from fastapi.encoders import jsonable_encoder
|
| 5 |
+
from langchain.chains import RetrievalQA
|
| 6 |
+
from langchain.document_loaders import DirectoryLoader, TextLoader
|
| 7 |
+
from langchain.text_splitter import CharacterTextSplitter
|
| 8 |
+
from qdrant_client.http.models import Distance, VectorParams
|
| 9 |
+
|
| 10 |
+
from edu_assistant.utils.common_utils import init_local_logging
|
| 11 |
+
from edu_assistant.utils.langchain_utils import load_llm, load_vectorstore
|
| 12 |
+
from edu_assistant.utils.qdrant_utils import load_qdrant_client
|
| 13 |
+
|
| 14 |
+
init_local_logging(logging.DEBUG)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def create_collection(collection_name: str):
|
| 18 |
+
client = load_qdrant_client()
|
| 19 |
+
client.recreate_collection(
|
| 20 |
+
collection_name=collection_name,
|
| 21 |
+
vectors_config=VectorParams(size=1536, distance=Distance.DOT),
|
| 22 |
+
)
|
| 23 |
+
collection_info = client.get_collection(collection_name=collection_name)
|
| 24 |
+
print(collection_info)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def delete_collection(collection_name: str):
|
| 28 |
+
client = load_qdrant_client()
|
| 29 |
+
client.delete_collection(collection_name=collection_name)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def add_docs(path: str, collection_name: str):
|
| 33 |
+
vs = load_vectorstore(collection_name=collection_name)
|
| 34 |
+
loader = DirectoryLoader(path=path, glob="*.txt", loader_cls=TextLoader)
|
| 35 |
+
documents = loader.load()
|
| 36 |
+
text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0)
|
| 37 |
+
docs = text_splitter.split_documents(documents)
|
| 38 |
+
|
| 39 |
+
for doc in docs:
|
| 40 |
+
vs.add_documents([doc])
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def qa(collection_name: str, question: str):
|
| 44 |
+
chain = RetrievalQA.from_llm(
|
| 45 |
+
llm=load_llm(),
|
| 46 |
+
retriever=load_vectorstore(collection_name=collection_name).as_retriever(),
|
| 47 |
+
return_source_documents=True,
|
| 48 |
+
)
|
| 49 |
+
result = chain(question)
|
| 50 |
+
print(json.dumps(jsonable_encoder(result), ensure_ascii=False, indent=4))
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
if __name__ == "__main__":
|
| 54 |
+
name = "example"
|
| 55 |
+
path = "examples/docs"
|
| 56 |
+
question = "C和C++的区别是什么?"
|
| 57 |
+
|
| 58 |
+
create_collection(name)
|
| 59 |
+
add_docs(path, name)
|
| 60 |
+
qa(name, question)
|
| 61 |
+
delete_collection(name)
|
poetry.lock
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
pyproject.toml
CHANGED
|
@@ -8,13 +8,16 @@ readme = "README.md"
|
|
| 8 |
packages = [{include = "edu_assistant"}]
|
| 9 |
|
| 10 |
[tool.poetry.dependencies]
|
| 11 |
-
python = "^3.10"
|
| 12 |
fastapi = "^0.95.1"
|
| 13 |
langchain = "^0.0.234"
|
| 14 |
openai = "^0.27.4"
|
| 15 |
pydantic = "^1.10.7"
|
| 16 |
tenacity = "^8.2.2"
|
| 17 |
uvicorn = "^0.21.1"
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
[tool.poetry.group.dev]
|
| 20 |
optional = true
|
|
|
|
| 8 |
packages = [{include = "edu_assistant"}]
|
| 9 |
|
| 10 |
[tool.poetry.dependencies]
|
| 11 |
+
python = "^3.10 <3.12"
|
| 12 |
fastapi = "^0.95.1"
|
| 13 |
langchain = "^0.0.234"
|
| 14 |
openai = "^0.27.4"
|
| 15 |
pydantic = "^1.10.7"
|
| 16 |
tenacity = "^8.2.2"
|
| 17 |
uvicorn = "^0.21.1"
|
| 18 |
+
qdrant-client = "^1.3.1"
|
| 19 |
+
tiktoken = "^0.4.0"
|
| 20 |
+
gradio = "^3.37.0"
|
| 21 |
|
| 22 |
[tool.poetry.group.dev]
|
| 23 |
optional = true
|
webui/coding_problem.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
|
| 3 |
+
with gr.Blocks() as coding_problem_ui:
|
| 4 |
+
pass
|
webui/qa.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from fastapi.encoders import jsonable_encoder
|
| 3 |
+
from langchain.callbacks import get_openai_callback
|
| 4 |
+
|
| 5 |
+
from edu_assistant.learning_tasks.qa import QaTask
|
| 6 |
+
from edu_assistant.utils.langchain_utils import load_vectorstore
|
| 7 |
+
|
| 8 |
+
DEFAULT_INSTRUCTION = """Act as a c++ professional to answer student aged 5-10 questions. Answer properly and politely.
|
| 9 |
+
Don't extend conversation multiple times. Only add one time saying."""
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
task = QaTask(
|
| 13 |
+
instruction=DEFAULT_INSTRUCTION,
|
| 14 |
+
knowledge=load_vectorstore("example").as_retriever(),
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def respond(message, chat_history, session_id):
|
| 19 |
+
with get_openai_callback() as cb:
|
| 20 |
+
if session_id:
|
| 21 |
+
result = task.ask(message, session_id=session_id)
|
| 22 |
+
else:
|
| 23 |
+
result = task.ask(message)
|
| 24 |
+
|
| 25 |
+
session_id = result["session_id"]
|
| 26 |
+
docs = jsonable_encoder(result.get("source_documents", []))
|
| 27 |
+
|
| 28 |
+
bot_message = result["answer"]
|
| 29 |
+
chat_history.append((message, bot_message))
|
| 30 |
+
|
| 31 |
+
status = {"tokens": cb.total_tokens, "cost": f"${cb.total_cost:.4f}"}
|
| 32 |
+
return "", chat_history, session_id, status, docs
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def recreate(instruction):
|
| 36 |
+
global task
|
| 37 |
+
task = QaTask(instruction=instruction, knowledge=load_vectorstore("example").as_retriever())
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
with gr.Blocks() as qa_ui:
|
| 41 |
+
with gr.Row():
|
| 42 |
+
with gr.Column(scale=6):
|
| 43 |
+
with gr.Row():
|
| 44 |
+
chatbot = gr.Chatbot(height=800)
|
| 45 |
+
with gr.Row():
|
| 46 |
+
msg = gr.Textbox()
|
| 47 |
+
with gr.Column(scale=1):
|
| 48 |
+
with gr.Row():
|
| 49 |
+
session_id = gr.Textbox(label="Session", interactive=False, value="")
|
| 50 |
+
with gr.Row():
|
| 51 |
+
telemetry = gr.JSON(value="""{"tokens":0}""", label="Telemetry")
|
| 52 |
+
with gr.Row():
|
| 53 |
+
docs = gr.JSON(value="""["docs"]""", label="Docs")
|
| 54 |
+
with gr.Row():
|
| 55 |
+
clear = gr.ClearButton([msg, chatbot, session_id, telemetry, docs])
|
| 56 |
+
with gr.Row():
|
| 57 |
+
with gr.Column(scale=6):
|
| 58 |
+
instruction = gr.Textbox(label="Instruction", value=DEFAULT_INSTRUCTION, interactive=False)
|
| 59 |
+
with gr.Column(scale=1):
|
| 60 |
+
apply = gr.Button(value="更换Prompt")
|
| 61 |
+
|
| 62 |
+
msg.submit(respond, [msg, chatbot, session_id], [msg, chatbot, session_id, telemetry])
|
| 63 |
+
apply.click(recreate, [instruction], [])
|
webui/ui.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from coding_problem import coding_problem_ui
|
| 3 |
+
from qa import qa_ui
|
| 4 |
+
|
| 5 |
+
from edu_assistant import version
|
| 6 |
+
|
| 7 |
+
with gr.Blocks() as ui:
|
| 8 |
+
with gr.Row():
|
| 9 |
+
gr.Markdown(f" v{version}")
|
| 10 |
+
|
| 11 |
+
with gr.Tab(label="答疑"):
|
| 12 |
+
qa_ui.render()
|
| 13 |
+
|
| 14 |
+
with gr.Tab(label="编程题"):
|
| 15 |
+
coding_problem_ui.render()
|
| 16 |
+
|
| 17 |
+
if __name__ == "__main__":
|
| 18 |
+
ui.launch()
|