zhangjf commited on
Commit
ebc603b
1 Parent(s): f15231e

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +216 -0
  2. qas.json +10 -0
  3. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import openai
2
+ import tiktoken
3
+
4
+ import numpy as np
5
+ import concurrent
6
+ import collections
7
+ import threading
8
+ import datetime
9
+ import time
10
+ import pytz
11
+ import json
12
+ import os
13
+
14
+ openai.api_key = os.getenv('API_KEY')
15
+
16
+ timezone = pytz.timezone('Asia/Shanghai')
17
+ timestamp2string = lambda timestamp: datetime.datetime.fromtimestamp(timestamp).astimezone(timezone).strftime('%Y-%m-%d %H:%M:%S')
18
+
19
+ def num_tokens_from_messages(messages, model="gpt-3.5-turbo"):
20
+ """Returns the number of tokens used by a list of messages."""
21
+ try:
22
+ encoding = tiktoken.encoding_for_model(model)
23
+ except KeyError:
24
+ encoding = tiktoken.get_encoding("cl100k_base")
25
+ if model == "gpt-3.5-turbo": # note: future models may deviate from this
26
+ num_tokens = 0
27
+ len_values = 0
28
+ for message in messages:
29
+ num_tokens += 4 # every message follows <im_start>{role/name}\n{content}<im_end>\n
30
+ for key, value in message.items():
31
+ try:
32
+ num_tokens += len(encoding.encode(value))
33
+ except:
34
+ num_tokens += int(num_tokens/len_values*len(value)) # linear estimation
35
+ len_values += len(value)
36
+ if key == "name": # if there's a name, the role is omitted
37
+ num_tokens += -1 # role is always required and always 1 token
38
+ num_tokens += 2 # every reply is primed with <im_start>assistant
39
+ return num_tokens
40
+ else:
41
+ raise NotImplementedError(f"""num_tokens_from_messages() is not presently implemented for model {model}.
42
+ See https://github.com/openai/openai-python/blob/main/chatml.md for information on how messages are converted to tokens.""")
43
+
44
+
45
+ def read_tasks():
46
+ with open(f"qas.json", "r", encoding="utf-8") as f:
47
+ qas = json.loads(f.read())
48
+ qs = [{"q":qa["q"], "a":qa["a"]} for qa in qas if qa["a"] is None] # 还未请求处理的queries
49
+ qas = [{"q":qa["q"], "a":qa["a"]} for qa in qas if qa["a"] is not None] # 已经完成请求处理的queries
50
+ print(f"read {len(qs)} queries without responses from qas.json")
51
+ print(f"read {len(qas)} queries with responses from qas.json")
52
+ return qs, qas
53
+
54
+ qs, qas = read_qs()
55
+ start_time = time.time()
56
+ num_read_qas = len(qas)
57
+
58
+ def ask(query, timeout=600):
59
+ answer = None
60
+ dead_time = time.time() + timeout
61
+ attempt_times = 0
62
+ while answer is None and time.time()<dead_time and attempt_times<10:
63
+ try:
64
+ messages=[
65
+ {"role": "user", "content": query}
66
+ ]
67
+ if num_tokens_from_messages(messages)>4096:
68
+ return None
69
+ answer = openai.ChatCompletion.create(
70
+ model="gpt-3.5-turbo",
71
+ messages=messages
72
+ )["choices"][0]["message"]["content"]
73
+ except Exception as e:
74
+ if time.time()<dead_time:
75
+ print(e)
76
+ if "Please reduce the length of the messages." in str(e):
77
+ return None
78
+ else:
79
+ attempt_times += 1
80
+ wait_time = int(attempt_times*10)
81
+ time.sleep(wait_time)
82
+ print(f"retry in {attempt_times*10} seconds...")
83
+ return answer
84
+
85
+
86
+ def askingChatGPT(qs, qas, min_interval_seconds=3, max_interval_seconds=15, max_retry_times=3):
87
+
88
+ history_elapsed_time = [max_interval_seconds]*10
89
+ return
90
+ for i, q in enumerate(qs):
91
+ ask_start_time = time.time()
92
+
93
+ # 最直接的方法,调用ask函数,但可能因为超时等原因阻塞住
94
+ #a = ask(q)
95
+
96
+ # 下面是我之前设计的一系列,超时->重试,的方法
97
+ def ask_(q, timeout):
98
+ executor = concurrent.futures.ThreadPoolExecutor()
99
+ future = executor.submit(ask, q, timeout) # 提交函数调用任务
100
+ try:
101
+ a = future.result(timeout=timeout) # 等待函数调用任务完成,超时时间为30秒
102
+ return a
103
+ except concurrent.futures.TimeoutError:
104
+ print(f"ask call timed out after {timeout:.2f} seconds, retrying...")
105
+ executor.shutdown(wait=False)
106
+ return ask_(q, timeout*2) # 当超时时,重新调用函数
107
+
108
+ retry_times = 0
109
+ a = None
110
+ while a is None and retry_times<max_retry_times:
111
+ a = ask_(q, timeout=max(max_interval_seconds,np.mean(sorted(history_elapsed_time)[:8])))
112
+ retry_times += 1
113
+
114
+ qas.append({"q":q, "a":a})
115
+
116
+ ask_end_time = time.time()
117
+ elapsed_time = ask_end_time - ask_start_time
118
+ history_elapsed_time = history_elapsed_time[1:] + [elapsed_time]
119
+ delayTime = min_interval_seconds - elapsed_time
120
+ if delayTime>0:
121
+ time.sleep(delayTime)
122
+
123
+ print(f"{timestamp2string(time.time())}: iterations: {i+1} / {len(qs)} | elapsed time of this query (s): {elapsed_time:.2f}")
124
+
125
+ return
126
+
127
+
128
+ thread = threading.Thread(target=lambda :askingChatGPT(qs, qas))
129
+ thread.daemon = True
130
+ thread.start()
131
+
132
+
133
+ import gradio as gr
134
+
135
+
136
+ def showcase(access_key):
137
+ if not access_key==os.getenv('access_key'):
138
+ chatbot_ret = [(f"Your entered Access Key:<br>{access_key}<br>is incorrect.", f"So i cannot provide you any information in this private space.")]
139
+ else:
140
+ recent_qas = qas[-10:]
141
+ chatbot_ret = [(f"Your entered Access Key is correct.", f"The latest {len(recent_qas)} query-responses are displayed below.")]
142
+ for qa in recent_qas:
143
+ chatbot_ret += [(qa["q"].replace("\n","<br>"), str(qa["a"]).replace("\n","<br>"))]
144
+ return chatbot_ret
145
+
146
+
147
+ def download(access_key):
148
+ if not access_key.startswith(os.getenv('access_key')):
149
+ chatbot_ret = [(f"Your entered Access Key:<br>{access_key}<br>is incorrect.", f"So i cannot provide you any information in this private space.")]
150
+ file_ret = gr.File.update(value=None, visible=False)
151
+ else:
152
+ chatbot_ret = [(f"Your entered Access Key is correct.", f"The file containing all processed query-responses ({len(qas)} in total) can be downloaded below.")]
153
+ filename = f"qas-{len(qas)}.json"
154
+ with open(filename, "w", encoding="utf-8") as f:
155
+ f.write(json.dumps(qas, ensure_ascii=False, indent=4))
156
+ file_ret = gr.File.update(value=filename, visible=True)
157
+ return chatbot_ret, file_ret
158
+
159
+
160
+ def display(access_key):
161
+ if not access_key==os.getenv('access_key'):
162
+ chatbot_ret = [(f"Your entered Access Key:<br>{access_key}<br>is incorrect.", f"So i cannot provide you any information in this private space.")]
163
+ elif len(qas)-num_read_qas<1:
164
+ chatbot_ret = [(f"Your entered Access Key is correct.", f"But the progress has just started for a while and has no useful progress information to provide.")]
165
+ else:
166
+ num_total_qs, num_processed_qs = len(qs), len(qas) - num_read_qas
167
+ time_takes = time.time() - start_time
168
+ time_remains = time_takes * (num_total_qs-num_processed_qs) / num_processed_qs
169
+ end_time = start_time + time_takes + time_remains
170
+
171
+ messages = []
172
+ for qa in qas:
173
+ messages.append({"role":"user", "content":qa["q"]})
174
+ messages.append({"role":"assistant", "content":qa["a"] or ""})
175
+ num_tokens_processed = num_tokens_from_messages(messages)
176
+ num_tokens_total = int(num_tokens_processed * (num_total_qs+num_read_qas) / (num_processed_qs+num_read_qas))
177
+ dollars_tokens_processed = 0.002 * int(num_tokens_processed/1000)
178
+ dollars_tokens_total = 0.002 * int(num_tokens_total/1000)
179
+
180
+ chatbot_ret = [(f"Your entered Access Key is correct.", f"The information of progress is displayed below.")]
181
+ chatbot_ret += [(f"The number of processed / total queries:", f"{num_processed_qs} / {num_total_qs} (+{num_read_qas})")]
182
+ chatbot_ret += [(f"The hours already takes / est. remains:", f"{time_takes/3600:.2f} / {time_remains/3600:.2f}")]
183
+ chatbot_ret += [(f"The time starts / est. ends:", f"{timestamp2string(start_time)} / {timestamp2string(end_time)}")]
184
+ chatbot_ret += [(f"The number of processed / est. total tokens:", f"{num_tokens_processed} / {num_tokens_total}")]
185
+ chatbot_ret += [(f"The dollars of processed / est. total tokens:", f"{dollars_tokens_processed:.2f} / {dollars_tokens_total:.2f}")]
186
+
187
+ return chatbot_ret
188
+
189
+
190
+ with gr.Blocks() as demo:
191
+
192
+ gr.Markdown(
193
+ """
194
+ Hello friends,
195
+
196
+ Thanks for your attention on this space. But this space is for my own use, i.e., building a dataset with answers from ChatGPT, and the access key for runtime feedback is only shared to my colleagues.
197
+
198
+ If you want to ask ChatGPT on Huggingface just as the title says, you can try this [one](https://huggingface.co/spaces/zhangjf/chatbot) I built for public.
199
+ """
200
+ )
201
+
202
+ with gr.Column(variant="panel"):
203
+ chatbot = gr.Chatbot()
204
+ txt = gr.Textbox(show_label=False, placeholder="Enter your Access Key to access this private space").style(container=False)
205
+ with gr.Row():
206
+ button_showcase = gr.Button("Show Recent Query-Responses")
207
+ button_download = gr.Button("Download All Query-Responses")
208
+ button_display = gr.Button("Display Progress Infomation")
209
+
210
+ downloadfile = gr.File(None, interactive=False, show_label=False, visible=False)
211
+
212
+ button_showcase.click(fn=showcase, inputs=[txt], outputs=[chatbot])
213
+ button_download.click(fn=download, inputs=[txt], outputs=[chatbot, downloadfile])
214
+ button_display.click(fn=display, inputs=[txt], outputs=[chatbot])
215
+
216
+ demo.launch()
qas.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "q": "�й����׶����ĸ�����",
4
+ "a": "����"
5
+ },
6
+ {
7
+ "q": "�������׶����ĸ�����",
8
+ "a": null
9
+ }
10
+ ]
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ openai==0.27.0
2
+ tiktoken==0.3.0