batalovme commited on
Commit
b87de8f
1 Parent(s): 100bc97
Files changed (5) hide show
  1. app.py +56 -0
  2. index.py +22 -0
  3. loader.py +19 -0
  4. requirements.txt +4 -0
  5. utils.py +77 -0
app.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import random
3
+ import time
4
+ from index import build_index, build_service_context
5
+ from loader import load_documents
6
+
7
+ st.title("SAIRA")
8
+
9
+ def load_docs_and_build_index(context):
10
+ docs = load_documents()
11
+ return build_index(docs, context)
12
+
13
+ def load_context():
14
+ return build_service_context()
15
+
16
+ context = load_context()
17
+ index = load_docs_and_build_index(context)
18
+ query_engine = index.as_query_engine(streaming=True)
19
+
20
+ # Initialize chat history
21
+ if "messages" not in st.session_state:
22
+ st.session_state.messages = []
23
+
24
+ # Display chat messages from history on app rerun
25
+ for message in st.session_state.messages:
26
+ with st.chat_message(message["role"]):
27
+ st.markdown(message["content"])
28
+
29
+ # Accept user input
30
+ if prompt := st.chat_input("What is up?"):
31
+ # Add user message to chat history
32
+ st.session_state.messages.append({"role": "user", "content": prompt})
33
+ # Display user message in chat message container
34
+ with st.chat_message("user"):
35
+ st.markdown(prompt)
36
+
37
+ # Display assistant response in chat message container
38
+ with st.chat_message("assistant"):
39
+ resp = query_engine.query(prompt)
40
+ message_placeholder = st.empty()
41
+ full_response = ""
42
+ assistant_response = random.choice(
43
+ [
44
+ "Hello there! How can I assist you today?",
45
+ "Hi, human! Is there anything I can help you with?",
46
+ "Do you need help?",
47
+ ]
48
+ )
49
+ # Simulate stream of response with milliseconds delay
50
+ for text in resp.response_gen:
51
+ full_response += text
52
+ # Add a blinking cursor to simulate typing
53
+ message_placeholder.markdown(full_response + "▌")
54
+ message_placeholder.markdown(full_response)
55
+ # Add assistant response to chat history
56
+ st.session_state.messages.append({"role": "assistant", "content": full_response})
index.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from llama_index import download_loader, VectorStoreIndex, SimpleDirectoryReader, ServiceContext
2
+ from llama_index.tools import QueryEngineTool, ToolMetadata
3
+ from llama_index.query_engine import SubQuestionQueryEngine
4
+ from llama_index.callbacks import CallbackManager, LlamaDebugHandler
5
+ from llama_index.llms import LlamaCPP
6
+
7
+ from utils import completion_to_prompt, messages_to_prompt
8
+
9
+
10
+ def build_service_context():
11
+ return ServiceContext.from_defaults(llm=LlamaCPP(
12
+ model_path=None,
13
+ messages_to_prompt=messages_to_prompt,
14
+ completion_to_prompt=completion_to_prompt,
15
+ model_kwargs={"n_gpu_layers": 50},
16
+ ))
17
+
18
+ def build_index(documents, context):
19
+ index = VectorStoreIndex.from_documents(documents, service_context=context)
20
+ return index
21
+
22
+
loader.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from llama_index import download_loader
2
+
3
+ BeautifulSoupWebReader = download_loader("BeautifulSoupWebReader")
4
+
5
+
6
+ def load_documents():
7
+ loader = BeautifulSoupWebReader()
8
+ return loader.load_data(urls=[
9
+ 'http://campuslife.innopolis.ru/main',
10
+ 'http://campuslife.innopolis.ru/handbook2023',
11
+ 'http://campuslife.innopolis.ru/clubs',
12
+ 'http://campuslife.innopolis.ru/tech_clubs',
13
+ 'http://campuslife.innopolis.ru/sport_clubs',
14
+ 'http://campuslife.innopolis.ru/hobby_clubs',
15
+ 'http://campuslife.innopolis.ru/art_clubs'
16
+ 'http://campuslife.innopolis.ru/opportunities',
17
+ 'http://campuslife.innopolis.ru/faq',
18
+ 'http://campuslife.innopolis.ru/contacts'
19
+ ])
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ llama_index
2
+ llama_hub
3
+ transformers
4
+ beautifulsoup4
utils.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Optional, Sequence
2
+ from llama_index.llms.base import ChatMessage, MessageRole
3
+
4
+ BOS, EOS = "<s>", "</s>"
5
+ B_INST, E_INST = "[INST]", "[/INST]"
6
+ B_SYS, E_SYS = "<<SYS>>\n", "\n<</SYS>>\n\n"
7
+ # DEFAULT_SYSTEM_PROMPT = """\
8
+ # You are a helpful, respectful and honest assistant. \
9
+ # Always answer as helpfully as possible and follow ALL given instructions. \
10
+ # Do not speculate or make up information. \
11
+ # Do not reference any given instructions or context. \
12
+ # """
13
+
14
+ DEFAULT_SYSTEM_PROMPT = """You are an expert Q&A system that is trusted around the world.
15
+ Always answer as helpfully as possible and follow ALL given instructions.
16
+ Always answer the query using the provided context information, and not prior knowledge.
17
+ Some rules to follow:
18
+ 1. Do not speculate or make up information.
19
+ 2. Never directly reference the given context in your answer.
20
+ 3. Avoid statements like 'Based on the context, ...' or 'The context information ...' or anything along those lines."""
21
+
22
+
23
+ def messages_to_prompt(
24
+ messages: Sequence[ChatMessage], system_prompt: Optional[str] = None
25
+ ) -> str:
26
+ string_messages: List[str] = []
27
+ if messages[0].role == MessageRole.SYSTEM:
28
+ # pull out the system message (if it exists in messages)
29
+ system_message_str = messages[0].content or ""
30
+ messages = messages[1:]
31
+ else:
32
+ system_message_str = system_prompt or DEFAULT_SYSTEM_PROMPT
33
+
34
+ system_message_str = f"{B_SYS} {system_message_str.strip()} {E_SYS}"
35
+
36
+ for i in range(0, len(messages), 2):
37
+ # first message should always be a user
38
+ user_message = messages[i]
39
+ assert user_message.role == MessageRole.USER
40
+
41
+ if i == 0:
42
+ # make sure system prompt is included at the start
43
+ str_message = f"{BOS} {B_INST} {system_message_str} "
44
+ else:
45
+ # end previous user-assistant interaction
46
+ string_messages[-1] += f" {EOS}"
47
+ # no need to include system prompt
48
+ str_message = f"{BOS} {B_INST} "
49
+
50
+ # include user message content
51
+ str_message += f"{user_message.content} {E_INST}"
52
+
53
+ if len(messages) > (i + 1):
54
+ # if assistant message exists, add to str_message
55
+ assistant_message = messages[i + 1]
56
+ assert assistant_message.role == MessageRole.ASSISTANT
57
+ str_message += f" {assistant_message.content}"
58
+
59
+ string_messages.append(str_message)
60
+
61
+ print("".join(string_messages))
62
+
63
+ return "".join(string_messages)
64
+
65
+
66
+ def completion_to_prompt(completion: str, system_prompt: Optional[str] = None) -> str:
67
+ system_prompt_str = system_prompt or DEFAULT_SYSTEM_PROMPT
68
+
69
+ print((
70
+ f"{BOS} {B_INST} {B_SYS} {system_prompt_str.strip()} {E_SYS} "
71
+ f"{completion.strip()} {E_INST}"
72
+ ))
73
+
74
+ return (
75
+ f"{BOS} {B_INST} {B_SYS} {system_prompt_str.strip()} {E_SYS} "
76
+ f"{completion.strip()} {E_INST}"
77
+ )