pmkhanh7890 commited on
Commit
87d7b67
·
1 Parent(s): 19cf5e6

add app.py and key

Browse files
Files changed (2) hide show
  1. ai_configs.py +84 -0
  2. app.py +219 -0
ai_configs.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Author: Khanh Phan
3
+ Date: 2023-04-20
4
+ """
5
+ import os
6
+ import sys
7
+
8
+ # MODEL PARAMETERS: https://platform.openai.com/docs/models/gpt-3-5
9
+ MODEL_NAME = "gpt-3.5-turbo" # Must select from MODEL_NAMES
10
+ MODEL_NAMES = ["gpt-4", "text-davinci-003", "gpt-3.5-turbo"]
11
+ EMBEDDING_MODEL = (
12
+ "text-embedding-ada-002" # OpenAI's best embeddings as of Apr 2023
13
+ )
14
+
15
+ # CHATBOT SERVICE
16
+ SERVICE = "freemind" # Must select from SERVICES
17
+ SERVICES = ["TokyoTechies", "Klever", "Test", "freemind"]
18
+
19
+ # DATA FORMATTING
20
+ DELIMITER_TOKYOTECHIES = "Sub Section:"
21
+ FILE_TYPE = ".txt"
22
+ FILE_ENCODING = "utf-8"
23
+ INTRODUCTION_MESSAGE = (
24
+ f"You are a chatbot of {SERVICE}. "
25
+ f"Use the below articles on the {SERVICE} to answer the subsequent question. " # noqa: E501
26
+ "If an answer cannot be found in the articles, write sorry that I cannot answer your request, please contact our support team for further assistance." # noqa: E501
27
+ r'If an answer is found, add embedding title in this format "[Title](URL)" to the end of an answer and ignore the same title.' # noqa: E501
28
+ )
29
+ SYSTEM_CONTENT = "You answer questions about {SERVICE}"
30
+
31
+ # CALCULATE EMBEDDING PARAMETERS
32
+ MAX_TOKENS = 1600 # maximum tokens for a section
33
+ BATCH_SIZE = 1000 # up to 2048 embedding inputs per request
34
+ TOKEN_BUDGET = 4096 - 500
35
+
36
+ # TRAINING PARAMETERS
37
+ CONTEXT_WINDOW = 4096 # Context window for the LLM.
38
+ NUM_OUTPUTS = 512 # Number of outputs for the LLM.
39
+ CHUNK_OVERLAP_RATIO = 0.1 # Chunk overlap as a ratio of chunk size
40
+ TEMPERATURE = 0.0 # A parameter that controls the “creativity” or
41
+ # randomness of the text generated. A higher temperature (e.g., 0.7)
42
+ # results in more diverse and creative output, while a lower temperature
43
+ # (e.g., 0.2) makes the output more deterministic and focused.
44
+
45
+ sys.path.append(os.path.abspath(os.path.join("..", "data")))
46
+
47
+ # PATH
48
+ if SERVICE in SERVICES:
49
+ if MODEL_NAME in MODEL_NAMES:
50
+ # Path to training files:
51
+ FOLDERPATH_DOCUMENTS = os.path.join(
52
+ "data",
53
+ SERVICE,
54
+ "training_files",
55
+ )
56
+ # Path to model
57
+ FOLDERPATH_INDEXES = os.path.join(
58
+ "models",
59
+ SERVICE,
60
+ MODEL_NAME,
61
+ )
62
+ FILEPATH_EMBEDDINGS = os.path.join(
63
+ "models",
64
+ SERVICE,
65
+ "embeddings",
66
+ f"{SERVICE}.csv",
67
+ )
68
+ # For evaluation
69
+ FOLDERPATH_QUESTION = os.path.join(
70
+ "data",
71
+ SERVICE,
72
+ "evaluation",
73
+ "questions",
74
+ )
75
+ FOLDERPATH_QA = os.path.join(
76
+ "data",
77
+ SERVICE,
78
+ "evaluation",
79
+ "QA_" + MODEL_NAME,
80
+ )
81
+ else:
82
+ raise ValueError("MODEL_NAME must be in MODEL_NAMES")
83
+ else:
84
+ raise ValueError("SERVICE must be in SERVICES")
app.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ast # for converting embeddings saved as strings back to arrays
2
+ import configparser
3
+ import os
4
+ import time
5
+
6
+ import gradio as gr
7
+ import openai # for calling the OpenAI API
8
+ import pandas as pd # for storing text and embeddings data
9
+ import tiktoken # for counting tokens
10
+ from ai_configs import (
11
+ EMBEDDING_MODEL,
12
+ FILEPATH_EMBEDDINGS,
13
+ INTRODUCTION_MESSAGE,
14
+ MODEL_NAME,
15
+ SYSTEM_CONTENT,
16
+ TOKEN_BUDGET,
17
+ )
18
+ from scipy import spatial # for calculating vector similarities for search
19
+
20
+ env = configparser.ConfigParser()
21
+ env.read(".env")
22
+ OPENAI_API_KEY = env["OpenAI"]["OPENAI_KEY_TT"] # huggingface
23
+ openai.api_key = env["OpenAI"]["OPENAI_KEY_TT"] # localhost
24
+
25
+ print(open)
26
+
27
+ model_name = MODEL_NAME
28
+ # Read embbeding file
29
+ embedding_data = pd.read_csv(FILEPATH_EMBEDDINGS)
30
+ # Convert embeddings from CSV str type back to list type
31
+ embedding_data["embedding"] = embedding_data["embedding"].apply(
32
+ ast.literal_eval,
33
+ )
34
+ print("Finished loading embedding data!")
35
+
36
+
37
+ # search function
38
+ def strings_ranked_by_relatedness(
39
+ query: str,
40
+ df: pd.DataFrame,
41
+ relatedness_fn=lambda x, y: 1 - spatial.distance.cosine(x, y),
42
+ top_n: int = 3,
43
+ ) -> tuple[list[str], list[float]]:
44
+ """Returns a list of strings and relatednesses,
45
+ sorted from most related to least.
46
+ """
47
+ query_embedding_response = openai.Embedding.create(
48
+ model=EMBEDDING_MODEL,
49
+ input=query,
50
+ )
51
+ query_embedding = query_embedding_response["data"][0]["embedding"]
52
+ strings_and_relatednesses = [
53
+ (row["text"], relatedness_fn(query_embedding, row["embedding"]))
54
+ for i, row in df.iterrows()
55
+ ]
56
+ strings_and_relatednesses.sort(key=lambda x: x[1], reverse=True)
57
+ strings, relatednesses = zip(*strings_and_relatednesses)
58
+
59
+ return strings[:top_n], relatednesses[:top_n]
60
+
61
+
62
+ def num_tokens(text: str, model: str = MODEL_NAME) -> int:
63
+ """Return the number of tokens in a string."""
64
+ encoding = tiktoken.encoding_for_model(model)
65
+ return len(encoding.encode(text))
66
+
67
+
68
+ def query_message(
69
+ query: str,
70
+ df: pd.DataFrame,
71
+ model: str,
72
+ token_budget: int,
73
+ ) -> str:
74
+ """Return a message for GPT,
75
+ with relevant source texts pulled from a dataframe.
76
+ """
77
+ strings, _ = strings_ranked_by_relatedness(query, df)
78
+
79
+ """ example:
80
+ #strings, relatednesses = strings_ranked_by_relatedness(
81
+ # "what solutions that TT provides?",
82
+ # df,
83
+ # top_n=5,
84
+ # )
85
+ #for string, relatedness in zip(strings, relatednesses):
86
+ # print(f"{relatedness=:.3f}\n{string}\n")
87
+ """
88
+
89
+ question = f"\n\nQuestion: {query}"
90
+ message = INTRODUCTION_MESSAGE
91
+ for string in strings:
92
+ next_article = f"\nTT article section:\n--\n{string}\n--"
93
+ next_article = f"\nFreemind article section:\n--\n{string}\n--"
94
+ if (
95
+ num_tokens(message + next_article + question, model=model)
96
+ > token_budget
97
+ ):
98
+ break
99
+ else:
100
+ message += next_article
101
+ return message + question
102
+
103
+
104
+ def get_response(
105
+ query: str,
106
+ df: pd.DataFrame,
107
+ model: str = MODEL_NAME,
108
+ token_budget: int = TOKEN_BUDGET,
109
+ print_message: bool = False,
110
+ ) -> str:
111
+ """Answers a query using GPT and a dataframe of
112
+ relevant texts and embeddings.
113
+ """
114
+ message = query_message(query, df, model=model, token_budget=token_budget)
115
+
116
+ if print_message:
117
+ print(message)
118
+ messages = [
119
+ {"role": "system", "content": SYSTEM_CONTENT},
120
+ {"role": "user", "content": message},
121
+ ]
122
+
123
+ response = openai.ChatCompletion.create(
124
+ model=model,
125
+ messages=messages,
126
+ temperature=0,
127
+ )
128
+ response_message = response["choices"][0]["message"]["content"]
129
+ print(f'Total used tokens: {response["usage"]["total_tokens"]}')
130
+ return response_message, message
131
+
132
+
133
+ # Code for getting chatbot's response ends here. Below code is for UI only.
134
+ def format_response(responses: dict):
135
+ """
136
+ (Optional) Format one or multiple responses from version(s) of chatbot
137
+
138
+ Parameters:
139
+ responses (dict): chatbot response with the name of model
140
+
141
+ Returns:
142
+ output (str): formatted reponse
143
+ """
144
+ output = ""
145
+ for response in responses:
146
+ output += response + (responses[response]) + "\n\n"
147
+ return output
148
+
149
+
150
+ with gr.Blocks() as chatgpt:
151
+ chatbot = gr.Chatbot(label="Freemind Bot", height=500)
152
+ message = gr.Textbox(
153
+ label="Enter your chat here",
154
+ placeholder="Press enter to send a message",
155
+ show_copy_button=True,
156
+ )
157
+ radio = gr.Radio(
158
+ [
159
+ "Full model (most capable but slow & expensive)",
160
+ "Lite model (Capable but fast & cheap)",
161
+ ],
162
+ label="Choose a chatbot model",
163
+ value="Lite model (Capable but fast & cheap)",
164
+ )
165
+ clear = gr.Button("Clear all chat")
166
+
167
+ def choice_model(choice):
168
+ if choice == "Full model (most capable but slow & expensive)":
169
+ return "gpt-4"
170
+ else:
171
+ return "gpt-3.5-turbo"
172
+
173
+ def get_user_message(user_message, history):
174
+ return "", history + [[user_message, None]]
175
+
176
+ def show_response(history, model):
177
+ message = history[-1][0]
178
+ model = choice_model(model)
179
+ print(f"model: {model}")
180
+ # Get the response from OpenAI
181
+ response, _ = get_response(
182
+ query=message,
183
+ df=embedding_data,
184
+ model=model,
185
+ )
186
+
187
+ # Correct URL
188
+ # I will remove this function after BE/FE fixing this bug
189
+ response = response.replace("help/document/", "wiki/1-")
190
+ response = response.replace(">>", ">")
191
+ print("Q: ", message, "\nA: ", response, "\n")
192
+
193
+ # Format the response
194
+ # responses = {
195
+ # f"[{MODEL_NAME}] → ": response,
196
+ # }
197
+ # response = format_response(responses)
198
+
199
+ history[-1][1] = ""
200
+ for character in response:
201
+ history[-1][1] += character
202
+ time.sleep(0.01)
203
+ yield history
204
+
205
+ message.submit(
206
+ get_user_message,
207
+ [message, chatbot],
208
+ [message, chatbot],
209
+ queue=False,
210
+ ).then(
211
+ show_response,
212
+ [chatbot, radio],
213
+ chatbot,
214
+ )
215
+ clear.click(lambda: None, None, chatbot, queue=False)
216
+
217
+
218
+ chatgpt.queue()
219
+ chatgpt.launch(share=True) # share=True to share the chat publicly