(20241209) Small failure view bug fix to show the 'logId' now.

This commit is contained in:
2024-12-09 12:42:28 +05:30
parent e2c9200941
commit a443a78e19
7 changed files with 239 additions and 234 deletions
+2 -2
View File
@@ -113,7 +113,7 @@ def init(blueprint_setup_state):
api_version = "1.0.0",
project = constants.PROJECT_NAME,
log_type = constants.MODULE_NAME,
operation = "gmailCallbk",
operation = "gmailCllbk",
log_input = 2,
log_output = 1,
sensitive_keys = ["sessionToken", "X-Session-Token"]
@@ -300,7 +300,7 @@ async def mail_auth_callback(
mail_client = mail_client.title(),
failure_hint = (
f"Invalid client '{mail_client}' selected. "
"Please use log-id '{g.log_id}' to check with the support team."
f"Please use log-id '{g.log_id}' to check with the support team."
)
)
View File
-221
View File
@@ -1,221 +0,0 @@
"""
AUTHOR:
Khushal P Soonderji
DATE:
Thursday, 5th Dec., 2024
OBJECTIVE:
To create an interface between OpenAI and our internal system to perform LLM-based activities.
REFERENCES:
N/A
DOWNLOADS:
N/A
"""
# *****************************************************************************************************************
# ***** ****
# *** IMPORT ***
# ***** ****
# *****************************************************************************************************************
# To make sibling directories accessible for imports:
import sys
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
# Base model:
from models.behaviour.base import BaseModel
# Data Models:
from models.data.api.ai.llm import LLMInput, LLMOutput, LLMUsageTokens
# To work with LLMs:
from langchain_openai import ChatOpenAI
# To work with MongoDB:
from bson import ObjectId
# 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 LLMOpenAI(BaseModel):
AI_USAGE_COLLECTION = "_aiUsage"
def __init__(
self,
llm_creds: dict,
cache = None,
alert_url = None,
http_client = None,
debug = True,
debug_prefix = "Model | ",
debug_only_errors = True
):
"""
This is the model that works with OpenAi's LLM to perform tasks like text completion.
:param llm_creds: The JSON that holds the credentials to access your OpenAI account. Should have the keys
'model', and 'openai_api_key'.
:param cache: The object to use for caching results from database calls.
:param alert_url: Which URL to call when something goes wrong.
:param http_client: The instance of an HTTP client to use when trying to send alerts and make other APIs.
:param debug: Whether, or not, you would like to print debugging messages:
:param debug_prefix: The prefix to print with the debugging messages.
:param debug_only_errors: Whether you would like to print only error messages or all messages.
:return: None.
"""
# Initialize the parent:
super().__init__(
cache = cache,
alert_url = alert_url,
http_client = http_client,
debug = debug,
debug_prefix = debug_prefix,
debug_only_errors = debug_only_errors
)
# Create the interface to the LLM:
self.__llm = ChatOpenAI(**llm_creds)
async def invoke(
self,
mongo_conn: AsyncMongo,
user_info: dict,
llm_input: LLMInput
) -> LLMOutput:
# Format the message as per the format of OpenAI:
prompt = [
{
"role": {"system": "system", "ai": "assistant", "human": "user"}[message.role],
"content": message.content
} for message in llm_input.messages
]
# Invoke the AI, and format the response:
llm_response = await self.__llm.ainvoke(prompt)
llm_response = LLMOutput(
messages = llm_input.messages,
output = llm_response.content,
client = "openai",
model = llm_response.response_metadata["model_name"],
tokens = LLMUsageTokens(
input = llm_response.usage_metadata["input_tokens"],
output = llm_response.usage_metadata["output_tokens"],
total = llm_response.usage_metadata["total_tokens"],
)
)
# Store this into MongoDB:
mongo_document = {"user": user_info}
for k, v in llm_response.model_dump().items(): mongo_document[k] = v
inserted_id = await mongo_conn.insert_one(
collection = self.AI_USAGE_COLLECTION,
document = mongo_document
)
# Done here:
return llm_response
# *****************************************************************************************************************
# ***** ****
# *** MAIN PROGRAM ***
# ***** ****
# *****************************************************************************************************************
if __name__ == "__main__":
pass
# import asyncio
#
# llm_messages = [
# {
# "role": "system",
# "content": "You are an office assistant."
# },
# {
# "role": "ai",
# "content": "Hello, sir. How may I help you today?"
# },
# {
# "role": "human",
# "content": "Please summarize this mail for me..."
# }
# ]
#
# my_llm = LLMOpenAI(
# llm_creds = {
# "model": "gpt-4o-mini",
# "openai_api_key": "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"
# }
# )
#
# async def main():
#
# llm_response = await my_llm.invoke(llm_input = LLMInput(messages = llm_messages))
# print("LLM RESPONSE:", llm_response.model_dump_json(indent = 4))
#
# asyncio.run(main())
+6 -6
View File
@@ -7,7 +7,7 @@
DATE:
ORIGINAL: Monday, 2nd Dec., 2024
UPGRADE: Monday, 9th Dec., 2024
UPGRADED: Monday, 9th Dec., 2024
OBJECTIVE:
@@ -134,9 +134,9 @@ class MailOAuthModel(BaseModel):
}),
update = {
"$set": {
"lastRequestTs": request_ts,
"lastRequestTs": auth_token.lastRequestTs,
"status": auth_token.status,
"syncFreq": max(auth_token.syncFreq, 60)
"syncFreq": auth_token.syncFreq
},
"$setOnInsert": {
"version": auth_token.version,
@@ -149,7 +149,7 @@ class MailOAuthModel(BaseModel):
"token": auth_token.token,
"firstRefreshTs": auth_token.firstRefreshTs,
"lastRefreshTs": auth_token.lastRefreshTs,
"firstRequestTs": auth_token.firstRequestTs,
"firstRequestTs": auth_token.firstRequestTs or request_ts,
}
},
projection = {
@@ -168,7 +168,7 @@ class MailOAuthModel(BaseModel):
proc_args = (
auth_token.user.entityId, # ......................................... 'p_entity_id'
auth_token.client, # ................................................ 'p_provider'
"Pending", # ........................................................ 'p_current_status'
auth_token.status, # ................................................ 'p_current_status'
"Auth Requested", # ................................................. 'p_last_action'
None, # ............................................................. 'p_display_name'
None, # ............................................................. 'p_display_picture'
@@ -254,7 +254,7 @@ class MailOAuthModel(BaseModel):
proc_args = (
mongo_json["user"]["entityId"], # ............................... 'p_entity_id'
mongo_json["client"], # ......................................... 'p_provider'
"Active", # ..................................................... 'p_current_status'
auth_token.status, # ............................................ 'p_current_status'
"Auth Granted", # ............................................... 'p_last_action'
auth_token.token.get("displayName"), # .......................... 'p_display_name'
auth_token.token.get("displayPictureUrl"), # .................... 'p_display_picture'
+227
View File
@@ -0,0 +1,227 @@
"""
AUTHOR:
Khushal P Soonderji
DATE:
ORIGINAL: Thursday, 5th Dec., 2024
UPGRADED: Monday, 9th Dec., 2024
OBJECTIVE:
To work with auth details of SMS clients like Nimbus SMS (India) and Savvy Bulk SMS (Kenya).
REFERENCES:
N/A
DOWNLOADS:
N/A
"""
# *****************************************************************************************************************
# ***** ****
# *** IMPORT ***
# ***** ****
# *****************************************************************************************************************
# To make sibling directories accessible for imports:
import sys
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
# Base model:
from models.behaviour.base import BaseModel
# Data models:
from models.data.core.auth_token import CoreAuthTokenModel
# To work with MongoDB:
from bson import ObjectId
# 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 SMSAuthModel(BaseModel):
AUTH_COLLECTION = "_authTokens"
async def set(
self,
db_conn: AsyncMySQL,
mongo_conn: AsyncMongo,
auth_token: CoreAuthTokenModel,
session_token: str = None
) -> ObjectId | None:
"""
To store auth/tokens for a particular service to the database.
: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 auth_token: An instance of the core auth-token model that holds data in the database.
:param session_token: The session token of the user who requested this service.
:return: An ObjectId to later store the granted tokens.
"""
# Note down the timestamp at which this event occurred:
request_ts = date_time.get_current_utc_date_time(as_string = False)
# Get the identifier from the database:
# BE CAREFUL WITH THE KEYS HERE, THEY SHOULD MATCH THE FIELDS OF THE CORE AUTH-TOKEN MODEL:
mongo_json = await mongo_conn.find_one_and_update(
collection = self.AUTH_COLLECTION,
filter = mongo_conn.dict_to_dot_notation({
"serviceType": "email",
"user": {
"entityId": auth_token.user.entityId,
"billingAccountId": auth_token.user.billingAccountId
},
"clientUserId": auth_token.clientUserId
}),
update = {
"$set": {
"lastRequestTs": auth_token.lastRequestTs,
"status": auth_token.status,
"syncFreq": auth_token.syncFreq
},
"$setOnInsert": {
"version": auth_token.version,
"serviceType": auth_token.serviceType,
"client": auth_token.client,
"authType": auth_token.authType,
"user": auth_token.user.model_dump(),
"clientUserId": auth_token.clientUserId,
"auth": auth_token.auth,
"token": auth_token.token,
"firstRefreshTs": auth_token.firstRefreshTs,
"lastRefreshTs": auth_token.lastRefreshTs,
"firstRequestTs": auth_token.firstRequestTs or request_ts
}
},
projection = {
"_id": True
},
upsert = True,
return_updated = True
)
# Tell MariaDB that an authorization request was initiated:
db_json = {}
if mongo_json is not None:
token_notes = auth_token.clientUserId
db_json = await self.call_procedure(
db_conn = db_conn,
proc_name = "entity_integration_save",
proc_args = (
auth_token.user.entityId, # ..................................... 'p_entity_id'
auth_token.client, # ............................................ 'p_provider'
auth_token.status, # ............................................ 'p_current_status'
"Auth Details Accepted", # ...................................... 'p_last_action'
None, # ......................................................... 'p_display_name'
None, # ......................................................... 'p_display_picture'
str(mongo_json["_id"]), # ....................................... 'p_token_id'
json.to_string(python_data = token_notes, no_space = True), # ... 'p_notes'
auth_token.user.userId # ........................................ 'p_created_by'
),
session_token = session_token
)
# Done here:
return mongo_json["_id"] if mongo_json and db_json.get("status") == 1 else None
async def get(
self,
mongo_conn: AsyncMongo,
token_id: ObjectId | str = None,
**kwargs
) -> dict | None:
"""
To retrieve stored auth/tokens from the database.
:param mongo_conn: The database connection (MongoDB) to use to perform the action.
:param token_id: The identifier granted providing auth details for the first time in 'set_token'.
: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 token_id: filter_json["_id"] = ObjectId(token_id)
# If there is no search criteria, we exit with failure:
if not filter_json: return None
# If there is some filtering possible, we fetch the token:
token = await mongo_conn.find_one(
collection = self.AUTH_COLLECTION,
filter = filter_json,
)
# Done here:
return CoreAuthTokenModel(**token) if token else None
# *****************************************************************************************************************
# ***** ****
# *** MAIN PROGRAM ***
# ***** ****
# *****************************************************************************************************************
if __name__ == "__main__":
pass
+2 -2
View File
@@ -112,13 +112,13 @@ class CoreAuthTokenModel(BaseModel):
firstRequestTs: AwareDatetime = Field(
description = "the time (utc) at which authorization was first requested",
frozen = True,
default_factory = lambda: date_time.get_current_utc_date_time(as_string = False)
default = None
)
lastRequestTs: AwareDatetime = Field(
description = "the time (utc) at which authorization was last requested",
frozen = False,
default = None
default_factory = lambda: date_time.get_current_utc_date_time(as_string = False)
)
firstRefreshTs: AwareDatetime = Field(
+2 -3
View File
@@ -1,4 +1,3 @@
kbdev.bicree.com
jc.ditscentre.in
wtt.ditscentre.in
del.ditscentre.in
jc.ditscentre.in
del.ditscentre.in