ak0601 commited on
Commit
256893e
·
verified ·
1 Parent(s): 7892b25

Update app_hug.py

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