dhisana 0.0.1.dev9__tar.gz → 0.0.1.dev10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/PKG-INFO +1 -1
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/setup.py +1 -1
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/google_workspace_tools.py +183 -0
- dhisana-0.0.1.dev10/src/dhisana/utils/hubspot_crm_tools.py +1126 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/openai_helpers.py +65 -39
- dhisana-0.0.1.dev10/src/dhisana/utils/serpapi_search_tools.py +227 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/web_download_parse_tools.py +11 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana.egg-info/PKG-INFO +1 -1
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana.egg-info/SOURCES.txt +1 -0
- dhisana-0.0.1.dev9/src/dhisana/utils/hubspot_crm_tools.py +0 -598
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/README.md +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/pyproject.toml +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/setup.cfg +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/__init__.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/cli/__init__.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/cli/cli.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/cli/datasets.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/cli/models.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/cli/predictions.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/ui/__init__.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/ui/components.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/__init__.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/agent_tools.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/apollo_tools.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/assistant_tool_tag.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/check_email_validity_tools.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/dataframe_tools.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/linkedin_crawler.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/python_function_to_tools.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/utils/tools_json.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/workflow/__init__.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana/workflow/task.py +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana.egg-info/dependency_links.txt +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana.egg-info/entry_points.txt +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana.egg-info/requires.txt +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/src/dhisana.egg-info/top_level.txt +0 -0
- {dhisana-0.0.1.dev9 → dhisana-0.0.1.dev10}/tests/test_agent_tools.py +0 -0
|
@@ -16,6 +16,8 @@ from googleapiclient.errors import HttpError
|
|
|
16
16
|
import datetime
|
|
17
17
|
from dhisana.utils.assistant_tool_tag import assistant_tool
|
|
18
18
|
|
|
19
|
+
|
|
20
|
+
|
|
19
21
|
def convert_base_64_json(base64_string):
|
|
20
22
|
"""
|
|
21
23
|
Convert a base64 encoded string to a JSON string.
|
|
@@ -445,6 +447,187 @@ async def list_emails_in_time_range_async(start_time: str, end_time: str, unread
|
|
|
445
447
|
|
|
446
448
|
return email_details
|
|
447
449
|
|
|
450
|
+
|
|
451
|
+
@assistant_tool
|
|
452
|
+
async def fetch_last_n_sent_messages(recipient_email: str, num_messages: int) -> List[Dict[str, Any]]:
|
|
453
|
+
"""
|
|
454
|
+
Fetch the last n messages sent to a specific recipient using the Gmail API with a service account.
|
|
455
|
+
The service account must have domain-wide delegation to impersonate the sender.
|
|
456
|
+
|
|
457
|
+
:param recipient_email: The recipient's email address.
|
|
458
|
+
:param num_messages: The number of recent messages to fetch.
|
|
459
|
+
:return: A list of email message details.
|
|
460
|
+
"""
|
|
461
|
+
# Retrieve the service account JSON and email for automation from environment variables
|
|
462
|
+
service_account_base64 = os.getenv('GOOGLE_SERVICE_KEY')
|
|
463
|
+
automationemails = os.getenv('EMAIL_FOR_AUTOMATION')
|
|
464
|
+
if not service_account_base64 or not automationemails:
|
|
465
|
+
raise EnvironmentError("Required environment variables are not set.")
|
|
466
|
+
|
|
467
|
+
allowed_emails_for_automation = automationemails.split(",")
|
|
468
|
+
if not allowed_emails_for_automation:
|
|
469
|
+
raise EnvironmentError("No allowed emails for automation found in environment variables.")
|
|
470
|
+
|
|
471
|
+
mailbox_email = allowed_emails_for_automation[0]
|
|
472
|
+
|
|
473
|
+
# Function to convert base64-encoded JSON to a string
|
|
474
|
+
def convert_base_64_json(base64_json: str) -> str:
|
|
475
|
+
return base64.b64decode(base64_json).decode('utf-8')
|
|
476
|
+
|
|
477
|
+
service_account_json = convert_base_64_json(service_account_base64)
|
|
478
|
+
|
|
479
|
+
# Parse the JSON string into a dictionary
|
|
480
|
+
service_account_info = json.loads(service_account_json)
|
|
481
|
+
|
|
482
|
+
# Define the required scope for reading emails via Gmail API
|
|
483
|
+
SCOPES = ['https://mail.google.com/']
|
|
484
|
+
|
|
485
|
+
# Authenticate using the service account info and impersonate the email for automation
|
|
486
|
+
credentials = service_account.Credentials.from_service_account_info(
|
|
487
|
+
service_account_info, scopes=SCOPES
|
|
488
|
+
).with_subject(mailbox_email)
|
|
489
|
+
|
|
490
|
+
# Refresh the token if necessary
|
|
491
|
+
if not credentials.valid:
|
|
492
|
+
request = Request()
|
|
493
|
+
credentials.refresh(request)
|
|
494
|
+
|
|
495
|
+
# Get the access token
|
|
496
|
+
access_token = credentials.token
|
|
497
|
+
|
|
498
|
+
# Define the Gmail API endpoint for listing messages
|
|
499
|
+
gmail_api_url = 'https://gmail.googleapis.com/gmail/v1/users/me/messages'
|
|
500
|
+
|
|
501
|
+
# Create the query parameters for the recipient email
|
|
502
|
+
query = f'to:{recipient_email}'
|
|
503
|
+
|
|
504
|
+
# Prepare the headers
|
|
505
|
+
headers = {
|
|
506
|
+
'Authorization': f'Bearer {access_token}'
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
# Prepare the parameters
|
|
510
|
+
params = {
|
|
511
|
+
'q': query,
|
|
512
|
+
'maxResults': num_messages
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async with httpx.AsyncClient() as client:
|
|
516
|
+
response = await client.get(gmail_api_url, headers=headers, params=params)
|
|
517
|
+
response.raise_for_status() # Raise an exception for HTTP errors
|
|
518
|
+
messages = response.json().get('messages', [])
|
|
519
|
+
|
|
520
|
+
email_details = []
|
|
521
|
+
for message in messages:
|
|
522
|
+
message_id = message['id']
|
|
523
|
+
message_url = f'https://gmail.googleapis.com/gmail/v1/users/me/messages/{message_id}'
|
|
524
|
+
message_response = await client.get(message_url, headers=headers)
|
|
525
|
+
message_response.raise_for_status()
|
|
526
|
+
message_data = message_response.json()
|
|
527
|
+
|
|
528
|
+
email_details.append({
|
|
529
|
+
"mailbox_email_id": message_data['id'],
|
|
530
|
+
"message_id": message_data['threadId'],
|
|
531
|
+
"email_subject": next((header['value'] for header in message_data['payload']['headers'] if header['name'] == 'Subject'), None),
|
|
532
|
+
"email_sender": next((header['value'] for header in message_data['payload']['headers'] if header['name'] == 'From'), None),
|
|
533
|
+
"email_recipients": [header['value'] for header in message_data['payload']['headers'] if header['name'] in ['To', 'Cc', 'Bcc']],
|
|
534
|
+
"email_date": next((header['value'] for header in message_data['payload']['headers'] if header['name'] == 'Date'), None),
|
|
535
|
+
"read_email_status": 'UNREAD' if 'UNREAD' in message_data['labelIds'] else 'READ',
|
|
536
|
+
"email_labels": message_data.get('labelIds', [])
|
|
537
|
+
})
|
|
538
|
+
|
|
539
|
+
return email_details
|
|
540
|
+
|
|
541
|
+
@assistant_tool
|
|
542
|
+
async def fetch_last_n_received_messages(sender_email: str, num_messages: int) -> List[Dict[str, Any]]:
|
|
543
|
+
"""
|
|
544
|
+
Fetch the last n messages received from a specific sender using the Gmail API with a service account.
|
|
545
|
+
The service account must have domain-wide delegation to impersonate the recipient.
|
|
546
|
+
|
|
547
|
+
:param sender_email: The sender's email address.
|
|
548
|
+
:param num_messages: The number of recent messages to fetch.
|
|
549
|
+
:return: A list of email message details.
|
|
550
|
+
"""
|
|
551
|
+
# Retrieve the service account JSON and email for automation from environment variables
|
|
552
|
+
service_account_base64 = os.getenv('GOOGLE_SERVICE_KEY')
|
|
553
|
+
automationemails = os.getenv('EMAIL_FOR_AUTOMATION')
|
|
554
|
+
if not service_account_base64 or not automationemails:
|
|
555
|
+
raise EnvironmentError("Required environment variables are not set.")
|
|
556
|
+
|
|
557
|
+
allowed_emails_for_automation = automationemails.split(",")
|
|
558
|
+
if not allowed_emails_for_automation:
|
|
559
|
+
raise EnvironmentError("No allowed emails for automation found in environment variables.")
|
|
560
|
+
|
|
561
|
+
mailbox_email = allowed_emails_for_automation[0]
|
|
562
|
+
|
|
563
|
+
# Function to convert base64-encoded JSON to a string
|
|
564
|
+
def convert_base_64_json(base64_json: str) -> str:
|
|
565
|
+
return base64.b64decode(base64_json).decode('utf-8')
|
|
566
|
+
|
|
567
|
+
service_account_json = convert_base_64_json(service_account_base64)
|
|
568
|
+
|
|
569
|
+
# Parse the JSON string into a dictionary
|
|
570
|
+
service_account_info = json.loads(service_account_json)
|
|
571
|
+
|
|
572
|
+
# Define the required scope for reading emails via Gmail API
|
|
573
|
+
SCOPES = ['https://mail.google.com/']
|
|
574
|
+
|
|
575
|
+
# Authenticate using the service account info and impersonate the email for automation
|
|
576
|
+
credentials = service_account.Credentials.from_service_account_info(
|
|
577
|
+
service_account_info, scopes=SCOPES
|
|
578
|
+
).with_subject(mailbox_email)
|
|
579
|
+
|
|
580
|
+
# Refresh the token if necessary
|
|
581
|
+
if not credentials.valid:
|
|
582
|
+
request = Request()
|
|
583
|
+
credentials.refresh(request)
|
|
584
|
+
|
|
585
|
+
# Get the access token
|
|
586
|
+
access_token = credentials.token
|
|
587
|
+
|
|
588
|
+
# Define the Gmail API endpoint for listing messages
|
|
589
|
+
gmail_api_url = 'https://gmail.googleapis.com/gmail/v1/users/me/messages'
|
|
590
|
+
|
|
591
|
+
# Create the query parameters for the sender email
|
|
592
|
+
query = f'from:{sender_email}'
|
|
593
|
+
|
|
594
|
+
# Prepare the headers
|
|
595
|
+
headers = {
|
|
596
|
+
'Authorization': f'Bearer {access_token}'
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
# Prepare the parameters
|
|
600
|
+
params = {
|
|
601
|
+
'q': query,
|
|
602
|
+
'maxResults': num_messages
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async with httpx.AsyncClient() as client:
|
|
606
|
+
response = await client.get(gmail_api_url, headers=headers, params=params)
|
|
607
|
+
response.raise_for_status() # Raise an exception for HTTP errors
|
|
608
|
+
messages = response.json().get('messages', [])
|
|
609
|
+
|
|
610
|
+
email_details = []
|
|
611
|
+
for message in messages:
|
|
612
|
+
message_id = message['id']
|
|
613
|
+
message_url = f'https://gmail.googleapis.com/gmail/v1/users/me/messages/{message_id}'
|
|
614
|
+
message_response = await client.get(message_url, headers=headers)
|
|
615
|
+
message_response.raise_for_status()
|
|
616
|
+
message_data = message_response.json()
|
|
617
|
+
|
|
618
|
+
email_details.append({
|
|
619
|
+
"mailbox_email_id": message_data['id'],
|
|
620
|
+
"message_id": message_data['threadId'],
|
|
621
|
+
"email_subject": next((header['value'] for header in message_data['payload']['headers'] if header['name'] == 'Subject'), None),
|
|
622
|
+
"email_sender": next((header['value'] for header in message_data['payload']['headers'] if header['name'] == 'From'), None),
|
|
623
|
+
"email_recipients": [header['value'] for header in message_data['payload']['headers'] if header['name'] in ['To', 'Cc', 'Bcc']],
|
|
624
|
+
"email_date": next((header['value'] for header in message_data['payload']['headers'] if header['name'] == 'Date'), None),
|
|
625
|
+
"read_email_status": 'UNREAD' if 'UNREAD' in message_data['labelIds'] else 'READ',
|
|
626
|
+
"email_labels": message_data.get('labelIds', [])
|
|
627
|
+
})
|
|
628
|
+
|
|
629
|
+
return email_details
|
|
630
|
+
|
|
448
631
|
@assistant_tool
|
|
449
632
|
async def get_email_details_async(message_id: str, mailbox_email: str = "") -> Dict[str, Any]:
|
|
450
633
|
"""
|