speqtr commited on
Commit
83c8492
1 Parent(s): 67bb950

basic inference pipeline

Browse files
README.md CHANGED
@@ -8,6 +8,7 @@ sdk_version: 3.3.1
8
  python_version: 3.10.4
9
  app_file: main_hf_space.py
10
  pinned: false
 
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
8
  python_version: 3.10.4
9
  app_file: main_hf_space.py
10
  pinned: false
11
+ license: mit
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
introduck/inference.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spacy
2
+
3
+
4
+ def extract_contacts_from_email(payload: str) -> list[list[str]]:
5
+ return [["John Doe", "Acme Corp.", "john@example.com", "ai, nn"]]
6
+
7
+
8
+ def generate_acceptance_reply(payload: str) -> str:
9
+ return "Good!"
10
+
11
+
12
+ def generate_rejection_reply(payload: str) -> str:
13
+ return "Not interested :("
14
+
15
+
16
+ def highlight_named_entities(payload: str, labels: list[str] = None) -> dict:
17
+ if labels is None:
18
+ labels = ["ORG", "PERSON"]
19
+
20
+ nlp: spacy.Language | None = None
21
+ if not hasattr(highlight_named_entities, "nlp"):
22
+ nlp = spacy.load(name="en_core_web_sm")
23
+ highlight_named_entities.nlp = nlp
24
+ print(f"Loaded {nlp.meta.get('name', 'unknown')} model from {nlp.path}")
25
+ else:
26
+ nlp = highlight_named_entities.nlp
27
+ print(f"Reused {nlp.meta.get('name', 'unknown')} model from {nlp.path}")
28
+
29
+ doc = nlp(payload)
30
+
31
+ entities: list = []
32
+ for ent in doc.ents:
33
+ if ent.label_ not in labels:
34
+ continue
35
+
36
+ entity: dict = {
37
+ "entity": ent.label_,
38
+ "start": ent.start_char,
39
+ "end": ent.end_char}
40
+
41
+ entities.append(entity)
42
+
43
+ return {"text": payload, "entities": entities}
introduck/routes.py CHANGED
@@ -3,29 +3,14 @@ import gradio as gr
3
  from fastapi import FastAPI
4
  from gradio.routes import App as GradioApp
5
 
6
-
7
- def _analyze_message(sender: str, recipients: str, subject: str, message: str):
8
- input_message: str = f"""
9
- From: {sender or '<empty>'}
10
- To: {recipients or '<empty>'}
11
- Subject: {subject or '<empty>'}
12
-
13
- {message or ''}
14
- """
15
-
16
- contacts: list = [["John Doe", "Acme Corp.", "john@example.com", "ai, nn"]]
17
-
18
- acceptance_reply: str = "Good!"
19
-
20
- rejection_reply: str = "Not interested :("
21
-
22
- return input_message, contacts, acceptance_reply, rejection_reply
23
-
24
-
25
- def _use_message_template() -> (str, str):
26
- subject: str = "Could you make an intro?"
27
-
28
- message: str = """\
29
  Hey,
30
 
31
  hope you are doing well! :-)
@@ -45,71 +30,93 @@ Relevant info:
45
  + <highlights list>
46
 
47
  Best,
48
- <your name>"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- return subject, message
 
 
 
 
51
 
52
 
53
  def create_base_route(title: str = "") -> FastAPI:
54
- with gr.Blocks(analytics_enabled=False, title=title) as base_blocks:
55
- gr.Markdown(f"""\
 
 
 
 
 
 
 
 
 
56
  # Introduck
57
- ## All introductions are better with an AI-powered 🦆
58
- No new tools. No complex setup. No hassle.
59
  """)
60
 
61
- with gr.Group():
62
- email_sender_input: gr.Textbox = gr.Textbox(
63
- label="From:",
64
- lines=1,
65
- max_lines=1,
66
- placeholder="founder@acme.com")
67
-
68
- email_recipients_input: gr.Textbox = gr.Textbox(
69
- label="To:",
70
- lines=1,
71
- max_lines=1,
72
- placeholder="vc@example.com")
73
-
74
- email_subject_input: gr.Textbox = gr.Textbox(
75
- show_label=False,
76
- lines=1,
77
- max_lines=1,
78
- placeholder="Subject...",
79
- interactive=True)
80
-
81
- email_message_input: gr.Textbox = gr.Textbox(
82
- show_label=False,
83
- lines=5,
84
- max_lines=42,
85
- placeholder="Type a message...",
86
- interactive=True)
87
-
88
- # TODO: Add support for attached files.
89
- # email_attachments_input: gr.File = gr.File(
90
- # label="Attachments:",
91
- # file_count="multiple")
92
-
93
- with gr.Row():
94
- email_template_button: gr.Button = gr.Button(
95
- value="Use template",
96
- variant="secondary")
97
-
98
- email_template_button.click(
99
- fn=_use_message_template,
100
- inputs=[],
101
- outputs=[email_subject_input, email_message_input])
102
-
103
- email_submit_button: gr.Button = gr.Button(
104
- value="Submit",
105
- variant="primary")
106
 
107
- with gr.Tabs(selected="default"):
108
- with gr.TabItem(label="Input"):
109
- rfc822_output: gr.HighlightedText = gr.HighlightedText(
110
- label="RFC822 message:",
111
- show_legend=False)
 
 
 
 
 
 
 
 
 
 
 
112
 
 
 
 
 
 
113
  with gr.TabItem(label="Contacts", id="default"):
114
  contacts_table_headers: list[str] = [
115
  "Name",
@@ -122,28 +129,21 @@ def create_base_route(title: str = "") -> FastAPI:
122
  max_cols=len(contacts_table_headers),
123
  max_rows=16)
124
 
125
- with gr.TabItem(label="Accept request"):
126
- acceptance_template_output: gr.Textbox = gr.Textbox(
127
- label="Use this message to accept an intro request:",
128
- interactive=True)
 
129
 
130
- with gr.TabItem(label="Decline request"):
131
- rejection_template_output: gr.Textbox = gr.Textbox(
132
- label="Use this message to decline an intro request:",
133
- interactive=True)
134
 
135
- email_submit_button.click(
136
- fn=_analyze_message,
137
- inputs=[
138
- email_sender_input,
139
- email_recipients_input,
140
- email_subject_input,
141
- email_message_input],
142
- outputs=[
143
- rfc822_output,
144
- contacts_output,
145
- acceptance_template_output,
146
- rejection_template_output])
147
 
148
  gr.Markdown("## FAQ")
149
 
@@ -162,6 +162,26 @@ def create_base_route(title: str = "") -> FastAPI:
162
 
163
  gr.Markdown("**&copy;** Introduck, 2022")
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  base_route = GradioApp.create_app(blocks=base_blocks)
166
 
167
  # TODO: overwrite /favicon.ico
 
3
  from fastapi import FastAPI
4
  from gradio.routes import App as GradioApp
5
 
6
+ from introduck.inference import extract_contacts_from_email
7
+ from introduck.inference import generate_acceptance_reply
8
+ from introduck.inference import generate_rejection_reply
9
+ from introduck.inference import highlight_named_entities
10
+ from introduck.utils import create_email_message
11
+
12
+ _INTRO_SUBJECT_EXAMPLE: str = "Could you make an intro?"
13
+ _INTRO_MESSAGE_EXAMPLE: str = """\
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  Hey,
15
 
16
  hope you are doing well! :-)
 
30
  + <highlights list>
31
 
32
  Best,
33
+ <your name>\
34
+ """
35
+
36
+
37
+ def _analyze_message(sender: str, recipients: str, subject: str, body: str):
38
+ msg_data: dict = {
39
+ "from": sender,
40
+ "to": recipients,
41
+ "subject": subject,
42
+ "body": body}
43
+
44
+ msg: str = create_email_message(data=msg_data)
45
+
46
+ contacts: list = extract_contacts_from_email(payload=msg)
47
+ acceptance_reply: str = generate_acceptance_reply(payload=msg)
48
+ rejection_reply: str = generate_rejection_reply(payload=msg)
49
+ text_with_named_entities: dict = highlight_named_entities(payload=msg)
50
 
51
+ return contacts, acceptance_reply, rejection_reply, text_with_named_entities
52
+
53
+
54
+ def _use_message_template() -> (str, str):
55
+ return _INTRO_SUBJECT_EXAMPLE, _INTRO_MESSAGE_EXAMPLE
56
 
57
 
58
  def create_base_route(title: str = "") -> FastAPI:
59
+ # TODO: Fix once resolved https://github.com/gradio-app/gradio/issues/1683
60
+ # TODO: ...and remove elem_id="htxt" from HighlightedText for RF822 output
61
+ css_workaround: str = "#htxt span {white-space: pre}"
62
+
63
+ base_blocks: gr.Blocks = gr.Blocks(
64
+ analytics_enabled=False,
65
+ title=title,
66
+ css=css_workaround)
67
+
68
+ with base_blocks:
69
+ gr.Markdown("""\
70
  # Introduck
71
+ ## Intro requests. Simplified. 🦆
72
+ No new tools. No complex setup. No hassle.\
73
  """)
74
 
75
+ with gr.Box():
76
+ with gr.Column():
77
+ gr.Markdown("## New intro request")
78
+
79
+ email_sender_input: gr.Textbox = gr.Textbox(
80
+ label="From:",
81
+ lines=1,
82
+ max_lines=1,
83
+ placeholder="founder@acme.com")
84
+
85
+ email_recipients_input: gr.Textbox = gr.Textbox(
86
+ label="To:",
87
+ lines=1,
88
+ max_lines=1,
89
+ placeholder="vc@example.com")
90
+
91
+ email_subject_input: gr.Textbox = gr.Textbox(
92
+ show_label=False,
93
+ lines=1,
94
+ max_lines=1,
95
+ placeholder="Subject...",
96
+ interactive=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
+ email_body_input: gr.Textbox = gr.Textbox(
99
+ show_label=False,
100
+ lines=5,
101
+ max_lines=42,
102
+ placeholder="Type a message...",
103
+ interactive=True)
104
+
105
+ # TODO: Add support for attached files.
106
+ # email_attachments_input: gr.File = gr.File(
107
+ # label="Attachments:",
108
+ # file_count="multiple")
109
+
110
+ with gr.Row():
111
+ email_template_button: gr.Button = gr.Button(
112
+ value="Use template",
113
+ variant="secondary")
114
 
115
+ email_submit_button: gr.Button = gr.Button(
116
+ value="Submit",
117
+ variant="primary")
118
+
119
+ with gr.Tabs(selected="default"):
120
  with gr.TabItem(label="Contacts", id="default"):
121
  contacts_table_headers: list[str] = [
122
  "Name",
 
129
  max_cols=len(contacts_table_headers),
130
  max_rows=16)
131
 
132
+ with gr.TabItem(label="Replies"):
133
+ with gr.Column():
134
+ acceptance_template_output: gr.Textbox = gr.Textbox(
135
+ label="Use this message to accept an intro request:",
136
+ interactive=True)
137
 
138
+ rejection_template_output: gr.Textbox = gr.Textbox(
139
+ label="Use this message to decline an intro request:",
140
+ interactive=True)
 
141
 
142
+ with gr.TabItem(label="RFC822"):
143
+ rfc822_output: gr.HighlightedText = gr.HighlightedText(
144
+ label="RFC822 message (for debugging purposes):",
145
+ show_legend=False,
146
+ elem_id="htxt") # temporary fix, see above for more info
 
 
 
 
 
 
 
147
 
148
  gr.Markdown("## FAQ")
149
 
 
162
 
163
  gr.Markdown("**&copy;** Introduck, 2022")
164
 
165
+ # ui end, continue with signals and slots...
166
+
167
+ email_template_button.click(
168
+ fn=_use_message_template,
169
+ inputs=[],
170
+ outputs=[email_subject_input, email_body_input])
171
+
172
+ email_submit_button.click(
173
+ fn=_analyze_message,
174
+ inputs=[
175
+ email_sender_input,
176
+ email_recipients_input,
177
+ email_subject_input,
178
+ email_body_input],
179
+ outputs=[
180
+ contacts_output,
181
+ acceptance_template_output,
182
+ rejection_template_output,
183
+ rfc822_output])
184
+
185
  base_route = GradioApp.create_app(blocks=base_blocks)
186
 
187
  # TODO: overwrite /favicon.ico
introduck/utils.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from email.message import EmailMessage
2
+
3
+
4
+ def create_email_message(data: dict) -> str:
5
+ msg: EmailMessage = EmailMessage()
6
+
7
+ body_text: str = data.get("body", "")
8
+ # body_html: str = ""
9
+
10
+ msg["From"] = data.get("from", "")
11
+ msg["To"] = data.get("to", "")
12
+ msg["Subject"] = data.get("subject", "")
13
+ msg.set_content(body_text)
14
+ # msg.add_alternative(body_html, subtype="html")
15
+
16
+ return msg.as_string()
requirements.txt CHANGED
@@ -1,3 +1,6 @@
1
  fastapi[all]
2
  gradio==3.3.1 # keep in sync with version from README.md metadata
 
3
  uvicorn[standard]
 
 
 
1
  fastapi[all]
2
  gradio==3.3.1 # keep in sync with version from README.md metadata
3
+ spacy==3.4.0
4
  uvicorn[standard]
5
+
6
+ https://huggingface.co/spacy/en_core_web_sm/resolve/main/en_core_web_sm-any-py3-none-any.whl