Justin-Sima commited on
Commit
465f2e4
1 Parent(s): af76e05

Initial upload.

Browse files
Files changed (6) hide show
  1. .gitignore +132 -0
  2. LICENSE +21 -0
  3. README.md +11 -7
  4. app.py +52 -0
  5. email_generator.py +63 -0
  6. requirements.txt +2 -0
.gitignore ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
130
+
131
+ # mac stuff
132
+ .DS_Store
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 simatry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,13 +1,17 @@
1
- ---
2
  title: Email Generator
3
- emoji: 🦀
4
- colorFrom: green
5
- colorTo: indigo
6
  sdk: gradio
 
7
  sdk_version: 3.18.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
1
  title: Email Generator
2
+ emoji: 📧
3
+ colorFrom: blue
4
+ colorTo: blue
5
  sdk: gradio
6
+ python_version: 3.9.16
7
  sdk_version: 3.18.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
+ models:
12
+ - pszemraj/opt-350m-email-generation
13
+ - pszemraj/opt-350m-email-generation
14
+ - postbot/gpt2-medium-emailgen
15
+ - sagorsarker/emailgenerator
16
+ tags:
17
+ - email
app.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ from email_generator import (
4
+ generate_email,
5
+ DEFAULT_GENERATOR, AVAILABLE_GENERATORS
6
+ )
7
+
8
+
9
+ with gr.Blocks() as demo:
10
+ # -- Description.
11
+ gr.Markdown('# Email Generation')
12
+ gr.Markdown("""
13
+ Start an email and let AI do the rest, courtesy of the HuggingFace community!
14
+ AI is supposed to help automate the boring stuff,
15
+ and there's nothing more boring to me than writing generic emails.
16
+ Use this demo to interact with various HuggingFace models for automatic email generation.
17
+
18
+ Select a model from the dropdown list to use a specific pretrained model,
19
+ or leave it unchanged to default to [pszemraj/opt-350m-email-generation](https://huggingface.co/pszemraj/opt-350m-email-generation).
20
+
21
+ Then you just have to begin your email and click 'Generate Email' to complete it automatically!
22
+ """
23
+ )
24
+ gr.Image('emails/images/bored.jpg', label='Credit: https://unsplash.com/@thomascpark')
25
+
26
+ # -- Model parameters.
27
+ with gr.Row():
28
+ model_tag = gr.Dropdown(
29
+ choices=AVAILABLE_GENERATORS,
30
+ label='Choose a HuggingFace model',
31
+ value=DEFAULT_GENERATOR
32
+ )
33
+ max_tokens = gr.Slider(10, 200, value=64, label='Max Tokens')
34
+
35
+ # -- Prompt.
36
+ with gr.Row():
37
+ with gr.Column():
38
+ prompt = gr.Textbox(
39
+ lines=4,
40
+ label='',
41
+ placeholder='Begin your email here...'
42
+ )
43
+ generate_button = gr.Button('Generate Email', variant='primary')
44
+
45
+ # -- Output.
46
+ with gr.Row():
47
+ output = gr.Textbox(lines=8, label='Output', interactive=False)
48
+
49
+ # -- Button actions.
50
+ generate_button.click(fn=generate_email, inputs=[model_tag, prompt, max_tokens], outputs=output)
51
+
52
+ demo.launch()
email_generator.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Functions for loading email generator."""
2
+ import torch
3
+ import transformers
4
+
5
+ DEVICE = 0 if torch.cuda.is_available() else -1
6
+
7
+ AVAILABLE_GENERATORS = [
8
+ 'pszemraj/opt-350m-email-generation',
9
+ 'pszemraj/opt-350m-email-generation',
10
+ 'postbot/gpt2-medium-emailgen',
11
+ 'sagorsarker/emailgenerator'
12
+ ]
13
+ DEFAULT_GENERATOR = 'pszemraj/opt-350m-email-generation'
14
+
15
+
16
+ class EmailGenerator:
17
+ """ Class that loads and wraps a HuggingFace email generation pipeline."""
18
+ def __init__(self, model_tag: str) -> None:
19
+ """ Initialize HuggingFace email generation pipeline.
20
+
21
+ Args:
22
+ model_tag (str): Model name.
23
+ """
24
+ self.tag = model_tag
25
+ self.generator = transformers.pipeline(
26
+ 'text-generation', model_tag,
27
+ use_fast=True, do_sample=False,
28
+ device=DEVICE
29
+ )
30
+
31
+ def generate(self, prompt: str, max_tokens: int) -> str:
32
+ """ Generate a sample from a given prompt.
33
+
34
+ Args:
35
+ prompt (str): Prompting for email generator.
36
+ max_tokens (int): Maximum number of tokens to return.
37
+
38
+ Returns:
39
+ str: Generated text.
40
+ """
41
+ output = self.generator(prompt, max_length=max_tokens)
42
+ return output[0]['generated_text']
43
+
44
+ def __str__(self):
45
+ return f'EmailGenerator({self.tag})'
46
+
47
+ def set_global_generator(model_tag: str=DEFAULT_GENERATOR):
48
+ """ Set global parameter 'generator' as specified EmailGenerator."""
49
+ global generator
50
+ generator = EmailGenerator(model_tag=model_tag)
51
+
52
+ def generator_exists():
53
+ """ Check if global variable 'generator' has been defined."""
54
+ return 'generator' in globals()
55
+
56
+ def generate_email(model_tag: str, prompt: str, max_tokens: int):
57
+ """ Check for generator and create prompt.
58
+ Initialize correct generator if incorrect generator or no generator is found.
59
+ """
60
+ if not generator_exists() or generator.tag != model_tag:
61
+ set_global_generator(model_tag=model_tag)
62
+
63
+ return generator.generate(prompt, max_tokens=max_tokens)
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ transformers==4.26.1
2
+ gradio==3.18.0