alvinprayuda-pinhome commited on
Commit
e4b5ea4
·
1 Parent(s): 0338c58

feat: update demo to pinsmart revamp

Browse files
Files changed (8) hide show
  1. .env.example +2 -4
  2. app.py +100 -84
  3. config.py +3 -5
  4. poetry.lock +0 -0
  5. prompts.py +68 -0
  6. pyproject.toml +4 -0
  7. requirements.txt +27 -1
  8. schemas.py +0 -77
.env.example CHANGED
@@ -1,4 +1,2 @@
1
- CHAT_RESPONSE_TOKEN="asd"
2
- CHAT_RESPONSE_URL="recombe-url"
3
- CACHE_RESPONSE_TOKEN="asd"
4
- CACHE_RESPONSE_URL="recom-calc-url"
 
1
+ OPENAI_API_KEY=asdasdasd
2
+ ES_URL=asdasdsad
 
 
app.py CHANGED
@@ -1,106 +1,122 @@
1
- from http import HTTPStatus
 
 
 
 
2
 
3
  import gradio as gr
4
- import requests
 
 
 
 
 
 
 
 
5
 
6
  from config import get_settings
7
- from schemas import (
8
- ChatbotQuestionAnswer,
9
- PropertyKnowledgeIndexFAQRequest,
10
- PropertyKnowledgeQuestionWithTokenObject,
11
- PropertyKnowledgeAnswerObject,
 
 
 
 
 
 
 
 
 
 
 
12
  )
13
- import logging
14
-
15
-
16
- def index_faq(chatbot_qa_object: ChatbotQuestionAnswer):
17
- data = PropertyKnowledgeIndexFAQRequest(
18
- question=PropertyKnowledgeQuestionWithTokenObject(
19
- token=chatbot_qa_object.question.token,
20
- content=chatbot_qa_object.question.content,
21
- embedding=chatbot_qa_object.question.embedding,
22
- modelName=chatbot_qa_object.question.model_name,
23
- ),
24
- answer=PropertyKnowledgeAnswerObject(
25
- content=chatbot_qa_object.answer.content,
26
- categories=chatbot_qa_object.answer.categories,
27
- source=chatbot_qa_object.answer.source,
28
- referenceURLs=chatbot_qa_object.answer.reference_urls,
29
- modelName=chatbot_qa_object.answer.model_name,
30
- ),
31
- )
32
 
33
- faq_index_response = requests.post(
34
- get_settings().cache_response_url,
35
- headers={
36
- "Authorization": "Bearer"
37
- f" {get_settings().cache_response_token}",
38
- "Content-Type": "application/json",
39
- },
40
- data=data.model_dump_json(by_alias=True),
41
- )
42
- if faq_index_response.status_code != HTTPStatus.OK:
43
- logging.error(
44
- f"failed to index FAQ, got error on: {faq_index_response.text}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  )
46
 
 
 
 
47
 
48
- def get_prompt_response(message: str):
49
- data = {"question": message}
50
- response = requests.post(
51
- get_settings().chat_response_url,
52
- headers={
53
- "Authorization": "Bearer" f" {get_settings().chat_response_token}",
54
- "Content-Type": "application/json",
55
- },
56
- json=data,
57
- )
58
 
59
- if response.status_code == HTTPStatus.OK:
60
- try:
61
- chatbot_qa_object = ChatbotQuestionAnswer.model_validate(
62
- response.json()["data"]
63
- )
64
- except ValueError as val_err:
65
- logging.error(
66
- f"got value on chatbot response: {response.text},"
67
- f"error message: {val_err}"
68
- )
69
 
70
- return "Terjadi kesalahan, silakan coba kembali"
71
 
72
- except Exception as e:
73
- logging.error(
74
- f"got unknown error on chabot find answer request, error: {e}"
75
- )
76
 
77
- return "Terjadi kesalahan, silakan coba kembali"
78
 
79
- if chatbot_qa_object.question.embedding is not None:
80
- try:
81
- index_faq(chatbot_qa_object)
82
- except Exception as e:
83
- logging.error(f"failed to index FAQ, error: {e}")
 
 
 
 
 
84
 
85
- if len(chatbot_qa_object.answer.reference_urls) > 0:
86
- bot_msg = chatbot_qa_object.answer.content + "\n\n" + "Sumber: \n"
87
 
88
- for source in chatbot_qa_object.answer.reference_urls:
89
- bot_msg = bot_msg + f"- {source}\n"
90
 
91
- return bot_msg
92
 
93
- return chatbot_qa_object.answer.content
94
 
95
- if response.status_code == HTTPStatus.NOT_FOUND:
96
- return "Maaf, saya tidak dapat menemukan jawaban untuk pertanyaan ini."
97
 
98
- logging.error(
99
- f"got status code: {response.status_code}"
100
- f"and error message: {response.text}"
101
- )
 
 
 
 
 
 
 
 
 
102
 
103
- return "Terjadi kesalahan, silakan coba kembali"
104
 
105
 
106
  def chat(message, history):
@@ -124,7 +140,7 @@ with gr.Blocks() as demo:
124
  "
125
  >
126
  <h1 style="font-weight: 900; margin-bottom: 7px; margin-top: 5px;">
127
- PinGPT
128
  </h1>
129
  </div>
130
  </div>"""
@@ -133,7 +149,7 @@ with gr.Blocks() as demo:
133
  with gr.Row():
134
  question = gr.Textbox(
135
  label=(
136
- "Masukkan pertanyaan seputar property (KPR, Take Over KPR,"
137
  " dsb)",
138
  ),
139
  placeholder="Apa dokumen yang diperlukan untuk KPR?",
 
1
+ import json
2
+
3
+ # Suppress all UserWarnings
4
+ import warnings
5
+ from typing import Any
6
 
7
  import gradio as gr
8
+ from langchain.retrievers import ContextualCompressionRetriever
9
+ from langchain.retrievers.document_compressors import LLMChainFilter
10
+ from langchain.schema import StrOutputParser
11
+ from langchain_community.vectorstores.elasticsearch import ElasticsearchStore
12
+ from langchain_core.documents import Document
13
+ from langchain_core.prompts import ChatPromptTemplate
14
+ from langchain_core.runnables import RunnablePassthrough
15
+ from langchain_core.runnables.base import RunnableSerializable
16
+ from langchain_openai import ChatOpenAI, OpenAIEmbeddings
17
 
18
  from config import get_settings
19
+ from prompts import CONTEXT_TEMPLATE, QA_WITH_CONTEXT_PROMPT, SYSTEM_PROMPT
20
+
21
+ warnings.filterwarnings("ignore", category=UserWarning)
22
+
23
+ KNOWLEDGE_BASE_INDEX_NAME = "pinsmart_revamp_prototype"
24
+ EMBEDDING_MODEL = "text-embedding-3-large"
25
+ RAG_LLM_MODEL = "gpt-3.5-turbo-0125"
26
+ NROF_RETRIEVED_CONTEXT = 5
27
+
28
+ ERROR_MESSAGE = "Terjadi kesalahan, silakan coba kembali"
29
+
30
+ # ES only support up to 2048 embedding dimension
31
+ embeddings = OpenAIEmbeddings(
32
+ model=EMBEDDING_MODEL,
33
+ api_key=get_settings().openai_api_key,
34
+ dimensions=2048,
35
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
+ vector_db = ElasticsearchStore(
38
+ es_url=get_settings().es_url,
39
+ index_name=KNOWLEDGE_BASE_INDEX_NAME,
40
+ embedding=embeddings,
41
+ )
42
+
43
+ llm = ChatOpenAI(
44
+ model_name=RAG_LLM_MODEL,
45
+ temperature=0,
46
+ api_key=get_settings().openai_api_key,
47
+ )
48
+
49
+ qa_prompt = ChatPromptTemplate.from_messages(
50
+ [
51
+ ("system", SYSTEM_PROMPT),
52
+ ("human", QA_WITH_CONTEXT_PROMPT),
53
+ ]
54
+ )
55
+
56
+ _filter = LLMChainFilter.from_llm(llm)
57
+ docs_retriever = vector_db.as_retriever(
58
+ search_kwargs={"k": NROF_RETRIEVED_CONTEXT}
59
+ )
60
+
61
+
62
+ def format_contexts(docs: list[Document]) -> str:
63
+ aggregate_context = ""
64
+ for doc in docs:
65
+ context = CONTEXT_TEMPLATE.format(
66
+ source=doc.metadata["document_id"],
67
+ title=doc.metadata["heading_title"],
68
+ content=doc.page_content,
69
  )
70
 
71
+ aggregate_context += context
72
+
73
+ return aggregate_context
74
 
 
 
 
 
 
 
 
 
 
 
75
 
76
+ docs_compression_retriever = ContextualCompressionRetriever(
77
+ base_compressor=_filter, base_retriever=docs_retriever
78
+ )
 
 
 
 
 
 
 
79
 
 
80
 
81
+ def get_end_device_target(*args: Any) -> str:
82
+ return "mobile"
 
 
83
 
 
84
 
85
+ rag_chain: RunnableSerializable = (
86
+ {
87
+ "context": docs_compression_retriever | format_contexts,
88
+ "device": get_end_device_target,
89
+ "question": RunnablePassthrough(),
90
+ }
91
+ | qa_prompt
92
+ | llm
93
+ | StrOutputParser()
94
+ )
95
 
 
 
96
 
97
+ def parse_response(response: str) -> tuple[str, list[dict]]:
98
+ answer = response.split("[ANSWER]")[1].split("[RELATED DOCS]")[0].strip()
99
 
100
+ related_docs = json.loads(response.split("[RELATED DOCS]")[1].strip())
101
 
102
+ return answer, related_docs
103
 
 
 
104
 
105
+ def get_prompt_response(message: str):
106
+ response = rag_chain.invoke(message)
107
+
108
+ try:
109
+ answer, related_docs = parse_response(response)
110
+ except Exception as e:
111
+ print(f"Error : {e}")
112
+ return ERROR_MESSAGE
113
+
114
+ reference_str = "Referensi: \n"
115
+ for doc in related_docs:
116
+ reference_title = doc["title"]
117
+ reference_str += f"- Artikel: {reference_title}\n"
118
 
119
+ return answer + "\n\n" + reference_str
120
 
121
 
122
  def chat(message, history):
 
140
  "
141
  >
142
  <h1 style="font-weight: 900; margin-bottom: 7px; margin-top: 5px;">
143
+ PinSmart Prototype
144
  </h1>
145
  </div>
146
  </div>"""
 
149
  with gr.Row():
150
  question = gr.Textbox(
151
  label=(
152
+ "Masukkan pertanyaan seputar properti (KPR, Take Over KPR,"
153
  " dsb)",
154
  ),
155
  placeholder="Apa dokumen yang diperlukan untuk KPR?",
config.py CHANGED
@@ -4,13 +4,11 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
4
 
5
 
6
  class Settings(BaseSettings):
7
- chat_response_url: str
8
- chat_response_token: str
9
- cache_response_url: str
10
- cache_response_token: str
11
 
12
  model_config = SettingsConfigDict(
13
- env_file=".env", env_file_encoding="utf-8"
14
  )
15
 
16
 
 
4
 
5
 
6
  class Settings(BaseSettings):
7
+ openai_api_key: str
8
+ es_url: str
 
 
9
 
10
  model_config = SettingsConfigDict(
11
+ env_file=".env", env_file_encoding="utf-8", extra="ignore"
12
  )
13
 
14
 
poetry.lock CHANGED
The diff for this file is too large to render. See raw diff
 
prompts.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ SYSTEM_PROMPT = (
2
+ "You are a world class property consultant for Indonesia market recognized"
3
+ " as PinSmart. You work for Pinhome.id and hence cannot mention other "
4
+ "competitor such as rumah.com, rumah123.com, lamudi.id, 99.co, and so on."
5
+ )
6
+ QA_WITH_CONTEXT_PROMPT = """
7
+ ## Instructions
8
+
9
+ - Always generate answer only based on the contexts and facts
10
+ - Take your time to generate the answer and elaborate all the supporting
11
+ details in the answer
12
+ - The generated response MUST use the following format:
13
+ ```
14
+ [ANSWER]
15
+ put the answer here
16
+
17
+ [RELATED DOCS]
18
+ [
19
+ {{
20
+ "source" : "context_source1",
21
+ "title" : "context_title1"
22
+ }},
23
+ {{
24
+ "source" : "context_source2",
25
+ "title" : "context_title2"
26
+ }},
27
+ ...
28
+ ]
29
+ ```
30
+ - Only show [RELATED DOCS] that is exist on the provided context and do
31
+ not show duplicate [RELATED DOCS]
32
+ - Always generate [ANSWER] in Indonesian language
33
+ - Generate the [ANSWER] using the following formatting rules:
34
+ - Must be easy to read and using good structure such as
35
+ bullet and numbering if necessary
36
+ - Use the best string formatting if the [ANSWER] is shown in
37
+ {device} app as chatbot app
38
+
39
+ ## Contexts
40
+ {context}
41
+
42
+ ## Question
43
+ {question}
44
+
45
+ ## Answer
46
+ """
47
+
48
+ CONTEXT_TEMPLATE = """
49
+ ---
50
+ ### Context Metadata
51
+ source: {source}
52
+ title: {title}
53
+
54
+ ### Content
55
+
56
+ {content}
57
+ """
58
+
59
+ CONTEXT_TEMPLATE = """
60
+ ---
61
+ ### Context Metadata
62
+ source: {source}
63
+ title: {title}
64
+
65
+ ### Content
66
+
67
+ {content}
68
+ """
pyproject.toml CHANGED
@@ -10,6 +10,10 @@ packages = []
10
  python = "^3.10"
11
  gradio = { version = "3.44.3", source = "pypi" }
12
  pydantic-settings = { version = "^2.0.3", extras = ["dotenv"], source = "pypi" }
 
 
 
 
13
 
14
 
15
  [tool.ruff]
 
10
  python = "^3.10"
11
  gradio = { version = "3.44.3", source = "pypi" }
12
  pydantic-settings = { version = "^2.0.3", extras = ["dotenv"], source = "pypi" }
13
+ langchain = {version = "^0.1.7", source = "pypi"}
14
+ langchain-openai = {version = "^0.0.6", source = "pypi"}
15
+ tiktoken = {version = "^0.6.0", source = "pypi"}
16
+ elasticsearch = {version = "^8.12.0", source = "pypi"}
17
 
18
 
19
  [tool.ruff]
requirements.txt CHANGED
@@ -1,7 +1,10 @@
1
  aiofiles==23.2.1 ; python_version >= "3.10" and python_version < "4.0"
 
 
2
  altair==5.1.1 ; python_version >= "3.10" and python_version < "4.0"
3
  annotated-types==0.5.0 ; python_version >= "3.10" and python_version < "4.0"
4
  anyio==4.0.0 ; python_version >= "3.10" and python_version < "4.0"
 
5
  attrs==23.1.0 ; python_version >= "3.10" and python_version < "4.0"
6
  certifi==2023.7.22 ; python_version >= "3.10" and python_version < "4.0"
7
  charset-normalizer==3.2.0 ; python_version >= "3.10" and python_version < "4.0"
@@ -9,14 +12,20 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0"
9
  colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows"
10
  contourpy==1.1.1 ; python_version >= "3.10" and python_version < "4.0"
11
  cycler==0.11.0 ; python_version >= "3.10" and python_version < "4.0"
 
 
 
 
12
  exceptiongroup==1.1.3 ; python_version >= "3.10" and python_version < "3.11"
13
  fastapi==0.103.0 ; python_version >= "3.10" and python_version < "4.0"
14
  ffmpy==0.3.1 ; python_version >= "3.10" and python_version < "4.0"
15
  filelock==3.12.4 ; python_version >= "3.10" and python_version < "4.0"
16
  fonttools==4.42.1 ; python_version >= "3.10" and python_version < "4.0"
 
17
  fsspec==2023.9.1 ; python_version >= "3.10" and python_version < "4.0"
18
  gradio-client==0.5.0 ; python_version >= "3.10" and python_version < "4.0"
19
  gradio==3.44.3 ; python_version >= "3.10" and python_version < "4.0"
 
20
  h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0"
21
  httpcore==0.18.0 ; python_version >= "3.10" and python_version < "4.0"
22
  httpx==0.25.0 ; python_version >= "3.10" and python_version < "4.0"
@@ -24,14 +33,25 @@ huggingface-hub==0.17.1 ; python_version >= "3.10" and python_version < "4.0"
24
  idna==3.4 ; python_version >= "3.10" and python_version < "4.0"
25
  importlib-resources==6.0.1 ; python_version >= "3.10" and python_version < "4.0"
26
  jinja2==3.1.2 ; python_version >= "3.10" and python_version < "4.0"
 
 
27
  jsonschema-specifications==2023.7.1 ; python_version >= "3.10" and python_version < "4.0"
28
  jsonschema==4.19.0 ; python_version >= "3.10" and python_version < "4.0"
29
  kiwisolver==1.4.5 ; python_version >= "3.10" and python_version < "4.0"
 
 
 
 
 
30
  markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0"
 
31
  matplotlib==3.8.0 ; python_version >= "3.10" and python_version < "4.0"
 
 
32
  numpy==1.25.2 ; python_version >= "3.10" and python_version < "4.0"
 
33
  orjson==3.9.7 ; python_version >= "3.10" and python_version < "4.0"
34
- packaging==23.1 ; python_version >= "3.10" and python_version < "4.0"
35
  pandas==2.1.0 ; python_version >= "3.10" and python_version < "4.0"
36
  pillow==10.0.1 ; python_version >= "3.10" and python_version < "4.0"
37
  pydantic-core==2.6.3 ; python_version >= "3.10" and python_version < "4.0"
@@ -45,6 +65,7 @@ python-multipart==0.0.6 ; python_version >= "3.10" and python_version < "4.0"
45
  pytz==2023.3.post1 ; python_version >= "3.10" and python_version < "4.0"
46
  pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0"
47
  referencing==0.30.2 ; python_version >= "3.10" and python_version < "4.0"
 
48
  requests==2.31.0 ; python_version >= "3.10" and python_version < "4.0"
49
  rpds-py==0.10.3 ; python_version >= "3.10" and python_version < "4.0"
50
  semantic-version==2.10.0 ; python_version >= "3.10" and python_version < "4.0"
@@ -52,12 +73,17 @@ setuptools-scm==7.1.0 ; python_version >= "3.10" and python_version < "4.0"
52
  setuptools==68.2.2 ; python_version >= "3.10" and python_version < "4.0"
53
  six==1.16.0 ; python_version >= "3.10" and python_version < "4.0"
54
  sniffio==1.3.0 ; python_version >= "3.10" and python_version < "4.0"
 
55
  starlette==0.27.0 ; python_version >= "3.10" and python_version < "4.0"
 
 
56
  tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11"
57
  toolz==0.12.0 ; python_version >= "3.10" and python_version < "4.0"
58
  tqdm==4.66.1 ; python_version >= "3.10" and python_version < "4.0"
59
  typing-extensions==4.7.1 ; python_version >= "3.10" and python_version < "4.0"
 
60
  tzdata==2023.3 ; python_version >= "3.10" and python_version < "4.0"
61
  urllib3==2.0.4 ; python_version >= "3.10" and python_version < "4.0"
62
  uvicorn==0.23.2 ; python_version >= "3.10" and python_version < "4.0"
63
  websockets==11.0.3 ; python_version >= "3.10" and python_version < "4.0"
 
 
1
  aiofiles==23.2.1 ; python_version >= "3.10" and python_version < "4.0"
2
+ aiohttp==3.9.3 ; python_version >= "3.10" and python_version < "4.0"
3
+ aiosignal==1.3.1 ; python_version >= "3.10" and python_version < "4.0"
4
  altair==5.1.1 ; python_version >= "3.10" and python_version < "4.0"
5
  annotated-types==0.5.0 ; python_version >= "3.10" and python_version < "4.0"
6
  anyio==4.0.0 ; python_version >= "3.10" and python_version < "4.0"
7
+ async-timeout==4.0.3 ; python_version >= "3.10" and python_version < "3.11"
8
  attrs==23.1.0 ; python_version >= "3.10" and python_version < "4.0"
9
  certifi==2023.7.22 ; python_version >= "3.10" and python_version < "4.0"
10
  charset-normalizer==3.2.0 ; python_version >= "3.10" and python_version < "4.0"
 
12
  colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows"
13
  contourpy==1.1.1 ; python_version >= "3.10" and python_version < "4.0"
14
  cycler==0.11.0 ; python_version >= "3.10" and python_version < "4.0"
15
+ dataclasses-json==0.6.4 ; python_version >= "3.10" and python_version < "4.0"
16
+ distro==1.9.0 ; python_version >= "3.10" and python_version < "4.0"
17
+ elastic-transport==8.12.0 ; python_version >= "3.10" and python_version < "4.0"
18
+ elasticsearch==8.12.0 ; python_version >= "3.10" and python_version < "4.0"
19
  exceptiongroup==1.1.3 ; python_version >= "3.10" and python_version < "3.11"
20
  fastapi==0.103.0 ; python_version >= "3.10" and python_version < "4.0"
21
  ffmpy==0.3.1 ; python_version >= "3.10" and python_version < "4.0"
22
  filelock==3.12.4 ; python_version >= "3.10" and python_version < "4.0"
23
  fonttools==4.42.1 ; python_version >= "3.10" and python_version < "4.0"
24
+ frozenlist==1.4.1 ; python_version >= "3.10" and python_version < "4.0"
25
  fsspec==2023.9.1 ; python_version >= "3.10" and python_version < "4.0"
26
  gradio-client==0.5.0 ; python_version >= "3.10" and python_version < "4.0"
27
  gradio==3.44.3 ; python_version >= "3.10" and python_version < "4.0"
28
+ greenlet==3.0.3 ; python_version >= "3.10" and python_version < "4.0" and (platform_machine == "win32" or platform_machine == "WIN32" or platform_machine == "AMD64" or platform_machine == "amd64" or platform_machine == "x86_64" or platform_machine == "ppc64le" or platform_machine == "aarch64")
29
  h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0"
30
  httpcore==0.18.0 ; python_version >= "3.10" and python_version < "4.0"
31
  httpx==0.25.0 ; python_version >= "3.10" and python_version < "4.0"
 
33
  idna==3.4 ; python_version >= "3.10" and python_version < "4.0"
34
  importlib-resources==6.0.1 ; python_version >= "3.10" and python_version < "4.0"
35
  jinja2==3.1.2 ; python_version >= "3.10" and python_version < "4.0"
36
+ jsonpatch==1.33 ; python_version >= "3.10" and python_version < "4.0"
37
+ jsonpointer==2.4 ; python_version >= "3.10" and python_version < "4.0"
38
  jsonschema-specifications==2023.7.1 ; python_version >= "3.10" and python_version < "4.0"
39
  jsonschema==4.19.0 ; python_version >= "3.10" and python_version < "4.0"
40
  kiwisolver==1.4.5 ; python_version >= "3.10" and python_version < "4.0"
41
+ langchain-community==0.0.20 ; python_version >= "3.10" and python_version < "4.0"
42
+ langchain-core==0.1.23 ; python_version >= "3.10" and python_version < "4.0"
43
+ langchain-openai==0.0.6 ; python_version >= "3.10" and python_version < "4.0"
44
+ langchain==0.1.7 ; python_version >= "3.10" and python_version < "4.0"
45
+ langsmith==0.0.87 ; python_version >= "3.10" and python_version < "4.0"
46
  markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0"
47
+ marshmallow==3.20.2 ; python_version >= "3.10" and python_version < "4.0"
48
  matplotlib==3.8.0 ; python_version >= "3.10" and python_version < "4.0"
49
+ multidict==6.0.5 ; python_version >= "3.10" and python_version < "4.0"
50
+ mypy-extensions==1.0.0 ; python_version >= "3.10" and python_version < "4.0"
51
  numpy==1.25.2 ; python_version >= "3.10" and python_version < "4.0"
52
+ openai==1.12.0 ; python_version >= "3.10" and python_version < "4.0"
53
  orjson==3.9.7 ; python_version >= "3.10" and python_version < "4.0"
54
+ packaging==23.2 ; python_version >= "3.10" and python_version < "4.0"
55
  pandas==2.1.0 ; python_version >= "3.10" and python_version < "4.0"
56
  pillow==10.0.1 ; python_version >= "3.10" and python_version < "4.0"
57
  pydantic-core==2.6.3 ; python_version >= "3.10" and python_version < "4.0"
 
65
  pytz==2023.3.post1 ; python_version >= "3.10" and python_version < "4.0"
66
  pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0"
67
  referencing==0.30.2 ; python_version >= "3.10" and python_version < "4.0"
68
+ regex==2023.12.25 ; python_version >= "3.10" and python_version < "4.0"
69
  requests==2.31.0 ; python_version >= "3.10" and python_version < "4.0"
70
  rpds-py==0.10.3 ; python_version >= "3.10" and python_version < "4.0"
71
  semantic-version==2.10.0 ; python_version >= "3.10" and python_version < "4.0"
 
73
  setuptools==68.2.2 ; python_version >= "3.10" and python_version < "4.0"
74
  six==1.16.0 ; python_version >= "3.10" and python_version < "4.0"
75
  sniffio==1.3.0 ; python_version >= "3.10" and python_version < "4.0"
76
+ sqlalchemy==2.0.27 ; python_version >= "3.10" and python_version < "4.0"
77
  starlette==0.27.0 ; python_version >= "3.10" and python_version < "4.0"
78
+ tenacity==8.2.3 ; python_version >= "3.10" and python_version < "4.0"
79
+ tiktoken==0.6.0 ; python_version >= "3.10" and python_version < "4.0"
80
  tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11"
81
  toolz==0.12.0 ; python_version >= "3.10" and python_version < "4.0"
82
  tqdm==4.66.1 ; python_version >= "3.10" and python_version < "4.0"
83
  typing-extensions==4.7.1 ; python_version >= "3.10" and python_version < "4.0"
84
+ typing-inspect==0.9.0 ; python_version >= "3.10" and python_version < "4.0"
85
  tzdata==2023.3 ; python_version >= "3.10" and python_version < "4.0"
86
  urllib3==2.0.4 ; python_version >= "3.10" and python_version < "4.0"
87
  uvicorn==0.23.2 ; python_version >= "3.10" and python_version < "4.0"
88
  websockets==11.0.3 ; python_version >= "3.10" and python_version < "4.0"
89
+ yarl==1.9.4 ; python_version >= "3.10" and python_version < "4.0"
schemas.py DELETED
@@ -1,77 +0,0 @@
1
- from typing import Optional
2
- from pydantic import BaseModel, Field, validator
3
- from enum import Enum
4
-
5
-
6
- class ChatbotQuestion(BaseModel):
7
- token: str = Field(..., alias="token")
8
- content: str = Field(..., alias="content")
9
- embedding: Optional[list[float]] = Field(None, alias="embedding")
10
- model_name: str = Field(..., alias="modelName")
11
-
12
-
13
- class ChatbotAnswer(BaseModel):
14
- token: str = Field(..., alias="token")
15
- content: str = Field(..., alias="content")
16
- reference_urls: list[str] = Field(..., alias="referenceURLs")
17
- categories: list[str] = Field(..., alias="categories")
18
- source: str = Field(..., alias="source")
19
- model_name: str = Field(..., alias="modelName")
20
-
21
-
22
- class ChatbotQuestionAnswer(BaseModel):
23
- question: ChatbotQuestion = Field(..., alias="question")
24
- answer: ChatbotAnswer = Field(..., alias="answer")
25
-
26
-
27
- class CategoriesObject(Enum):
28
- property_seekers = "property_seekers"
29
- property_owners = "property_owners"
30
- mortgage = "mortgage"
31
-
32
-
33
- class SourcesObject(Enum):
34
- manual = "manual"
35
- chatbot = "chatbot"
36
- knowledge_docs_unavailable = "knowledge_docs_unavailable"
37
-
38
-
39
- class PropertyKnowledgeAnswerObject(BaseModel):
40
- content: str
41
- categories: list[CategoriesObject] = Field([])
42
- source: SourcesObject
43
- reference_urls: list[str] = Field([], alias="referenceURLs")
44
- model_name: Optional[str] = Field(None, alias="modelName")
45
-
46
- @validator("content")
47
- def validate_answer_content(cls, content: str) -> dict:
48
- if content == "":
49
- raise ValueError("content can't be empty string")
50
-
51
- return content
52
-
53
- @validator("model_name")
54
- def validate_answer_model_name(cls, model_name: str) -> dict:
55
- if model_name is not None and model_name == "":
56
- return None
57
-
58
- return model_name
59
-
60
-
61
- class PropertyKnowledgeQuestionWithTokenObject(BaseModel):
62
- token: Optional[str]
63
- content: str
64
- embedding: Optional[list[float]] = Field([])
65
- model_name: Optional[str] = Field(None, alias="modelName")
66
-
67
- @validator("content")
68
- def validate_question_content(cls, content: str) -> dict:
69
- if content == "":
70
- raise ValueError("content can't be empty string")
71
-
72
- return content
73
-
74
-
75
- class PropertyKnowledgeIndexFAQRequest(BaseModel):
76
- question: PropertyKnowledgeQuestionWithTokenObject
77
- answer: PropertyKnowledgeAnswerObject