File size: 15,343 Bytes
b5da0b6
a653c90
 
b5da0b6
a653c90
37ba5c3
 
b5da0b6
3a8936a
 
b5da0b6
3a8936a
6f5c2ce
b5da0b6
a653c90
0593f84
37ba5c3
 
151a260
a653c90
fff5583
 
a653c90
 
 
6e08f32
b5da0b6
 
fff5583
b5da0b6
a653c90
 
 
985fcdb
fd3d54c
 
 
 
 
 
 
a653c90
fd3d54c
49dc4c4
fd3d54c
8d3828f
 
 
 
 
 
 
 
fd3d54c
985fcdb
a653c90
49dc4c4
ecfe394
 
 
 
 
 
 
 
6deae97
 
6ed5b63
 
 
1ca5518
ecfe394
 
 
 
 
 
 
 
 
 
 
 
 
a653c90
b5da0b6
 
a653c90
3a8936a
b5da0b6
a653c90
b5da0b6
 
 
 
aa84904
b5da0b6
3a8936a
b5da0b6
 
 
3a8936a
b5da0b6
 
3a8936a
b5da0b6
 
 
 
 
 
3a8936a
b5da0b6
3a8936a
aa84904
 
b5da0b6
3a8936a
b5da0b6
 
 
3a8936a
fd3d54c
 
 
3a8936a
fd3d54c
 
 
fff5583
6e08f32
a1a0a74
f6fc453
fff5583
3a8936a
 
f6fc453
3a8936a
c72adb4
fd3d54c
 
 
 
b5da0b6
a653c90
fd3d54c
490f507
fd3d54c
b5da0b6
fff5583
d7a12c5
490f507
f8cf18b
 
 
 
a653c90
f8cf18b
490f507
3a8936a
8d3828f
d7a12c5
fff5583
3a8936a
fd3d54c
7479e07
 
8d19f5f
7479e07
3a8936a
b5da0b6
8d3828f
 
fff5583
 
 
 
 
 
b7dec5f
89404ed
b7dec5f
a653c90
b7dec5f
 
89404ed
 
a653c90
89404ed
b7dec5f
b63b5f7
cde44ab
b7dec5f
26d20d3
e123b6b
a653c90
26d20d3
a653c90
bf633c1
fff5583
b7dec5f
8d3828f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490f507
8d3828f
 
 
 
 
490f507
8d3828f
b5da0b6
 
3a8936a
fff5583
 
fd3d54c
 
 
 
 
 
b5da0b6
 
fd3d54c
3a8936a
 
fd3d54c
3a8936a
a653c90
3a8936a
 
6e08f32
3a8936a
6e08f32
3a8936a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd3d54c
 
c0531f2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
import gradio as gr
import os
import json
import requests
import datetime
import pytz


# 流式端点
API_URL = "https://ai.fakeopen.com/v1/chat/completions"  # 用户需要提供自己的 OPENAI_API_KEY

# 推断函数
def predict(openai_gptapi_key, model, system_msg, inputs, top_p, temperature, max_tokens, presence_penalty, frequency_penalty, chat_counter, chatbot=[], history=[]):  

    print(f"——————————————————————————————")
    # 获取当前中国时间
    current_time = datetime.datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y年-%m月-%d日 %H时:%M分:%S秒")

    if inputs.strip() == '':
        inputs = "你好呀,使用英语与中文简单介绍下你自己吧!"
    if openai_gptapi_key.strip() == '':
        openai_gptapi_key = "pk-this-is-a-real-free-pool-token-for-everyone"
        print(f"[{current_time}] 聊天:API密钥 - Fake Open 服务提供的免费共享密钥")
    else:
        print(f"[{current_time}] 聊天:API密钥 - {openai_gptapi_key}")

    headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {openai_gptapi_key}"  # 用户将提供自己的 OPENAI_API_KEY 
    }
    
    print(f"[{current_time}] 聊天:用户消息 - {inputs}")
    

    if system_msg.strip() == '':
        initial_message = [{"role": "user", "content": f"{inputs}"},]
        multi_turn_message = []
    else:
        initial_message= [{"role": "system", "content": system_msg},
                   {"role": "user", "content": f"{inputs}"},]
        multi_turn_message = [{"role": "system", "content": system_msg},]
        print(f"[{current_time}] 聊天:系统消息 - {system_msg}")
        
    """if chat_counter == 0 :
        payload = {
            "model": "gpt-4",
            "messages": initial_message , 
            "temperature" : 1.0,
            "top_p":1.0,
            "n" : 1,
            "stream": True,
            "presence_penalty":0,
            "frequency_penalty":0,
        }
        chat_counter+=1
        print(f"聊天:对话计数 - {chat_counter}")
    else: # 如果 chat_counter 不等于 0"""
    messages=multi_turn_message  # 类型为 - [{"role": "system", "content": system_msg},]
    for data in chatbot:
        user = {}
        user["role"] = "user" 
        user["content"] = data[0] 
        assistant = {}
        assistant["role"] = "assistant" 
        assistant["content"] = data[1]
        messages.append(user)
        messages.append(assistant)
    temp = {}
    temp["role"] = "user" 
    temp["content"] = inputs
    messages.append(temp)
    # 消息
    payload = {
        "model": model,
        "messages": messages,  # 类型为 [{"role": "user", "content": f"{inputs}"}],
        "temperature": temperature,  # 温度
        "top_p": top_p,  # Top-p
        "n": 1,
        "stream": True,
        "presence_penalty": presence_penalty,  # 存在惩罚
        "frequency_penalty": frequency_penalty,  # 频率惩罚
        "max_tokens": max_tokens  # 最大 Token 数
    }
    chat_counter+=1
    print(f"[{current_time}] 聊天:对话计数 - {chat_counter}")

    history.append(inputs)
    print(f"[{current_time}] 日志:发送数据 - {payload}")
    # 使用 requests.post 方法向 API 端点发出 POST 请求,传递 stream=True
    response = requests.post(API_URL, headers=headers, json=payload, stream=True)
    print(f"[{current_time}] 服务:响应代码 - {response}")
    token_counter = 0 
    partial_words = "" 

    counter=0
    partial_words = ""
    for chunk in response.iter_lines():
        # 跳过第一个块
        if counter == 0:
          counter+=1
          continue
        # 检查每行是否非空
        if chunk.decode() :
          chunk = chunk.decode()
          # 将每行解码为响应数据,因为响应数据是以字节形式返回的
          if len(chunk) > 12 and "content" in json.loads(chunk[6:])['choices'][0]['delta']:
              partial_words = partial_words + json.loads(chunk[6:])['choices'][0]["delta"]["content"]
              if token_counter == 0:
                history.append(" " + partial_words)
              else:
                history[-1] = partial_words
              chat = [(history[i], history[i + 1]) for i in range(0, len(history) - 1, 2) ]  # 转换为列表的元组
              token_counter+=1
              yield chat, history, chat_counter, response  # 类似于 {chatbot: chat, state: history}  

    print(f"[{current_time}] 聊天:模型回复 - {partial_words}")
                   
# 重置文本框
def reset_textbox():
    return gr.update(value='')

# 将组件设置为 visible=False
def set_visible_false():
    return gr.update(visible=False)

# 将组件设置为 visible=True
def set_visible_true():
    return gr.update(visible=True)

title = """<h1 align="center">🔥 使用 Chat-Completions API 和 🚀 Gradio-Streaming 的 ChatGPT</h1>"""
theme_addon_msg = """<center>🌟 这个演示还向你介绍了 Gradio 主题。在 Gradio 网站上查看我们的 <a href="https://gradio.app/theming-guide/" target="_blank">主题指南🎨</a>来了解更多吧!你可以从头开始开发,用 <code>theme.push_to_hub()</code> 修改现有的 Gradio 主题,并简单地上传到 huggingface-hub 来与社区分享你的主题。</center>
""" 

# 使用信息添加有关 ChatGPT 系统消息的其他信息
system_msg_info = """对话可以从系统消息开始,以轻松地指导助手的行为。 
系统消息有助于设置 AI 助手的行为。例如,可以用 '你是一个有帮助的助手。' 来指示助手。"""

# 修改现有的 Gradio 主题
theme = gr.themes.Soft(primary_hue="zinc", secondary_hue="purple", neutral_hue="purple",
                      text_size=gr.themes.sizes.text_lg)                

with gr.Blocks(css = """#col_container { margin-left: auto; margin-right: auto;} #chatbot {height: 520px; overflow: auto;}""",
                      theme=theme) as demo:
    gr.HTML(title)
    gr.HTML("""<h3 align="center">🔥 这个 Huggingface Gradio 演示为你提供了使用 ChatGPT API 的访问权限,还支持系统消息。请注意,你需要提供 OPENAI API 密钥以访问 ChatGPT 🙌</h1>""")
    gr.HTML(theme_addon_msg)
    gr.HTML('''<center><a href="https://huggingface.co/spaces/Hmjz100/ChatGPT4?duplicate=true"><img src="https://img.shields.io/badge/-%E5%A4%8D%E5%88%B6%E7%A9%BA%E9%97%B4-blue?labelColor=white&style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAP5JREFUOE+lk7FqAkEURY+ltunEgFXS2sZGIbXfEPdLlnxJyDdYB62sbbUKpLbVNhyYFzbrrA74YJlh9r079973psed0cvUD4A+4HoCjsA85X0Dfn/RBLBgBDxnQPfAEJgBY+A9gALA4tcbamSzS4xq4FOQAJgCDwV2CPKV8tZAJcAjMMkUe1vX+U+SMhfAJEHasQIWmXNN3abzDwHUrgcRGmYcgKe0bxrblHEB4E/pndMazNpSZGcsZdBlYJcEL9Afo75molJyM2FxmPgmgPqlWNLGfwZGG6UiyEvLzHYDmoPkDDiNm9JR9uboiONcBXrpY1qmgs21x1QwyZcpvxt9NS09PlsPAAAAAElFTkSuQmCC&logoWidth=14" alt="复制空间"></a>复制这个空间并使用你的 OpenAI API 密钥安全运行</center>''')

    with gr.Column(elem_id = "col_container"):
        # 用户需要提供自己的 ChatGPT API 密钥,不再由 Huggingface 提供
        with gr.Row():
            with gr.Accordion(label="OpenAI API 密钥", open=False):
                openai_gptapi_key = gr.Textbox(
                    label="API 密钥",
                    type="password",
                    placeholder="pk-this-is-a-real-free-pool-token-for-everyone",
                    info="您可以提供自己的 OpenAI ChatGPT API 密钥,或者使用自带的密钥",
                )
            with gr.Accordion(label="系统消息", open=False):
                system_msg = gr.Textbox(label="指示 AI 助手设置其行为", info=system_msg_info, value="", placeholder="在这里输入..")
                accordion_msg = gr.HTML(value="🚧 要修改系统消息,你必须刷新页面", visible=False)
                          
        chatbot = gr.Chatbot(label='ChatGPT', elem_id="chatbot")
        inputs = gr.Textbox(placeholder="嗨!", label="输入文本并按 Enter 键")
        state = gr.State([]) 
        with gr.Row():
            with gr.Column(scale=7):
                b1 = gr.Button().style(full_width=True)
            with gr.Column(scale=3):
                server_status_code = gr.Textbox(label="来自 OpenAI 服务器的状态代码", )
    
        # 参数设置
        with gr.Accordion("高级参数", open=False):
            model_max_tokens = {
                "gpt-4": 8192,
                "gpt-4-32k": 32768,
                "gpt-3.5-turbo": 4096,
                "gpt-3.5-turbo-16k": 16384,
            }

            max_tokens = gr.Slider(
                minimum=-0,
                maximum=model_max_tokens["gpt-4-32k"],  # 设置初始最大值
                value=4000,
                step=1,
                interactive=True,
                label="最大 Token",
                info="助手生成一条信息可以包含的最大 token 数。最大 token 数也受到模型的总长度限制,上文的 token 数和生成的 token 数之和不能超过模型的 token 总数。(默认: 4000)",
            )

            def update_max_tokens(model_name):
                max_tokens.change(maximum = model_max_tokens[model_name])

            model = gr.Radio(
                ["gpt-4", "gpt-4-32k", "gpt-3.5-turbo", "gpt-3.5-turbo-16k"],
                value="gpt-4",
                label="模型",
                info="生成文本所使用的模型,“32k”以及“16k”所指的是模型支持生成的最大Token。(默认: gpt-4)",
                update=update_max_tokens,
            )

            top_p = gr.Slider(
                minimum=-0, maximum=1.0, value=1.0, step=0.05,
                interactive=True,
                label="Top-p (核心采样)",
                info="数值在 0 到 1 之间。采用核采样(nucleus sampling)的一种采样温度的替代方法,模型仅考虑前 Top-p 概率质量的 token。因此,0.1 表示仅考虑前 10% 概率质量的 token。我们通常建议修改此参数或采样温度,但不要同时修改两者。(默认: 1)",
                )
            temperature = gr.Slider(
                minimum=-0, maximum=5.0, value=1.0, step=0.1,
                interactive=True,
                label="采样温度",
                info="使用何种采样温度,值在 0 到 2 之间。较高的数值如 0.8 会使输出更加随机,而较低的数值如 0.2 会使输出更加集中和确定。我们通常建议修改此参数或 Top-p,但不要同时修改两者。(默认: 1)",
                )
            presence_penalty = gr.Slider(
                minimum=-2.0, maximum=2.0, value=0, step=0.1,
                interactive=True,
                label="存在惩罚",
                info="数值在 -2.0 到 2.0 之间。正值会根据新 token 是否已经出现在文本中来惩罚它们,增加模型谈论新话题的可能性,以降低生成的回复中出现不常见 token 的频率。(默认: 0)",
            )
            frequency_penalty = gr.Slider(
                minimum=-2.0, maximum=2.0, value=0, step=0.1,
                interactive=True,
                label="频率惩罚",
                info="数值在 -2.0 到 2.0 之间。正值会根据新 token 在文本中的现有频率来惩罚它们,降低模型直接重复相同语句的可能性,以降低生成的回复中重复 token 的频率。(默认: 0)",
            )
            chat_counter = gr.Number(value=0, visible=False, precision=0)

    # 事件处理
    inputs.submit(predict, [openai_gptapi_key, model, system_msg, inputs, top_p, temperature, max_tokens, presence_penalty, frequency_penalty, chat_counter, chatbot, state], [chatbot, state, chat_counter, server_status_code],)  # openai_api_key
    b1.click(predict, [openai_gptapi_key, model, system_msg, inputs, top_p, temperature, max_tokens, presence_penalty, frequency_penalty, chat_counter, chatbot, state], [chatbot, state, chat_counter, server_status_code],)  # openai_api_key
    
    inputs.submit(set_visible_false, [], [system_msg])
    b1.click(set_visible_false, [], [system_msg])
    inputs.submit(set_visible_true, [], [accordion_msg])
    b1.click(set_visible_true, [], [accordion_msg])
    
    b1.click(reset_textbox, [], [inputs])
    inputs.submit(reset_textbox, [], [inputs])

    # 示例
    with gr.Accordion(label="系统消息示例:", open=False):
        gr.Examples(
                examples = [
                ["""你是一个叫做 ChatGPT 的 AI 助手。

                - 仔细并准确地遵循用户的要求。
                - 先逐步思考 - 详细描述你在伪代码中要构建的计划。
                - 然后将代码以单个代码块的形式输出。
                - 尽少说无聊的闲话。"""],
                ["你是一位幽默的助手,名叫 ComedianGPT。你的回答都带有笑话和机智的回复。"],
                ["你是 ChefGPT,一位乐于助人的助手,用烹饪专业知识和一点点幽默来回答问题。"],
                ["你是 FitnessGuruGPT,一位健身专家,以轻松的方式分享锻炼技巧和动力。"],
                ["你是 SciFiGPT,一位科幻话题的 AI 助手,以知识和机智的方式讨论科幻话题。"],
                ["你是 PhilosopherGPT,一位深思熟虑的助手,以哲学的见解和一点点幽默来回应问题。"],
                ["你是 EcoWarriorGPT,一位乐于助人的助手,以轻松的方式分享环保建议。"],
                ["你是 MusicMaestroGPT,一位知识渊博的 AI,以事实和俏皮的玩笑讨论音乐和其历史。"],
                ["你是 SportsFanGPT,一位兴致勃勃的助手,谈论体育并分享有趣的轶事。"],
                ["你是 TechWhizGPT,一位精通科技的 AI,可以帮助用户解决问题并回答与设备和软件相关的问题。"],
                ["你是 FashionistaGPT,一位时尚专家 AI,以幽默的方式分享时尚建议和潮流趋势。"],
                ["你是 ArtConnoisseurGPT,一位 AI 助手,以知识和俏皮的评论讨论艺术及其历史。"],
                ["你是一位提供详细准确信息的乐于助人的助手。"],
                ["你是一位讲莎士比亚语言的助手。"],
                ["你是一位友好的助手,使用非正式的语言和幽默。"],
                ["你是一位金融顾问,为投资和预算提供专业建议。"],
                ["你是一位健康和健身专家,提供营养和锻炼建议。"],
                ["你是一位旅行顾问,为目的地、住宿和景点提供建议。"],
                ["你是一位电影评论家,分享有关电影和其主题的深刻见解。"],
                ["你是一位热爱历史的助手,喜欢讨论历史事件和人物。"],
                ["你是一位精通科技的助手,可以帮助用户解决有关设备和软件的问题。"],
                ["你是一位能够在任何给定主题上创作富有创意和感染力的诗歌的 AI 诗人。"],
                ],
                inputs = system_msg,)
        
demo.queue(max_size=99, concurrency_count=20).launch(debug=True)