rabbiitt commited on
Commit
3f630d7
·
verified ·
1 Parent(s): b40f3be

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +291 -0
app.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import pprint as pp
3
+ import logging
4
+ import time
5
+ import gradio as gr
6
+ import torch
7
+ from transformers import pipeline
8
+
9
+ from utils import make_mailto_form, postprocess, clear, make_email_link
10
+
11
+ logging.basicConfig(
12
+ level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
13
+ )
14
+
15
+ use_gpu = torch.cuda.is_available()
16
+
17
+
18
+ def generate_text(
19
+ prompt: str,
20
+ gen_length=64,
21
+ penalty_alpha=0.6,
22
+ top_k=6,
23
+ length_penalty=1.0,
24
+ # perma params (not set by user)
25
+ abs_max_length=512,
26
+ verbose=False,
27
+ ):
28
+ """
29
+ generate_text - generate text using the text generation pipeline
30
+ :param str prompt: the prompt to use for the text generation pipeline
31
+ :param int gen_length: the number of tokens to generate
32
+ :param float penalty_alpha: the penalty alpha for the text generation pipeline (contrastive search)
33
+ :param int top_k: the top k for the text generation pipeline (contrastive search)
34
+ :param int abs_max_length: the absolute max length for the text generation pipeline
35
+ :param bool verbose: verbose output
36
+ :return str: the generated text
37
+ """
38
+ global generator
39
+ if verbose:
40
+ logging.info(f"Generating text from prompt:\n\n{prompt}")
41
+ logging.info(
42
+ pp.pformat(
43
+ f"params:\tmax_length={gen_length}, penalty_alpha={penalty_alpha}, top_k={top_k}, length_penalty={length_penalty}"
44
+ )
45
+ )
46
+ st = time.perf_counter()
47
+
48
+ input_tokens = generator.tokenizer(prompt)
49
+ input_len = len(input_tokens["input_ids"])
50
+ if input_len > abs_max_length:
51
+ logging.info(f"Input too long {input_len} > {abs_max_length}, may cause errors")
52
+ result = generator(
53
+ prompt,
54
+ max_length=gen_length + input_len, # old API for generation
55
+ min_length=input_len + 4,
56
+ penalty_alpha=penalty_alpha,
57
+ top_k=top_k,
58
+ length_penalty=length_penalty,
59
+ ) # generate
60
+ response = result[0]["generated_text"]
61
+ rt = time.perf_counter() - st
62
+ if verbose:
63
+ logging.info(f"Generated text: {response}")
64
+ rt_string = f"Generation time: {rt:.2f}s"
65
+ logging.info(rt_string)
66
+
67
+ formatted_email = postprocess(response)
68
+ return make_mailto_form(body=formatted_email), formatted_email
69
+
70
+
71
+ def load_emailgen_model(model_tag: str):
72
+ """
73
+ load_emailgen_model - load a text generation pipeline for email generation
74
+ Args:
75
+ model_tag (str): the huggingface model tag to load
76
+ Returns:
77
+ transformers.pipelines.TextGenerationPipeline: the text generation pipeline
78
+ """
79
+ global generator
80
+ generator = pipeline(
81
+ "text-generation",
82
+ model_tag,
83
+ device=0 if use_gpu else -1,
84
+ )
85
+
86
+
87
+ def get_parser():
88
+ """
89
+ get_parser - a helper function for the argparse module
90
+ """
91
+ parser = argparse.ArgumentParser(
92
+ description="Text Generation demo for postbot",
93
+ )
94
+
95
+ parser.add_argument(
96
+ "-m",
97
+ "--model",
98
+ required=False,
99
+ type=str,
100
+ default="postbot/distilgpt2-emailgen-V2",
101
+ help="Pass an different huggingface model tag to use a custom model",
102
+ )
103
+ parser.add_argument(
104
+ "-l",
105
+ "--max_length",
106
+ required=False,
107
+ type=int,
108
+ default=40,
109
+ help="default max length of the generated text",
110
+ )
111
+ parser.add_argument(
112
+ "-a",
113
+ "--penalty_alpha",
114
+ type=float,
115
+ default=0.6,
116
+ help="The penalty alpha for the text generation pipeline (contrastive search) - default 0.6",
117
+ )
118
+
119
+ parser.add_argument(
120
+ "-k",
121
+ "--top_k",
122
+ type=int,
123
+ default=6,
124
+ help="The top k for the text generation pipeline (contrastive search) - default 6",
125
+ )
126
+ parser.add_argument(
127
+ "-v",
128
+ "--verbose",
129
+ required=False,
130
+ action="store_true",
131
+ help="Verbose output",
132
+ )
133
+ return parser
134
+
135
+
136
+ default_prompt = """
137
+ Hello,
138
+ Following up on last week's bubblegum shipment, I"""
139
+
140
+ available_models = [
141
+ "postbot/distilgpt2-emailgen-V2",
142
+ "postbot/distilgpt2-emailgen",
143
+ "postbot/gpt2-medium-emailgen",
144
+ "postbot/pythia-160m-hq-emails",
145
+ ]
146
+
147
+ if __name__ == "__main__":
148
+
149
+ logging.info("\n\n\nStarting new instance of app.py")
150
+ args = get_parser().parse_args()
151
+ logging.info(f"received args:\t{args}")
152
+ model_tag = args.model
153
+ verbose = args.verbose
154
+ max_length = args.max_length
155
+ top_k = args.top_k
156
+ alpha = args.penalty_alpha
157
+
158
+ assert top_k > 0, "top_k must be greater than 0"
159
+ assert alpha >= 0.0 and alpha <= 1.0, "penalty_alpha must be between 0 and 1"
160
+
161
+ logging.info(f"Loading model: {model_tag}, use GPU = {use_gpu}")
162
+ generator = pipeline(
163
+ "text-generation",
164
+ model_tag,
165
+ device=0 if use_gpu else -1,
166
+ )
167
+
168
+ demo = gr.Blocks()
169
+
170
+ logging.info("launching interface...")
171
+
172
+ with demo:
173
+ gr.Markdown("# Auto-Complete Emails - Demo")
174
+ gr.Markdown(
175
+ "Enter part of an email, and a text-gen model will complete it! See details below. "
176
+ )
177
+ gr.Markdown("---")
178
+
179
+ with gr.Column():
180
+
181
+ gr.Markdown("## Generate Text")
182
+ gr.Markdown("Edit the prompt and parameters and press **Generate**!")
183
+ prompt_text = gr.Textbox(
184
+ lines=4,
185
+ label="Email Prompt",
186
+ value=default_prompt,
187
+ )
188
+
189
+ with gr.Row():
190
+ clear_button = gr.Button(
191
+ value="Clear Prompt",
192
+ )
193
+ num_gen_tokens = gr.Slider(
194
+ label="Generation Tokens",
195
+ value=max_length,
196
+ maximum=96,
197
+ minimum=16,
198
+ step=8,
199
+ )
200
+
201
+ generate_button = gr.Button(
202
+ value="Generate!",
203
+ variant="primary",
204
+ )
205
+ gr.Markdown("---")
206
+ gr.Markdown("### Results")
207
+ # put a large HTML placeholder here
208
+ generated_email = gr.Textbox(
209
+ label="Generated Text",
210
+ placeholder="This is where the generated text will appear",
211
+ interactive=False,
212
+ )
213
+ email_mailto_button = gr.HTML(
214
+ "<i>a clickable email button will appear here</i>"
215
+ )
216
+
217
+ gr.Markdown("---")
218
+ gr.Markdown("## Advanced Options")
219
+ gr.Markdown(
220
+ "This demo generates text via the new [contrastive search](https://huggingface.co/blog/introducing-csearch). See the csearch blog post for details on the parameters or [here](https://huggingface.co/blog/how-to-generate), for general decoding."
221
+ )
222
+ with gr.Row():
223
+ model_name = gr.Dropdown(
224
+ choices=available_models,
225
+ label="Choose a model",
226
+ value=model_tag,
227
+ )
228
+ load_model_button = gr.Button(
229
+ "Load Model",
230
+ variant="secondary",
231
+ )
232
+ with gr.Row():
233
+ contrastive_top_k = gr.Radio(
234
+ choices=[2, 4, 6, 8],
235
+ label="Top K",
236
+ value=top_k,
237
+ )
238
+
239
+ penalty_alpha = gr.Slider(
240
+ label="Penalty Alpha",
241
+ value=alpha,
242
+ maximum=1.0,
243
+ minimum=0.0,
244
+ step=0.1,
245
+ )
246
+ length_penalty = gr.Slider(
247
+ minimum=0.5,
248
+ maximum=1.0,
249
+ label="Length Penalty",
250
+ value=1.0,
251
+ step=0.1,
252
+ )
253
+ gr.Markdown("---")
254
+
255
+ with gr.Column():
256
+
257
+ gr.Markdown("## About")
258
+ gr.Markdown(
259
+ "[This model](https://huggingface.co/postbot/distilgpt2-emailgen) is a fine-tuned version of distilgpt2 on a dataset of 100k emails sourced from the internet, including the classic `aeslc` dataset.\n\nCheck out the model card for details on notebook & command line usage."
260
+ )
261
+ gr.Markdown(
262
+ "The intended use of this model is to provide suggestions to _auto-complete_ the rest of your email. Said another way, it should serve as a **tool to write predictable emails faster**. It is not intended to write entire emails from scratch; at least **some input** is required to guide the direction of the model.\n\nPlease verify any suggestions by the model for A) False claims and B) negation statements **before** accepting/sending something."
263
+ )
264
+ gr.Markdown("---")
265
+
266
+ clear_button.click(
267
+ fn=clear,
268
+ inputs=[prompt_text],
269
+ outputs=[prompt_text],
270
+ )
271
+ generate_button.click(
272
+ fn=generate_text,
273
+ inputs=[
274
+ prompt_text,
275
+ num_gen_tokens,
276
+ penalty_alpha,
277
+ contrastive_top_k,
278
+ length_penalty,
279
+ ],
280
+ outputs=[email_mailto_button, generated_email],
281
+ )
282
+
283
+ load_model_button.click(
284
+ fn=load_emailgen_model,
285
+ inputs=[model_name],
286
+ outputs=[],
287
+ )
288
+ demo.launch(
289
+ enable_queue=True,
290
+ share=True, # for local testing
291
+ )