diff --git a/HubSpot/HubSpot_Chat_about_a_contact.ipynb b/HubSpot/HubSpot_Chat_about_a_contact.ipynb new file mode 100644 index 0000000000..006067a948 --- /dev/null +++ b/HubSpot/HubSpot_Chat_about_a_contact.ipynb @@ -0,0 +1,537 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "27486f01-77c3-4774-a098-29c706202d62", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "\"Naas\"" + ] + }, + { + "cell_type": "markdown", + "id": "85c6497e-923f-41fa-b85b-81f47a5ab9c7", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "# HubSpot - Chat about a contact\n", + "

Give Feedback | Bug report" + ] + }, + { + "cell_type": "markdown", + "id": "661f554e-7065-4101-81c2-9e799a812b67", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Tags:** #hubspot #contact #activity #notes #emails #communications #meetings #snippet" + ] + }, + { + "cell_type": "markdown", + "id": "a852a18f-e277-4aa5-bdec-8dd1fccb57d2", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Author:** [Florent Ravenel](https://www.linkedin.com/in/florent-ravenel)" + ] + }, + { + "cell_type": "markdown", + "id": "6dd7c05c-17ed-459f-88a8-3c6629b80cde", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Last update:** 2023-08-21 (Created: 2023-08-21)" + ] + }, + { + "cell_type": "markdown", + "id": "7dcfd269-589b-4199-b521-6884053ff935", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Description:** This notebook demonstrates how to retrieve all activities from a contact URL in HuSpot in use it in Naas Chat." + ] + }, + { + "cell_type": "markdown", + "id": "0da5ca2d-a6a1-424c-b41f-391428555503", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**References:**\n", + "- [HubSpot API - Contacts](https://developers.hubspot.com/docs/api/crm/contacts)\n", + "- [HubSpot API - Associations v4](https://developers.hubspot.com/docs/api/crm/associations)\n", + "- [HubSpot API - Communications](https://developers.hubspot.com/docs/api/crm/communications)" + ] + }, + { + "cell_type": "markdown", + "id": "8c6e5050-800a-4f05-a1d2-5a682c54e069", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Input" + ] + }, + { + "cell_type": "markdown", + "id": "6c27222b-7468-4daa-9a77-c446aaf66f72", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3fad6df-27f3-4e13-a934-083468860bf3", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "import requests\n", + "import naas\n", + "from naas_drivers import hubspot, naas_chat_plugin\n", + "import pandas as pd\n", + "pd.set_option('display.max_colwidth', None)" + ] + }, + { + "cell_type": "markdown", + "id": "17d095ea-e80c-4d8d-896b-271f3e0ea121", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Setup variables\n", + "**Mandatory**\n", + "\n", + "[Get your HubSpot Access token](https://knowledge.hubspot.com/articles/kcs_article/integrations/how-do-i-get-my-hubspot-api-key)\n", + "- `hs_access_token`: This variable stores an access token used for accessing the HubSpot API.\n", + "- `contact_url`: This variable stores the HubSpot contact URL.\n", + "\n", + "**Optional**\n", + "- `contact_properties`: It represents the list of properties to retrieve from your contact\n", + "- `associations`: It represents the list of associations to get from your contact\n", + "- `plugin_name`: It represents the name of the plugin." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13df3457-9ca4-4a77-ace7-2cd5a386362d", + "metadata": { + "papermill": {}, + "tags": [ + "parameters" + ] + }, + "outputs": [], + "source": [ + "# Mandatory\n", + "hs_access_token = naas.secret.get(\"HS_ACCESS_TOKEN\") or \"YOUR_HS_ACCESS_TOKEN\"\n", + "contact_url = \"https://app.hubspot.com/contacts/2474088/record/0-1/666001\" # \"https://app.hubspot.com/contacts/xxxxx/record/0-1/xxxxx\"\n", + "\n", + "# Optional\n", + "contact_properties = [\"hs_object_id\", \"firstname\", \"lastname\", 'email', 'linkedinbio', 'jobtitle']\n", + "associations = [\"notes\", \"emails\", \"meetings\", \"communications\"]\n", + "plugin_name = \"Sales Agent\"" + ] + }, + { + "cell_type": "markdown", + "id": "58f1d275-a026-45a5-8629-9b5f1f8b038f", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Model" + ] + }, + { + "cell_type": "markdown", + "id": "f0e82a5f-83c1-4d61-af17-a1e0ce040419", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "#### Engineer system prompt\n", + "We used Playground to refined it: https://platform.openai.com/playground?mode=chat&model=gpt-4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bd6583c-630d-4307-88f8-e68e2a5b04ef", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "system_prompt = f\"\"\"\n", + "Act as a Sales Agent expert in analyzing conversations and extracting action items.\n", + "\n", + "Please present the contact giving access to it with the URL and then review the text and identify any tasks, assignments, or actions that were agreed upon or mentioned as needing to be done.\n", + "These could be tasks assigned to specific individuals, or general actions that the group has decided to take.\n", + "Please list these action items clearly and concisely.\n", + "\n", + "Data: [ACTIVITIES]\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "f6ef36c3-13ab-45e5-97fb-3ba6e4c2ff99", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Get contact ID from URL" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3588e3a-0829-485a-81c5-bcde7f137549", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_contact_ID_from_URL(url):\n", + " # Init\n", + " uid = url\n", + " \n", + " # Check if URL is valid\n", + " if not url.startswith(\"https://app.hubspot.com/contacts/\"):\n", + " raise BaseException(\"HubSpot URL Invalid! It must start by https://app.hubspot.com/contacts/\")\n", + " \n", + " # Split URL to get ID\n", + " if \"/record/0-1/\" in url:\n", + " uid = url.split(\"/record/0-1/\")[-1].split(\"/\")[0]\n", + " return uid\n", + "\n", + "contact_id = get_contact_ID_from_URL(contact_url)\n", + "print(\"Contact ID:\", contact_id)" + ] + }, + { + "cell_type": "markdown", + "id": "dd600b6a-2298-421e-80d7-1d101e1aecb4", + "metadata": {}, + "source": [ + "### Get contact details" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c5c7fdf-be1e-4b0c-8cc2-705b460d00f3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def retrieve_object_details(\n", + " token,\n", + " object_id,\n", + " object_type,\n", + " properties=None,\n", + "):\n", + " # Init\n", + " data = []\n", + " params = {\n", + " \"archived\": \"false\"\n", + " }\n", + " \n", + " # Requests\n", + " if properties:\n", + " params[\"properties\"] = properties\n", + " headers = {\n", + " \"Content-Type\": \"application/json\",\n", + " \"Authorization\": f\"Bearer {token}\"\n", + " }\n", + " url = f\"https://api.hubapi.com/crm/v3/objects/{object_type}/{object_id}\"\n", + " \n", + " # Response\n", + " res = requests.get(url, headers=headers, params=params)\n", + " if res.status_code == 200:\n", + " data = res.json().get(\"properties\")\n", + " else:\n", + " print(res.text)\n", + " return pd.DataFrame([data])\n", + "\n", + "def create_activity_df(\n", + " token,\n", + " object_id,\n", + " activity,\n", + " properties_dict=None,\n", + "):\n", + " # Init\n", + " properties = [x for x in properties_dict]\n", + " \n", + " # List activities\n", + " df = retrieve_object_details(\n", + " token,\n", + " object_id,\n", + " activity,\n", + " properties\n", + " )\n", + " if len(df) > 0:\n", + " df = df[properties]\n", + " \n", + " if len(df) > 0:\n", + " df = df.rename(columns=properties_dict)\n", + " if 'activity_type' not in df:\n", + " df.insert(loc=1, column=\"activity_type\", value=activity.upper())\n", + " \n", + " return df.reset_index(drop=True)\n", + "\n", + "def get_contact_details(\n", + " hs_access_token,\n", + " contact_id,\n", + " properties,\n", + " associations\n", + "):\n", + " # Init\n", + " message = \"CONTACT:\\n\"\n", + " df = pd.DataFrame()\n", + " \n", + " # Get contact\n", + " contact = hubspot.connect(hs_access_token).contacts.get(\n", + " contact_id,\n", + " hs_properties=properties,\n", + " hs_associations=associations\n", + " )\n", + " \n", + " # Get contact properties\n", + " contact_properties = contact.get(\"properties\")\n", + " for p in properties:\n", + " message = f\"{message}- {p}: {contact_properties.get(p)}\\n\"\n", + " \n", + " # Get contact associations\n", + " contact_associations = contact.get(\"associations\")\n", + " for a in contact_associations:\n", + " results = contact_associations.get(a).get(\"results\")\n", + " for r in results:\n", + " if a == \"communications\":\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_communication_channel_type\": \"activity_type\",\n", + " \"hs_body_preview\": \"activity_content\"\n", + " }\n", + " elif a == \"meetings\":\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_meeting_title\": \"activity_content\"\n", + " }\n", + " else:\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_body_preview\": \"activity_content\"\n", + " }\n", + " association_id = r.get(\"id\")\n", + " \n", + " # Create activity df\n", + " tmp_df = create_activity_df(\n", + " hs_access_token,\n", + " association_id,\n", + " a,\n", + " properties_dict\n", + " )\n", + " df = pd.concat([df, tmp_df])\n", + " \n", + " # Cleaning df\n", + " if len(df) > 0:\n", + " # Exclude empty or None value\n", + " df = df[~(df[\"activity_content\"].astype(str).isin([\"None\"]))]\n", + "\n", + " # Format date\n", + " df[\"activity_date\"] = pd.to_datetime(df[\"activity_date\"]).dt.strftime(\"%Y-%m-%d %H:%M:%S\")\n", + " df = df.sort_values(by=\"activity_date\", ascending=False).reset_index(drop=True)\n", + " \n", + " # Create activity message\n", + " message = f\"{message}\\nACTIVITIES:\\n\"\n", + " for row in df.itertuples():\n", + " activity_date = row.activity_date\n", + " activity_type = row.activity_type\n", + " activity_content = row.activity_content.replace(\"\\xa0\\u200c\", \"\")\n", + " message = f\"{message}-{activity_date}: {activity_type} - {activity_content}\\n\"\n", + " return message, df.reset_index(drop=True)\n", + "\n", + "prompt_message, df_activity = get_contact_details(\n", + " hs_access_token,\n", + " contact_id,\n", + " contact_properties,\n", + " associations\n", + ")\n", + "print(prompt_message)" + ] + }, + { + "cell_type": "markdown", + "id": "6e9729cd-8e75-4c13-a06c-87afb9923e53", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Output" + ] + }, + { + "cell_type": "markdown", + "id": "f09fcd0a-5b7f-4a96-9822-f4a6995a6ac0", + "metadata": { + "execution": { + "iopub.execute_input": "2023-08-21T14:13:58.779716Z", + "iopub.status.busy": "2023-08-21T14:13:58.779474Z", + "iopub.status.idle": "2023-08-21T14:13:58.784746Z", + "shell.execute_reply": "2023-08-21T14:13:58.784135Z", + "shell.execute_reply.started": "2023-08-21T14:13:58.779693Z" + }, + "papermill": {}, + "tags": [] + }, + "source": [ + "### Save DataFrame to CSV" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62e3f7af-5383-45fc-b5ec-31796a179f34", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "df_activity.to_csv(f\"contact_activity_{contact_id}.csv\", index=False)" + ] + }, + { + "cell_type": "markdown", + "id": "57da8bd3-11fa-463d-b93e-ab67b7842e2c", + "metadata": {}, + "source": [ + "### Generate plugin" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b14ce0e-c458-49cd-ae47-8c5fadcc1f3b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# System prompt\n", + "system_prompt = system_prompt.replace(\"[ACTIVITIES]\", prompt_message)\n", + "\n", + "# Plugin file path\n", + "plugin_file_path = naas_chat_plugin.create_plugin(\n", + " plugin_name,\n", + " system_prompt,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fce5b5d8-e68d-4eba-bcab-63724e2b2795", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Create asset\n", + "You can now use in your Naas Chat by copy/pasting the URL after the command `/use `" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "399ad4c9-153f-42b6-8a24-3cddd4d29a6e", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "naas.asset.add(plugin_file_path, params={\"inline\": True})" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.6" + }, + "naas": { + "notebook_id": "06b11cf336c1e0d493eb89898cd3a39adcb000113e2f74b4d12d64c5e7f04932", + "notebook_path": "HubSpot/HubSpot_Get_activities_from_contact.ipynb" + }, + "papermill": { + "default_parameters": {}, + "environment_variables": {}, + "parameters": {}, + "version": "2.4.0" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/HubSpot/HubSpot_Get_contact_brief.ipynb b/HubSpot/HubSpot_Get_contact_brief.ipynb new file mode 100644 index 0000000000..cae2fb2a87 --- /dev/null +++ b/HubSpot/HubSpot_Get_contact_brief.ipynb @@ -0,0 +1,474 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "27486f01-77c3-4774-a098-29c706202d62", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "\"Naas\"" + ] + }, + { + "cell_type": "markdown", + "id": "85c6497e-923f-41fa-b85b-81f47a5ab9c7", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "# HubSpot - Get contact brief\n", + "

Give Feedback | Bug report" + ] + }, + { + "cell_type": "markdown", + "id": "661f554e-7065-4101-81c2-9e799a812b67", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Tags:** #hubspot #contact #activity #notes #emails #communications #meetings #snippet" + ] + }, + { + "cell_type": "markdown", + "id": "a852a18f-e277-4aa5-bdec-8dd1fccb57d2", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Author:** [Florent Ravenel](https://www.linkedin.com/in/florent-ravenel)" + ] + }, + { + "cell_type": "markdown", + "id": "6dd7c05c-17ed-459f-88a8-3c6629b80cde", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Last update:** 2023-09-22 (Created: 2023-09-22)" + ] + }, + { + "cell_type": "markdown", + "id": "7dcfd269-589b-4199-b521-6884053ff935", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Description:** This notebook illustrates the process of obtaining a contact brief in HubSpot. It fetches detailed contact information, along with all related activities between you and your sales team. These activities may include emails, notes, meetings, and communications via LinkedIn, WhatsApp, and SMS. The output is conveniently delivered as a text file." + ] + }, + { + "cell_type": "markdown", + "id": "0da5ca2d-a6a1-424c-b41f-391428555503", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**References:**\n", + "- [HubSpot API - Contacts](https://developers.hubspot.com/docs/api/crm/contacts)\n", + "- [HubSpot API - Associations v4](https://developers.hubspot.com/docs/api/crm/associations)\n", + "- [HubSpot API - Communications](https://developers.hubspot.com/docs/api/crm/communications)" + ] + }, + { + "cell_type": "markdown", + "id": "8c6e5050-800a-4f05-a1d2-5a682c54e069", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Input" + ] + }, + { + "cell_type": "markdown", + "id": "6c27222b-7468-4daa-9a77-c446aaf66f72", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3fad6df-27f3-4e13-a934-083468860bf3", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "import requests\n", + "import naas\n", + "from naas_drivers import hubspot, naas_chat_plugin\n", + "import pandas as pd\n", + "import os\n", + "pd.set_option('display.max_colwidth', None)" + ] + }, + { + "cell_type": "markdown", + "id": "17d095ea-e80c-4d8d-896b-271f3e0ea121", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Setup variables\n", + "**Mandatory**\n", + "\n", + "[Get your HubSpot Access token](https://knowledge.hubspot.com/articles/kcs_article/integrations/how-do-i-get-my-hubspot-api-key)\n", + "- `hs_access_token`: This variable stores an access token used for accessing the HubSpot API.\n", + "- `contact_url`: This variable stores the HubSpot contact URL.\n", + "\n", + "**Optional**\n", + "- `contact_properties`: It represents the list of properties to retrieve from your contact\n", + "- `associations`: It represents the list of associations to get from your contact\n", + "- `output_dir`: This parameter specifies the directory path where the output text file will be stored." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13df3457-9ca4-4a77-ace7-2cd5a386362d", + "metadata": { + "papermill": {}, + "tags": [ + "parameters" + ] + }, + "outputs": [], + "source": [ + "# Mandatory\n", + "hs_access_token = naas.secret.get(\"HS_ACCESS_TOKEN\") or \"YOUR_HS_ACCESS_TOKEN\"\n", + "contact_url = \"https://app.hubspot.com/contacts/2474088/record/0-1/666001\" # \"https://app.hubspot.com/contacts/xxxxx/record/0-1/xxxxx\"\n", + "\n", + "# Optional\n", + "contact_properties = [\"hs_object_id\", \"firstname\", \"lastname\", 'email', 'linkedinbio', 'jobtitle']\n", + "associations = [\"notes\", \"emails\", \"meetings\", \"communications\"]\n", + "output_dir = \"hubspot\"" + ] + }, + { + "cell_type": "markdown", + "id": "58f1d275-a026-45a5-8629-9b5f1f8b038f", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Model" + ] + }, + { + "cell_type": "markdown", + "id": "f6ef36c3-13ab-45e5-97fb-3ba6e4c2ff99", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Get contact ID from URL" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3588e3a-0829-485a-81c5-bcde7f137549", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_contact_ID_from_URL(url):\n", + " # Init\n", + " uid = url\n", + " \n", + " # Check if URL is valid\n", + " if not url.startswith(\"https://app.hubspot.com/contacts/\"):\n", + " raise BaseException(\"HubSpot URL Invalid! It must start by https://app.hubspot.com/contacts/\")\n", + " \n", + " # Split URL to get ID\n", + " if \"/record/0-1/\" in url:\n", + " uid = url.split(\"/record/0-1/\")[-1].split(\"/\")[0]\n", + " return uid\n", + "\n", + "contact_id = get_contact_ID_from_URL(contact_url)\n", + "print(\"Contact ID:\", contact_id)" + ] + }, + { + "cell_type": "markdown", + "id": "dd600b6a-2298-421e-80d7-1d101e1aecb4", + "metadata": {}, + "source": [ + "### Get contact details" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c5c7fdf-be1e-4b0c-8cc2-705b460d00f3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def retrieve_object_details(\n", + " token,\n", + " object_id,\n", + " object_type,\n", + " properties=None,\n", + "):\n", + " # Init\n", + " data = []\n", + " params = {\n", + " \"archived\": \"false\"\n", + " }\n", + " \n", + " # Requests\n", + " if properties:\n", + " params[\"properties\"] = properties\n", + " headers = {\n", + " \"Content-Type\": \"application/json\",\n", + " \"Authorization\": f\"Bearer {token}\"\n", + " }\n", + " url = f\"https://api.hubapi.com/crm/v3/objects/{object_type}/{object_id}\"\n", + " \n", + " # Response\n", + " res = requests.get(url, headers=headers, params=params)\n", + " if res.status_code == 200:\n", + " data = res.json().get(\"properties\")\n", + " else:\n", + " print(res.text)\n", + " return pd.DataFrame([data])\n", + "\n", + "def create_activity_df(\n", + " token,\n", + " object_id,\n", + " activity,\n", + " properties_dict=None,\n", + "):\n", + " # Init\n", + " properties = [x for x in properties_dict]\n", + " \n", + " # List activities\n", + " df = retrieve_object_details(\n", + " token,\n", + " object_id,\n", + " activity,\n", + " properties\n", + " )\n", + " if len(df) > 0:\n", + " df = df[properties]\n", + " \n", + " if len(df) > 0:\n", + " df = df.rename(columns=properties_dict)\n", + " if 'activity_type' not in df:\n", + " df.insert(loc=1, column=\"activity_type\", value=activity.upper())\n", + " \n", + " return df.reset_index(drop=True)\n", + "\n", + "def get_contact_details(\n", + " hs_access_token,\n", + " contact_id,\n", + " properties,\n", + " associations\n", + "):\n", + " # Init\n", + " message = \"CONTACT:\\n\"\n", + " df = pd.DataFrame()\n", + " \n", + " # Get contact\n", + " contact = hubspot.connect(hs_access_token).contacts.get(\n", + " contact_id,\n", + " hs_properties=properties,\n", + " hs_associations=associations\n", + " )\n", + " \n", + " # Get contact properties\n", + " contact_properties = contact.get(\"properties\")\n", + " for p in properties:\n", + " message = f\"{message}- {p}: {contact_properties.get(p)}\\n\"\n", + " \n", + " # Get contact associations\n", + " contact_associations = contact.get(\"associations\")\n", + " for a in contact_associations:\n", + " results = contact_associations.get(a).get(\"results\")\n", + " for r in results:\n", + " if a == \"communications\":\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_communication_channel_type\": \"activity_type\",\n", + " \"hs_body_preview\": \"activity_content\"\n", + " }\n", + " elif a == \"meetings\":\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_meeting_title\": \"activity_content\"\n", + " }\n", + " else:\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_body_preview\": \"activity_content\"\n", + " }\n", + " association_id = r.get(\"id\")\n", + " \n", + " # Create activity df\n", + " tmp_df = create_activity_df(\n", + " hs_access_token,\n", + " association_id,\n", + " a,\n", + " properties_dict\n", + " )\n", + " df = pd.concat([df, tmp_df])\n", + " \n", + " # Cleaning df\n", + " if len(df) > 0:\n", + " # Exclude empty or None value\n", + " df = df[~(df[\"activity_content\"].astype(str).isin([\"None\"]))]\n", + "\n", + " # Format date\n", + " df[\"activity_date\"] = pd.to_datetime(df[\"activity_date\"]).dt.strftime(\"%Y-%m-%d %H:%M:%S\")\n", + " df = df.sort_values(by=\"activity_date\", ascending=False).reset_index(drop=True)\n", + " \n", + " # Create activity message\n", + " message = f\"{message}\\nACTIVITIES:\\n\"\n", + " for row in df.itertuples():\n", + " activity_date = row.activity_date\n", + " activity_type = row.activity_type\n", + " activity_content = row.activity_content.replace(\"\\xa0\\u200c\", \"\")\n", + " message = f\"{message}-{activity_date}: {activity_type} - {activity_content}\\n\"\n", + " return message, df.reset_index(drop=True)\n", + "\n", + "brief, df_activity = get_contact_details(\n", + " hs_access_token,\n", + " contact_id,\n", + " contact_properties,\n", + " associations\n", + ")\n", + "print(brief)" + ] + }, + { + "cell_type": "markdown", + "id": "6e9729cd-8e75-4c13-a06c-87afb9923e53", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Output" + ] + }, + { + "cell_type": "markdown", + "id": "f09fcd0a-5b7f-4a96-9822-f4a6995a6ac0", + "metadata": { + "execution": { + "iopub.execute_input": "2023-08-21T14:13:58.779716Z", + "iopub.status.busy": "2023-08-21T14:13:58.779474Z", + "iopub.status.idle": "2023-08-21T14:13:58.784746Z", + "shell.execute_reply": "2023-08-21T14:13:58.784135Z", + "shell.execute_reply.started": "2023-08-21T14:13:58.779693Z" + }, + "papermill": {}, + "tags": [] + }, + "source": [ + "### Save data to txt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62e3f7af-5383-45fc-b5ec-31796a179f34", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "def save_txt(output_dir, contact_id, txt):\n", + " # Create dirs\n", + " os.makedirs(output_dir, exist_ok=True)\n", + " \n", + " # Create path\n", + " file_path = os.path.join(output_dir, f\"{contact_id}_contact_brief.txt\")\n", + " \n", + " # Save file\n", + " file = open(file_path, 'w') # Open the file in write mode ('w')\n", + " file.write(txt) # Write the text to the file\n", + " file.close() # Always remember to close the file\n", + " print(f\"File successfully saved: {file_path}\")\n", + " \n", + "save_txt(output_dir, contact_id, brief)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf3f5ec4-9c47-40e0-be8a-9bfd17cf4dea", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.6" + }, + "naas": { + "notebook_id": "06b11cf336c1e0d493eb89898cd3a39adcb000113e2f74b4d12d64c5e7f04932", + "notebook_path": "HubSpot/HubSpot_Get_activities_from_contact.ipynb" + }, + "papermill": { + "default_parameters": {}, + "environment_variables": {}, + "parameters": {}, + "version": "2.4.0" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/HubSpot/HubSpot_Get_deal_brief.ipynb b/HubSpot/HubSpot_Get_deal_brief.ipynb new file mode 100644 index 0000000000..34939bcb76 --- /dev/null +++ b/HubSpot/HubSpot_Get_deal_brief.ipynb @@ -0,0 +1,466 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "27486f01-77c3-4774-a098-29c706202d62", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "\"Naas\"" + ] + }, + { + "cell_type": "markdown", + "id": "85c6497e-923f-41fa-b85b-81f47a5ab9c7", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "# HubSpot - Get deal brief\n", + "

Give Feedback | Bug report" + ] + }, + { + "cell_type": "markdown", + "id": "661f554e-7065-4101-81c2-9e799a812b67", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Tags:** #hubspot #deal #activity #notes #emails #communications #meetings #snippet" + ] + }, + { + "cell_type": "markdown", + "id": "a852a18f-e277-4aa5-bdec-8dd1fccb57d2", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Author:** [Florent Ravenel](https://www.linkedin.com/in/florent-ravenel)" + ] + }, + { + "cell_type": "markdown", + "id": "6dd7c05c-17ed-459f-88a8-3c6629b80cde", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Last update:** 2023-09-22 (Created: 2023-09-22)" + ] + }, + { + "cell_type": "markdown", + "id": "7dcfd269-589b-4199-b521-6884053ff935", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**Description:** This notebook illustrates the process of obtaining a deal brief in HubSpot. It fetches detailed detail information, along with all related activities between you and your sales team. These activities may include emails, notes, meetings, and communications via LinkedIn, WhatsApp, and SMS. The output is conveniently delivered as a text file." + ] + }, + { + "cell_type": "markdown", + "id": "0da5ca2d-a6a1-424c-b41f-391428555503", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "**References:**\n", + "- [HubSpot API - Deals](https://developers.hubspot.com/docs/api/crm/deals)\n", + "- [HubSpot API - Associations v4](https://developers.hubspot.com/docs/api/crm/associations)\n", + "- [HubSpot API - Communications](https://developers.hubspot.com/docs/api/crm/communications)" + ] + }, + { + "cell_type": "markdown", + "id": "8c6e5050-800a-4f05-a1d2-5a682c54e069", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Input" + ] + }, + { + "cell_type": "markdown", + "id": "6c27222b-7468-4daa-9a77-c446aaf66f72", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3fad6df-27f3-4e13-a934-083468860bf3", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "import requests\n", + "import naas\n", + "from naas_drivers import hubspot, naas_chat_plugin\n", + "import pandas as pd\n", + "import os\n", + "pd.set_option('display.max_colwidth', None)" + ] + }, + { + "cell_type": "markdown", + "id": "17d095ea-e80c-4d8d-896b-271f3e0ea121", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Setup variables\n", + "**Mandatory**\n", + "\n", + "[Get your HubSpot Access token](https://knowledge.hubspot.com/articles/kcs_article/integrations/how-do-i-get-my-hubspot-api-key)\n", + "- `hs_access_token`: This variable stores an access token used for accessing the HubSpot API.\n", + "- `deal_url`: This variable stores the HubSpot deal URL.\n", + "\n", + "**Optional**\n", + "- `deal_properties`: It represents the list of properties to retrieve from your deal\n", + "- `associations`: It represents the list of associations to get from your deal\n", + "- `output_dir`: This parameter specifies the directory path where the output text file will be stored." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13df3457-9ca4-4a77-ace7-2cd5a386362d", + "metadata": { + "papermill": {}, + "tags": [ + "parameters" + ] + }, + "outputs": [], + "source": [ + "# Mandatory\n", + "hs_access_token = naas.secret.get(\"HS_ACCESS_TOKEN\") or \"YOUR_HS_ACCESS_TOKEN\"\n", + "deal_url = \"https://app.hubspot.com/contacts/2474088/record/0-3/15220482319/\" # \"https://app.hubspot.com/contacts/xxxxx/record/0-1/xxxxx\"\n", + "\n", + "# Optional\n", + "deal_properties = [\"hs_object_id\", \"dealname\", \"dealstage\", 'amount']\n", + "associations = [\"notes\", \"emails\", \"meetings\", \"communications\"]\n", + "output_dir = \"hubspot\"" + ] + }, + { + "cell_type": "markdown", + "id": "58f1d275-a026-45a5-8629-9b5f1f8b038f", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Model" + ] + }, + { + "cell_type": "markdown", + "id": "f6ef36c3-13ab-45e5-97fb-3ba6e4c2ff99", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Get deal ID from URL" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3588e3a-0829-485a-81c5-bcde7f137549", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_contact_ID_from_URL(url):\n", + " # Init\n", + " uid = url\n", + " \n", + " # Check if URL is valid\n", + " if not url.startswith(\"https://app.hubspot.com/contacts/\"):\n", + " raise BaseException(\"HubSpot URL Invalid! It must start by https://app.hubspot.com/contacts/\")\n", + " \n", + " # Split URL to get ID\n", + " if \"/record/0-3/\" in url:\n", + " uid = url.split(\"/record/0-3/\")[-1].split(\"/\")[0]\n", + " return uid\n", + "\n", + "deal_id = get_contact_ID_from_URL(deal_url)\n", + "print(\"Deal ID:\", deal_id)" + ] + }, + { + "cell_type": "markdown", + "id": "dd600b6a-2298-421e-80d7-1d101e1aecb4", + "metadata": {}, + "source": [ + "### Get contact details" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c5c7fdf-be1e-4b0c-8cc2-705b460d00f3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def retrieve_object_details(\n", + " token,\n", + " object_id,\n", + " object_type,\n", + " properties=None,\n", + "):\n", + " # Init\n", + " data = []\n", + " params = {\n", + " \"archived\": \"false\"\n", + " }\n", + " \n", + " # Requests\n", + " if properties:\n", + " params[\"properties\"] = properties\n", + " headers = {\n", + " \"Content-Type\": \"application/json\",\n", + " \"Authorization\": f\"Bearer {token}\"\n", + " }\n", + " url = f\"https://api.hubapi.com/crm/v3/objects/{object_type}/{object_id}\"\n", + " \n", + " # Response\n", + " res = requests.get(url, headers=headers, params=params)\n", + " if res.status_code == 200:\n", + " data = res.json().get(\"properties\")\n", + " else:\n", + " print(res.text)\n", + " return pd.DataFrame([data])\n", + "\n", + "def create_activity_df(\n", + " token,\n", + " object_id,\n", + " activity,\n", + " properties_dict=None,\n", + "):\n", + " # Init\n", + " properties = [x for x in properties_dict]\n", + " \n", + " # List activities\n", + " df = retrieve_object_details(\n", + " token,\n", + " object_id,\n", + " activity,\n", + " properties\n", + " )\n", + " if len(df) > 0:\n", + " df = df[properties]\n", + " \n", + " if len(df) > 0:\n", + " df = df.rename(columns=properties_dict)\n", + " if 'activity_type' not in df:\n", + " df.insert(loc=1, column=\"activity_type\", value=activity.upper())\n", + " \n", + " return df.reset_index(drop=True)\n", + "\n", + "def get_details(\n", + " hs_access_token,\n", + " hubspot_id,\n", + " properties,\n", + " associations\n", + "):\n", + " # Init\n", + " message = \"DEAL:\\n\"\n", + " df = pd.DataFrame()\n", + " \n", + " # Get object\n", + " obj = hubspot.connect(hs_access_token).deals.get(\n", + " hubspot_id,\n", + " hs_properties=properties,\n", + " hs_associations=associations\n", + " )\n", + " \n", + " # Get properties\n", + " obj_properties = obj.get(\"properties\")\n", + " for p in properties:\n", + " message = f\"{message}- {p}: {obj_properties.get(p)}\\n\"\n", + " \n", + " # Get contact associations\n", + " obj_associations = obj.get(\"associations\")\n", + " for a in obj_associations:\n", + " results = obj_associations.get(a).get(\"results\")\n", + " for r in results:\n", + " if a == \"communications\":\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_communication_channel_type\": \"activity_type\",\n", + " \"hs_body_preview\": \"activity_content\"\n", + " }\n", + " elif a == \"meetings\":\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_meeting_title\": \"activity_content\"\n", + " }\n", + " else:\n", + " properties_dict = {\n", + " \"hs_object_id\": \"activity_hs_id\",\n", + " \"hs_timestamp\": \"activity_date\",\n", + " \"hs_body_preview\": \"activity_content\"\n", + " }\n", + " association_id = r.get(\"id\")\n", + " \n", + " # Create activity df\n", + " tmp_df = create_activity_df(\n", + " hs_access_token,\n", + " association_id,\n", + " a,\n", + " properties_dict\n", + " )\n", + " df = pd.concat([df, tmp_df])\n", + " \n", + " # Cleaning df\n", + " if len(df) > 0:\n", + " # Exclude empty or None value\n", + " df = df[~(df[\"activity_content\"].astype(str).isin([\"None\"]))]\n", + "\n", + " # Format date\n", + " df[\"activity_date\"] = pd.to_datetime(df[\"activity_date\"]).dt.strftime(\"%Y-%m-%d %H:%M:%S\")\n", + " df = df.sort_values(by=\"activity_date\", ascending=False).reset_index(drop=True)\n", + " \n", + " # Create activity message\n", + " message = f\"{message}\\nACTIVITIES:\\n\"\n", + " for row in df.itertuples():\n", + " activity_date = row.activity_date\n", + " activity_type = row.activity_type\n", + " activity_content = row.activity_content.replace(\"\\xa0\\u200c\", \"\")\n", + " message = f\"{message}-{activity_date}: {activity_type} - {activity_content}\\n\"\n", + " return message, df.reset_index(drop=True)\n", + "\n", + "brief, df_activity = get_details(\n", + " hs_access_token,\n", + " deal_id,\n", + " deal_properties,\n", + " associations\n", + ")\n", + "print(brief)" + ] + }, + { + "cell_type": "markdown", + "id": "6e9729cd-8e75-4c13-a06c-87afb9923e53", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "## Output" + ] + }, + { + "cell_type": "markdown", + "id": "f09fcd0a-5b7f-4a96-9822-f4a6995a6ac0", + "metadata": { + "execution": { + "iopub.execute_input": "2023-08-21T14:13:58.779716Z", + "iopub.status.busy": "2023-08-21T14:13:58.779474Z", + "iopub.status.idle": "2023-08-21T14:13:58.784746Z", + "shell.execute_reply": "2023-08-21T14:13:58.784135Z", + "shell.execute_reply.started": "2023-08-21T14:13:58.779693Z" + }, + "papermill": {}, + "tags": [] + }, + "source": [ + "### Save data to txt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62e3f7af-5383-45fc-b5ec-31796a179f34", + "metadata": { + "papermill": {}, + "tags": [] + }, + "outputs": [], + "source": [ + "def save_txt(output_dir, contact_id, txt):\n", + " # Create dirs\n", + " os.makedirs(output_dir, exist_ok=True)\n", + " \n", + " # Create path\n", + " file_path = os.path.join(output_dir, f\"{contact_id}_deal_brief.txt\")\n", + " \n", + " # Save file\n", + " file = open(file_path, 'w') # Open the file in write mode ('w')\n", + " file.write(txt) # Write the text to the file\n", + " file.close() # Always remember to close the file\n", + " print(f\"File successfully saved: {file_path}\")\n", + " \n", + "save_txt(output_dir, contact_id, brief)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.6" + }, + "naas": { + "notebook_id": "06b11cf336c1e0d493eb89898cd3a39adcb000113e2f74b4d12d64c5e7f04932", + "notebook_path": "HubSpot/HubSpot_Get_activities_from_contact.ipynb" + }, + "papermill": { + "default_parameters": {}, + "environment_variables": {}, + "parameters": {}, + "version": "2.4.0" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}