Skip to content

Commit

Permalink
341 gads team should not randomly recommend locations which should be…
Browse files Browse the repository at this point in the history
… targeted (#346)

* Update python libraries versions

* Fix geo targeting endpoint

* Update prompts for geo targeting
  • Loading branch information
rjambrecic committed Feb 19, 2024
1 parent 3cd6b75 commit 2a0e2cf
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 18 deletions.
1 change: 1 addition & 0 deletions captn/__about__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
"""Captn backend client"""

__version__ = "0.0.1"
12 changes: 7 additions & 5 deletions captn/captn_agents/backend/google_ads_team.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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).
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -816,9 +820,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,
Expand Down
12 changes: 8 additions & 4 deletions google_ads/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -1237,22 +1237,26 @@ 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.",
)

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
)


Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
]
Expand Down
23 changes: 18 additions & 5 deletions tests/ci/test_google_ads_application.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
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


@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):
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() -> 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",
Expand All @@ -40,7 +51,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",
Expand Down

0 comments on commit 2a0e2cf

Please sign in to comment.