(20241129) Day-end push.

This commit is contained in:
2024-11-29 18:19:52 +05:30
parent 0c05dcf6c5
commit 4d8b40a6c7
4 changed files with 170 additions and 16 deletions
+42 -6
View File
@@ -100,7 +100,6 @@ class MailOAuthModel(BaseModel):
db_conn: AsyncMySQL,
mongo_conn: AsyncMongo,
user_info: dict,
service_type: Literal["email", "chat"],
service_client: Literal["gmail"],
auth_type: Literal["oauth"],
session_token: str = None
@@ -112,7 +111,6 @@ class MailOAuthModel(BaseModel):
:param db_conn: The database connection (MariaDB) to use to perform the action.
:param mongo_conn: The database connection (MongoDB) to use to perform the action.
:param user_info: The dictionary that has the user's session information.
:param service_type: The type of service being provided.
:param service_client: The name of the company or brand that is providing this service that is being integrated.
:param auth_type: To identify the type of authentication being done here. This could indicate simple password
authentication, more advance OAuth2.0 authentication, etc.
@@ -127,7 +125,7 @@ class MailOAuthModel(BaseModel):
mongo_json = await mongo_conn.find_one_and_update(
collection = MailOAuthModel.AUTH_COLLECTION,
filter = {
"serviceType": service_type,
"serviceType": "email",
"client": service_client,
"authType": auth_type,
"user": user_info,
@@ -138,7 +136,7 @@ class MailOAuthModel(BaseModel):
},
"$setOnInsert": {
"version": "1.0.0",
"serviceType": service_type,
"serviceType": "email",
"client": service_client,
"authType": auth_type,
"user": user_info,
@@ -189,10 +187,10 @@ class MailOAuthModel(BaseModel):
"""
This method is to be called when the end user authorizes your service to connect to his third-party account. For
example, when the end user allows you to access his GMail account.
example, when the end user allows you to access his GMail account. USE THIS FOR UPDATING (REFRESHING) TOKENS
ALSO.
:param db_conn: The database connection (MariaDB) to use to perform the action.
:param mongo_conn: The database connection (MongoDB) to use to perform the action.
:param user_info: The dictionary that has the user's session information.
:param user_identifier: The identifier granted by the 'get_user_identifier' method.
:param token: The token granted by the third-party service.
:param session_token: The session token of the user who requested this service.
@@ -243,6 +241,44 @@ class MailOAuthModel(BaseModel):
# Done here:
return token_saved
async def get_token(
self,
mongo_conn: AsyncMongo,
user_identifier: ObjectId | str = None,
**kwargs
) -> dict | None:
"""
To retrieve stored tokens from the database.
:param mongo_conn: The database connection (MongoDB) to use to perform the action.
:param user_identifier: The identifier granted by the 'get_user_identifier' method.
:param kwargs: Any set of key-value pairs to build custom search criteria. This could be things like the user
info, the client, the type of authentication used, or even the kind of service.
:return: The retrieved record that has the token, and information about the service and client if found, else
None when there is no matching record.
"""
# Build the filter:
filter_json = {k: v for k, v in kwargs.items()}
if user_identifier: filter_json["_id"] = ObjectId(user_identifier)
# If there is no search criteria, we exit with failure:
if not filter_json: return None
# If there is some filtering possible,
# we fetch and return the token:
return await mongo_conn.find_one(
collection = self.AUTH_COLLECTION,
filter = filter_json,
projection = {
"_id": True,
"serviceType": True,
"authType": True,
"client": True,
"token": True
}
)
# *****************************************************************************************************************
# ***** ****
+96 -9
View File
@@ -32,6 +32,9 @@
# To make sibling directories accessible for imports:
import sys
from langchain.chains.summarize.stuff_prompt import prompt_template
sys.path.append(".")
sys.path.append("..")
@@ -41,12 +44,20 @@ 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
@@ -91,22 +102,98 @@ import copy
# *****************************************************************************************************************
class MailReadModel(BaseModel):
class MailSyncModel(BaseModel):
# For MongoDB:
AUTH_COLLECTION = "_authTokens"
MAIL_COLLECTION = "_messages"
async def read_one(
# 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,
db_conn: AsyncMySQL,
mongo_conn: AsyncMongo,
user_info: dict,
service_type: Literal["email", "chat"],
service_client: Literal["gmail"],
auth_type: Literal["oauth"],
session_token: str = None
user_identifier: str | ObjectId,
mail_client: AsyncGMailClient,
tokens: GoogleAuthTokens,
message_id: str,
llm: ChatOpenAI = None,
session_token: str = None,
force_sync: bool = False
) -> ObjectId:
pass
# ┏┓┓ ┓ ┏┓ • • ┳┓ ┓
# ┃ ┣┓┏┓┏┃┏ ┣ ┓┏┓┏╋┓┏┓┏┓ ┣┫┏┓┏┏┓┏┓┏┫┏
# ┗┛┛┗┗ ┗┛┗ ┗┛┛┗┗┛┗┗┛┗┗┫ ┛┗┗ ┗┗┛┛ ┗┻┛
# ┛
# 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
# *****************************************************************************************************************