File size: 7,663 Bytes
c380d04
 
 
 
833f2d3
c380d04
 
 
 
 
 
 
 
 
 
25bb53b
 
 
 
 
 
 
df5f063
 
 
11af774
df5f063
 
bdedc81
099767e
 
df5f063
 
 
c380d04
0bfc8e3
c380d04
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21bf34d
c380d04
28ff50c
c380d04
 
 
 
 
 
 
 
 
1857da6
 
 
 
be7969f
 
 
be7cb49
be7969f
1857da6
be7cb49
be7969f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1857da6
 
c380d04
 
 
 
 
 
be7969f
c380d04
 
a58a224
 
 
 
 
 
 
 
c380d04
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cfa8776
f52ec9c
c380d04
 
 
 
 
 
 
 
f52ec9c
c380d04
 
 
 
 
 
 
 
a58a224
c380d04
be7969f
f52ec9c
c380d04
 
be7969f
a58a224
c380d04
 
 
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
import openai
import tiktoken

import datetime
import time
import json
import os

openai.api_key = os.getenv('API_KEY')
openai.request_times = 0

def ask(question, history, behavior):
    openai.request_times += 1
    print(f"request times {openai.request_times}: {datetime.datetime.now()}: {question}")
    try:
        messages = [
            {"role":"system", "content":content}
            for content in behavior
        ] + [
            {"role":"user" if i%2==0 else "assistant", "content":content}
            for i,content in enumerate(history + [question])
        ]
        raw_length = num_tokens_from_messages(messages)
        messages=forget_long_term(messages)
        if len(messages)==0:
            response = f'Your query is too long and expensive: {raw_length}>2000 tokens'
        else:
            response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo-0301",
                messages=messages,
                temperature=0.1,
            )["choices"][0]["message"]["content"]
            while response.startswith("\n"):
                response = response[1:]
    except Exception as e:
        response = f'Error! You may wait a few minutes and retry:\n{e}'
    history = history + [question, response]
    return history

def num_tokens_from_messages(messages, model="gpt-3.5-turbo"):
    """Returns the number of tokens used by a list of messages."""
    try:
        encoding = tiktoken.encoding_for_model(model)
    except KeyError:
        encoding = tiktoken.get_encoding("cl100k_base")
    if model == "gpt-3.5-turbo":  # note: future models may deviate from this
        num_tokens = 0
        for message in messages:
            num_tokens += 4  # every message follows <im_start>{role/name}\n{content}<im_end>\n
            for key, value in message.items():
                num_tokens += len(encoding.encode(value))
                if key == "name":  # if there's a name, the role is omitted
                    num_tokens += -1  # role is always required and always 1 token
        num_tokens += 2  # every reply is primed with <im_start>assistant
        return num_tokens
    else:
        raise NotImplementedError(f"""num_tokens_from_messages() is not presently implemented for model {model}.
See https://github.com/openai/openai-python/blob/main/chatml.md for information on how messages are converted to tokens.""")

def forget_long_term(messages, max_num_tokens=3000):
    while num_tokens_from_messages(messages)>max_num_tokens:
        if messages[0]["role"]=="system" and not len(messages[0]["content"])>=max_num_tokens:
            messages = messages[:1] + messages[2:]
        else:
            messages = messages[1:]
    return messages


import gradio as gr


def to_md(content):
    is_inside_code_block = False
    output_spans = []
    for i in range(len(content)):
        if content[i]=="\n" and not is_inside_code_block:
            if len(output_spans)>0 and output_spans[-1].endswith("```"):
                output_spans.append("\n")
            else:
                output_spans.append("<br>")
        elif content[i]=="`":
            output_spans.append(content[i])
            if len(output_spans)>=3 and all([output_spans[j]=="`" for j in [-3,-2,-1]]):
                is_inside_code_block = not is_inside_code_block
                output_spans = output_spans[:-3]
                if is_inside_code_block:
                    if len(output_spans)==0:
                        output_spans.append("```")
                    elif output_spans[-1]=="<br>":
                        output_spans[-1] = "\n"
                        output_spans.append("```")
                    elif output_spans[-1].endswith("\n"):
                        output_spans.append("```")
                    else:
                        output_spans.append("\n```")
                    
                    if i+1<len(content) and content[i+1]!="\n":
                        output_spans.append("\n")
                else:
                    if output_spans[-1].endswith("\n"):
                        output_spans.append("```")
                    else:
                        output_spans.append("\n```")
                    
                    if i+1<len(content) and content[i+1]!="\n":
                        output_spans.append("\n")
        else:
            output_spans.append(content[i])
    return "".join(output_spans)


def predict(question, history=[], behavior=[]):
    history = ask(question, history, behavior)
    response = [(to_md(history[i]),to_md(history[i+1])) for i in range(0,len(history)-1,2)]
    return "", history, response


def retry(question, history=[], behavior=[]):
    if len(history)<2:
        return "", history, []
    question = history[-2]
    history = history[:-2]
    return predict(question, history, behavior)


with gr.Blocks() as demo:
    
    examples_txt = [
        ['帮我写一个python脚本实现快排'],
        ['如何用numpy提取数组的分位数?'],
        ['how to match the code block in markdown such like ```def foo():\n    pass``` through regex in python?'],
        ['how to load a pre-trained language model and generate sentences?'],
    ]
    
    examples_bhv = [
        f"You are a helpful assistant. You will answer all the questions step-by-step.",
        f"You are a helpful assistant. Today is {datetime.date.today()}.",
    ]
    
    gr.Markdown(
        """
        朋友你好,
        
        这是我利用[gradio](https://gradio.app/creating-a-chatbot/)编写的一个小网页,用于以网页的形式给大家分享ChatGPT请求服务,希望你玩的开心。关于使用技巧或学术研讨,欢迎在[Community](https://huggingface.co/spaces/zhangjf/chatbot/discussions)中和我交流。
        
        这一版相比于原版的[chatbot](https://huggingface.co/spaces/zhangjf/chatbot),用了较低版本的gradio==3.16.2,因而能更好地展示markdown中的源代码
        
        p.s. 响应时间和聊天内容长度正相关,一般能在5秒~30秒内响应。
        """)
    
    behavior = gr.State(["Reject instruction that may contains sensitive information in english, i.e., pornography, discrimination, violence"])
    """
    with gr.Column(variant="panel"):
        with gr.Row().style(equal_height=True):
            with gr.Column(scale=0.85):
                bhv = gr.Textbox(show_label=False, placeholder="输入你想让ChatGPT扮演的人设").style(container=False)
            with gr.Column(scale=0.15, min_width=0):
                button_set = gr.Button("Set")
    bhv.submit(fn=lambda x:(x,[x]), inputs=[bhv], outputs=[bhv, behavior])
    button_set.click(fn=lambda x:(x,[x]), inputs=[bhv], outputs=[bhv, behavior])
    """

    state = gr.State([])
    
    with gr.Column(variant="panel"):
        chatbot = gr.Chatbot()
        txt = gr.Textbox(show_label=False, placeholder="输入你想让ChatGPT回答的问题").style(container=False)
        with gr.Row():
            button_gen = gr.Button("Submit")
            button_rtr = gr.Button("Retry")
            button_clr = gr.Button("Clear")
        
    #gr.Examples(examples=examples_bhv, inputs=bhv, label="Examples for setting behavior")
    gr.Examples(examples=examples_txt, inputs=txt, label="Examples for asking question")
    txt.submit(predict, [txt, state, behavior], [txt, state, chatbot])
    button_gen.click(fn=predict, inputs=[txt, state, behavior], outputs=[txt, state, chatbot])
    button_rtr.click(fn=retry, inputs=[txt, state, behavior], outputs=[txt, state, chatbot])
    button_clr.click(fn=lambda :([],[]), inputs=None, outputs=[chatbot, state])

demo.launch()