From 5151e69690d83d41b82d8ed465bd00ae4e1cf205 Mon Sep 17 00:00:00 2001 From: Robert Jambrecic Date: Mon, 19 Feb 2024 11:14:04 +0100 Subject: [PATCH 1/3] Update python libraries versions --- captn/__about__.py | 1 + captn/captn_agents/backend/google_ads_team.py | 4 +--- pyproject.toml | 8 ++++---- tests/ci/test_google_ads_application.py | 12 +++++++++--- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/captn/__about__.py b/captn/__about__.py index 63e4ba50..01a05ccb 100644 --- a/captn/__about__.py +++ b/captn/__about__.py @@ -1,2 +1,3 @@ """Captn backend client""" + __version__ = "0.0.1" diff --git a/captn/captn_agents/backend/google_ads_team.py b/captn/captn_agents/backend/google_ads_team.py index d6152816..22718f7a 100644 --- a/captn/captn_agents/backend/google_ads_team.py +++ b/captn/captn_agents/backend/google_ads_team.py @@ -816,9 +816,7 @@ def _string_to_list( return function_map -def _get_update_ad_copy( - user_id: int, conv_id: int -) -> Callable[ +def _get_update_ad_copy(user_id: int, conv_id: int) -> Callable[ [ str, str, diff --git a/pyproject.toml b/pyproject.toml index 9bc895d3..7f927f56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,11 +59,11 @@ lint = [ "types-docutils", "types-requests", "mypy==1.8.0", - "black==23.12.1", + "black==24.2.0", "isort>=5", "ruff==0.1.14", "pyupgrade-directories", - "bandit==1.7.6", + "bandit==1.7.7", "semgrep==1.52.0", "pre-commit==3.6.0", "detect-secrets==1.4.0", @@ -91,14 +91,14 @@ agents = [ "prisma==0.12.0", "google-ads==22.1.0", "httpx==0.26.0", - "uvicorn==0.26.0", + "uvicorn==0.27.1", "python-dotenv==1.0.0", #"pyautogen[websurfer] @ git+https://github.com/microsoft/autogen.git@19b5c85", "pyautogen[websurfer]==0.2.9", "pandas>=2.1", "fastcore==1.5.29", - "asyncer==0.0.2", + "asyncer==0.0.4", "pydantic==2.5.3", "markdownify==0.11.6", ] diff --git a/tests/ci/test_google_ads_application.py b/tests/ci/test_google_ads_application.py index adb38f15..31a44e00 100644 --- a/tests/ci/test_google_ads_application.py +++ b/tests/ci/test_google_ads_application.py @@ -8,7 +8,9 @@ @pytest.mark.asyncio -async def test_add_geo_targeting_to_campaign_raises_exception_if_location_names_and_location_ids_are_none() -> None: +async def test_add_geo_targeting_to_campaign_raises_exception_if_location_names_and_location_ids_are_none() -> ( + None +): geo_target = GeoTargetCriterion(customer_id="123", campaign_id="456") with pytest.raises(HTTPException): @@ -16,7 +18,9 @@ async def test_add_geo_targeting_to_campaign_raises_exception_if_location_names_ @pytest.mark.asyncio -async def test_add_geo_targeting_to_campaign_raises_exception_if_location_ids_are_none() -> None: +async def test_add_geo_targeting_to_campaign_raises_exception_if_location_ids_are_none() -> ( + None +): geo_target = GeoTargetCriterion( customer_id="123", campaign_id="456", @@ -40,7 +44,9 @@ async def test_add_geo_targeting_to_campaign_raises_exception_if_location_ids_ar @pytest.mark.asyncio -async def test_add_geo_targeting_to_campaign_raises_exception_if_location_ids_are_not_none() -> None: +async def test_add_geo_targeting_to_campaign_raises_exception_if_location_ids_are_not_none() -> ( + None +): geo_target = GeoTargetCriterion( customer_id="123", campaign_id="456", From f0269f833ab8644d8f59b59d5bf68e084d1eaf10 Mon Sep 17 00:00:00 2001 From: Robert Jambrecic Date: Mon, 19 Feb 2024 12:26:38 +0100 Subject: [PATCH 2/3] Fix geo targeting endpoint --- google_ads/application.py | 12 ++++++++---- tests/ci/test_google_ads_application.py | 11 +++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/google_ads/application.py b/google_ads/application.py index a4d2fe4d..a44ac440 100644 --- a/google_ads/application.py +++ b/google_ads/application.py @@ -1237,7 +1237,11 @@ def _create_locations_by_ids_to_campaign( async def create_geo_targeting_for_campaign( user_id: int, model: GeoTargetCriterion = Depends() ) -> str: - if model.location_names is None and model.location_ids is None: + location_names = ( + model.location_names if isinstance(model.location_names, list) else None + ) + location_ids = model.location_ids if isinstance(model.location_ids, list) else None + if location_names is None and location_ids is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Either location_names or location_ids must be provided.", @@ -1245,14 +1249,14 @@ async def create_geo_targeting_for_campaign( client = await _get_client(user_id=user_id) - if model.location_ids is None: - return _get_geo_target_constant_by_names(client=client, location_names=model.location_names) # type: ignore + if location_ids is None: + return _get_geo_target_constant_by_names(client=client, location_names=location_names) # type: ignore return _create_locations_by_ids_to_campaign( client=client, customer_id=model.customer_id, # type: ignore campaign_id=model.campaign_id, # type: ignore - location_ids=model.location_ids, # type: ignore + location_ids=location_ids, # type: ignore ) diff --git a/tests/ci/test_google_ads_application.py b/tests/ci/test_google_ads_application.py index 31a44e00..a082da9a 100644 --- a/tests/ci/test_google_ads_application.py +++ b/tests/ci/test_google_ads_application.py @@ -1,7 +1,7 @@ import unittest import pytest -from fastapi import HTTPException +from fastapi import HTTPException, status from google_ads.application import create_geo_targeting_for_campaign from google_ads.model import GeoTargetCriterion @@ -13,9 +13,16 @@ async def test_add_geo_targeting_to_campaign_raises_exception_if_location_names_ ): geo_target = GeoTargetCriterion(customer_id="123", campaign_id="456") - with pytest.raises(HTTPException): + with pytest.raises(HTTPException) as exc: await create_geo_targeting_for_campaign(user_id=-1, model=geo_target) + expected_exception = HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Either location_names or location_ids must be provided.", + ) + assert exc.value.status_code == expected_exception.status_code + assert exc.value.detail == expected_exception.detail + @pytest.mark.asyncio async def test_add_geo_targeting_to_campaign_raises_exception_if_location_ids_are_none() -> ( From 57084ce6015671ee655f66e22dd31849b1b19f4b Mon Sep 17 00:00:00 2001 From: Robert Jambrecic Date: Mon, 19 Feb 2024 12:27:06 +0100 Subject: [PATCH 3/3] Update prompts for geo targeting --- captn/captn_agents/backend/google_ads_team.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/captn/captn_agents/backend/google_ads_team.py b/captn/captn_agents/backend/google_ads_team.py index 22718f7a..65d3d4d7 100644 --- a/captn/captn_agents/backend/google_ads_team.py +++ b/captn/captn_agents/backend/google_ads_team.py @@ -281,7 +281,7 @@ def _guidelines(self) -> str: - create/update/remove headlines and descriptions in the Ad Copy. Make sure to follow the restrictions for the headlines and descriptions (MAXIMUM 30 characters for headlines and MAXIMUM 90 characters for descriptions) - create/update/remove new keywords - create/update/remove campaign/ ad group / ad / positive and negative keywords -- create/remove Geo Targeting for the campaign +- create/remove location (geo) Targeting for the campaign Do NOT suggest making changes of the following things: - Ad Extensions @@ -295,7 +295,10 @@ def _guidelines(self) -> str: Currently we are in a demo phase and clients need to see what we are CURRENTLY able to do. So you do NOT need to suggest optimal Google Ads solutions, just suggest making changes which we can do right away. -If you are asked to optimize campaigns, start with updating ad copy or creating/removing positive/negative keywords and geo targeting. +If you are asked to optimize campaigns, start with: +- updating ad copy +- creating/removing positive/negative keywords +- creating/removing location (geo) targeting. - Use 'get_info_from_the_web_page' command when the client provides you some url or for already existing ad copies (based on the final_url). This command can be very useful for figuring out the clients business and what he wants to achieve. Before asking the client for additional information, ask him for his company/product url and try to figure out as much as possible yourself (WITHOUT doing any permanent modifications). @@ -478,6 +481,7 @@ def _commands(self) -> str: campaign_id: string, clients_approval_message: string, client_approved_modicifation_for_this_resource: boolean, location_names: Optional[List[str]], location_ids: Optional[List[str]]) When the client provides the location names (country/city/region), use the 'location_names' parameter without the 'location_ids' parameter. By doing so, you will receive a list of avaliable locations and their IDs. +Do NOT improvise with the location names, use the names which the client provided! If you know the clients business location, you can ask him if he wants to target that location, but do NOT execute 'create_geo_targeting_for_campaign' without checking with the client first! Once the client approves the locations, you can use the 'location_ids' parameter to create the geo targeting for the campaign. Later, if you want to remove the geo targeting, you can use the following query to retrieve the criterion_id and geo_target_constant (location_id and name):