hushell Pearx commited on
Commit
e2b2a3b
0 Parent(s):

Duplicate from Pearx/ChatGPT-Assistant

Browse files

Co-authored-by: uy <Pearx@users.noreply.huggingface.co>

Files changed (7) hide show
  1. .gitattributes +34 -0
  2. README.md +15 -0
  3. app.py +274 -0
  4. custom.py +134 -0
  5. helper.py +137 -0
  6. requirements.txt +4 -0
  7. set_context.py +64 -0
.gitattributes ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: ChatGPT Assistant
3
+ emoji: 🔥
4
+ colorFrom: gray
5
+ colorTo: gray
6
+ sdk: streamlit
7
+ sdk_version: 1.19.0
8
+ app_file: app.py
9
+ pinned: true
10
+ license: apache-2.0
11
+ fullWidth: true
12
+ duplicated_from: Pearx/ChatGPT-Assistant
13
+ ---
14
+
15
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from helper import *
2
+ import streamlit as st
3
+ import uuid
4
+ import copy
5
+ import pandas as pd
6
+ import openai
7
+ from requests.models import ChunkedEncodingError
8
+ from streamlit.components import v1
9
+ from custom import css_code, js_code, set_context_all
10
+
11
+ st.set_page_config(page_title='ChatGPT Assistant', layout='wide', page_icon='🤖')
12
+ # 自定义元素样式
13
+ st.markdown(css_code, unsafe_allow_html=True)
14
+
15
+ if "initial_settings" not in st.session_state:
16
+ # 历史聊天窗口
17
+ st.session_state["path"] = set_chats_path()
18
+ st.session_state['history_chats'] = get_history_chats(st.session_state["path"])
19
+ # ss参数初始化
20
+ st.session_state['pre_chat'] = None
21
+ st.session_state['if_chat_change'] = False
22
+ st.session_state['error_info'] = ''
23
+ st.session_state["current_chat_index"] = 0
24
+ st.session_state['user_input_content'] = ''
25
+ # 设置完成
26
+ st.session_state["initial_settings"] = True
27
+
28
+ with st.sidebar:
29
+ st.markdown("# 🤖 聊天窗口")
30
+ current_chat = st.radio(
31
+ label='历史聊天窗口',
32
+ format_func=lambda x: x.split('_')[0] if '_' in x else x,
33
+ options=st.session_state['history_chats'],
34
+ label_visibility='collapsed',
35
+ index=st.session_state["current_chat_index"],
36
+ key='current_chat' + st.session_state['history_chats'][st.session_state["current_chat_index"]],
37
+ # on_change=current_chat_callback # 此处不适合用回调,无法识别到窗口增减的变动
38
+ )
39
+ if st.session_state['pre_chat'] != current_chat:
40
+ st.session_state['pre_chat'] = current_chat
41
+ st.session_state['if_chat_change'] = True
42
+ st.write("---")
43
+
44
+ c1, c2 = st.columns(2)
45
+
46
+ create_chat_button = c1.button('新建', use_container_width=True, key='create_chat_button')
47
+ if create_chat_button:
48
+ st.session_state['history_chats'] = ['New Chat_' + str(uuid.uuid4())] + st.session_state['history_chats']
49
+ st.session_state["current_chat_index"] = 0
50
+ st.experimental_rerun()
51
+
52
+ delete_chat_button = c2.button('删除', use_container_width=True, key='delete_chat_button')
53
+ if delete_chat_button:
54
+ if len(st.session_state['history_chats']) == 1:
55
+ chat_init = 'New Chat_' + str(uuid.uuid4())
56
+ st.session_state['history_chats'].append(chat_init)
57
+ st.session_state['current_chat'] = chat_init
58
+ pre_chat_index = st.session_state['history_chats'].index(current_chat)
59
+ if pre_chat_index > 0:
60
+ st.session_state["current_chat_index"] = st.session_state['history_chats'].index(current_chat) - 1
61
+ else:
62
+ st.session_state["current_chat_index"] = 0
63
+ st.session_state['history_chats'].remove(current_chat)
64
+ remove_data(st.session_state["path"], current_chat)
65
+ st.experimental_rerun()
66
+
67
+ for i in range(5):
68
+ st.write("\n")
69
+ st.caption("""
70
+ - 双击页面可直接定位输入栏
71
+ - Ctrl + Enter 可快捷提交问题
72
+ """)
73
+ st.markdown('<a href="https://github.com/PierXuY/ChatGPT-Assistant" target="_blank" rel="ChatGPT-Assistant">'
74
+ '<img src="https://badgen.net/badge/icon/GitHub?icon=github&amp;label=ChatGPT Assistant" alt="GitHub">'
75
+ '</a>', unsafe_allow_html=True)
76
+ # 加载数据
77
+ if ("history" + current_chat not in st.session_state) or (st.session_state['if_chat_change']):
78
+ for key, value in load_data(st.session_state["path"], current_chat).items():
79
+ if key == 'history':
80
+ st.session_state[key + current_chat] = value
81
+ else:
82
+ for k, v in value.items():
83
+ st.session_state[k + current_chat + 'default'] = v
84
+ st.session_state['if_chat_change'] = False
85
+
86
+
87
+ # 一键复制按钮
88
+ st.markdown('<center><a href="https://huggingface.co/spaces/Pearx/ChatGPT-Assistant?duplicate=true">'
89
+ '<img src="https://bit.ly/3gLdBN6" alt="Duplicate Space"></a><center>', unsafe_allow_html=True)
90
+ # 对话展示
91
+ show_messages(st.session_state["history" + current_chat])
92
+
93
+
94
+ # 数据写入文件
95
+ def write_data(new_chat_name=current_chat):
96
+ # 防止高频创建时组件尚未渲染完成,不影响正常写入
97
+ if "frequency_penalty" + current_chat in st.session_state:
98
+ st.session_state["paras"] = {
99
+ "temperature": st.session_state["temperature" + current_chat],
100
+ "top_p": st.session_state["top_p" + current_chat],
101
+ "presence_penalty": st.session_state["presence_penalty" + current_chat],
102
+ "frequency_penalty": st.session_state["frequency_penalty" + current_chat],
103
+ }
104
+ st.session_state["contexts"] = {
105
+ "context_select": st.session_state["context_select" + current_chat],
106
+ "context_input": st.session_state["context_input" + current_chat],
107
+ "context_level": st.session_state["context_level" + current_chat],
108
+ }
109
+ save_data(st.session_state["path"], new_chat_name, st.session_state["history" + current_chat],
110
+ st.session_state["paras"], st.session_state["contexts"])
111
+
112
+
113
+ # 输入内容展示
114
+ area_user_svg = st.empty()
115
+ area_user_content = st.empty()
116
+ # 回复展示
117
+ area_gpt_svg = st.empty()
118
+ area_gpt_content = st.empty()
119
+ # 报错展示
120
+ area_error = st.empty()
121
+
122
+ st.header('ChatGPT Assistant')
123
+ tap_input, tap_context, tap_set = st.tabs(['💬 聊天', '🗒️ 预设', '⚙️ 设置'])
124
+
125
+ with tap_context:
126
+ set_context_list = list(set_context_all.keys())
127
+ context_select_index = set_context_list.index(st.session_state['context_select' + current_chat + "default"])
128
+ st.selectbox(label='选择上下文', options=set_context_list, key='context_select' + current_chat,
129
+ index=context_select_index, on_change=write_data)
130
+ st.caption(set_context_all[st.session_state['context_select' + current_chat]])
131
+ context_input = st.text_area(label='补充或自定义上下文:', key="context_input" + current_chat,
132
+ value=st.session_state['context_input' + current_chat + "default"],
133
+ on_change=write_data)
134
+ st.caption(context_input)
135
+
136
+ with tap_set:
137
+ def clear_button_callback():
138
+ st.session_state['history' + current_chat] = copy.deepcopy(initial_content_history)
139
+ write_data()
140
+
141
+
142
+ st.button("清空聊天记录", use_container_width=True, on_click=clear_button_callback)
143
+
144
+ st.markdown("OpenAI API Key (可选)")
145
+ st.text_input("OpenAI API Key (可选)", type='password', key='apikey_input', label_visibility='collapsed')
146
+ st.caption(
147
+ "此Key仅在当前网页有效,且优先级高于Secrets中的配置,仅自己可用,他人无法共享。[官网获取](https://platform.openai.com/account/api-keys)")
148
+
149
+ st.markdown("包含对话次数:")
150
+ st.slider("Context Level", 0, 10, st.session_state['context_level' + current_chat + "default"], 1,
151
+ on_change=write_data,
152
+ key='context_level' + current_chat, help="表示每次会话中包含的历史对话次数,预设内容不计算在内。")
153
+
154
+ st.markdown("模型参数:")
155
+ st.slider("Temperature", 0.0, 2.0, st.session_state["temperature" + current_chat + "default"], 0.1,
156
+ help="""在0和2之间,应该使用什么样的采样温度?较高的值(如0.8)会使输出更随机,而较低的值(如0.2)则会使其更加集中和确定性。
157
+ 我们一般建议只更改这个参数或top_p参数中的一个,而不要同时更改两个。""",
158
+ on_change=write_data, key='temperature' + current_chat)
159
+ st.slider("Top P", 0.1, 1.0, st.session_state["top_p" + current_chat + "default"], 0.1,
160
+ help="""一种替代采用温度进行采样的方法,称为“基于核心概率”的采样。在该方法中,模型会考虑概率最高的top_p个标记的预测结果。
161
+ 因此,当该参数为0.1时,只有包括前10%概率质量的标记将被考虑。我们一般建议只更改这个参数或采样温度参数中的一个,而不要同时更改两个。""",
162
+ on_change=write_data, key='top_p' + current_chat)
163
+ st.slider("Presence Penalty", -2.0, 2.0,
164
+ st.session_state["presence_penalty" + current_chat + "default"], 0.1,
165
+ help="""该参数的取值范围为-2.0到2.0。正值会根据新标记是否出现在当前生成的文本中对其进行惩罚,从而增加模型谈论新话题的可能性。""",
166
+ on_change=write_data, key='presence_penalty' + current_chat)
167
+ st.slider("Frequency Penalty", -2.0, 2.0,
168
+ st.session_state["frequency_penalty" + current_chat + "default"], 0.1,
169
+ help="""该参数的取值范围为-2.0到2.0。正值会根据新标记在当前生成的文本中的已有频率对其进行惩罚,从而减少模型直接重复相同语句的可能性。""",
170
+ on_change=write_data, key='frequency_penalty' + current_chat)
171
+ st.caption("[官网参数说明](https://platform.openai.com/docs/api-reference/completions/create)")
172
+
173
+ with tap_input:
174
+ def input_callback():
175
+ if st.session_state['user_input_area'] != "":
176
+ # 修改窗口名称
177
+ user_input_content = st.session_state['user_input_area']
178
+ df_history = pd.DataFrame(st.session_state["history" + current_chat])
179
+ if len(df_history.query('role!="system"')) == 0:
180
+ remove_data(st.session_state["path"], current_chat)
181
+ current_chat_index = st.session_state['history_chats'].index(current_chat)
182
+ new_name = extract_chars(user_input_content, 18) + '_' + str(uuid.uuid4())
183
+ st.session_state['history_chats'][current_chat_index] = new_name
184
+ st.session_state["current_chat_index"] = current_chat_index
185
+ # 写入新文件
186
+ write_data(new_name)
187
+
188
+
189
+
190
+ with st.form("input_form", clear_on_submit=True):
191
+ user_input = st.text_area("**输入:**", key="user_input_area")
192
+ submitted = st.form_submit_button("确认提交", use_container_width=True, on_click=input_callback)
193
+ if submitted:
194
+ st.session_state['user_input_content'] = user_input
195
+
196
+ if st.session_state['user_input_content'] != '':
197
+ if 'r' in st.session_state:
198
+ st.session_state.pop("r")
199
+ st.session_state[current_chat + 'report'] = ""
200
+ st.session_state['pre_user_input_content'] = (remove_hashtag_right__space(st.session_state['user_input_content']
201
+ .replace('\n', '\n\n')))
202
+ st.session_state['user_input_content'] = ''
203
+ show_each_message(st.session_state['pre_user_input_content'], 'user',
204
+ [area_user_svg.markdown, area_user_content.markdown])
205
+ context_level_tem = st.session_state['context_level' + current_chat]
206
+ history_tem = get_history_input(st.session_state["history" + current_chat], context_level_tem) + \
207
+ [{"role": "user", "content": st.session_state['pre_user_input_content']}]
208
+ history_need_input = ([{"role": "system",
209
+ "content": set_context_all[st.session_state['context_select' + current_chat]]}]
210
+ + [{"role": "system",
211
+ "content": st.session_state['context_input' + current_chat]}]
212
+ + history_tem)
213
+ paras_need_input = {
214
+ "temperature": st.session_state["temperature" + current_chat],
215
+ "top_p": st.session_state["top_p" + current_chat],
216
+ "presence_penalty": st.session_state["presence_penalty" + current_chat],
217
+ "frequency_penalty": st.session_state["frequency_penalty" + current_chat],
218
+ }
219
+ with st.spinner("🤔"):
220
+ try:
221
+ if apikey := st.session_state['apikey_input']:
222
+ openai.api_key = apikey
223
+ else:
224
+ openai.api_key = st.secrets["apikey"]
225
+ r = openai.ChatCompletion.create(model="gpt-3.5-turbo", messages=history_need_input, stream=True,
226
+ **paras_need_input)
227
+ except (FileNotFoundError, KeyError):
228
+ area_error.error("缺失 OpenAI API Key,请在复制项目后配置Secrets,或者在设置中进行临时配置。"
229
+ "详情见[项目仓库](https://github.com/PierXuY/ChatGPT-Assistant)。")
230
+ except openai.error.AuthenticationError:
231
+ area_error.error("无效的 OpenAI API Key。")
232
+ except openai.error.APIConnectionError as e:
233
+ area_error.error("连接超时,请重试。报错: \n" + str(e.args[0]))
234
+ except openai.error.InvalidRequestError as e:
235
+ area_error.error("无效的请求,请重试。报错: \n" + str(e.args[0]))
236
+ except openai.error.RateLimitError as e:
237
+ area_error.error("请求速率过快,请重试。报错: \n" + str(e.args[0]))
238
+ else:
239
+ st.session_state["chat_of_r"] = current_chat
240
+ st.session_state["r"] = r
241
+ st.experimental_rerun()
242
+
243
+ if ("r" in st.session_state) and (current_chat == st.session_state["chat_of_r"]):
244
+ if current_chat + 'report' not in st.session_state:
245
+ st.session_state[current_chat + 'report'] = ""
246
+ try:
247
+ for e in st.session_state["r"]:
248
+ if "content" in e["choices"][0]["delta"]:
249
+ st.session_state[current_chat + 'report'] += e["choices"][0]["delta"]["content"]
250
+ show_each_message(st.session_state['pre_user_input_content'], 'user',
251
+ [area_user_svg.markdown, area_user_content.markdown])
252
+ show_each_message(st.session_state[current_chat + 'report'], 'assistant',
253
+ [area_gpt_svg.markdown, area_gpt_content.markdown])
254
+ except ChunkedEncodingError:
255
+ area_error.error("网络状况不佳,请刷新页面重试。")
256
+ # 应对stop情形
257
+ except Exception:
258
+ pass
259
+ else:
260
+ # 保存内容
261
+ st.session_state["history" + current_chat].append(
262
+ {"role": "user", "content": st.session_state['pre_user_input_content']})
263
+ st.session_state["history" + current_chat].append(
264
+ {"role": "assistant", "content": st.session_state[current_chat + 'report']})
265
+ write_data()
266
+
267
+ # 用户在网页点击stop时,ss某些情形下会暂时为空
268
+ if current_chat + 'report' in st.session_state:
269
+ st.session_state.pop(current_chat + 'report')
270
+ if 'r' in st.session_state:
271
+ st.session_state.pop("r")
272
+
273
+ # 添加事件监听
274
+ v1.html(js_code, height=0)
custom.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from set_context import set_context
2
+
3
+ # 用户名
4
+ user_name = 'User'
5
+ gpt_name = 'ChatGPT'
6
+ # 头像(svg格式) 来自 https://www.dicebear.com/playground?style=identicon
7
+ user_svg = """
8
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5 5" fill="none" shape-rendering="crispEdges" width="512" height="512"><desc>"Identicon" by "Florian Körner", licensed under "CC0 1.0". / Remix of the original. - Created with dicebear.com</desc><metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:RDF><cc:Work><dc:title>Identicon</dc:title><dc:creator><cc:Agent rdf:about="https://dicebear.com"><dc:title>Florian Körner</dc:title></cc:Agent></dc:creator><dc:source>https://dicebear.com</dc:source><cc:license rdf:resource="https://creativecommons.org/publicdomain/zero/1.0/" /></cc:Work></rdf:RDF></metadata><mask id="viewboxMask"><rect width="5" height="5" rx="0" ry="0" x="0" y="0" fill="#fff" /></mask><g mask="url(#viewboxMask)"><path d="M0 0h1v1H0V0ZM4 0h1v1H4V0ZM3 0H2v1h1V0Z" fill="#00acc1"/><path fill="#00acc1" d="M2 1h1v1H2z"/><path fill="#00acc1" d="M1 2h3v1H1z"/><path fill="#00acc1" d="M2 3h1v1H2z"/><path d="M2 4H1v1h1V4ZM4 4H3v1h1V4Z" fill="#00acc1"/></g></svg>
9
+ """
10
+ gpt_svg = """
11
+ <svg width="41" height="41" viewBox="0 0 41 41" fill="none" xmlns="http://www.w3.org/2000/svg" stroke-width="1.5" class="h-6 w-6"><path d="M37.5324 16.8707C37.9808 15.5241 38.1363 14.0974 37.9886 12.6859C37.8409 11.2744 37.3934 9.91076 36.676 8.68622C35.6126 6.83404 33.9882 5.3676 32.0373 4.4985C30.0864 3.62941 27.9098 3.40259 25.8215 3.85078C24.8796 2.7893 23.7219 1.94125 22.4257 1.36341C21.1295 0.785575 19.7249 0.491269 18.3058 0.500197C16.1708 0.495044 14.0893 1.16803 12.3614 2.42214C10.6335 3.67624 9.34853 5.44666 8.6917 7.47815C7.30085 7.76286 5.98686 8.3414 4.8377 9.17505C3.68854 10.0087 2.73073 11.0782 2.02839 12.312C0.956464 14.1591 0.498905 16.2988 0.721698 18.4228C0.944492 20.5467 1.83612 22.5449 3.268 24.1293C2.81966 25.4759 2.66413 26.9026 2.81182 28.3141C2.95951 29.7256 3.40701 31.0892 4.12437 32.3138C5.18791 34.1659 6.8123 35.6322 8.76321 36.5013C10.7141 37.3704 12.8907 37.5973 14.9789 37.1492C15.9208 38.2107 17.0786 39.0587 18.3747 39.6366C19.6709 40.2144 21.0755 40.5087 22.4946 40.4998C24.6307 40.5054 26.7133 39.8321 28.4418 38.5772C30.1704 37.3223 31.4556 35.5506 32.1119 33.5179C33.5027 33.2332 34.8167 32.6547 35.9659 31.821C37.115 30.9874 38.0728 29.9178 38.7752 28.684C39.8458 26.8371 40.3023 24.6979 40.0789 22.5748C39.8556 20.4517 38.9639 18.4544 37.5324 16.8707ZM22.4978 37.8849C20.7443 37.8874 19.0459 37.2733 17.6994 36.1501C17.7601 36.117 17.8666 36.0586 17.936 36.0161L25.9004 31.4156C26.1003 31.3019 26.2663 31.137 26.3813 30.9378C26.4964 30.7386 26.5563 30.5124 26.5549 30.2825V19.0542L29.9213 20.998C29.9389 21.0068 29.9541 21.0198 29.9656 21.0359C29.977 21.052 29.9842 21.0707 29.9867 21.0902V30.3889C29.9842 32.375 29.1946 34.2791 27.7909 35.6841C26.3872 37.0892 24.4838 37.8806 22.4978 37.8849ZM6.39227 31.0064C5.51397 29.4888 5.19742 27.7107 5.49804 25.9832C5.55718 26.0187 5.66048 26.0818 5.73461 26.1244L13.699 30.7248C13.8975 30.8408 14.1233 30.902 14.3532 30.902C14.583 30.902 14.8088 30.8408 15.0073 30.7248L24.731 25.1103V28.9979C24.7321 29.0177 24.7283 29.0376 24.7199 29.0556C24.7115 29.0736 24.6988 29.0893 24.6829 29.1012L16.6317 33.7497C14.9096 34.7416 12.8643 35.0097 10.9447 34.4954C9.02506 33.9811 7.38785 32.7263 6.39227 31.0064ZM4.29707 13.6194C5.17156 12.0998 6.55279 10.9364 8.19885 10.3327C8.19885 10.4013 8.19491 10.5228 8.19491 10.6071V19.808C8.19351 20.0378 8.25334 20.2638 8.36823 20.4629C8.48312 20.6619 8.64893 20.8267 8.84863 20.9404L18.5723 26.5542L15.206 28.4979C15.1894 28.5089 15.1703 28.5155 15.1505 28.5173C15.1307 28.5191 15.1107 28.516 15.0924 28.5082L7.04046 23.8557C5.32135 22.8601 4.06716 21.2235 3.55289 19.3046C3.03862 17.3858 3.30624 15.3413 4.29707 13.6194ZM31.955 20.0556L22.2312 14.4411L25.5976 12.4981C25.6142 12.4872 25.6333 12.4805 25.6531 12.4787C25.6729 12.4769 25.6928 12.4801 25.7111 12.4879L33.7631 17.1364C34.9967 17.849 36.0017 18.8982 36.6606 20.1613C37.3194 21.4244 37.6047 22.849 37.4832 24.2684C37.3617 25.6878 36.8382 27.0432 35.9743 28.1759C35.1103 29.3086 33.9415 30.1717 32.6047 30.6641C32.6047 30.5947 32.6047 30.4733 32.6047 30.3889V21.188C32.6066 20.9586 32.5474 20.7328 32.4332 20.5338C32.319 20.3348 32.154 20.1698 31.955 20.0556ZM35.3055 15.0128C35.2464 14.9765 35.1431 14.9142 35.069 14.8717L27.1045 10.2712C26.906 10.1554 26.6803 10.0943 26.4504 10.0943C26.2206 10.0943 25.9948 10.1554 25.7963 10.2712L16.0726 15.8858V11.9982C16.0715 11.9783 16.0753 11.9585 16.0837 11.9405C16.0921 11.9225 16.1048 11.9068 16.1207 11.8949L24.1719 7.25025C25.4053 6.53903 26.8158 6.19376 28.2383 6.25482C29.6608 6.31589 31.0364 6.78077 32.2044 7.59508C33.3723 8.40939 34.2842 9.53945 34.8334 10.8531C35.3826 12.1667 35.5464 13.6095 35.3055 15.0128ZM14.2424 21.9419L10.8752 19.9981C10.8576 19.9893 10.8423 19.9763 10.8309 19.9602C10.8195 19.9441 10.8122 19.9254 10.8098 19.9058V10.6071C10.8107 9.18295 11.2173 7.78848 11.9819 6.58696C12.7466 5.38544 13.8377 4.42659 15.1275 3.82264C16.4173 3.21869 17.8524 2.99464 19.2649 3.1767C20.6775 3.35876 22.0089 3.93941 23.1034 4.85067C23.0427 4.88379 22.937 4.94215 22.8668 4.98473L14.9024 9.58517C14.7025 9.69878 14.5366 9.86356 14.4215 10.0626C14.3065 10.2616 14.2466 10.4877 14.2479 10.7175L14.2424 21.9419ZM16.071 17.9991L20.4018 15.4978L24.7325 17.9975V22.9985L20.4018 25.4983L16.071 22.9985V17.9991Z" fill="currentColor"></path></svg>
12
+ """
13
+ # 内容背景
14
+ user_background_color = '#ffffff'
15
+ gpt_background_color = '#fafbfc'
16
+ # 模型初始设置
17
+ initial_content_history = [{"role": 'system',
18
+ "content": '当你的回复中涉及代码块时,请在markdown语法中标明语言类型。如果不涉及,请忽略这句话。'}]
19
+ initial_content_all = {"history": initial_content_history,
20
+ "paras": {
21
+ "temperature": 1.0,
22
+ "top_p": 1.0,
23
+ "presence_penalty": 0.0,
24
+ "frequency_penalty": 0.0,
25
+ },
26
+ "contexts": {
27
+ 'context_select': '不设置',
28
+ 'context_input': '',
29
+ 'context_level': 4
30
+ }}
31
+ # 上下文
32
+ set_context_all = {"不设置": ""}
33
+ set_context_all.update(set_context)
34
+
35
+ # 自定义css、js
36
+ css_code = """
37
+ <style>
38
+ section[data-testid="stSidebar"]>div>div:nth-child(2) {
39
+ padding-top: 1.7rem !important;
40
+ }
41
+ .avatar {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 10px;
45
+ pointer-events: none;
46
+ margin:10px;
47
+ }
48
+ .avatar svg {
49
+ width: 30px;
50
+ height: 30px;
51
+ }
52
+ .avatar h2 {
53
+ font-size: 20px;
54
+ margin: 0px;
55
+ }
56
+
57
+ .content-div {
58
+ padding: 5px 20px;
59
+ margin: 5px;
60
+ text-align: left;
61
+ border-radius: 10px;
62
+ border: none;
63
+ line-height: 1.6;
64
+ font-size:17px;
65
+ }
66
+ .content-div p{
67
+ padding: 4px;
68
+ margin : 2px;
69
+ }
70
+ #chat-window{
71
+ padding: 10px 0px;
72
+ text-decoration: none;
73
+ }
74
+ #chat-window:hover{
75
+ color: blue;
76
+ }
77
+ .stRadio {
78
+ overflow: overlay;
79
+ max-height: 200px;
80
+ min-height: 200px;
81
+ }
82
+ div[data-testid="stForm"]{
83
+ border: none;
84
+ padding: 0;
85
+ }
86
+ button[kind="primaryFormSubmit"]{
87
+ border: none;
88
+ padding: 0;
89
+ }
90
+ h1{
91
+ text-shadow: 2px 2px #ccc;
92
+ font-size: 28px !important;
93
+ font-family: "微软雅黑","auto";
94
+ margin-bottom: 10px;
95
+ font-weight: 500 !important;
96
+ }
97
+ </style>
98
+ """
99
+
100
+ js_code = """
101
+ <script>
102
+ var body = window.parent.document.querySelector(".main");
103
+ var textinput = window.parent.document.querySelector("textarea[aria-label='**输入:**']"); //label需要相对应
104
+ var baseweb = window.parent.document.querySelector("div[data-baseweb = 'textarea']");
105
+ var button = window.parent.document.querySelector("button[kind='secondaryFormSubmit']");
106
+ window.parent.document.addEventListener('dblclick', function (event) {
107
+ event.stopPropagation();
108
+ event.preventDefault();
109
+ textinput.focus();
110
+ });
111
+ window.parent.document.addEventListener('mousedown', (event) => {
112
+ if (event.detail === 2) {
113
+ event.preventDefault();
114
+ }
115
+ });
116
+ window.parent.document.addEventListener("keydown", event => {
117
+ // 按下Ctrl + Enter时
118
+ if (event.ctrlKey && event.key === "Enter") {
119
+ // 模拟按钮的点击事件
120
+ if (textinput.textContent != ''){
121
+ button.click();}
122
+ textinput.blur();
123
+ }
124
+ });
125
+ textinput.addEventListener('focusin', function() {
126
+ event.stopPropagation();
127
+ baseweb.style.borderColor = 'rgb(255,75,75)';
128
+ });
129
+ textinput.addEventListener('focusout', function() {
130
+ event.stopPropagation();
131
+ baseweb.style.borderColor = 'white';
132
+ });
133
+ </script>
134
+ """
helper.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import re
4
+ import builtins
5
+ import shutil
6
+ import uuid
7
+ from functools import wraps
8
+ import streamlit as st
9
+ import pandas as pd
10
+ from custom import *
11
+
12
+
13
+ # 聊天记录处理
14
+ def clear_folder(path):
15
+ if not os.path.exists(path):
16
+ return
17
+ for file_name in os.listdir(path):
18
+ file_path = os.path.join(path, file_name)
19
+ try:
20
+ shutil.rmtree(file_path)
21
+ except Exception:
22
+ pass
23
+
24
+
25
+ def set_chats_path():
26
+ save_path = 'chat_history'
27
+ if 'apikey' not in st.secrets:
28
+ clear_folder('tem_files')
29
+ save_path = 'tem_files/tem_chat' + str(uuid.uuid4())
30
+ return save_path
31
+
32
+
33
+ # 重新open函数,路径不存在时自动创建
34
+ def create_path(func):
35
+ @wraps(func)
36
+ def wrapper(path, *args, **kwargs):
37
+ if not os.path.exists(os.path.dirname(path)):
38
+ os.makedirs(os.path.dirname(path))
39
+ return func(path, *args, **kwargs)
40
+
41
+ return wrapper
42
+
43
+
44
+ open = create_path(builtins.open)
45
+
46
+
47
+ def get_history_chats(path):
48
+ try:
49
+ os.makedirs(path)
50
+ except FileExistsError:
51
+ pass
52
+ files = [f for f in os.listdir(f'./{path}') if f.endswith('.json')]
53
+ files_with_time = [(f, os.stat(f'./{path}/' + f).st_ctime) for f in files]
54
+ sorted_files = sorted(files_with_time, key=lambda x: x[1], reverse=True)
55
+ chat_names = [os.path.splitext(f[0])[0] for f in sorted_files]
56
+ if len(chat_names) == 0:
57
+ chat_names.append('New Chat_' + str(uuid.uuid4()))
58
+ return chat_names
59
+
60
+
61
+ def save_data(path: str, file_name: str, history: list, paras: dict, contexts: dict, **kwargs):
62
+ with open(f"./{path}/{file_name}.json", 'w', encoding='utf-8') as f:
63
+ json.dump({"history": history, "paras": paras, "contexts": contexts, **kwargs}, f)
64
+
65
+
66
+ def remove_data(path: str, file_name: str):
67
+ try:
68
+ os.remove(f"./{path}/{file_name}.json")
69
+ except FileNotFoundError:
70
+ pass
71
+
72
+
73
+ def load_data(path: str, file_name: str) -> dict:
74
+ try:
75
+ with open(f"./{path}/{file_name}.json", 'r', encoding='utf-8') as f:
76
+ data = json.load(f)
77
+ return data
78
+ except FileNotFoundError:
79
+ with open(f"./{path}/{file_name}.json", 'w', encoding='utf-8') as f:
80
+ f.write(json.dumps(initial_content_all))
81
+ return initial_content_all
82
+
83
+
84
+ def show_each_message(message, role, area=None):
85
+ if area is None:
86
+ area = [st.markdown] * 2
87
+ if role == 'user':
88
+ icon = user_svg
89
+ name = user_name
90
+ background_color = user_background_color
91
+ else:
92
+ icon = gpt_svg
93
+ name = gpt_name
94
+ background_color = gpt_background_color
95
+ area[0](f"\n<div class='avatar'>{icon}<h2>{name}:</h2></div>", unsafe_allow_html=True)
96
+ area[1](f"""<div class='content-div' style='background-color: {background_color};'>\n\n{message}""",
97
+ unsafe_allow_html=True)
98
+
99
+
100
+ def show_messages(messages: list):
101
+ for each in messages:
102
+ if (each["role"] == "user") or (each["role"] == "assistant"):
103
+ show_each_message(each["content"], each["role"])
104
+ if each["role"] == "assistant":
105
+ st.write("---")
106
+
107
+
108
+ # 根据context_level提取history
109
+ def get_history_input(history, level):
110
+ df_history = pd.DataFrame(history)
111
+ df_system = df_history.query('role=="system"')
112
+ df_input = df_history.query('role!="system"')
113
+ df_input = df_input[-level * 2:]
114
+ res = pd.concat([df_system, df_input], ignore_index=True).to_dict('records')
115
+ return res
116
+
117
+
118
+ # 去除#号右边的空格
119
+ def remove_hashtag_right__space(text):
120
+ res = re.sub(r"(#+)\s*", r"\1", text)
121
+ return res
122
+
123
+
124
+ # 提取文本
125
+ def extract_chars(text, num):
126
+ char_num = 0
127
+ chars = ''
128
+ for char in text:
129
+ # 汉字算两个字符
130
+ if '\u4e00' <= char <= '\u9fff':
131
+ char_num += 2
132
+ else:
133
+ char_num += 1
134
+ chars += char
135
+ if char_num >= num:
136
+ break
137
+ return chars
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ openai==0.27.0
2
+ streamlit==1.19.0
3
+ pandas==1.5.3
4
+ requests==2.28.2
set_context.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ set_context = {
2
+ "英语学术润色":
3
+ "Below is a paragraph from an academic paper. Polish the writing to meet the academic style, improve the "
4
+ "spelling, grammar, clarity, concision and overall readability."
5
+ "When necessary, rewrite the whole sentence. Furthermore, list all modification and explain the reasons to do "
6
+ "so in markdown table.",
7
+
8
+ '中文学术润色':
9
+ "在这次会话中,你将作为一名中文学术论文写作改进助理。你的任务是改进所提供文本的拼写、语法、清晰、简洁和整体可读性。"
10
+ "同时分解长句,减少重复,并提供改进建议。请只提供文本的更正版本,避免包括解释。",
11
+
12
+ '查找语法错误':
13
+ r"Can you help me ensure that the grammar and the spelling is correct? " +
14
+ r"Do not try to polish the text, if no mistake is found, tell me that this paragraph is good." +
15
+ r"If you find grammar or spelling mistakes, please list mistakes you find in a two-column markdown table, " +
16
+ r"put the original text the first column, " +
17
+ r"put the corrected text in the second column and highlight the key words you fixed.""\n"
18
+ r"Example:""\n"
19
+ r"Paragraph: How is you? Do you knows what is it?""\n"
20
+ r"| Original sentence | Corrected sentence |""\n"
21
+ r"| :--- | :--- |""\n"
22
+ r"| How **is** you? | How **are** you? |""\n"
23
+ r"| Do you **knows** what **is** **it**? | Do you **know** what **it** **is** ? |""\n"
24
+ r"Below is a paragraph from an academic paper. "
25
+ r"You need to report all grammar and spelling mistakes as the example before.",
26
+
27
+ '学术中英互译':
28
+ "I want you to act as a scientific English-Chinese translator, I will provide you with some paragraphs in one "
29
+ "language and your task is to accurately and academically translate the paragraphs only into the other "
30
+ "language."
31
+ "Do not repeat the original provided paragraphs after translation. You should use artificial intelligence "
32
+ "tools, such as natural language processing, and rhetorical knowledge and experience about effective writing "
33
+ "techniques to reply."
34
+ "I'll give you my paragraphs as follows, tell me what language it is written in, and then translate.",
35
+
36
+ '英语交流老师':
37
+ "I want you to act as a spoken English teacher and improver. I will speak to you in English and you will "
38
+ "reply to me in English to practice my spoken English. I want you to keep your reply neat, limiting the reply "
39
+ "to 100 words. I want you to strictly correct my grammar mistakes, typos, and factual errors. I want you to "
40
+ "ask me a question in your reply.Remember, I want you to strictly correct my grammar mistakes, typos, "
41
+ "and factual errors. Now let's start practicing.",
42
+
43
+ '英文翻译与改进':
44
+ "在这次会话中,我想让你充当英语翻译员、拼写纠正员和改进员。我会用任何语言与你交谈,你会检测语言,并在更正和改进我的句子后用英语回答。"
45
+ "我希望你用更优美优雅的高级英语单词和句子来替换我使用的简单单词和句子。保持相同的意思,但使它们更文艺。我要你只回复更正、改进,不要写任何解释。",
46
+
47
+ '寻找网络图片':
48
+ '我需要你找一张网络图片。使用Unsplash API(https://source.unsplash.com/960x640/?<英语关键词>)获取图片URL,'
49
+ '然后请使用Markdown格式封装,并且不要有反斜线,不要用代码块。'
50
+ '现在,请按以下描述给我发送图片:',
51
+
52
+ '数据检索助理':
53
+ "在此次聊天中,你将担任数据检索助理。接下来我会发送数据名称,你告诉我在哪里可以获取到相关数据,并说明如何获取,数据来源要尽量丰富。",
54
+
55
+ '充当Python解释器':
56
+ 'I want you to act like a Python interpreter. I will give you Python code, and you will execute it. Do not '
57
+ 'provide any explanations. Do not respond with anything except the output of the code.',
58
+
59
+ '正则表达式生成器':
60
+ "I want you to act as a regex generator. Your role is to generate regular expressions that match specific "
61
+ "patterns in text. You should provide the regular expressions in a format that can be easily copied and "
62
+ "pasted into a regex-enabled text editor or programming language. Do not write explanations or examples of "
63
+ "how the regular expressions work; simply provide only the regular expressions themselves.",
64
+ }