ak0601 commited on
Commit
76f2592
·
verified ·
1 Parent(s): 92a00c6

Update app_hug.py

Browse files
Files changed (1) hide show
  1. app_hug.py +0 -611
app_hug.py CHANGED
@@ -1,614 +1,3 @@
1
- # from fastapi import FastAPI, HTTPException, BackgroundTasks
2
- # from pydantic import BaseModel, EmailStr, Field
3
- # from typing import Optional, Tuple
4
- # from enum import Enum
5
- # import os
6
- # import base64
7
- # import pickle
8
- # import pandas as pd
9
- # from dotenv import load_dotenv
10
- # from langchain_openai import ChatOpenAI
11
- # from langchain.schema import HumanMessage, SystemMessage
12
- # from email.mime.text import MIMEText
13
- # from google.auth.transport.requests import Request
14
- # from google.oauth2.credentials import Credentials
15
- # from google_auth_oauthlib.flow import InstalledAppFlow
16
- # from googleapiclient.discovery import build
17
- # from googleapiclient.errors import HttpError
18
- # from datetime import datetime
19
- # import json
20
-
21
- # # Load environment variables (not needed on Hugging Face, but harmless)
22
- # load_dotenv()
23
-
24
- # # ------------------------------------------
25
- # # Helper: Write GOOGLE_CREDENTIALS_JSON to file if needed
26
- # # ------------------------------------------
27
- # def ensure_credentials_file():
28
- # credentials_env = os.getenv("GOOGLE_CREDENTIALS_JSON")
29
- # credentials_path = "credentials_SYNAPSE.json"
30
- # if not os.path.exists(credentials_path):
31
- # if not credentials_env:
32
- # raise Exception("GOOGLE_CREDENTIALS_JSON not found in environment variables.")
33
- # try:
34
- # parsed_json = json.loads(credentials_env)
35
- # except json.JSONDecodeError:
36
- # raise Exception("Invalid JSON in GOOGLE_CREDENTIALS_JSON")
37
- # with open(credentials_path, "w") as f:
38
- # json.dump(parsed_json, f, indent=2)
39
- # return credentials_path
40
-
41
- # # ------------------------------------------
42
- # # FastAPI app
43
- # # ------------------------------------------
44
- # app = FastAPI(title="Recruitment Message Generator API", version="1.0.0")
45
-
46
- # SCOPES = ["https://www.googleapis.com/auth/gmail.send"]
47
- # openai_api_key = os.getenv("OPENAI_API_KEY")
48
-
49
- # # ------------------------------------------
50
- # # Enums and Models
51
- # # ------------------------------------------
52
- # class MessageType(str, Enum):
53
- # OUTREACH = "outreach"
54
- # INTRODUCTORY = "introductory"
55
- # FOLLOWUP = "followup"
56
-
57
- # class GenerateMessageRequest(BaseModel):
58
- # job_evaluation: Optional[str] = Field(None, description="(Optional) Recruiter's evaluation of candidate for the job")
59
- # sender_email: EmailStr
60
- # reply_to_email: Optional[EmailStr] = Field(None, description="Recruiter's email for reply-to header")
61
- # recipient_email: EmailStr
62
- # candidate_name: str
63
- # current_role: str
64
- # current_company: str
65
- # company_name: str
66
- # role: str
67
- # recruiter_name: str
68
- # organisation: str
69
- # message_type: MessageType
70
- # send_email: bool = False
71
- # past_conversation: Optional[str] = Field(None, description="(Optional) Previous messages with candidate")
72
-
73
- # class FeedbackRequest(BaseModel):
74
- # message: str
75
- # feedback: str
76
-
77
- # class AuthenticateRequest(BaseModel):
78
- # email: EmailStr
79
-
80
- # class AuthenticateResponse(BaseModel):
81
- # success: bool
82
- # message: str
83
- # error: Optional[str] = None
84
-
85
- # class MessageResponse(BaseModel):
86
- # success: bool
87
- # message: str
88
- # email_sent: bool = False
89
- # email_subject: Optional[str] = None
90
- # error: Optional[str] = None
91
-
92
- # class SendMessageRequest(BaseModel):
93
- # subject: str
94
- # email_body: str
95
- # sender_email: EmailStr
96
- # recipient_email: EmailStr
97
- # reply_to_email: Optional[EmailStr] = None
98
-
99
- # # ------------------------------------------
100
- # # Gmail Helper Functions
101
- # # ------------------------------------------
102
- # def get_token_file_path(email: str) -> str:
103
- # tokens_dir = "gmail_tokens"
104
- # if not os.path.exists(tokens_dir):
105
- # os.makedirs(tokens_dir)
106
- # safe_email = email.replace("@", "_at_").replace(".", "_dot_")
107
- # return os.path.join(tokens_dir, f"token_{safe_email}.pickle")
108
-
109
- # def check_user_token_exists(email: str) -> bool:
110
- # token_file = get_token_file_path(email)
111
- # return os.path.exists(token_file)
112
-
113
- # def load_user_credentials(email: str):
114
- # token_file = get_token_file_path(email)
115
- # if os.path.exists(token_file):
116
- # try:
117
- # with open(token_file, 'rb') as token:
118
- # creds = pickle.load(token)
119
- # return creds
120
- # except Exception:
121
- # if os.path.exists(token_file):
122
- # os.remove(token_file)
123
- # return None
124
-
125
- # def save_user_credentials(email: str, creds):
126
- # token_file = get_token_file_path(email)
127
- # with open(token_file, 'wb') as token:
128
- # pickle.dump(creds, token)
129
-
130
- # def create_new_credentials(email: str):
131
- # credentials_path = ensure_credentials_file()
132
- # flow = InstalledAppFlow.from_client_secrets_file(
133
- # credentials_path, SCOPES
134
- # )
135
- # creds = flow.run_local_server(port=0)
136
- # save_user_credentials(email, creds)
137
- # return creds
138
-
139
- # def authenticate_gmail(email: str, create_if_missing: bool = False):
140
- # creds = load_user_credentials(email)
141
- # if creds:
142
- # if creds.expired and creds.refresh_token:
143
- # try:
144
- # creds.refresh(Request())
145
- # save_user_credentials(email, creds)
146
- # except Exception:
147
- # if create_if_missing:
148
- # try:
149
- # creds = create_new_credentials(email)
150
- # except:
151
- # return None
152
- # else:
153
- # return None
154
- # elif not creds.valid:
155
- # creds = None
156
- # if not creds:
157
- # if create_if_missing:
158
- # try:
159
- # creds = create_new_credentials(email)
160
- # except:
161
- # return None
162
- # else:
163
- # return None
164
- # try:
165
- # service = build("gmail", "v1", credentials=creds)
166
- # return service
167
- # except Exception:
168
- # return None
169
-
170
- # from email.mime.text import MIMEText
171
-
172
- # def create_email_message(sender: str, to: str, subject: str, message_text: str, reply_to: Optional[str] = None, is_html: bool = False):
173
- # if is_html:
174
- # message = MIMEText(message_text, "html")
175
- # else:
176
- # message = MIMEText(message_text, "plain")
177
- # message["To"] = to
178
- # message["From"] = sender
179
- # message["Subject"] = subject
180
- # if reply_to:
181
- # message["Reply-To"] = reply_to
182
- # raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
183
- # return {"raw": raw_message}
184
-
185
- # def send_gmail_message(service, user_id: str, message: dict):
186
- # try:
187
- # result = service.users().messages().send(userId=user_id, body=message).execute()
188
- # return result is not None
189
- # except HttpError:
190
- # return False
191
-
192
- # # ------------------------------------------
193
- # # LLM (OpenAI) Message Generation Helpers
194
- # # ------------------------------------------
195
- # def refine_message_with_feedback(
196
- # original_message: str,
197
- # feedback: str,
198
- # ) -> Tuple[str, str]:
199
- # api_key = os.getenv("OPENAI_API_KEY")
200
- # llm = ChatOpenAI(
201
- # model="gpt-4o-mini",
202
- # temperature=0.7,
203
- # max_tokens=600,
204
- # openai_api_key=api_key
205
- # )
206
- # prompt = f"""
207
- # Please refine the following recruitment message based on the provided feedback:
208
-
209
- # ORIGINAL MESSAGE:
210
- # {original_message}
211
-
212
- # FEEDBACK:
213
- # {feedback}
214
-
215
- # Please provide your response in the following format:
216
- # SUBJECT: [Your subject line here]
217
-
218
- # BODY:
219
- # [Your refined email body content here]
220
- # Keep the same tone and intent as the original message, but incorporate the feedback to improve it.
221
- # """
222
- # try:
223
- # messages = [
224
- # SystemMessage(content="You are a professional recruitment message writer. Refine the given message based on feedback while maintaining professionalism and the original intent."),
225
- # HumanMessage(content=prompt)
226
- # ]
227
- # response = llm.invoke(messages)
228
- # content = response.content.strip()
229
- # subject_line = ""
230
- # body_content = ""
231
- # lines = content.split('\n')
232
- # body_found = False
233
- # body_lines = []
234
- # for line in lines:
235
- # if line.strip().startswith('SUBJECT:'):
236
- # subject_line = line.replace('SUBJECT:', '').strip()
237
- # elif line.strip().startswith('BODY:'):
238
- # body_found = True
239
- # elif body_found and line.strip():
240
- # body_lines.append(line)
241
- # body_content = '\n'.join(body_lines).strip()
242
- # if not subject_line:
243
- # subject_line = "Recruitment Opportunity - Updated"
244
- # if not body_content:
245
- # body_content = content
246
- # return subject_line, body_content
247
- # except Exception as e:
248
- # raise HTTPException(status_code=500, detail=f"Error refining message: {str(e)}")
249
-
250
- # def generate_recruitment_message_with_subject(
251
- # msg_type: str,
252
- # company: str,
253
- # role_title: str,
254
- # recruiter: str,
255
- # org: str,
256
- # candidate: str,
257
- # current_pos: str,
258
- # evaluation: Optional[str] = None,
259
- # feedback: Optional[str] = None,
260
- # past_conversation: Optional[str] = None
261
- # ) -> Tuple[str, str]:
262
- # api_key = os.getenv("OPENAI_API_KEY")
263
- # llm = ChatOpenAI(
264
- # model="gpt-4o-mini",
265
- # temperature=0.7,
266
- # max_tokens=600,
267
- # openai_api_key=api_key
268
- # )
269
- # # Outreach: Only request consent
270
- # if msg_type == "outreach":
271
- # prompt = f"""
272
- # Generate a professional initial outreach message to a candidate.
273
- # - Introduce yourself as {recruiter} from {org}
274
- # - Clearly state you are reaching out about an open role ({role_title}) at {company}
275
- # - Ask if they are open to learning more or interested in a quick chat.
276
- # - Do NOT discuss any job evaluation or judgment.
277
- # - Explicitly request their consent to share more details. E.g., 'Would you be open to hearing more about this opportunity?'
278
- # - Keep it short and friendly.
279
- # - No placeholders like [Candidate Name] or [Role Title] in the output.
280
- # """
281
- # else:
282
- # base_prompt = f"""
283
- # Generate a professional recruitment {msg_type} with the following details:
284
- # - Company hiring: {company}
285
- # - Role: {role_title}
286
- # - Recruiter: {recruiter} from {org}
287
- # - Candidate: {candidate}
288
- # - Candidate's current position: {current_pos}
289
- # """
290
- # if evaluation:
291
- # base_prompt += f"- Evaluation: {evaluation}\n"
292
- # prompt = base_prompt
293
- # if msg_type == "introductory":
294
- # prompt += """
295
- # Create an introductory message that:
296
- # - Thanks the candidate for their initial response
297
- # - Provides more details about the role and company
298
- # - Explains why this opportunity aligns with their background
299
- # - Suggests next steps (like a call or meeting)
300
- # - Maintains a warm, professional tone
301
- # """
302
- # else: # followup
303
- # prompt += """
304
- # Create a follow-up message that:
305
- # - References previous communication
306
- # - Reiterates interest in the candidate
307
- # - Addresses any potential concerns
308
- # - Provides additional compelling reasons to consider the role
309
- # - Includes a clear call to action
310
- # """
311
-
312
- # # Use feedback if provided
313
- # if feedback:
314
- # prompt += f"\n\nPlease modify the message based on this feedback: {feedback}"
315
-
316
- # # Use past conversation if provided
317
- # if past_conversation:
318
- # prompt += f"""
319
- # Use the following past conversation as context to inform your reply:
320
-
321
- # PAST CONVERSATION:
322
- # {past_conversation}
323
-
324
- # Write a reply message to the candidate, maintaining professionalism and continuity.
325
- # """
326
-
327
- # prompt += """
328
-
329
- # Please provide your response in the following format:
330
- # SUBJECT: [Your subject line here]
331
-
332
- # BODY:
333
- # [Your email body content here]
334
- # """
335
-
336
- # try:
337
- # messages = [
338
- # SystemMessage(content="You are a professional recruitment message writer. Generate both an email subject line and body content. Follow the exact format requested."),
339
- # HumanMessage(content=prompt)
340
- # ]
341
- # response = llm.invoke(messages)
342
- # content = response.content.strip()
343
- # subject_line = ""
344
- # body_content = ""
345
- # lines = content.split('\n')
346
- # body_found = False
347
- # body_lines = []
348
- # for line in lines:
349
- # if line.strip().startswith('SUBJECT:'):
350
- # subject_line = line.replace('SUBJECT:', '').strip()
351
- # elif line.strip().startswith('BODY:'):
352
- # body_found = True
353
- # elif body_found and line.strip():
354
- # body_lines.append(line)
355
- # body_content = '\n'.join(body_lines).strip()
356
- # if not subject_line:
357
- # subject_line = f"Opportunity at {company} - {role_title}"
358
- # if not body_content:
359
- # body_content = content
360
- # return subject_line, body_content
361
- # except Exception as e:
362
- # raise HTTPException(status_code=500, detail=f"Error generating message: {str(e)}")
363
-
364
-
365
- # def format_email_html(body: str, sender_name: Optional[str]=None, sender_org: Optional[str]=None):
366
- # """Wrap plain text body in an HTML template for better appearance."""
367
- # # Convert consecutive line breaks into HTML paragraphs
368
- # import re
369
- # # Smart paragraphing
370
- # body = re.sub(r"\n\s*\n", "</p><p>", body.strip()) # Double newlines => new paragraph
371
- # body = re.sub(r"\n", "<br>", body) # Single newlines => <br>
372
- # # Optional signature
373
- # signature = ""
374
- # if sender_name or sender_org:
375
- # signature = "<br><br>Best regards,<br>"
376
- # if sender_name:
377
- # signature += f"{sender_name}<br>"
378
- # if sender_org:
379
- # signature += f"{sender_org}"
380
- # html = f"""
381
- # <html>
382
- # <body style="font-family: Arial, sans-serif; color: #222; line-height: 1.7; max-width: 540px;">
383
- # <p>{body}</p>
384
- # {signature}
385
- # </body>
386
- # </html>
387
- # """
388
- # return html
389
-
390
-
391
- # # ------------------------------------------
392
- # # FastAPI Endpoints
393
- # # ------------------------------------------
394
- # @app.get("/")
395
- # async def root():
396
- # return {
397
- # "message": "Recruitment Message Generator API",
398
- # "version": "1.0.0",
399
- # "endpoints": [
400
- # "/generate-message",
401
- # "/refine-message",
402
- # "/authenticate",
403
- # "/send-message",
404
- # "/docs"
405
-
406
- # ]
407
- # }
408
-
409
- # @app.post("/send-message", response_model=MessageResponse)
410
- # async def send_message(request: SendMessageRequest):
411
- # try:
412
- # # Authenticate sender
413
- # service = authenticate_gmail(request.sender_email)
414
- # if not service:
415
- # return MessageResponse(
416
- # success=False,
417
- # message="",
418
- # error="Gmail authentication failed"
419
- # )
420
-
421
-
422
- # formatted_html = format_email_html(
423
- # request.email_body
424
- # )
425
- # # Create the email
426
- # email_message = create_email_message(
427
- # sender=request.sender_email,
428
- # to=request.recipient_email,
429
- # subject=request.subject,
430
- # message_text=formatted_html,
431
- # reply_to=request.reply_to_email,
432
- # is_html=True
433
- # )
434
- # # Send the email
435
- # email_sent = send_gmail_message(service, "me", email_message)
436
- # if email_sent:
437
- # return MessageResponse(
438
- # success=True,
439
- # message="Email sent successfully.",
440
- # email_sent=True,
441
- # email_subject=request.subject
442
- # )
443
- # else:
444
- # return MessageResponse(
445
- # success=False,
446
- # message="",
447
- # email_sent=False,
448
- # email_subject=request.subject,
449
- # error="Failed to send via Gmail API"
450
- # )
451
- # except Exception as e:
452
- # return MessageResponse(
453
- # success=False,
454
- # message="",
455
- # error=str(e)
456
- # )
457
-
458
- # @app.post("/generate-message", response_model=MessageResponse)
459
- # async def generate_message(request: GenerateMessageRequest, background_tasks: BackgroundTasks):
460
- # try:
461
- # current_position = f"{request.current_role} at {request.current_company}"
462
- # email_subject, generated_message = generate_recruitment_message_with_subject(
463
- # msg_type=request.message_type.value.replace('followup', 'follow-up'),
464
- # company=request.company_name,
465
- # role_title=request.role,
466
- # recruiter=request.recruiter_name,
467
- # org=request.organisation,
468
- # candidate=request.candidate_name,
469
- # current_pos=current_position,
470
- # evaluation=request.job_evaluation,
471
- # past_conversation=request.past_conversation
472
- # )
473
- # email_sent = False
474
- # if request.send_email:
475
- # registered_users = []
476
- # if os.path.exists("registered_users.csv"):
477
- # df = pd.read_csv("registered_users.csv")
478
- # registered_users = df['email'].tolist() if 'email' in df.columns else []
479
- # if request.sender_email.lower() not in [user.lower() for user in registered_users]:
480
- # return MessageResponse(
481
- # success=True,
482
- # message=generated_message,
483
- # email_sent=False,
484
- # email_subject=email_subject,
485
- # error="Email not sent: Sender email is not registered"
486
- # )
487
- # service = authenticate_gmail(request.sender_email)
488
- # if service:
489
- # formatted_html = format_email_html(
490
- # generated_message,
491
- # sender_name=request.recruiter_name,
492
- # sender_org=request.organisation
493
- # )
494
- # email_message = create_email_message(
495
- # sender=request.sender_email,
496
- # to=request.recipient_email,
497
- # subject=email_subject,
498
- # message_text=formatted_html,
499
- # reply_to=request.reply_to_email,
500
- # is_html=True
501
- # )
502
- # email_sent = send_gmail_message(service, "me", email_message)
503
- # if not email_sent:
504
- # return MessageResponse(
505
- # success=True,
506
- # message=generated_message,
507
- # email_sent=False,
508
- # email_subject=email_subject,
509
- # error="Email not sent: Failed to send via Gmail API"
510
- # )
511
- # else:
512
- # return MessageResponse(
513
- # success=True,
514
- # message=generated_message,
515
- # email_sent=False,
516
- # email_subject=email_subject,
517
- # error="Email not sent: Gmail authentication failed"
518
- # )
519
- # return MessageResponse(
520
- # success=True,
521
- # message=generated_message,
522
- # email_sent=email_sent,
523
- # email_subject=email_subject
524
- # )
525
- # except Exception as e:
526
- # return MessageResponse(
527
- # success=False,
528
- # message="",
529
- # error=str(e)
530
- # )
531
-
532
- # @app.post("/refine-message", response_model=MessageResponse)
533
- # async def refine_message(request: FeedbackRequest):
534
- # try:
535
- # email_subject, refined_message = refine_message_with_feedback(
536
- # original_message=request.message,
537
- # feedback=request.feedback
538
- # )
539
- # return MessageResponse(
540
- # success=True,
541
- # message=refined_message,
542
- # email_sent=False,
543
- # email_subject=email_subject
544
- # )
545
- # except Exception as e:
546
- # return MessageResponse(
547
- # success=False,
548
- # message="",
549
- # error=str(e)
550
- # )
551
-
552
- # @app.post("/authenticate", response_model=AuthenticateResponse)
553
- # async def authenticate_user(request: AuthenticateRequest):
554
- # try:
555
- # if check_user_token_exists(request.email):
556
- # service = authenticate_gmail(request.email, create_if_missing=False)
557
- # if service:
558
- # return AuthenticateResponse(
559
- # success=True,
560
- # message="User already authenticated and token is valid"
561
- # )
562
- # else:
563
- # service = authenticate_gmail(request.email, create_if_missing=True)
564
- # if service:
565
- # return AuthenticateResponse(
566
- # success=True,
567
- # message="Token refreshed successfully"
568
- # )
569
- # else:
570
- # return AuthenticateResponse(
571
- # success=False,
572
- # message="Failed to refresh token",
573
- # error="Could not refresh existing token. Please check credentials.json"
574
- # )
575
- # else:
576
- # try:
577
- # creds = create_new_credentials(request.email)
578
- # if creds:
579
- # return AuthenticateResponse(
580
- # success=True,
581
- # message="Authentication successful. Token created and saved."
582
- # )
583
- # else:
584
- # return AuthenticateResponse(
585
- # success=False,
586
- # message="Authentication failed",
587
- # error="Failed to create credentials"
588
- # )
589
- # except Exception as e:
590
- # return AuthenticateResponse(
591
- # success=False,
592
- # message="Authentication failed",
593
- # error=str(e)
594
- # )
595
- # except Exception as e:
596
- # return AuthenticateResponse(
597
- # success=False,
598
- # message="Authentication error",
599
- # error=str(e)
600
- # )
601
-
602
- # @app.get("/health")
603
- # async def health_check():
604
- # return {"status": "healthy", "timestamp": datetime.utcnow().isoformat()}
605
-
606
- # if __name__ == "__main__":
607
- # import uvicorn
608
- # uvicorn.run(app, host="0.0.0.0", port=8000)
609
-
610
-
611
-
612
  from fastapi import FastAPI, HTTPException, BackgroundTasks, Depends, Header, status
613
  from fastapi.middleware.cors import CORSMiddleware
614
  from fastapi.security import APIKeyHeader
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from fastapi import FastAPI, HTTPException, BackgroundTasks, Depends, Header, status
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.security import APIKeyHeader