Keldos commited on
Commit
ed31090
2 Parent(s): ddd1766 d3b93fb

Merge branch 'main' into expansive

Browse files
Files changed (7) hide show
  1. CITATION.cff +20 -0
  2. ChuanhuChatbot.py +10 -10
  3. README.md +5 -3
  4. assets/custom.css +114 -38
  5. assets/custom.js +206 -54
  6. config_example.json +9 -3
  7. modules/presets.py +12 -4
CITATION.cff ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cff-version: 1.2.0
2
+ title: ChuanhuChatGPT
3
+ message: >-
4
+ If you use this software, please cite it using these
5
+ metadata.
6
+ type: software
7
+ authors:
8
+ - given-names: Chuanhu
9
+ orcid: https://orcid.org/0000-0001-8954-8598
10
+ - given-names: MZhao
11
+ orcid: https://orcid.org/0000-0003-2298-6213
12
+ - given-names: Keldos
13
+ orcid: https://orcid.org/0009-0005-0357-272X
14
+ repository-code: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
15
+ url: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
16
+ abstract: Provided a light and easy to use interface for ChatGPT API
17
+ license: GPL-3.0
18
+ commit: bd0034c37e5af6a90bd9c2f7dd073f6cd27c61af
19
+ version: '20230405'
20
+ date-released: '2023-04-05'
ChuanhuChatbot.py CHANGED
@@ -27,10 +27,10 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
27
  topic = gr.State("未命名对话历史记录")
28
 
29
  with gr.Row():
30
- with gr.Column():
31
- gr.HTML(CHUANHU_TITLE)
32
- user_info = gr.Markdown(value="", elem_id="user_info")
33
  status_display = gr.Markdown(get_geoip(), elem_id="status_display")
 
 
34
 
35
  # https://github.com/gradio-app/gradio/pull/3296
36
  def create_greeting(request: gr.Request):
@@ -46,14 +46,14 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
46
  with gr.Row():
47
  chatbot = gr.Chatbot(elem_id="chuanhu_chatbot").style(height="100%")
48
  with gr.Row():
49
- with gr.Column(scale=12):
50
  user_input = gr.Textbox(
51
  elem_id="user_input_tb",
52
  show_label=False, placeholder="在这里输入"
53
  ).style(container=False)
54
- with gr.Column(min_width=70, scale=1):
55
- submitBtn = gr.Button("发送", variant="primary")
56
- cancelBtn = gr.Button("取消", variant="secondary", visible=False)
57
  with gr.Row():
58
  emptyBtn = gr.Button(
59
  "🧹 新的对话",
@@ -74,9 +74,9 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
74
  label="API-Key",
75
  )
76
  if multi_api_key:
77
- usageTxt = gr.Markdown("多账号模式已开启,无需输入key,可直接开始对话", elem_id="usage_display")
78
  else:
79
- usageTxt = gr.Markdown("**发送消息** 或 **提交key** 以显示额度", elem_id="usage_display")
80
  model_select_dropdown = gr.Dropdown(
81
  label="选择模型", choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
82
  )
@@ -159,7 +159,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
159
 
160
  with gr.Tab(label="高级"):
161
  gr.Markdown("# ⚠️ 务必谨慎更改 ⚠️\n\n如果无法使用请恢复默认设置")
162
-
163
  with gr.Accordion("参数", open=False):
164
  temperature_slider = gr.Slider(
165
  minimum=-0,
 
27
  topic = gr.State("未命名对话历史记录")
28
 
29
  with gr.Row():
30
+ gr.HTML(CHUANHU_TITLE, elem_id="app_title")
 
 
31
  status_display = gr.Markdown(get_geoip(), elem_id="status_display")
32
+ with gr.Row(elem_id="float_display"):
33
+ user_info = gr.Markdown(value="getting user info...", elem_id="user_info")
34
 
35
  # https://github.com/gradio-app/gradio/pull/3296
36
  def create_greeting(request: gr.Request):
 
46
  with gr.Row():
47
  chatbot = gr.Chatbot(elem_id="chuanhu_chatbot").style(height="100%")
48
  with gr.Row():
49
+ with gr.Column(min_width=225, scale=12):
50
  user_input = gr.Textbox(
51
  elem_id="user_input_tb",
52
  show_label=False, placeholder="在这里输入"
53
  ).style(container=False)
54
+ with gr.Column(min_width=42, scale=1):
55
+ submitBtn = gr.Button(value="", variant="primary", elem_id="submit_btn")
56
+ cancelBtn = gr.Button(value="", variant="secondary", visible=False, elem_id="cancel_btn")
57
  with gr.Row():
58
  emptyBtn = gr.Button(
59
  "🧹 新的对话",
 
74
  label="API-Key",
75
  )
76
  if multi_api_key:
77
+ usageTxt = gr.Markdown("多账号模式已开启,无需输入key,可直接开始对话", elem_id="usage_display", elem_classes="insert_block")
78
  else:
79
+ usageTxt = gr.Markdown("**发送消息** 或 **提交key** 以显示额度", elem_id="usage_display", elem_classes="insert_block")
80
  model_select_dropdown = gr.Dropdown(
81
  label="选择模型", choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
82
  )
 
159
 
160
  with gr.Tab(label="高级"):
161
  gr.Markdown("# ⚠️ 务必谨慎更改 ⚠️\n\n如果无法使用请恢复默认设置")
162
+ gr.HTML(APPEARANCE_SWITCHER, elem_classes="insert_block")
163
  with gr.Accordion("参数", open=False):
164
  temperature_slider = gr.Slider(
165
  minimum=-0,
README.md CHANGED
@@ -17,9 +17,9 @@
17
  <img alt="GitHub pull requests" src="https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram" />
18
  </a>
19
  <p>
20
- 实时回复 / 无限对话 / 保存对话记录 / 预设Prompt集 / 联网搜索 / 根据文件回答
21
- <br/>
22
- 渲染LaTex / 渲染表格 / 渲染代码 / 代码高亮 / 自定义api-URL / “小而美”的体验 / Ready for GPT-4
23
  </p>
24
  <a href="https://www.bilibili.com/video/BV1mo4y1r7eE"><strong>视频教程</strong></a>
25
  ·
@@ -340,6 +340,8 @@ docker run -d --name chatgpt \
340
 
341
  - [想要做出贡献?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/贡献指南)
342
  - [项目更新情况?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/更新日志)
 
 
343
 
344
  ## Starchart
345
 
 
17
  <img alt="GitHub pull requests" src="https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram" />
18
  </a>
19
  <p>
20
+ 实时回复 / 无限对话 / 保存对话记录 / 预设Prompt集 / 联网搜索 / 根据文件回答 <br />
21
+ 渲染LaTeX / 渲染表格 / 代码高亮 / 自动亮暗色切换 / 自适应输入框位置 / “小而美”的体验 <br />
22
+ 自定义api-Host / 多API Key均衡负载 / 多用户显示 / 适配GPT-4
23
  </p>
24
  <a href="https://www.bilibili.com/video/BV1mo4y1r7eE"><strong>视频教程</strong></a>
25
  ·
 
340
 
341
  - [想要做出贡献?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/贡献指南)
342
  - [项目更新情况?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/更新日志)
343
+ - [二次开发许可?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用许可)
344
+ - [如何引用项目?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用许可#如何引用该项目)
345
 
346
  ## Starchart
347
 
assets/custom.css CHANGED
@@ -3,14 +3,18 @@
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{
@@ -18,16 +22,34 @@ footer {
18
  opacity: 0.85;
19
  }
20
 
21
- /* user_info */
 
 
 
 
22
  #user_info {
23
  white-space: nowrap;
24
- margin-top: -1.3em !important;
25
- padding-left: 112px !important;
 
 
 
 
 
 
 
 
 
 
 
26
  }
27
  #user_info p {
28
- font-size: .85em;
29
- font-family: monospace;
30
- color: var(--body-text-color-subdued);
 
 
 
31
  }
32
 
33
  /* status_display */
@@ -43,14 +65,18 @@ footer {
43
  color: var(--body-text-color-subdued);
44
  }
45
 
46
- #chuanhu_chatbot, #status_display {
47
  transition: all 0.6s;
48
  }
 
 
 
49
 
50
  /* usage_display */
51
- #usage_display {
52
  position: relative;
53
  margin: 0;
 
54
  box-shadow: var(--block-shadow);
55
  border-width: var(--block-border-width);
56
  border-color: var(--block-border-color);
@@ -62,7 +88,6 @@ footer {
62
  }
63
  #usage_display p, #usage_display span {
64
  margin: 0;
65
- padding: .5em 1em;
66
  font-size: .85em;
67
  color: var(--body-text-color-subdued);
68
  }
@@ -74,7 +99,7 @@ footer {
74
  overflow: hidden;
75
  }
76
  .progress {
77
- background-color: var(--block-title-background-fill);;
78
  height: 100%;
79
  border-radius: 10px;
80
  text-align: right;
@@ -88,41 +113,86 @@ footer {
88
  padding-right: 10px;
89
  line-height: 20px;
90
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  /* list */
92
  ol:not(.options), ul:not(.options) {
93
  padding-inline-start: 2em !important;
94
  }
95
 
96
- /* 亮色 */
97
- @media (prefers-color-scheme: light) {
98
- #chuanhu_chatbot {
99
- background-color: var(--chatbot-color-light) !important;
100
- color: #000000 !important;
101
- }
102
- [data-testid = "bot"] {
103
- background-color: #FFFFFF !important;
104
- }
105
- [data-testid = "user"] {
106
- background-color: #95EC69 !important;
107
- }
108
  }
109
  /* 暗色 */
110
- @media (prefers-color-scheme: dark) {
111
- #chuanhu_chatbot {
112
- background-color: var(--chatbot-color-dark) !important;
113
- color: #FFFFFF !important;
114
- }
115
- [data-testid = "bot"] {
116
- background-color: #2C2C2C !important;
117
- }
118
- [data-testid = "user"] {
119
- background-color: #26B561 !important;
120
- }
121
- body {
122
- background-color: var(--neutral-950) !important;
123
- }
124
  }
 
 
 
 
125
  /* 屏幕宽度大于等于500px的设备 */
 
126
  @media screen and (min-width: 500px) {
127
  #chuanhu_chatbot {
128
  height: calc(100vh - 200px);
@@ -139,6 +209,12 @@ ol:not(.options), ul:not(.options) {
139
  #chuanhu_chatbot .wrap {
140
  max-height: calc(100vh - 140px - var(--line-sm)*1rem - 2*var(--block-label-margin) );
141
  }
 
 
 
 
 
 
142
  }
143
  /* 对话气泡 */
144
  [class *= "message"] {
 
3
  --chatbot-color-dark: #121111;
4
  }
5
 
6
+ #app_title {
7
+ margin-top: 6px;
8
+ white-space: nowrap;
9
+ }
10
  /* 覆盖gradio的页脚信息QAQ */
11
  footer {
12
  display: none !important;
13
  }
14
+ #footer {
15
  text-align: center;
16
  }
17
+ #footer div {
18
  display: inline-block;
19
  }
20
  #footer .versions{
 
22
  opacity: 0.85;
23
  }
24
 
25
+ #float_display {
26
+ position: absolute;
27
+ max-height: 30px;
28
+ }
29
+ /* user_info */
30
  #user_info {
31
  white-space: nowrap;
32
+ position: absolute; left: 8em; top: .2em;
33
+ z-index: var(--layer-2);
34
+ box-shadow: var(--block-shadow);
35
+ border: none; border-radius: var(--block-label-radius);
36
+ background: var(--color-accent);
37
+ padding: var(--block-label-padding);
38
+ font-size: var(--block-label-text-size); line-height: var(--line-sm);
39
+ width: auto; min-height: 30px!important;
40
+ opacity: 1;
41
+ transition: opacity 0.3s ease-in-out;
42
+ }
43
+ #user_info .wrap {
44
+ opacity: 0;
45
  }
46
  #user_info p {
47
+ color: white;
48
+ font-weight: var(--block-label-text-weight);
49
+ }
50
+ #user_info.hideK {
51
+ opacity: 0;
52
+ transition: opacity 1s ease-in-out;
53
  }
54
 
55
  /* status_display */
 
65
  color: var(--body-text-color-subdued);
66
  }
67
 
68
+ #status_display {
69
  transition: all 0.6s;
70
  }
71
+ #chuanhu_chatbot {
72
+ transition: height 0.3s ease;
73
+ }
74
 
75
  /* usage_display */
76
+ .insert_block {
77
  position: relative;
78
  margin: 0;
79
+ padding: .5em 1em;
80
  box-shadow: var(--block-shadow);
81
  border-width: var(--block-border-width);
82
  border-color: var(--block-border-color);
 
88
  }
89
  #usage_display p, #usage_display span {
90
  margin: 0;
 
91
  font-size: .85em;
92
  color: var(--body-text-color-subdued);
93
  }
 
99
  overflow: hidden;
100
  }
101
  .progress {
102
+ background-color: var(--block-title-background-fill);
103
  height: 100%;
104
  border-radius: 10px;
105
  text-align: right;
 
113
  padding-right: 10px;
114
  line-height: 20px;
115
  }
116
+
117
+ .apSwitch {
118
+ top: 2px;
119
+ display: inline-block;
120
+ height: 24px;
121
+ position: relative;
122
+ width: 48px;
123
+ border-radius: 12px;
124
+ }
125
+ .apSwitch input {
126
+ display: none !important;
127
+ }
128
+ .apSlider {
129
+ background-color: var(--block-label-background-fill);
130
+ bottom: 0;
131
+ cursor: pointer;
132
+ left: 0;
133
+ position: absolute;
134
+ right: 0;
135
+ top: 0;
136
+ transition: .4s;
137
+ font-size: 18px;
138
+ border-radius: 12px;
139
+ }
140
+ .apSlider::before {
141
+ bottom: -1.5px;
142
+ left: 1px;
143
+ position: absolute;
144
+ transition: .4s;
145
+ content: "🌞";
146
+ }
147
+ input:checked + .apSlider {
148
+ background-color: var(--block-label-background-fill);
149
+ }
150
+ input:checked + .apSlider::before {
151
+ transform: translateX(23px);
152
+ content:"🌚";
153
+ }
154
+
155
+ #submit_btn, #cancel_btn {
156
+ height: 42px !important;
157
+ }
158
+ #submit_btn::before {
159
+ content: url("data:image/svg+xml, %3Csvg width='21px' height='20px' viewBox='0 0 21 20' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cg id='page' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E %3Cg id='send' transform='translate(0.435849, 0.088463)' fill='%23FFFFFF' fill-rule='nonzero'%3E %3Cpath d='M0.579148261,0.0428666046 C0.301105539,-0.0961547561 -0.036517765,0.122307382 0.0032026237,0.420210298 L1.4927172,18.1553639 C1.5125774,18.4334066 1.79062012,18.5922882 2.04880264,18.4929872 L8.24518329,15.8913017 L11.6412765,19.7441794 C11.8597387,19.9825018 12.2370824,19.8832008 12.3165231,19.5852979 L13.9450591,13.4882182 L19.7839562,11.0255541 C20.0619989,10.8865327 20.0818591,10.4694687 19.7839562,10.3105871 L0.579148261,0.0428666046 Z M11.6138902,17.0883151 L9.85385903,14.7195502 L0.718169621,0.618812241 L12.69945,12.9346347 L11.6138902,17.0883151 Z' id='shape'%3E%3C/path%3E %3C/g%3E %3C/g%3E %3C/svg%3E");
160
+ height: 21px;
161
+ }
162
+ #cancel_btn::before {
163
+ content: url("data:image/svg+xml,%3Csvg width='21px' height='21px' viewBox='0 0 21 21' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cg id='pg' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E %3Cpath d='M10.2072007,20.088463 C11.5727865,20.088463 12.8594566,19.8259823 14.067211,19.3010209 C15.2749653,18.7760595 16.3386126,18.0538087 17.2581528,17.1342685 C18.177693,16.2147282 18.8982283,15.1527965 19.4197586,13.9484733 C19.9412889,12.7441501 20.202054,11.4557644 20.202054,10.0833163 C20.202054,8.71773046 19.9395733,7.43106036 19.4146119,6.22330603 C18.8896505,5.01555169 18.1673997,3.95018885 17.2478595,3.0272175 C16.3283192,2.10424615 15.2646719,1.3837109 14.0569176,0.865611739 C12.8491633,0.34751258 11.5624932,0.088463 10.1969073,0.088463 C8.83132146,0.088463 7.54636692,0.34751258 6.34204371,0.865611739 C5.1377205,1.3837109 4.07407321,2.10424615 3.15110186,3.0272175 C2.22813051,3.95018885 1.5058797,5.01555169 0.984349419,6.22330603 C0.46281914,7.43106036 0.202054,8.71773046 0.202054,10.0833163 C0.202054,11.4557644 0.4645347,12.7441501 0.9894961,13.9484733 C1.5144575,15.1527965 2.23670831,16.2147282 3.15624854,17.1342685 C4.07578877,18.0538087 5.1377205,18.7760595 6.34204371,19.3010209 C7.54636692,19.8259823 8.83475258,20.088463 10.2072007,20.088463 Z M10.2072007,18.2562448 C9.07493099,18.2562448 8.01471483,18.0452309 7.0265522,17.6232031 C6.03838956,17.2011753 5.17031614,16.6161693 4.42233192,15.8681851 C3.6743477,15.1202009 3.09105726,14.2521274 2.67246059,13.2639648 C2.25386392,12.2758022 2.04456558,11.215586 2.04456558,10.0833163 C2.04456558,8.95104663 2.25386392,7.89083047 2.67246059,6.90266784 C3.09105726,5.9145052 3.6743477,5.04643178 4.42233192,4.29844756 C5.17031614,3.55046334 6.036674,2.9671729 7.02140552,2.54857623 C8.00613703,2.12997956 9.06463763,1.92068122 10.1969073,1.92068122 C11.329177,1.92068122 12.3911087,2.12997956 13.3827025,2.54857623 C14.3742962,2.9671729 15.2440852,3.55046334 15.9920694,4.29844756 C16.7400537,5.04643178 17.3233441,5.9145052 17.7419408,6.90266784 C18.1605374,7.89083047 18.3698358,8.95104663 18.3698358,10.0833163 C18.3698358,11.215586 18.1605374,12.2758022 17.7419408,13.2639648 C17.3233441,14.2521274 16.7400537,15.1202009 15.9920694,15.8681851 C15.2440852,16.6161693 14.3760118,17.2011753 13.3878492,17.6232031 C12.3996865,18.0452309 11.3394704,18.2562448 10.2072007,18.2562448 Z M7.65444721,13.6242324 L12.7496608,13.6242324 C13.0584616,13.6242324 13.3003556,13.5384544 13.4753427,13.3668984 C13.6503299,13.1953424 13.7378234,12.9585951 13.7378234,12.6566565 L13.7378234,7.49968276 C13.7378234,7.19774418 13.6503299,6.96099688 13.4753427,6.78944087 C13.3003556,6.61788486 13.0584616,6.53210685 12.7496608,6.53210685 L7.65444721,6.53210685 C7.33878414,6.53210685 7.09345904,6.61788486 6.91847191,6.78944087 C6.74348478,6.96099688 6.65599121,7.19774418 6.65599121,7.49968276 L6.65599121,12.6566565 C6.65599121,12.9585951 6.74348478,13.1953424 6.91847191,13.3668984 C7.09345904,13.5384544 7.33878414,13.6242324 7.65444721,13.6242324 Z' id='shape' fill='%23FF3B30' fill-rule='nonzero'%3E%3C/path%3E %3C/g%3E %3C/svg%3E");
164
+ height: 21px;
165
+ }
166
  /* list */
167
  ol:not(.options), ul:not(.options) {
168
  padding-inline-start: 2em !important;
169
  }
170
 
171
+ /* 亮色(默认) */
172
+ #chuanhu_chatbot {
173
+ background-color: var(--chatbot-color-light) !important;
174
+ color: #000000 !important;
175
+ }
176
+ [data-testid = "bot"] {
177
+ background-color: #FFFFFF !important;
178
+ }
179
+ [data-testid = "user"] {
180
+ background-color: #95EC69 !important;
 
 
181
  }
182
  /* 暗色 */
183
+ .dark #chuanhu_chatbot {
184
+ background-color: var(--chatbot-color-dark) !important;
185
+ color: #FFFFFF !important;
186
+ }
187
+ .dark [data-testid = "bot"] {
188
+ background-color: #2C2C2C !important;
 
 
 
 
 
 
 
 
189
  }
190
+ .dark [data-testid = "user"] {
191
+ background-color: #26B561 !important;
192
+ }
193
+
194
  /* 屏幕宽度大于等于500px的设备 */
195
+ /* update on 2023.4.8: 高度的细致调整已写入JavaScript */
196
  @media screen and (min-width: 500px) {
197
  #chuanhu_chatbot {
198
  height: calc(100vh - 200px);
 
209
  #chuanhu_chatbot .wrap {
210
  max-height: calc(100vh - 140px - var(--line-sm)*1rem - 2*var(--block-label-margin) );
211
  }
212
+ [data-testid = "bot"] {
213
+ max-width: 98% !important;
214
+ }
215
+ #app_title h1{
216
+ letter-spacing: -1px; font-size: 22px;
217
+ }
218
  }
219
  /* 对话气泡 */
220
  [class *= "message"] {
assets/custom.js CHANGED
@@ -1,70 +1,222 @@
 
1
  // custom javascript here
 
2
  const MAX_HISTORY_LENGTH = 32;
3
 
4
  var key_down_history = [];
5
  var currentIndex = -1;
6
  var user_input_ta;
7
 
 
 
 
 
 
 
 
 
8
  var ga = document.getElementsByTagName("gradio-app");
9
  var targetNode = ga[0];
10
- var observer = new MutationObserver(function(mutations) {
 
 
 
11
  for (var i = 0; i < mutations.length; i++) {
12
- if (mutations[i].addedNodes.length) {
13
- var user_input_tb = document.getElementById('user_input_tb');
14
- if (user_input_tb) {
15
- // 监听到user_input_tb被添加到DOM树中
16
- // 这里可以编写元素加载完成后需要执行的代码
17
- user_input_ta = user_input_tb.querySelector("textarea");
18
- if (user_input_ta){
19
- observer.disconnect(); // 停止监听
20
- // textarea 上监听 keydown 事件
21
- user_input_ta.addEventListener("keydown", function (event) {
22
- var value = user_input_ta.value.trim();
23
- // 判断按下的是否为方向键
24
- if (event.code === 'ArrowUp' || event.code === 'ArrowDown') {
25
- // 如果按下的是方向键,且输入框中有内容,且历史记录中没有该内容,则不执行操作
26
- if(value && key_down_history.indexOf(value) === -1)
27
- return;
28
- // 对于需要响应的动作,阻止默认行为。
29
- event.preventDefault();
30
- var length = key_down_history.length;
31
- if(length === 0) {
32
- currentIndex = -1; // 如果历史记录为空,直接将当前选中的记录重置
33
- return;
34
- }
35
- if (currentIndex === -1) {
36
- currentIndex = length;
37
- }
38
- if (event.code === 'ArrowUp' && currentIndex > 0) {
39
- currentIndex--;
40
- user_input_ta.value = key_down_history[currentIndex];
41
- } else if (event.code === 'ArrowDown' && currentIndex < length - 1) {
42
- currentIndex++;
43
- user_input_ta.value = key_down_history[currentIndex];
44
- }
45
- user_input_ta.selectionStart = user_input_ta.value.length;
46
- user_input_ta.selectionEnd = user_input_ta.value.length;
47
- const input_event = new InputEvent("input", {bubbles: true, cancelable: true});
48
- user_input_ta.dispatchEvent(input_event);
49
- }else if(event.code === "Enter") {
50
- if (value) {
51
- currentIndex = -1;
52
- if(key_down_history.indexOf(value) === -1){
53
- key_down_history.push(value);
54
- if (key_down_history.length > MAX_HISTORY_LENGTH) {
55
- key_down_history.shift();
56
- }
57
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  }
59
  }
60
- });
61
- break;
62
  }
63
- }
 
 
 
 
 
 
 
 
 
64
  }
65
- }
66
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- // 监听目标节点的子节点列表是否发生变化
69
- observer.observe(targetNode, { childList: true , subtree: true });
 
 
 
 
 
 
 
 
 
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
  // custom javascript here
3
+
4
  const MAX_HISTORY_LENGTH = 32;
5
 
6
  var key_down_history = [];
7
  var currentIndex = -1;
8
  var user_input_ta;
9
 
10
+ var gradioContainer = null;
11
+ var user_input_ta = null;
12
+ var user_input_tb = null;
13
+ var userInfoDiv = null;
14
+ var appTitleDiv = null;
15
+ var chatbot = null;
16
+ var apSwitch = null;
17
+
18
  var ga = document.getElementsByTagName("gradio-app");
19
  var targetNode = ga[0];
20
+ var isInIframe = (window.self !== window.top);
21
+
22
+ // gradio 页面加载好了么??? 我能动你的元素了么??
23
+ function gradioLoaded(mutations) {
24
  for (var i = 0; i < mutations.length; i++) {
25
+ if (mutations[i].addedNodes.length) {
26
+ gradioContainer = document.querySelector(".gradio-container");
27
+ user_input_tb = document.getElementById('user_input_tb');
28
+ userInfoDiv = document.getElementById("user_info");
29
+ appTitleDiv = document.getElementById("app_title");
30
+ chatbot = document.querySelector('#chuanhu_chatbot');
31
+ apSwitch = document.querySelector('.apSwitch input[type="checkbox"]');
32
+
33
+ if (gradioContainer && apSwitch) { // gradioCainter 加载出来了没?
34
+ adjustDarkMode();
35
+ }
36
+ if (user_input_tb) { // user_input_tb 加载出来了没?
37
+ selectHistory();
38
+ }
39
+ if (userInfoDiv && appTitleDiv) { // userInfoDiv 和 appTitleDiv 加载出来了没?
40
+ setTimeout(showOrHideUserInfo(), 2000);
41
+ }
42
+ if (chatbot) { // chatbot 加载出来了没?
43
+ setChatbotHeight()
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ function selectHistory() {
50
+ user_input_ta = user_input_tb.querySelector("textarea");
51
+ if (user_input_ta) {
52
+ observer.disconnect(); // 停止监听
53
+ // textarea 上监听 keydown 事件
54
+ user_input_ta.addEventListener("keydown", function (event) {
55
+ var value = user_input_ta.value.trim();
56
+ // 判断按下的是否为方向键
57
+ if (event.code === 'ArrowUp' || event.code === 'ArrowDown') {
58
+ // ���果按下的是方向键,且输入框中有内容,且历史记录中没有该内容,则不执行操作
59
+ if (value && key_down_history.indexOf(value) === -1)
60
+ return;
61
+ // 对于需要响应的动作,阻止默认行为。
62
+ event.preventDefault();
63
+ var length = key_down_history.length;
64
+ if (length === 0) {
65
+ currentIndex = -1; // 如果历史记录为空,直接将当前选中的记录重置
66
+ return;
67
+ }
68
+ if (currentIndex === -1) {
69
+ currentIndex = length;
70
+ }
71
+ if (event.code === 'ArrowUp' && currentIndex > 0) {
72
+ currentIndex--;
73
+ user_input_ta.value = key_down_history[currentIndex];
74
+ } else if (event.code === 'ArrowDown' && currentIndex < length - 1) {
75
+ currentIndex++;
76
+ user_input_ta.value = key_down_history[currentIndex];
77
+ }
78
+ user_input_ta.selectionStart = user_input_ta.value.length;
79
+ user_input_ta.selectionEnd = user_input_ta.value.length;
80
+ const input_event = new InputEvent("input", { bubbles: true, cancelable: true });
81
+ user_input_ta.dispatchEvent(input_event);
82
+ } else if (event.code === "Enter") {
83
+ if (value) {
84
+ currentIndex = -1;
85
+ if (key_down_history.indexOf(value) === -1) {
86
+ key_down_history.push(value);
87
+ if (key_down_history.length > MAX_HISTORY_LENGTH) {
88
+ key_down_history.shift();
89
  }
90
  }
91
+ }
 
92
  }
93
+ });
94
+ }
95
+ }
96
+
97
+ function toggleUserInfoVisibility(shouldHide) {
98
+ if (userInfoDiv) {
99
+ if (shouldHide) {
100
+ userInfoDiv.classList.add("hideK");
101
+ } else {
102
+ userInfoDiv.classList.remove("hideK");
103
  }
104
+ }
105
+ }
106
+ function showOrHideUserInfo() {
107
+ var sendBtn = document.getElementById("submit_btn");
108
+
109
+ // Bind mouse/touch events to show/hide user info
110
+ appTitleDiv.addEventListener("mouseenter", function () {
111
+ toggleUserInfoVisibility(false);
112
+ });
113
+ userInfoDiv.addEventListener("mouseenter", function () {
114
+ toggleUserInfoVisibility(false);
115
+ });
116
+ sendBtn.addEventListener("mouseenter", function () {
117
+ toggleUserInfoVisibility(false);
118
+ });
119
+
120
+ appTitleDiv.addEventListener("mouseleave", function () {
121
+ toggleUserInfoVisibility(true);
122
+ });
123
+ userInfoDiv.addEventListener("mouseleave", function () {
124
+ toggleUserInfoVisibility(true);
125
+ });
126
+ sendBtn.addEventListener("mouseleave", function () {
127
+ toggleUserInfoVisibility(true);
128
+ });
129
+
130
+ appTitleDiv.ontouchstart = function () {
131
+ toggleUserInfoVisibility(false);
132
+ };
133
+ userInfoDiv.ontouchstart = function () {
134
+ toggleUserInfoVisibility(false);
135
+ };
136
+ sendBtn.ontouchstart = function () {
137
+ toggleUserInfoVisibility(false);
138
+ };
139
+
140
+ appTitleDiv.ontouchend = function () {
141
+ setTimeout(function () {
142
+ toggleUserInfoVisibility(true);
143
+ }, 3000);
144
+ };
145
+ userInfoDiv.ontouchend = function () {
146
+ setTimeout(function () {
147
+ toggleUserInfoVisibility(true);
148
+ }, 3000);
149
+ };
150
+ sendBtn.ontouchend = function () {
151
+ setTimeout(function () {
152
+ toggleUserInfoVisibility(true);
153
+ }, 3000); // Delay 1 second to hide user info
154
+ };
155
+
156
+ // Hide user info after 2 second
157
+ setTimeout(function () {
158
+ toggleUserInfoVisibility(true);
159
+ }, 2000);
160
+ }
161
 
162
+ function toggleDarkMode(isEnabled) {
163
+ if (isEnabled) {
164
+ gradioContainer.classList.add("dark");
165
+ document.body.style.setProperty("background-color", "var(--neutral-950)", "important");
166
+ } else {
167
+ gradioContainer.classList.remove("dark");
168
+ document.body.style.backgroundColor = "";
169
+ }
170
+ }
171
+ function adjustDarkMode() {
172
+ const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)");
173
 
174
+ // 根据当前颜色模式设置初始状态
175
+ toggleDarkMode(darkModeQuery.matches);
176
+ // 监听颜色模式变化
177
+ darkModeQuery.addEventListener("change", (e) => {
178
+ toggleDarkMode(e.matches);
179
+ });
180
+ // apSwitch = document.querySelector('.apSwitch input[type="checkbox"]');
181
+ apSwitch.addEventListener("change", (e) => {
182
+ toggleDarkMode(e.target.checked);
183
+ });
184
+ }
185
+
186
+ function setChatbotHeight() {
187
+ const screenWidth = window.innerWidth;
188
+ const statusDisplay = document.querySelector('#status_display');
189
+ const statusDisplayHeight = statusDisplay ? statusDisplay.offsetHeight : 0;
190
+ const wrap = chatbot.querySelector('.wrap');
191
+ const vh = window.innerHeight * 0.01;
192
+ document.documentElement.style.setProperty('--vh', `${vh}px`);
193
+ if (isInIframe) {
194
+ chatbot.style.height = `700px`;
195
+ wrap.style.maxHeight = `calc(700px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`
196
+ } else {
197
+ if (screenWidth <= 320) {
198
+ chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px)`;
199
+ wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
200
+ } else if (screenWidth <= 499) {
201
+ chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px)`;
202
+ wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
203
+ } else {
204
+ chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px)`;
205
+ wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
206
+ }
207
+ }
208
+ }
209
+
210
+ // 监视页面内部 DOM 变动
211
+ var observer = new MutationObserver(function (mutations) {
212
+ gradioLoaded(mutations);
213
+ });
214
+ observer.observe(targetNode, { childList: true, subtree: true });
215
+
216
+ // 监视页面变化
217
+ window.addEventListener("DOMContentLoaded", function () {
218
+ isInIframe = (window.self !== window.top);
219
+ });
220
+ window.addEventListener('resize', setChatbotHeight);
221
+ window.addEventListener('scroll', setChatbotHeight);
222
+ window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode);
config_example.json CHANGED
@@ -1,14 +1,20 @@
1
  {
 
 
2
  "openai_api_key": "sk-xxxxxxxxxxxxxxxxxxxxxxxxx",
3
- "https_proxy": "http://127.0.0.1:1079",
4
- "http_proxy": "http://127.0.0.1:1079",
5
- "users": [],
 
6
  "advance_docs": {
7
  "pdf": {
 
8
  "two_column": false,
 
9
  "formula_ocr": true
10
  }
11
  },
 
12
  "multi_api_key": false,
13
  "api_key_list": [
14
  "sk-xxxxxxxxxxxxxxxxxxxxxxxx1",
 
1
  {
2
+ // 你的OpenAI API Key,一般必填,
3
+ // 若缺省填为 "openai_api_key": "" 则必须再在图形界面中填入API Key
4
  "openai_api_key": "sk-xxxxxxxxxxxxxxxxxxxxxxxxx",
5
+ // 如果使用代理,请取消注释下面的两行,并替换代理URL
6
+ // "https_proxy": "http://127.0.0.1:1079",
7
+ // "http_proxy": "http://127.0.0.1:1079",
8
+ "users": [],
9
  "advance_docs": {
10
  "pdf": {
11
+ // 是否认为PDF是双栏的
12
  "two_column": false,
13
+ // 是否使用OCR识别PDF中的公式
14
  "formula_ocr": true
15
  }
16
  },
17
+ // 是否多个API Key轮换使用
18
  "multi_api_key": false,
19
  "api_key_list": [
20
  "sk-xxxxxxxxxxxxxxxxxxxxxxxx1",
modules/presets.py CHANGED
@@ -24,7 +24,7 @@ NO_APIKEY_MSG = "API key为空,请检查是否输入正确。" # API key 长
24
  NO_INPUT_MSG = "请输入对话内容。" # 未输入对话内容
25
  BILLING_NOT_APPLICABLE_MSG = "模型本地运行中" # 本地运行的模型返回的账单信息
26
 
27
- TIMEOUT_STREAMING = 30 # 流式对话时的超时时间
28
  TIMEOUT_ALL = 200 # 非流式对话时的超时时间
29
  ENABLE_STREAMING_OPTION = True # 是否启用选择选择是否实时显示回答的勾选框
30
  HIDE_MY_KEY = False # 如果你想在UI中隐藏你的 API 密钥,将此值设置为 True
@@ -33,7 +33,7 @@ CONCURRENT_COUNT = 100 # 允许同时使用的用户数量
33
  SIM_K = 5
34
  INDEX_QUERY_TEMPRATURE = 1.0
35
 
36
- CHUANHU_TITLE = """<h1 align="left" style="min-width:200px; margin-top:6px; white-space: nowrap;">川虎ChatGPT 🚀</h1>"""
37
  CHUANHU_DESCRIPTION = """\
38
  <div align="center" style="margin:16px 0">
39
 
@@ -44,8 +44,16 @@ CHUANHU_DESCRIPTION = """\
44
  </div>
45
  """
46
 
47
- FOOTER = """\
48
- <div class="versions">{versions}</div>
 
 
 
 
 
 
 
 
49
  """
50
 
51
  SUMMARIZE_PROMPT = "你是谁?我们刚才聊了什么?" # 总结对话时的 prompt
 
24
  NO_INPUT_MSG = "请输入对话内容。" # 未输入对话内容
25
  BILLING_NOT_APPLICABLE_MSG = "模型本地运行中" # 本地运行的模型返回的账单信息
26
 
27
+ TIMEOUT_STREAMING = 60 # 流式对话时的超时时间
28
  TIMEOUT_ALL = 200 # 非流式对话时的超时时间
29
  ENABLE_STREAMING_OPTION = True # 是否启用选择选择是否实时显示回答的勾选框
30
  HIDE_MY_KEY = False # 如果你想在UI中隐藏你的 API 密钥,将此值设置为 True
 
33
  SIM_K = 5
34
  INDEX_QUERY_TEMPRATURE = 1.0
35
 
36
+ CHUANHU_TITLE = """<h1 align="left">川虎ChatGPT 🚀</h1>"""
37
  CHUANHU_DESCRIPTION = """\
38
  <div align="center" style="margin:16px 0">
39
 
 
44
  </div>
45
  """
46
 
47
+ FOOTER = """<div class="versions">{versions}</div>"""
48
+
49
+ APPEARANCE_SWITCHER = """
50
+ <div style="display: flex; justify-content: space-between;">
51
+ <span style="margin-top: 4px !important;">切换亮暗色主题</span>
52
+ <span><label class="apSwitch" for="checkbox">
53
+ <input type="checkbox" id="checkbox">
54
+ <div class="apSlider"></div>
55
+ </label></span>
56
+ </div>
57
  """
58
 
59
  SUMMARIZE_PROMPT = "你是谁?我们刚才聊了什么?" # 总结对话时的 prompt