209 lines
8.0 KiB
Python
209 lines
8.0 KiB
Python
"""
|
|
|
|
AUTHOR:
|
|
|
|
Khushal P Soonderji
|
|
|
|
DATE:
|
|
|
|
Wednesday, 27th Nov., 2024
|
|
|
|
OBJECTIVE:
|
|
|
|
To define the interaction between the UI layer and the database connectivity in one place. Here we shall handle
|
|
all the activities for OAuth2.0 authorization requests for all the users of our service.
|
|
|
|
REFERENCES:
|
|
|
|
N/A
|
|
|
|
DOWNLOADS:
|
|
|
|
N/A
|
|
|
|
"""
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** IMPORT ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
# To make sibling directories accessible for imports:
|
|
import sys
|
|
|
|
from langchain.chains.summarize.stuff_prompt import prompt_template
|
|
|
|
sys.path.append(".")
|
|
sys.path.append("..")
|
|
|
|
# My async utils:
|
|
from utils_v2.string import json
|
|
from utils_v2.date_time import date_time
|
|
from utils_v2.database.async_mysql_v2 import AsyncMySQL
|
|
from utils_v2.database.async_mongo_v2 import AsyncMongo
|
|
|
|
# Mail Clients:
|
|
from utils_v2.goog.gmail.gmail_client import AsyncGMailClient
|
|
from utils_v2.goog.models.data.auth_tokens import GoogleAuthTokens
|
|
|
|
# Base model:
|
|
from models.behaviour.base import BaseModel
|
|
|
|
# To work with MongoDB:
|
|
from bson import ObjectId
|
|
|
|
# To work with LLMs:
|
|
from langchain_openai import ChatOpenAI
|
|
from langchain_core.prompts import ChatPromptTemplate
|
|
|
|
# To work with datatypes:
|
|
from typing import Literal
|
|
|
|
# To make deep-copies:
|
|
import copy
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** MACROS / ONE-TIME INIT ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
# --- Nothing Yet
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** VARIABLES ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
# --- Nothing Yet
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** FUNCTIONS ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
# --- Nothing Yet
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** CLASSES ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
class MailSyncModel(BaseModel):
|
|
|
|
# For MongoDB:
|
|
AUTH_COLLECTION = "_authTokens"
|
|
MAIL_COLLECTION = "_messages"
|
|
|
|
# For AI Magic through LLMs:
|
|
prompt_template = ChatPromptTemplate.from_messages([
|
|
(
|
|
"system",
|
|
"You're a mail summary expert that summarizes mails in 150 chars or less. HIDE SENSITIVE INFO (LIKE OTPS) FROM THE SUMMARY."
|
|
),
|
|
(
|
|
"user",
|
|
"Please summarize this mail: \"\"\"{mail}\"\"\""
|
|
)
|
|
])
|
|
|
|
async def sync_one(
|
|
self,
|
|
mongo_conn: AsyncMongo,
|
|
user_identifier: str | ObjectId,
|
|
mail_client: AsyncGMailClient,
|
|
tokens: GoogleAuthTokens,
|
|
message_id: str,
|
|
llm: ChatOpenAI = None,
|
|
session_token: str = None,
|
|
force_sync: bool = False
|
|
) -> ObjectId:
|
|
|
|
# ┏┓┓ ┓ ┏┓ • • ┳┓ ┓
|
|
# ┃ ┣┓┏┓┏┃┏ ┣ ┓┏┓┏╋┓┏┓┏┓ ┣┫┏┓┏┏┓┏┓┏┫┏
|
|
# ┗┛┛┗┗ ┗┛┗ ┗┛┛┗┗┛┗┗┛┗┗┫ ┛┗┗ ┗┗┛┛ ┗┻┛
|
|
# ┛
|
|
|
|
# Check if you already have that mail in your database:
|
|
existing_record = await mongo_conn.find_one(
|
|
collection = self.MAIL_COLLECTION,
|
|
filter = {
|
|
"messageType": "email",
|
|
"$or": [
|
|
{"payload.messageId": message_id}
|
|
]
|
|
},
|
|
projection = {"_id": True}
|
|
)
|
|
|
|
# If there already exists such a record, and we haven't been forced to re-sync it:
|
|
if existing_record and not force_sync: return existing_record["_id"]
|
|
|
|
# ┏┓ ┓┏ • ┓ ┓
|
|
# ┃┃┏┓┏┓┏┓┏┓┏┓┏┓ ┃┃┏┓┏┓┓┏┓┣┓┃┏┓┏
|
|
# ┣┛┛ ┗ ┣┛┗┻┛ ┗ ┗┛┗┻┛ ┗┗┻┗┛┗┗ ┛
|
|
# ┛
|
|
|
|
mail_payload = None
|
|
mail_id = existing_record["_id"] if existing_record else None
|
|
|
|
# ┏┓┳┳┓ •┓
|
|
# ┃┓┃┃┃┏┓┓┃
|
|
# ┗┛┛ ┗┗┻┗┗
|
|
|
|
if isinstance(mail_client, AsyncGMailClient):
|
|
|
|
# Refresh the tokens:
|
|
tokens_refreshed
|
|
|
|
# Fetch the mail formatted message:
|
|
client_response = await mail_client.get_message(
|
|
tokens = tokens,
|
|
message_id = message_id,
|
|
return_raw = False
|
|
)
|
|
|
|
# If the fetch was successful:
|
|
if client_response.success:
|
|
|
|
# Summarize the content:
|
|
prompt = self.prompt_template.invoke({"mail": client_response.data.pop["unformattedText"]})
|
|
llm_response = await llm.ainvoke(prompt)
|
|
client_response.data["aiSnippet"] = llm_response.content
|
|
|
|
# Note down the response:
|
|
mail_payload = client_response.data
|
|
|
|
# ┏┓ ┏┳┓┓ ┳┳┓ •┓
|
|
# ┗┓┓┏┏┓┏ ┃ ┣┓┏┓ ┃┃┃┏┓┓┃
|
|
# ┗┛┗┫┛┗┗ ┻ ┛┗┗ ┛ ┗┗┻┗┗
|
|
# ┛
|
|
|
|
if mail_payload:
|
|
pass
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** MAIN PROGRAM ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
pass
|