JohnSmith9982
commited on
Commit
•
b6fb8c4
1
Parent(s):
976b4d3
Upload 13 files
Browse files- app.py +24 -19
- assets/custom.css +52 -5
- modules/chat_func.py +86 -58
- modules/llama_func.py +44 -30
- modules/openai_func.py +59 -47
- modules/presets.py +34 -3
- modules/utils.py +94 -10
- requirements.txt +1 -0
app.py
CHANGED
@@ -25,6 +25,7 @@ else:
|
|
25 |
dockerflag = False
|
26 |
|
27 |
authflag = False
|
|
|
28 |
|
29 |
if not my_api_key:
|
30 |
my_api_key = os.environ.get("my_api_key")
|
@@ -36,6 +37,7 @@ if dockerflag:
|
|
36 |
username = os.environ.get("USERNAME")
|
37 |
password = os.environ.get("PASSWORD")
|
38 |
if not (isinstance(username, type(None)) or isinstance(password, type(None))):
|
|
|
39 |
authflag = True
|
40 |
else:
|
41 |
if (
|
@@ -46,12 +48,15 @@ else:
|
|
46 |
with open("api_key.txt", "r") as f:
|
47 |
my_api_key = f.read().strip()
|
48 |
if os.path.exists("auth.json"):
|
|
|
49 |
with open("auth.json", "r", encoding='utf-8') as f:
|
50 |
auth = json.load(f)
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
55 |
|
56 |
gr.Chatbot.postprocess = postprocess
|
57 |
PromptHelper.compact_text_chunks = compact_text_chunks
|
@@ -76,19 +81,19 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
76 |
with gr.Column(scale=4):
|
77 |
status_display = gr.Markdown(get_geoip(), elem_id="status_display")
|
78 |
|
79 |
-
with gr.Row(
|
80 |
with gr.Column(scale=5):
|
81 |
-
with gr.Row(
|
82 |
chatbot = gr.Chatbot(elem_id="chuanhu_chatbot").style(height="100%")
|
83 |
-
with gr.Row(
|
84 |
with gr.Column(scale=12):
|
85 |
user_input = gr.Textbox(
|
86 |
-
show_label=False, placeholder="在这里输入"
|
87 |
).style(container=False)
|
88 |
with gr.Column(min_width=70, scale=1):
|
89 |
submitBtn = gr.Button("发送", variant="primary")
|
90 |
cancelBtn = gr.Button("取消", variant="secondary", visible=False)
|
91 |
-
with gr.Row(
|
92 |
emptyBtn = gr.Button(
|
93 |
"🧹 新的对话",
|
94 |
)
|
@@ -108,7 +113,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
108 |
visible=not HIDE_MY_KEY,
|
109 |
label="API-Key",
|
110 |
)
|
111 |
-
usageTxt = gr.Markdown(
|
112 |
model_select_dropdown = gr.Dropdown(
|
113 |
label="选择模型", choices=MODELS, multiselect=False, value=MODELS[0]
|
114 |
)
|
@@ -208,7 +213,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
208 |
label="Temperature",
|
209 |
)
|
210 |
|
211 |
-
with gr.Accordion("网络设置", open=False):
|
212 |
apiurlTxt = gr.Textbox(
|
213 |
show_label=True,
|
214 |
placeholder=f"在这里输入API地址...",
|
@@ -227,7 +232,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
227 |
changeProxyBtn = gr.Button("🔄 设置代理地址")
|
228 |
|
229 |
gr.Markdown(description)
|
230 |
-
|
231 |
chatgpt_predict_args = dict(
|
232 |
fn=predict,
|
233 |
inputs=[
|
@@ -265,13 +270,14 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
265 |
)
|
266 |
|
267 |
transfer_input_args = dict(
|
268 |
-
fn=transfer_input, inputs=[user_input], outputs=[user_question, user_input], show_progress=True
|
269 |
)
|
270 |
|
271 |
get_usage_args = dict(
|
272 |
fn=get_usage, inputs=[user_api_key], outputs=[usageTxt], show_progress=False
|
273 |
)
|
274 |
|
|
|
275 |
# Chatbot
|
276 |
cancelBtn.click(cancel_outputing, [], [])
|
277 |
|
@@ -288,8 +294,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
288 |
)
|
289 |
emptyBtn.click(**reset_textbox_args)
|
290 |
|
291 |
-
retryBtn.click(**
|
292 |
-
retryBtn.click(
|
293 |
retry,
|
294 |
[
|
295 |
user_api_key,
|
@@ -305,7 +310,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
305 |
],
|
306 |
[chatbot, history, status_display, token_count],
|
307 |
show_progress=True,
|
308 |
-
)
|
309 |
retryBtn.click(**get_usage_args)
|
310 |
|
311 |
delFirstBtn.click(
|
@@ -331,7 +336,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
331 |
token_count,
|
332 |
top_p,
|
333 |
temperature,
|
334 |
-
gr.State(
|
335 |
model_select_dropdown,
|
336 |
language_select_dropdown,
|
337 |
],
|
@@ -419,7 +424,7 @@ if __name__ == "__main__":
|
|
419 |
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
|
420 |
server_name="0.0.0.0",
|
421 |
server_port=7860,
|
422 |
-
auth=
|
423 |
favicon_path="./assets/favicon.ico",
|
424 |
)
|
425 |
else:
|
@@ -434,7 +439,7 @@ if __name__ == "__main__":
|
|
434 |
if authflag:
|
435 |
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
|
436 |
share=False,
|
437 |
-
auth=
|
438 |
favicon_path="./assets/favicon.ico",
|
439 |
inbrowser=True,
|
440 |
)
|
|
|
25 |
dockerflag = False
|
26 |
|
27 |
authflag = False
|
28 |
+
auth_list = []
|
29 |
|
30 |
if not my_api_key:
|
31 |
my_api_key = os.environ.get("my_api_key")
|
|
|
37 |
username = os.environ.get("USERNAME")
|
38 |
password = os.environ.get("PASSWORD")
|
39 |
if not (isinstance(username, type(None)) or isinstance(password, type(None))):
|
40 |
+
auth_list.append((os.environ.get("USERNAME"), os.environ.get("PASSWORD")))
|
41 |
authflag = True
|
42 |
else:
|
43 |
if (
|
|
|
48 |
with open("api_key.txt", "r") as f:
|
49 |
my_api_key = f.read().strip()
|
50 |
if os.path.exists("auth.json"):
|
51 |
+
authflag = True
|
52 |
with open("auth.json", "r", encoding='utf-8') as f:
|
53 |
auth = json.load(f)
|
54 |
+
for _ in auth:
|
55 |
+
if auth[_]["username"] and auth[_]["password"]:
|
56 |
+
auth_list.append((auth[_]["username"], auth[_]["password"]))
|
57 |
+
else:
|
58 |
+
logging.error("请检查auth.json文件中的用户名和密码!")
|
59 |
+
sys.exit(1)
|
60 |
|
61 |
gr.Chatbot.postprocess = postprocess
|
62 |
PromptHelper.compact_text_chunks = compact_text_chunks
|
|
|
81 |
with gr.Column(scale=4):
|
82 |
status_display = gr.Markdown(get_geoip(), elem_id="status_display")
|
83 |
|
84 |
+
with gr.Row().style(equal_height=True):
|
85 |
with gr.Column(scale=5):
|
86 |
+
with gr.Row():
|
87 |
chatbot = gr.Chatbot(elem_id="chuanhu_chatbot").style(height="100%")
|
88 |
+
with gr.Row():
|
89 |
with gr.Column(scale=12):
|
90 |
user_input = gr.Textbox(
|
91 |
+
show_label=False, placeholder="在这里输入"
|
92 |
).style(container=False)
|
93 |
with gr.Column(min_width=70, scale=1):
|
94 |
submitBtn = gr.Button("发送", variant="primary")
|
95 |
cancelBtn = gr.Button("取消", variant="secondary", visible=False)
|
96 |
+
with gr.Row():
|
97 |
emptyBtn = gr.Button(
|
98 |
"🧹 新的对话",
|
99 |
)
|
|
|
113 |
visible=not HIDE_MY_KEY,
|
114 |
label="API-Key",
|
115 |
)
|
116 |
+
usageTxt = gr.Markdown("**发送消息** 或 **提交key** 以显示额度", elem_id="usage_display")
|
117 |
model_select_dropdown = gr.Dropdown(
|
118 |
label="选择模型", choices=MODELS, multiselect=False, value=MODELS[0]
|
119 |
)
|
|
|
213 |
label="Temperature",
|
214 |
)
|
215 |
|
216 |
+
with gr.Accordion("网络设置", open=False, visible=False):
|
217 |
apiurlTxt = gr.Textbox(
|
218 |
show_label=True,
|
219 |
placeholder=f"在这里输入API地址...",
|
|
|
232 |
changeProxyBtn = gr.Button("🔄 设置代理地址")
|
233 |
|
234 |
gr.Markdown(description)
|
235 |
+
gr.HTML(footer.format(versions=versions_html()), elem_id="footer")
|
236 |
chatgpt_predict_args = dict(
|
237 |
fn=predict,
|
238 |
inputs=[
|
|
|
270 |
)
|
271 |
|
272 |
transfer_input_args = dict(
|
273 |
+
fn=transfer_input, inputs=[user_input], outputs=[user_question, user_input, submitBtn, cancelBtn], show_progress=True
|
274 |
)
|
275 |
|
276 |
get_usage_args = dict(
|
277 |
fn=get_usage, inputs=[user_api_key], outputs=[usageTxt], show_progress=False
|
278 |
)
|
279 |
|
280 |
+
|
281 |
# Chatbot
|
282 |
cancelBtn.click(cancel_outputing, [], [])
|
283 |
|
|
|
294 |
)
|
295 |
emptyBtn.click(**reset_textbox_args)
|
296 |
|
297 |
+
retryBtn.click(**start_outputing_args).then(
|
|
|
298 |
retry,
|
299 |
[
|
300 |
user_api_key,
|
|
|
310 |
],
|
311 |
[chatbot, history, status_display, token_count],
|
312 |
show_progress=True,
|
313 |
+
).then(**end_outputing_args)
|
314 |
retryBtn.click(**get_usage_args)
|
315 |
|
316 |
delFirstBtn.click(
|
|
|
336 |
token_count,
|
337 |
top_p,
|
338 |
temperature,
|
339 |
+
gr.State(sum(token_count.value[-4:])),
|
340 |
model_select_dropdown,
|
341 |
language_select_dropdown,
|
342 |
],
|
|
|
424 |
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
|
425 |
server_name="0.0.0.0",
|
426 |
server_port=7860,
|
427 |
+
auth=auth_list,
|
428 |
favicon_path="./assets/favicon.ico",
|
429 |
)
|
430 |
else:
|
|
|
439 |
if authflag:
|
440 |
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
|
441 |
share=False,
|
442 |
+
auth=auth_list,
|
443 |
favicon_path="./assets/favicon.ico",
|
444 |
inbrowser=True,
|
445 |
)
|
assets/custom.css
CHANGED
@@ -3,6 +3,21 @@
|
|
3 |
--chatbot-color-dark: #121111;
|
4 |
}
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
/* status_display */
|
7 |
#status_display {
|
8 |
display: flex;
|
@@ -22,14 +37,45 @@
|
|
22 |
|
23 |
/* usage_display */
|
24 |
#usage_display {
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
font-size: .85em;
|
30 |
-
font-family: monospace;
|
31 |
color: var(--body-text-color-subdued);
|
32 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
/* list */
|
34 |
ol:not(.options), ul:not(.options) {
|
35 |
padding-inline-start: 2em !important;
|
@@ -64,6 +110,7 @@ ol:not(.options), ul:not(.options) {
|
|
64 |
background-color: var(--neutral-950) !important;
|
65 |
}
|
66 |
}
|
|
|
67 |
/* 对话气泡 */
|
68 |
[class *= "message"] {
|
69 |
border-radius: var(--radius-xl) !important;
|
|
|
3 |
--chatbot-color-dark: #121111;
|
4 |
}
|
5 |
|
6 |
+
/* 覆盖gradio的页脚信息QAQ */
|
7 |
+
footer {
|
8 |
+
display: none !important;
|
9 |
+
}
|
10 |
+
#footer{
|
11 |
+
text-align: center;
|
12 |
+
}
|
13 |
+
#footer div{
|
14 |
+
display: inline-block;
|
15 |
+
}
|
16 |
+
#footer .versions{
|
17 |
+
font-size: 85%;
|
18 |
+
opacity: 0.85;
|
19 |
+
}
|
20 |
+
|
21 |
/* status_display */
|
22 |
#status_display {
|
23 |
display: flex;
|
|
|
37 |
|
38 |
/* usage_display */
|
39 |
#usage_display {
|
40 |
+
position: relative;
|
41 |
+
margin: 0;
|
42 |
+
box-shadow: var(--block-shadow);
|
43 |
+
border-width: var(--block-border-width);
|
44 |
+
border-color: var(--block-border-color);
|
45 |
+
border-radius: var(--block-radius);
|
46 |
+
background: var(--block-background-fill);
|
47 |
+
width: 100%;
|
48 |
+
line-height: var(--line-sm);
|
49 |
+
min-height: 2em;
|
50 |
+
}
|
51 |
+
#usage_display p, #usage_display span {
|
52 |
+
margin: 0;
|
53 |
+
padding: .5em 1em;
|
54 |
font-size: .85em;
|
|
|
55 |
color: var(--body-text-color-subdued);
|
56 |
}
|
57 |
+
.progress-bar {
|
58 |
+
background-color: var(--input-background-fill);;
|
59 |
+
margin: 0 1em;
|
60 |
+
height: 20px;
|
61 |
+
border-radius: 10px;
|
62 |
+
overflow: hidden;
|
63 |
+
}
|
64 |
+
.progress {
|
65 |
+
background-color: var(--block-title-background-fill);;
|
66 |
+
height: 100%;
|
67 |
+
border-radius: 10px;
|
68 |
+
text-align: right;
|
69 |
+
transition: width 0.5s ease-in-out;
|
70 |
+
}
|
71 |
+
.progress-text {
|
72 |
+
/* color: white; */
|
73 |
+
color: var(--color-accent) !important;
|
74 |
+
font-size: 1em !important;
|
75 |
+
font-weight: bold;
|
76 |
+
padding-right: 10px;
|
77 |
+
line-height: 20px;
|
78 |
+
}
|
79 |
/* list */
|
80 |
ol:not(.options), ul:not(.options) {
|
81 |
padding-inline-start: 2em !important;
|
|
|
110 |
background-color: var(--neutral-950) !important;
|
111 |
}
|
112 |
}
|
113 |
+
|
114 |
/* 对话气泡 */
|
115 |
[class *= "message"] {
|
116 |
border-radius: var(--radius-xl) !important;
|
modules/chat_func.py
CHANGED
@@ -13,6 +13,9 @@ import colorama
|
|
13 |
from duckduckgo_search import ddg
|
14 |
import asyncio
|
15 |
import aiohttp
|
|
|
|
|
|
|
16 |
|
17 |
from modules.presets import *
|
18 |
from modules.llama_func import *
|
@@ -58,39 +61,21 @@ def get_response(
|
|
58 |
else:
|
59 |
timeout = timeout_all
|
60 |
|
61 |
-
|
62 |
-
http_proxy = os.environ.get("HTTP_PROXY") or os.environ.get("http_proxy")
|
63 |
-
https_proxy = os.environ.get("HTTPS_PROXY") or os.environ.get("https_proxy")
|
64 |
-
|
65 |
-
# 如果存在代理设置,使用它们
|
66 |
-
proxies = {}
|
67 |
-
if http_proxy:
|
68 |
-
logging.info(f"使用 HTTP 代理: {http_proxy}")
|
69 |
-
proxies["http"] = http_proxy
|
70 |
-
if https_proxy:
|
71 |
-
logging.info(f"使用 HTTPS 代理: {https_proxy}")
|
72 |
-
proxies["https"] = https_proxy
|
73 |
|
74 |
# 如果有自定义的api-url,使用自定义url发送请求,否则使用默认设置发送请求
|
75 |
if shared.state.api_url != API_URL:
|
76 |
logging.info(f"使用自定义API URL: {shared.state.api_url}")
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
response = requests.post(
|
88 |
-
shared.state.api_url,
|
89 |
-
headers=headers,
|
90 |
-
json=payload,
|
91 |
-
stream=True,
|
92 |
-
timeout=timeout,
|
93 |
-
)
|
94 |
return response
|
95 |
|
96 |
|
@@ -121,13 +106,17 @@ def stream_predict(
|
|
121 |
else:
|
122 |
chatbot.append((inputs, ""))
|
123 |
user_token_count = 0
|
|
|
|
|
|
|
|
|
124 |
if len(all_token_counts) == 0:
|
125 |
system_prompt_token_count = count_token(construct_system(system_prompt))
|
126 |
user_token_count = (
|
127 |
-
|
128 |
)
|
129 |
else:
|
130 |
-
user_token_count =
|
131 |
all_token_counts.append(user_token_count)
|
132 |
logging.info(f"输入token计数: {user_token_count}")
|
133 |
yield get_return_value()
|
@@ -155,7 +144,9 @@ def stream_predict(
|
|
155 |
yield get_return_value()
|
156 |
error_json_str = ""
|
157 |
|
158 |
-
|
|
|
|
|
159 |
if counter == 0:
|
160 |
counter += 1
|
161 |
continue
|
@@ -219,7 +210,10 @@ def predict_all(
|
|
219 |
chatbot.append((fake_input, ""))
|
220 |
else:
|
221 |
chatbot.append((inputs, ""))
|
222 |
-
|
|
|
|
|
|
|
223 |
try:
|
224 |
response = get_response(
|
225 |
openai_api_key,
|
@@ -242,13 +236,22 @@ def predict_all(
|
|
242 |
status_text = standard_error_msg + ssl_error_prompt + error_retrieve_prompt
|
243 |
return chatbot, history, status_text, all_token_counts
|
244 |
response = json.loads(response.text)
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
|
253 |
|
254 |
def predict(
|
@@ -268,40 +271,59 @@ def predict(
|
|
268 |
should_check_token_count=True,
|
269 |
): # repetition_penalty, top_k
|
270 |
logging.info("输入为:" + colorama.Fore.BLUE + f"{inputs}" + colorama.Style.RESET_ALL)
|
271 |
-
|
|
|
272 |
if reply_language == "跟随问题语言(不稳定)":
|
273 |
reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
|
|
|
|
|
|
|
274 |
if files:
|
|
|
|
|
275 |
msg = "加载索引中……(这可能需要几分钟)"
|
276 |
logging.info(msg)
|
277 |
yield chatbot+[(inputs, "")], history, msg, all_token_counts
|
278 |
index = construct_index(openai_api_key, file_src=files)
|
279 |
msg = "索引构建完成,获取回答中……"
|
|
|
280 |
yield chatbot+[(inputs, "")], history, msg, all_token_counts
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
search_results = ddg(inputs, max_results=5)
|
289 |
old_inputs = inputs
|
290 |
-
|
291 |
for idx, result in enumerate(search_results):
|
292 |
logging.info(f"搜索结果{idx + 1}:{result}")
|
293 |
domain_name = urllib3.util.parse_url(result["href"]).host
|
294 |
-
|
295 |
-
|
296 |
-
|
|
|
297 |
inputs = (
|
298 |
replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
|
299 |
.replace("{query}", inputs)
|
300 |
-
.replace("{web_results}", "\n\n".join(
|
301 |
.replace("{reply_language}", reply_language )
|
302 |
)
|
303 |
else:
|
304 |
-
|
305 |
|
306 |
if len(openai_api_key) != 51:
|
307 |
status_text = standard_error_msg + no_apikey_msg
|
@@ -334,7 +356,7 @@ def predict(
|
|
334 |
temperature,
|
335 |
selected_model,
|
336 |
fake_input=old_inputs,
|
337 |
-
display_append=
|
338 |
)
|
339 |
for chatbot, history, status_text, all_token_counts in iter:
|
340 |
if shared.state.interrupted:
|
@@ -354,7 +376,7 @@ def predict(
|
|
354 |
temperature,
|
355 |
selected_model,
|
356 |
fake_input=old_inputs,
|
357 |
-
display_append=
|
358 |
)
|
359 |
yield chatbot, history, status_text, all_token_counts
|
360 |
|
@@ -367,10 +389,15 @@ def predict(
|
|
367 |
+ colorama.Style.RESET_ALL
|
368 |
)
|
369 |
|
|
|
|
|
|
|
|
|
|
|
370 |
if stream:
|
371 |
-
max_token =
|
372 |
else:
|
373 |
-
max_token =
|
374 |
|
375 |
if sum(all_token_counts) > max_token and should_check_token_count:
|
376 |
status_text = f"精简token中{all_token_counts}/{max_token}"
|
@@ -460,6 +487,7 @@ def reduce_token_size(
|
|
460 |
flag = False
|
461 |
for chatbot, history, status_text, previous_token_count in iter:
|
462 |
num_chat = find_n(previous_token_count, max_token_count)
|
|
|
463 |
if flag:
|
464 |
chatbot = chatbot[:-1]
|
465 |
flag = True
|
|
|
13 |
from duckduckgo_search import ddg
|
14 |
import asyncio
|
15 |
import aiohttp
|
16 |
+
from llama_index.indices.query.vector_store import GPTVectorStoreIndexQuery
|
17 |
+
from llama_index.indices.query.schema import QueryBundle
|
18 |
+
from langchain.llms import OpenAIChat
|
19 |
|
20 |
from modules.presets import *
|
21 |
from modules.llama_func import *
|
|
|
61 |
else:
|
62 |
timeout = timeout_all
|
63 |
|
64 |
+
proxies = get_proxies()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
66 |
# 如果有自定义的api-url,使用自定义url发送请求,否则使用默认设置发送请求
|
67 |
if shared.state.api_url != API_URL:
|
68 |
logging.info(f"使用自定义API URL: {shared.state.api_url}")
|
69 |
+
|
70 |
+
response = requests.post(
|
71 |
+
shared.state.api_url,
|
72 |
+
headers=headers,
|
73 |
+
json=payload,
|
74 |
+
stream=True,
|
75 |
+
timeout=timeout,
|
76 |
+
proxies=proxies,
|
77 |
+
)
|
78 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
return response
|
80 |
|
81 |
|
|
|
106 |
else:
|
107 |
chatbot.append((inputs, ""))
|
108 |
user_token_count = 0
|
109 |
+
if fake_input is not None:
|
110 |
+
input_token_count = count_token(construct_user(fake_input))
|
111 |
+
else:
|
112 |
+
input_token_count = count_token(construct_user(inputs))
|
113 |
if len(all_token_counts) == 0:
|
114 |
system_prompt_token_count = count_token(construct_system(system_prompt))
|
115 |
user_token_count = (
|
116 |
+
input_token_count + system_prompt_token_count
|
117 |
)
|
118 |
else:
|
119 |
+
user_token_count = input_token_count
|
120 |
all_token_counts.append(user_token_count)
|
121 |
logging.info(f"输入token计数: {user_token_count}")
|
122 |
yield get_return_value()
|
|
|
144 |
yield get_return_value()
|
145 |
error_json_str = ""
|
146 |
|
147 |
+
if fake_input is not None:
|
148 |
+
history[-2] = construct_user(fake_input)
|
149 |
+
for chunk in tqdm(response.iter_lines()):
|
150 |
if counter == 0:
|
151 |
counter += 1
|
152 |
continue
|
|
|
210 |
chatbot.append((fake_input, ""))
|
211 |
else:
|
212 |
chatbot.append((inputs, ""))
|
213 |
+
if fake_input is not None:
|
214 |
+
all_token_counts.append(count_token(construct_user(fake_input)))
|
215 |
+
else:
|
216 |
+
all_token_counts.append(count_token(construct_user(inputs)))
|
217 |
try:
|
218 |
response = get_response(
|
219 |
openai_api_key,
|
|
|
236 |
status_text = standard_error_msg + ssl_error_prompt + error_retrieve_prompt
|
237 |
return chatbot, history, status_text, all_token_counts
|
238 |
response = json.loads(response.text)
|
239 |
+
if fake_input is not None:
|
240 |
+
history[-2] = construct_user(fake_input)
|
241 |
+
try:
|
242 |
+
content = response["choices"][0]["message"]["content"]
|
243 |
+
history[-1] = construct_assistant(content)
|
244 |
+
chatbot[-1] = (chatbot[-1][0], content+display_append)
|
245 |
+
total_token_count = response["usage"]["total_tokens"]
|
246 |
+
if fake_input is not None:
|
247 |
+
all_token_counts[-1] += count_token(construct_assistant(content))
|
248 |
+
else:
|
249 |
+
all_token_counts[-1] = total_token_count - sum(all_token_counts)
|
250 |
+
status_text = construct_token_message(total_token_count)
|
251 |
+
return chatbot, history, status_text, all_token_counts
|
252 |
+
except KeyError:
|
253 |
+
status_text = standard_error_msg + str(response)
|
254 |
+
return chatbot, history, status_text, all_token_counts
|
255 |
|
256 |
|
257 |
def predict(
|
|
|
271 |
should_check_token_count=True,
|
272 |
): # repetition_penalty, top_k
|
273 |
logging.info("输入为:" + colorama.Fore.BLUE + f"{inputs}" + colorama.Style.RESET_ALL)
|
274 |
+
if should_check_token_count:
|
275 |
+
yield chatbot+[(inputs, "")], history, "开始生成回答……", all_token_counts
|
276 |
if reply_language == "跟随问题语言(不稳定)":
|
277 |
reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
|
278 |
+
old_inputs = None
|
279 |
+
display_reference = []
|
280 |
+
limited_context = False
|
281 |
if files:
|
282 |
+
limited_context = True
|
283 |
+
old_inputs = inputs
|
284 |
msg = "加载索引中……(这可能需要几分钟)"
|
285 |
logging.info(msg)
|
286 |
yield chatbot+[(inputs, "")], history, msg, all_token_counts
|
287 |
index = construct_index(openai_api_key, file_src=files)
|
288 |
msg = "索引构建完成,获取回答中……"
|
289 |
+
logging.info(msg)
|
290 |
yield chatbot+[(inputs, "")], history, msg, all_token_counts
|
291 |
+
llm_predictor = LLMPredictor(llm=OpenAIChat(temperature=0, model_name=selected_model))
|
292 |
+
prompt_helper = PromptHelper(max_input_size = 4096, num_output = 5, max_chunk_overlap = 20, chunk_size_limit=600)
|
293 |
+
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, prompt_helper=prompt_helper)
|
294 |
+
query_object = GPTVectorStoreIndexQuery(index.index_struct, service_context=service_context, similarity_top_k=5, vector_store=index._vector_store, docstore=index._docstore)
|
295 |
+
query_bundle = QueryBundle(inputs)
|
296 |
+
nodes = query_object.retrieve(query_bundle)
|
297 |
+
reference_results = [n.node.text for n in nodes]
|
298 |
+
reference_results = add_source_numbers(reference_results, use_source=False)
|
299 |
+
display_reference = add_details(reference_results)
|
300 |
+
display_reference = "\n\n" + "".join(display_reference)
|
301 |
+
inputs = (
|
302 |
+
replace_today(PROMPT_TEMPLATE)
|
303 |
+
.replace("{query_str}", inputs)
|
304 |
+
.replace("{context_str}", "\n\n".join(reference_results))
|
305 |
+
.replace("{reply_language}", reply_language )
|
306 |
+
)
|
307 |
+
elif use_websearch:
|
308 |
+
limited_context = True
|
309 |
search_results = ddg(inputs, max_results=5)
|
310 |
old_inputs = inputs
|
311 |
+
reference_results = []
|
312 |
for idx, result in enumerate(search_results):
|
313 |
logging.info(f"搜索结果{idx + 1}:{result}")
|
314 |
domain_name = urllib3.util.parse_url(result["href"]).host
|
315 |
+
reference_results.append([result["body"], result["href"]])
|
316 |
+
display_reference.append(f"{idx+1}. [{domain_name}]({result['href']})\n")
|
317 |
+
reference_results = add_source_numbers(reference_results)
|
318 |
+
display_reference = "\n\n" + "".join(display_reference)
|
319 |
inputs = (
|
320 |
replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
|
321 |
.replace("{query}", inputs)
|
322 |
+
.replace("{web_results}", "\n\n".join(reference_results))
|
323 |
.replace("{reply_language}", reply_language )
|
324 |
)
|
325 |
else:
|
326 |
+
display_reference = ""
|
327 |
|
328 |
if len(openai_api_key) != 51:
|
329 |
status_text = standard_error_msg + no_apikey_msg
|
|
|
356 |
temperature,
|
357 |
selected_model,
|
358 |
fake_input=old_inputs,
|
359 |
+
display_append=display_reference
|
360 |
)
|
361 |
for chatbot, history, status_text, all_token_counts in iter:
|
362 |
if shared.state.interrupted:
|
|
|
376 |
temperature,
|
377 |
selected_model,
|
378 |
fake_input=old_inputs,
|
379 |
+
display_append=display_reference
|
380 |
)
|
381 |
yield chatbot, history, status_text, all_token_counts
|
382 |
|
|
|
389 |
+ colorama.Style.RESET_ALL
|
390 |
)
|
391 |
|
392 |
+
if limited_context:
|
393 |
+
history = history[-4:]
|
394 |
+
all_token_counts = all_token_counts[-2:]
|
395 |
+
yield chatbot, history, status_text, all_token_counts
|
396 |
+
|
397 |
if stream:
|
398 |
+
max_token = MODEL_SOFT_TOKEN_LIMIT[selected_model]["streaming"]
|
399 |
else:
|
400 |
+
max_token = MODEL_SOFT_TOKEN_LIMIT[selected_model]["all"]
|
401 |
|
402 |
if sum(all_token_counts) > max_token and should_check_token_count:
|
403 |
status_text = f"精简token中{all_token_counts}/{max_token}"
|
|
|
487 |
flag = False
|
488 |
for chatbot, history, status_text, previous_token_count in iter:
|
489 |
num_chat = find_n(previous_token_count, max_token_count)
|
490 |
+
logging.info(f"previous_token_count: {previous_token_count}, keeping {num_chat} chats")
|
491 |
if flag:
|
492 |
chatbot = chatbot[:-1]
|
493 |
flag = True
|
modules/llama_func.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
import os
|
2 |
import logging
|
3 |
|
4 |
-
from llama_index import GPTSimpleVectorIndex
|
5 |
from llama_index import download_loader
|
6 |
from llama_index import (
|
7 |
Document,
|
@@ -11,19 +11,32 @@ from llama_index import (
|
|
11 |
RefinePrompt,
|
12 |
)
|
13 |
from langchain.llms import OpenAI
|
|
|
14 |
import colorama
|
|
|
|
|
15 |
|
16 |
from modules.presets import *
|
17 |
from modules.utils import *
|
18 |
|
19 |
def get_index_name(file_src):
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
def get_documents(file_src):
|
29 |
documents = []
|
@@ -33,9 +46,12 @@ def get_documents(file_src):
|
|
33 |
logging.info(f"loading file: {file.name}")
|
34 |
if os.path.splitext(file.name)[1] == ".pdf":
|
35 |
logging.debug("Loading PDF...")
|
36 |
-
|
37 |
-
|
38 |
-
|
|
|
|
|
|
|
39 |
elif os.path.splitext(file.name)[1] == ".docx":
|
40 |
logging.debug("Loading DOCX...")
|
41 |
DocxReader = download_loader("DocxReader")
|
@@ -51,7 +67,10 @@ def get_documents(file_src):
|
|
51 |
with open(file.name, "r", encoding="utf-8") as f:
|
52 |
text_raw = f.read()
|
53 |
text = add_space(text_raw)
|
|
|
|
|
54 |
documents += [Document(text)]
|
|
|
55 |
return documents
|
56 |
|
57 |
|
@@ -59,13 +78,11 @@ def construct_index(
|
|
59 |
api_key,
|
60 |
file_src,
|
61 |
max_input_size=4096,
|
62 |
-
num_outputs=
|
63 |
max_chunk_overlap=20,
|
64 |
chunk_size_limit=600,
|
65 |
embedding_limit=None,
|
66 |
-
separator=" "
|
67 |
-
num_children=10,
|
68 |
-
max_keywords_per_chunk=10,
|
69 |
):
|
70 |
os.environ["OPENAI_API_KEY"] = api_key
|
71 |
chunk_size_limit = None if chunk_size_limit == 0 else chunk_size_limit
|
@@ -73,16 +90,9 @@ def construct_index(
|
|
73 |
separator = " " if separator == "" else separator
|
74 |
|
75 |
llm_predictor = LLMPredictor(
|
76 |
-
llm=
|
77 |
-
)
|
78 |
-
prompt_helper = PromptHelper(
|
79 |
-
max_input_size,
|
80 |
-
num_outputs,
|
81 |
-
max_chunk_overlap,
|
82 |
-
embedding_limit,
|
83 |
-
chunk_size_limit,
|
84 |
-
separator=separator,
|
85 |
)
|
|
|
86 |
index_name = get_index_name(file_src)
|
87 |
if os.path.exists(f"./index/{index_name}.json"):
|
88 |
logging.info("找到了缓存的索引文件,加载中……")
|
@@ -90,14 +100,19 @@ def construct_index(
|
|
90 |
else:
|
91 |
try:
|
92 |
documents = get_documents(file_src)
|
93 |
-
logging.
|
94 |
-
|
95 |
-
|
|
|
96 |
)
|
|
|
97 |
os.makedirs("./index", exist_ok=True)
|
98 |
index.save_to_disk(f"./index/{index_name}.json")
|
|
|
99 |
return index
|
|
|
100 |
except Exception as e:
|
|
|
101 |
print(e)
|
102 |
return None
|
103 |
|
@@ -144,7 +159,7 @@ def ask_ai(
|
|
144 |
question,
|
145 |
prompt_tmpl,
|
146 |
refine_tmpl,
|
147 |
-
sim_k=
|
148 |
temprature=0,
|
149 |
prefix_messages=[],
|
150 |
reply_language="中文",
|
@@ -154,7 +169,7 @@ def ask_ai(
|
|
154 |
logging.debug("Index file found")
|
155 |
logging.debug("Querying index...")
|
156 |
llm_predictor = LLMPredictor(
|
157 |
-
llm=
|
158 |
temperature=temprature,
|
159 |
model_name="gpt-3.5-turbo-0301",
|
160 |
prefix_messages=prefix_messages,
|
@@ -166,7 +181,6 @@ def ask_ai(
|
|
166 |
rf_prompt = RefinePrompt(refine_tmpl.replace("{reply_language}", reply_language))
|
167 |
response = index.query(
|
168 |
question,
|
169 |
-
llm_predictor=llm_predictor,
|
170 |
similarity_top_k=sim_k,
|
171 |
text_qa_template=qa_prompt,
|
172 |
refine_template=rf_prompt,
|
|
|
1 |
import os
|
2 |
import logging
|
3 |
|
4 |
+
from llama_index import GPTSimpleVectorIndex, ServiceContext
|
5 |
from llama_index import download_loader
|
6 |
from llama_index import (
|
7 |
Document,
|
|
|
11 |
RefinePrompt,
|
12 |
)
|
13 |
from langchain.llms import OpenAI
|
14 |
+
from langchain.chat_models import ChatOpenAI
|
15 |
import colorama
|
16 |
+
import PyPDF2
|
17 |
+
from tqdm import tqdm
|
18 |
|
19 |
from modules.presets import *
|
20 |
from modules.utils import *
|
21 |
|
22 |
def get_index_name(file_src):
|
23 |
+
file_paths = [x.name for x in file_src]
|
24 |
+
file_paths.sort(key=lambda x: os.path.basename(x))
|
25 |
+
|
26 |
+
md5_hash = hashlib.md5()
|
27 |
+
for file_path in file_paths:
|
28 |
+
with open(file_path, "rb") as f:
|
29 |
+
while chunk := f.read(8192):
|
30 |
+
md5_hash.update(chunk)
|
31 |
+
|
32 |
+
return md5_hash.hexdigest()
|
33 |
+
|
34 |
+
def block_split(text):
|
35 |
+
blocks = []
|
36 |
+
while len(text) > 0:
|
37 |
+
blocks.append(Document(text[:1000]))
|
38 |
+
text = text[1000:]
|
39 |
+
return blocks
|
40 |
|
41 |
def get_documents(file_src):
|
42 |
documents = []
|
|
|
46 |
logging.info(f"loading file: {file.name}")
|
47 |
if os.path.splitext(file.name)[1] == ".pdf":
|
48 |
logging.debug("Loading PDF...")
|
49 |
+
pdftext = ""
|
50 |
+
with open(file.name, 'rb') as pdfFileObj:
|
51 |
+
pdfReader = PyPDF2.PdfReader(pdfFileObj)
|
52 |
+
for page in tqdm(pdfReader.pages):
|
53 |
+
pdftext += page.extract_text()
|
54 |
+
text_raw = pdftext
|
55 |
elif os.path.splitext(file.name)[1] == ".docx":
|
56 |
logging.debug("Loading DOCX...")
|
57 |
DocxReader = download_loader("DocxReader")
|
|
|
67 |
with open(file.name, "r", encoding="utf-8") as f:
|
68 |
text_raw = f.read()
|
69 |
text = add_space(text_raw)
|
70 |
+
# text = block_split(text)
|
71 |
+
# documents += text
|
72 |
documents += [Document(text)]
|
73 |
+
logging.debug("Documents loaded.")
|
74 |
return documents
|
75 |
|
76 |
|
|
|
78 |
api_key,
|
79 |
file_src,
|
80 |
max_input_size=4096,
|
81 |
+
num_outputs=5,
|
82 |
max_chunk_overlap=20,
|
83 |
chunk_size_limit=600,
|
84 |
embedding_limit=None,
|
85 |
+
separator=" "
|
|
|
|
|
86 |
):
|
87 |
os.environ["OPENAI_API_KEY"] = api_key
|
88 |
chunk_size_limit = None if chunk_size_limit == 0 else chunk_size_limit
|
|
|
90 |
separator = " " if separator == "" else separator
|
91 |
|
92 |
llm_predictor = LLMPredictor(
|
93 |
+
llm=ChatOpenAI(model_name="gpt-3.5-turbo-0301", openai_api_key=api_key)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
)
|
95 |
+
prompt_helper = PromptHelper(max_input_size = max_input_size, num_output = num_outputs, max_chunk_overlap = max_chunk_overlap, embedding_limit=embedding_limit, chunk_size_limit=600, separator=separator)
|
96 |
index_name = get_index_name(file_src)
|
97 |
if os.path.exists(f"./index/{index_name}.json"):
|
98 |
logging.info("找到了缓存的索引文件,加载中……")
|
|
|
100 |
else:
|
101 |
try:
|
102 |
documents = get_documents(file_src)
|
103 |
+
logging.info("构建索引中……")
|
104 |
+
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, prompt_helper=prompt_helper, chunk_size_limit=chunk_size_limit)
|
105 |
+
index = GPTSimpleVectorIndex.from_documents(
|
106 |
+
documents, service_context=service_context
|
107 |
)
|
108 |
+
logging.debug("索引构建完成!")
|
109 |
os.makedirs("./index", exist_ok=True)
|
110 |
index.save_to_disk(f"./index/{index_name}.json")
|
111 |
+
logging.debug("索引已保存至本地!")
|
112 |
return index
|
113 |
+
|
114 |
except Exception as e:
|
115 |
+
logging.error("索引构建失败!", e)
|
116 |
print(e)
|
117 |
return None
|
118 |
|
|
|
159 |
question,
|
160 |
prompt_tmpl,
|
161 |
refine_tmpl,
|
162 |
+
sim_k=5,
|
163 |
temprature=0,
|
164 |
prefix_messages=[],
|
165 |
reply_language="中文",
|
|
|
169 |
logging.debug("Index file found")
|
170 |
logging.debug("Querying index...")
|
171 |
llm_predictor = LLMPredictor(
|
172 |
+
llm=ChatOpenAI(
|
173 |
temperature=temprature,
|
174 |
model_name="gpt-3.5-turbo-0301",
|
175 |
prefix_messages=prefix_messages,
|
|
|
181 |
rf_prompt = RefinePrompt(refine_tmpl.replace("{reply_language}", reply_language))
|
182 |
response = index.query(
|
183 |
question,
|
|
|
184 |
similarity_top_k=sim_k,
|
185 |
text_qa_template=qa_prompt,
|
186 |
refine_template=rf_prompt,
|
modules/openai_func.py
CHANGED
@@ -1,70 +1,82 @@
|
|
1 |
import requests
|
2 |
import logging
|
3 |
-
from modules.presets import
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
|
|
|
|
|
|
7 |
|
8 |
-
def
|
9 |
headers = {
|
10 |
"Content-Type": "application/json",
|
11 |
-
"Authorization": f"Bearer {openai_api_key}"
|
12 |
}
|
13 |
-
|
14 |
timeout = timeout_all
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
if
|
24 |
-
|
25 |
-
|
26 |
-
if https_proxy:
|
27 |
-
logging.info(f"使用 HTTPS 代理: {https_proxy}")
|
28 |
-
proxies["https"] = https_proxy
|
29 |
-
|
30 |
-
# 如果有代理,使用代理发送请求,否则使用默认设置发送请求
|
31 |
-
"""
|
32 |
-
暂不支持修改
|
33 |
-
if shared.state.balance_api_url != BALANCE_API_URL:
|
34 |
-
logging.info(f"使用自定义BALANCE API URL: {shared.state.balance_api_url}")
|
35 |
-
"""
|
36 |
-
if proxies:
|
37 |
-
response = requests.get(
|
38 |
-
BALANCE_API_URL,
|
39 |
-
headers=headers,
|
40 |
-
timeout=timeout,
|
41 |
-
proxies=proxies,
|
42 |
-
)
|
43 |
else:
|
44 |
-
|
45 |
-
|
46 |
-
headers=headers,
|
47 |
-
timeout=timeout,
|
48 |
-
)
|
49 |
-
return response
|
50 |
|
51 |
def get_usage(openai_api_key):
|
52 |
try:
|
53 |
-
|
54 |
-
logging.debug(
|
55 |
try:
|
56 |
-
balance =
|
57 |
-
|
58 |
-
|
59 |
-
"total_used") else 0
|
60 |
except Exception as e:
|
61 |
logging.error(f"API使用情况解析失败:"+str(e))
|
62 |
balance = 0
|
63 |
total_used=0
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
except requests.exceptions.ConnectTimeout:
|
66 |
status_text = standard_error_msg + connection_timeout_prompt + error_retrieve_prompt
|
67 |
return status_text
|
68 |
except requests.exceptions.ReadTimeout:
|
69 |
status_text = standard_error_msg + read_timeout_prompt + error_retrieve_prompt
|
70 |
return status_text
|
|
|
|
|
|
|
|
1 |
import requests
|
2 |
import logging
|
3 |
+
from modules.presets import (
|
4 |
+
timeout_all,
|
5 |
+
USAGE_API_URL,
|
6 |
+
BALANCE_API_URL,
|
7 |
+
standard_error_msg,
|
8 |
+
connection_timeout_prompt,
|
9 |
+
error_retrieve_prompt,
|
10 |
+
read_timeout_prompt
|
11 |
+
)
|
12 |
|
13 |
+
from modules import shared
|
14 |
+
from modules.utils import get_proxies
|
15 |
+
import os, datetime
|
16 |
|
17 |
+
def get_billing_data(openai_api_key, billing_url):
|
18 |
headers = {
|
19 |
"Content-Type": "application/json",
|
20 |
+
"Authorization": f"Bearer {openai_api_key}"
|
21 |
}
|
22 |
+
|
23 |
timeout = timeout_all
|
24 |
+
proxies = get_proxies()
|
25 |
+
response = requests.get(
|
26 |
+
billing_url,
|
27 |
+
headers=headers,
|
28 |
+
timeout=timeout,
|
29 |
+
proxies=proxies,
|
30 |
+
)
|
31 |
+
|
32 |
+
if response.status_code == 200:
|
33 |
+
data = response.json()
|
34 |
+
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
else:
|
36 |
+
raise Exception(f"API request failed with status code {response.status_code}: {response.text}")
|
37 |
+
|
|
|
|
|
|
|
|
|
38 |
|
39 |
def get_usage(openai_api_key):
|
40 |
try:
|
41 |
+
balance_data=get_billing_data(openai_api_key, BALANCE_API_URL)
|
42 |
+
logging.debug(balance_data)
|
43 |
try:
|
44 |
+
balance = balance_data["total_available"] if balance_data["total_available"] else 0
|
45 |
+
total_used = balance_data["total_used"] if balance_data["total_used"] else 0
|
46 |
+
usage_percent = round(total_used / (total_used+balance) * 100, 2)
|
|
|
47 |
except Exception as e:
|
48 |
logging.error(f"API使用情况解析失败:"+str(e))
|
49 |
balance = 0
|
50 |
total_used=0
|
51 |
+
return f"**API使用情况解析失败**"
|
52 |
+
if balance == 0:
|
53 |
+
last_day_of_month = datetime.datetime.now().strftime("%Y-%m-%d")
|
54 |
+
first_day_of_month = datetime.datetime.now().replace(day=1).strftime("%Y-%m-%d")
|
55 |
+
usage_url = f"{USAGE_API_URL}?start_date={first_day_of_month}&end_date={last_day_of_month}"
|
56 |
+
try:
|
57 |
+
usage_data = get_billing_data(openai_api_key, usage_url)
|
58 |
+
except Exception as e:
|
59 |
+
logging.error(f"获取API使用情况失败:"+str(e))
|
60 |
+
return f"**获取API使用情况失败**"
|
61 |
+
return f"**本月使用金额** \u3000 ${usage_data['total_usage'] / 100}"
|
62 |
+
|
63 |
+
# return f"**免费额度**(已用/余额)\u3000${total_used} / ${balance}"
|
64 |
+
return f"""\
|
65 |
+
<b>免费额度使用情况</b>
|
66 |
+
<div class="progress-bar">
|
67 |
+
<div class="progress" style="width: {usage_percent}%;">
|
68 |
+
<span class="progress-text">{usage_percent}%</span>
|
69 |
+
</div>
|
70 |
+
</div>
|
71 |
+
<div style="display: flex; justify-content: space-between;"><span>已用 ${total_used}</span><span>可用 ${balance}</span></div>
|
72 |
+
"""
|
73 |
+
|
74 |
except requests.exceptions.ConnectTimeout:
|
75 |
status_text = standard_error_msg + connection_timeout_prompt + error_retrieve_prompt
|
76 |
return status_text
|
77 |
except requests.exceptions.ReadTimeout:
|
78 |
status_text = standard_error_msg + read_timeout_prompt + error_retrieve_prompt
|
79 |
return status_text
|
80 |
+
except Exception as e:
|
81 |
+
logging.error(f"获取API使用情况失败:"+str(e))
|
82 |
+
return standard_error_msg + error_retrieve_prompt
|
modules/presets.py
CHANGED
@@ -5,6 +5,7 @@ import gradio as gr
|
|
5 |
initial_prompt = "You are a helpful assistant."
|
6 |
API_URL = "https://api.openai.com/v1/chat/completions"
|
7 |
BALANCE_API_URL="https://api.openai.com/dashboard/billing/credit_grants"
|
|
|
8 |
HISTORY_DIR = "history"
|
9 |
TEMPLATES_DIR = "templates"
|
10 |
|
@@ -18,9 +19,7 @@ ssl_error_prompt = "SSL错误,无法获取对话。" # SSL 错误
|
|
18 |
no_apikey_msg = "API key长度不是51位,请检查是否输入正确。" # API key 长度不足 51 位
|
19 |
no_input_msg = "请输入对话内容。" # 未输入对话内容
|
20 |
|
21 |
-
max_token_streaming = 3500 # 流式对话时的最大 token 数
|
22 |
timeout_streaming = 10 # 流式对话时的超时时间
|
23 |
-
max_token_all = 3500 # 非流式对话时的最大 token 数
|
24 |
timeout_all = 200 # 非流式对话时的超时时间
|
25 |
enable_streaming_option = True # 是否启用选择选择是否实时显示回答的勾选框
|
26 |
HIDE_MY_KEY = False # 如果你想在UI中隐藏你的 API 密钥,将此值设置为 True
|
@@ -41,6 +40,10 @@ description = """\
|
|
41 |
</div>
|
42 |
"""
|
43 |
|
|
|
|
|
|
|
|
|
44 |
summarize_prompt = "你是谁?我们刚才聊了什么?" # 总结对话时的 prompt
|
45 |
|
46 |
MODELS = [
|
@@ -52,8 +55,36 @@ MODELS = [
|
|
52 |
"gpt-4-32k-0314",
|
53 |
] # 可选的模型
|
54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
REPLY_LANGUAGES = [
|
56 |
-
"
|
|
|
57 |
"English",
|
58 |
"日本語",
|
59 |
"Español",
|
|
|
5 |
initial_prompt = "You are a helpful assistant."
|
6 |
API_URL = "https://api.openai.com/v1/chat/completions"
|
7 |
BALANCE_API_URL="https://api.openai.com/dashboard/billing/credit_grants"
|
8 |
+
USAGE_API_URL="https://api.openai.com/dashboard/billing/usage"
|
9 |
HISTORY_DIR = "history"
|
10 |
TEMPLATES_DIR = "templates"
|
11 |
|
|
|
19 |
no_apikey_msg = "API key长度不是51位,请检查是否输入正确。" # API key 长度不足 51 位
|
20 |
no_input_msg = "请输入对话内容。" # 未输入对话内容
|
21 |
|
|
|
22 |
timeout_streaming = 10 # 流式对话时的超时时间
|
|
|
23 |
timeout_all = 200 # 非流式对话时的超时时间
|
24 |
enable_streaming_option = True # 是否启用选择选择是否实时显示回答的勾选框
|
25 |
HIDE_MY_KEY = False # 如果你想在UI中隐藏你的 API 密钥,将此值设置为 True
|
|
|
40 |
</div>
|
41 |
"""
|
42 |
|
43 |
+
footer = """\
|
44 |
+
<div class="versions">{versions}</div>
|
45 |
+
"""
|
46 |
+
|
47 |
summarize_prompt = "你是谁?我们刚才聊了什么?" # 总结对话时的 prompt
|
48 |
|
49 |
MODELS = [
|
|
|
55 |
"gpt-4-32k-0314",
|
56 |
] # 可选的模型
|
57 |
|
58 |
+
MODEL_SOFT_TOKEN_LIMIT = {
|
59 |
+
"gpt-3.5-turbo": {
|
60 |
+
"streaming": 3500,
|
61 |
+
"all": 3500
|
62 |
+
},
|
63 |
+
"gpt-3.5-turbo-0301": {
|
64 |
+
"streaming": 3500,
|
65 |
+
"all": 3500
|
66 |
+
},
|
67 |
+
"gpt-4": {
|
68 |
+
"streaming": 7500,
|
69 |
+
"all": 7500
|
70 |
+
},
|
71 |
+
"gpt-4-0314": {
|
72 |
+
"streaming": 7500,
|
73 |
+
"all": 7500
|
74 |
+
},
|
75 |
+
"gpt-4-32k": {
|
76 |
+
"streaming": 31000,
|
77 |
+
"all": 31000
|
78 |
+
},
|
79 |
+
"gpt-4-32k-0314": {
|
80 |
+
"streaming": 31000,
|
81 |
+
"all": 31000
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
REPLY_LANGUAGES = [
|
86 |
+
"简体中文",
|
87 |
+
"繁體中文",
|
88 |
"English",
|
89 |
"日本語",
|
90 |
"Español",
|
modules/utils.py
CHANGED
@@ -10,6 +10,8 @@ import csv
|
|
10 |
import requests
|
11 |
import re
|
12 |
import html
|
|
|
|
|
13 |
|
14 |
import gradio as gr
|
15 |
from pypinyin import lazy_pinyin
|
@@ -115,7 +117,11 @@ def convert_mdtext(md_text):
|
|
115 |
|
116 |
|
117 |
def convert_asis(userinput):
|
118 |
-
return
|
|
|
|
|
|
|
|
|
119 |
|
120 |
def detect_converted_mark(userinput):
|
121 |
if userinput.endswith(ALREADY_CONVERTED_MARK):
|
@@ -153,6 +159,7 @@ def construct_assistant(text):
|
|
153 |
def construct_token_message(token, stream=False):
|
154 |
return f"Token 计数: {token}"
|
155 |
|
|
|
156 |
def delete_first_conversation(history, previous_token_count):
|
157 |
if history:
|
158 |
del history[:2]
|
@@ -364,20 +371,14 @@ def submit_key(key):
|
|
364 |
return key, msg
|
365 |
|
366 |
|
367 |
-
def sha1sum(filename):
|
368 |
-
sha1 = hashlib.sha1()
|
369 |
-
sha1.update(filename.encode("utf-8"))
|
370 |
-
return sha1.hexdigest()
|
371 |
-
|
372 |
-
|
373 |
def replace_today(prompt):
|
374 |
today = datetime.datetime.today().strftime("%Y-%m-%d")
|
375 |
return prompt.replace("{current_date}", today)
|
376 |
|
377 |
|
378 |
def get_geoip():
|
379 |
-
response = requests.get("https://ipapi.co/json/", timeout=5)
|
380 |
try:
|
|
|
381 |
data = response.json()
|
382 |
except:
|
383 |
data = {"error": True, "reason": "连接ipapi失败"}
|
@@ -385,7 +386,7 @@ def get_geoip():
|
|
385 |
logging.warning(f"无法获取IP地址信息。\n{data}")
|
386 |
if data["reason"] == "RateLimited":
|
387 |
return (
|
388 |
-
f"获取IP地理位置失败,因为达到了检测IP
|
389 |
)
|
390 |
else:
|
391 |
return f"获取IP地理位置失败。原因:{data['reason']}。你仍然可以使用聊天功能。"
|
@@ -429,8 +430,91 @@ def cancel_outputing():
|
|
429 |
logging.info("中止输出……")
|
430 |
shared.state.interrupt()
|
431 |
|
|
|
432 |
def transfer_input(inputs):
|
433 |
# 一次性返回,降低延迟
|
434 |
textbox = reset_textbox()
|
435 |
outputing = start_outputing()
|
436 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
import requests
|
11 |
import re
|
12 |
import html
|
13 |
+
import sys
|
14 |
+
import subprocess
|
15 |
|
16 |
import gradio as gr
|
17 |
from pypinyin import lazy_pinyin
|
|
|
117 |
|
118 |
|
119 |
def convert_asis(userinput):
|
120 |
+
return (
|
121 |
+
f'<p style="white-space:pre-wrap;">{html.escape(userinput)}</p>'
|
122 |
+
+ ALREADY_CONVERTED_MARK
|
123 |
+
)
|
124 |
+
|
125 |
|
126 |
def detect_converted_mark(userinput):
|
127 |
if userinput.endswith(ALREADY_CONVERTED_MARK):
|
|
|
159 |
def construct_token_message(token, stream=False):
|
160 |
return f"Token 计数: {token}"
|
161 |
|
162 |
+
|
163 |
def delete_first_conversation(history, previous_token_count):
|
164 |
if history:
|
165 |
del history[:2]
|
|
|
371 |
return key, msg
|
372 |
|
373 |
|
|
|
|
|
|
|
|
|
|
|
|
|
374 |
def replace_today(prompt):
|
375 |
today = datetime.datetime.today().strftime("%Y-%m-%d")
|
376 |
return prompt.replace("{current_date}", today)
|
377 |
|
378 |
|
379 |
def get_geoip():
|
|
|
380 |
try:
|
381 |
+
response = requests.get("https://ipapi.co/json/", timeout=5)
|
382 |
data = response.json()
|
383 |
except:
|
384 |
data = {"error": True, "reason": "连接ipapi失败"}
|
|
|
386 |
logging.warning(f"无法获取IP地址信息。\n{data}")
|
387 |
if data["reason"] == "RateLimited":
|
388 |
return (
|
389 |
+
f"获取IP地理位置失败,因为达到了检测IP的速率限制。聊天功能可能仍然可用。"
|
390 |
)
|
391 |
else:
|
392 |
return f"获取IP地理位置失败。原因:{data['reason']}。你仍然可以使用聊天功能。"
|
|
|
430 |
logging.info("中止输出……")
|
431 |
shared.state.interrupt()
|
432 |
|
433 |
+
|
434 |
def transfer_input(inputs):
|
435 |
# 一次性返回,降低延迟
|
436 |
textbox = reset_textbox()
|
437 |
outputing = start_outputing()
|
438 |
+
return (
|
439 |
+
inputs,
|
440 |
+
gr.update(value=""),
|
441 |
+
gr.Button.update(visible=True),
|
442 |
+
gr.Button.update(visible=False),
|
443 |
+
)
|
444 |
+
|
445 |
+
|
446 |
+
def get_proxies():
|
447 |
+
# 获取环境变量中的代理设置
|
448 |
+
http_proxy = os.environ.get("HTTP_PROXY") or os.environ.get("http_proxy")
|
449 |
+
https_proxy = os.environ.get("HTTPS_PROXY") or os.environ.get("https_proxy")
|
450 |
+
|
451 |
+
# 如果存在代理设置,使用它们
|
452 |
+
proxies = {}
|
453 |
+
if http_proxy:
|
454 |
+
logging.info(f"使用 HTTP 代理: {http_proxy}")
|
455 |
+
proxies["http"] = http_proxy
|
456 |
+
if https_proxy:
|
457 |
+
logging.info(f"使用 HTTPS 代理: {https_proxy}")
|
458 |
+
proxies["https"] = https_proxy
|
459 |
+
|
460 |
+
if proxies == {}:
|
461 |
+
proxies = None
|
462 |
+
|
463 |
+
return proxies
|
464 |
+
|
465 |
+
def run(command, desc=None, errdesc=None, custom_env=None, live=False):
|
466 |
+
if desc is not None:
|
467 |
+
print(desc)
|
468 |
+
if live:
|
469 |
+
result = subprocess.run(command, shell=True, env=os.environ if custom_env is None else custom_env)
|
470 |
+
if result.returncode != 0:
|
471 |
+
raise RuntimeError(f"""{errdesc or 'Error running command'}.
|
472 |
+
Command: {command}
|
473 |
+
Error code: {result.returncode}""")
|
474 |
+
|
475 |
+
return ""
|
476 |
+
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, env=os.environ if custom_env is None else custom_env)
|
477 |
+
if result.returncode != 0:
|
478 |
+
message = f"""{errdesc or 'Error running command'}.
|
479 |
+
Command: {command}
|
480 |
+
Error code: {result.returncode}
|
481 |
+
stdout: {result.stdout.decode(encoding="utf8", errors="ignore") if len(result.stdout)>0 else '<empty>'}
|
482 |
+
stderr: {result.stderr.decode(encoding="utf8", errors="ignore") if len(result.stderr)>0 else '<empty>'}
|
483 |
+
"""
|
484 |
+
raise RuntimeError(message)
|
485 |
+
return result.stdout.decode(encoding="utf8", errors="ignore")
|
486 |
+
|
487 |
+
def versions_html():
|
488 |
+
git = os.environ.get('GIT', "git")
|
489 |
+
python_version = ".".join([str(x) for x in sys.version_info[0:3]])
|
490 |
+
try:
|
491 |
+
commit_hash = run(f"{git} rev-parse HEAD").strip()
|
492 |
+
except Exception:
|
493 |
+
commit_hash = "<none>"
|
494 |
+
if commit_hash != "<none>":
|
495 |
+
short_commit = commit_hash[0:7]
|
496 |
+
commit_info = f"<a style=\"text-decoration:none\" href=\"https://github.com/GaiZhenbiao/ChuanhuChatGPT/commit/{short_commit}\">{short_commit}</a>"
|
497 |
+
else:
|
498 |
+
commit_info = "unknown \U0001F615"
|
499 |
+
return f"""
|
500 |
+
Python: <span title="{sys.version}">{python_version}</span>
|
501 |
+
•
|
502 |
+
Gradio: {gr.__version__}
|
503 |
+
•
|
504 |
+
Commit: {commit_info}
|
505 |
+
"""
|
506 |
+
|
507 |
+
def add_source_numbers(lst, source_name = "Source", use_source = True):
|
508 |
+
if use_source:
|
509 |
+
return [f'[{idx+1}]\t "{item[0]}"\n{source_name}: {item[1]}' for idx, item in enumerate(lst)]
|
510 |
+
else:
|
511 |
+
return [f'[{idx+1}]\t "{item}"' for idx, item in enumerate(lst)]
|
512 |
+
|
513 |
+
def add_details(lst):
|
514 |
+
nodes = []
|
515 |
+
for index, txt in enumerate(lst):
|
516 |
+
brief = txt[:25].replace("\n", "")
|
517 |
+
nodes.append(
|
518 |
+
f"<details><summary>{brief}...</summary><p>{txt}</p></details>"
|
519 |
+
)
|
520 |
+
return nodes
|
requirements.txt
CHANGED
@@ -10,3 +10,4 @@ Pygments
|
|
10 |
llama_index
|
11 |
langchain
|
12 |
markdown
|
|
|
|
10 |
llama_index
|
11 |
langchain
|
12 |
markdown
|
13 |
+
PyPDF2
|