interloper-assets 0.2.0__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.
- interloper_assets-0.2.0/PKG-INFO +23 -0
- interloper_assets-0.2.0/README.md +3 -0
- interloper_assets-0.2.0/pyproject.toml +53 -0
- interloper_assets-0.2.0/src/interloper_assets/__init__.py +85 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/schemas/__init__.py +15 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/schemas/campaigns.py +60 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/schemas/campaigns_by_browser.py +22 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/schemas/campaigns_by_city.py +24 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/schemas/campaigns_by_device_type.py +23 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/schemas/conversions.py +50 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/schemas/conversions_by_time_of_day.py +15 -0
- interloper_assets-0.2.0/src/interloper_assets/adservice/source.py +148 -0
- interloper_assets-0.2.0/src/interloper_assets/adup/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/adup/constants.py +148 -0
- interloper_assets-0.2.0/src/interloper_assets/adup/schemas/__init__.py +7 -0
- interloper_assets-0.2.0/src/interloper_assets/adup/schemas/account.py +14 -0
- interloper_assets-0.2.0/src/interloper_assets/adup/schemas/ads.py +42 -0
- interloper_assets-0.2.0/src/interloper_assets/adup/source.py +71 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/constants.py +981 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/__init__.py +45 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/brands_ad_groups.py +93 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/brands_ads.py +94 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/brands_campaigns.py +86 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/brands_gross_and_invalid_traffic.py +24 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/brands_placements.py +78 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/brands_purchased_products.py +44 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/brands_search_terms.py +54 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/brands_targeting.py +79 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/display_ad_groups.py +58 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/display_advertised_products.py +78 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/display_campaigns.py +73 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/display_gross_and_invalid_traffic.py +24 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/display_purchased_products.py +31 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/display_targeting.py +79 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/products_advertised_products.py +80 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/products_campaigns.py +77 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/products_gross_and_invalid_traffic.py +24 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/products_purchased_products.py +80 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/products_search_terms.py +80 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/products_targeting.py +79 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/schemas/profiles.py +14 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_ads/source.py +679 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_selling_partner/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/amazon_selling_partner/source.py +67 -0
- interloper_assets-0.2.0/src/interloper_assets/awin/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/awin/source.py +27 -0
- interloper_assets-0.2.0/src/interloper_assets/bing_ads/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/bing_ads/source.py +11 -0
- interloper_assets-0.2.0/src/interloper_assets/campaign_manager_360/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/campaign_manager_360/source.py +29 -0
- interloper_assets-0.2.0/src/interloper_assets/campaign_performance_analysis/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/campaign_performance_analysis/source.py +36 -0
- interloper_assets-0.2.0/src/interloper_assets/criteo/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/criteo/source.py +21 -0
- interloper_assets-0.2.0/src/interloper_assets/demo/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/demo/source.py +119 -0
- interloper_assets-0.2.0/src/interloper_assets/display_video_360/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/display_video_360/source.py +19 -0
- interloper_assets-0.2.0/src/interloper_assets/facebook_ads/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/facebook_ads/source.py +33 -0
- interloper_assets-0.2.0/src/interloper_assets/facebook_insights/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/facebook_insights/source.py +13 -0
- interloper_assets-0.2.0/src/interloper_assets/instagram_insights/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/instagram_insights/source.py +47 -0
- interloper_assets-0.2.0/src/interloper_assets/linkedin_ads/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/linkedin_ads/source.py +6 -0
- interloper_assets-0.2.0/src/interloper_assets/linkedin_organic/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/linkedin_organic/source.py +29 -0
- interloper_assets-0.2.0/src/interloper_assets/pinterest_ads/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/pinterest_ads/source.py +21 -0
- interloper_assets-0.2.0/src/interloper_assets/search_ads_360/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/search_ads_360/source.py +37 -0
- interloper_assets-0.2.0/src/interloper_assets/search_console/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/search_console/source.py +39 -0
- interloper_assets-0.2.0/src/interloper_assets/snapchat_ads/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/snapchat_ads/source.py +31 -0
- interloper_assets-0.2.0/src/interloper_assets/teads/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/teads/source.py +11 -0
- interloper_assets-0.2.0/src/interloper_assets/thetradedesk/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/thetradedesk/source.py +6 -0
- interloper_assets-0.2.0/src/interloper_assets/tiktok_ads/__init__.py +0 -0
- interloper_assets-0.2.0/src/interloper_assets/tiktok_ads/source.py +37 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: interloper-assets
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Interloper Assets
|
|
5
|
+
Author: Guillaume Onfroy
|
|
6
|
+
Author-email: Guillaume Onfroy <guillaume@digitlcloud.com>
|
|
7
|
+
Requires-Dist: interloper-core
|
|
8
|
+
Requires-Dist: interloper-pandas
|
|
9
|
+
Requires-Dist: httpx>=0.28.1
|
|
10
|
+
Requires-Dist: pandas>=2.3.3
|
|
11
|
+
Requires-Dist: tenacity>=9.1.4
|
|
12
|
+
Requires-Dist: bingads>=13.0.24.1 ; extra == 'bing'
|
|
13
|
+
Requires-Dist: facebook-business>=20.0.0 ; extra == 'facebook'
|
|
14
|
+
Requires-Dist: google-api-python-client>=2.167.0 ; extra == 'google'
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Provides-Extra: bing
|
|
17
|
+
Provides-Extra: facebook
|
|
18
|
+
Provides-Extra: google
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# interloper-assets
|
|
22
|
+
|
|
23
|
+
Asset definitions and source registry for Interloper.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# ###############
|
|
2
|
+
# PROJECT / UV
|
|
3
|
+
# ###############
|
|
4
|
+
[project]
|
|
5
|
+
name = "interloper-assets"
|
|
6
|
+
version = "0.2.0"
|
|
7
|
+
description = "Interloper Assets"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
authors = [{ name = "Guillaume Onfroy", email = "guillaume@digitlcloud.com" }]
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"interloper-core",
|
|
13
|
+
"interloper-pandas",
|
|
14
|
+
"httpx>=0.28.1",
|
|
15
|
+
"pandas>=2.3.3",
|
|
16
|
+
"tenacity>=9.1.4",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
bing = ["bingads>=13.0.24.1"]
|
|
21
|
+
google = ["google-api-python-client>=2.167.0"]
|
|
22
|
+
facebook = ["facebook-business>=20.0.0"]
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["uv_build>=0.9.5,<0.10.0"]
|
|
26
|
+
build-backend = "uv_build"
|
|
27
|
+
|
|
28
|
+
[tool.uv.sources]
|
|
29
|
+
interloper-core = { workspace = true }
|
|
30
|
+
interloper-pandas = { workspace = true }
|
|
31
|
+
|
|
32
|
+
# ###############
|
|
33
|
+
# RUFF
|
|
34
|
+
# ###############
|
|
35
|
+
[tool.ruff]
|
|
36
|
+
line-length = 120
|
|
37
|
+
|
|
38
|
+
[tool.ruff.lint]
|
|
39
|
+
extend-select = ["E", "I", "UP", "ANN001", "ANN201", "ANN202"]
|
|
40
|
+
|
|
41
|
+
[tool.ruff.lint.per-file-ignores]
|
|
42
|
+
"__init__.py" = ["F401", "F403"]
|
|
43
|
+
"**/schemas/**" = ["E501"]
|
|
44
|
+
"tests/**" = ["ANN", "F811"]
|
|
45
|
+
|
|
46
|
+
# ###############
|
|
47
|
+
# PYRIGHT
|
|
48
|
+
# ###############
|
|
49
|
+
[tool.pyright]
|
|
50
|
+
include = ["src"]
|
|
51
|
+
typeCheckingMode = "basic"
|
|
52
|
+
reportMissingParameterType = true
|
|
53
|
+
ignore = ["libs/**", "tests/**", "scripts/**"]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import interloper as il
|
|
2
|
+
from interloper.errors import SourceError
|
|
3
|
+
|
|
4
|
+
from interloper_assets.adservice.source import Adservice, AdserviceConfig
|
|
5
|
+
from interloper_assets.adup.source import Adup, AdupConfig
|
|
6
|
+
from interloper_assets.amazon_ads.source import AmazonAds, AmazonAdsConfig
|
|
7
|
+
from interloper_assets.amazon_selling_partner.source import AmazonSellingPartner
|
|
8
|
+
from interloper_assets.awin.source import Awin
|
|
9
|
+
from interloper_assets.bing_ads.source import BingAds
|
|
10
|
+
from interloper_assets.campaign_manager_360.source import CampaignManager360
|
|
11
|
+
from interloper_assets.campaign_performance_analysis.source import CampaignPerformanceAnalysis
|
|
12
|
+
from interloper_assets.criteo.source import Criteo
|
|
13
|
+
from interloper_assets.demo.source import DemoConfig, DemoSource
|
|
14
|
+
from interloper_assets.display_video_360.source import DisplayVideo360
|
|
15
|
+
from interloper_assets.facebook_ads.source import FacebookAds
|
|
16
|
+
from interloper_assets.facebook_insights.source import FacebookInsights
|
|
17
|
+
from interloper_assets.instagram_insights.source import InstagramInsights
|
|
18
|
+
from interloper_assets.linkedin_ads.source import LinkedinAds
|
|
19
|
+
from interloper_assets.linkedin_organic.source import LinkedinOrganic
|
|
20
|
+
from interloper_assets.pinterest_ads.source import PinterestAds
|
|
21
|
+
from interloper_assets.search_ads_360.source import SearchAds360
|
|
22
|
+
from interloper_assets.search_console.source import SearchConsole
|
|
23
|
+
from interloper_assets.snapchat_ads.source import SnapchatAds
|
|
24
|
+
from interloper_assets.teads.source import Teads
|
|
25
|
+
from interloper_assets.thetradedesk.source import TheTradeDesk
|
|
26
|
+
from interloper_assets.tiktok_ads.source import TiktokAds
|
|
27
|
+
|
|
28
|
+
SOURCE_REGISTRY: dict[str, tuple[il.SourceDefinition, type[il.Config] | None]] = {
|
|
29
|
+
DemoSource.name: (DemoSource, DemoConfig),
|
|
30
|
+
Adup.name: (Adup, AdupConfig),
|
|
31
|
+
Adservice.name: (Adservice, AdserviceConfig),
|
|
32
|
+
AmazonAds.name: (AmazonAds, AmazonAdsConfig),
|
|
33
|
+
AmazonSellingPartner.name: (AmazonSellingPartner, None),
|
|
34
|
+
Awin.name: (Awin, None),
|
|
35
|
+
BingAds.name: (BingAds, None),
|
|
36
|
+
CampaignManager360.name: (CampaignManager360, None),
|
|
37
|
+
CampaignPerformanceAnalysis.name: (CampaignPerformanceAnalysis, None),
|
|
38
|
+
Criteo.name: (Criteo, None),
|
|
39
|
+
DisplayVideo360.name: (DisplayVideo360, None),
|
|
40
|
+
FacebookAds.name: (FacebookAds, None),
|
|
41
|
+
FacebookInsights.name: (FacebookInsights, None),
|
|
42
|
+
InstagramInsights.name: (InstagramInsights, None),
|
|
43
|
+
LinkedinAds.name: (LinkedinAds, None),
|
|
44
|
+
LinkedinOrganic.name: (LinkedinOrganic, None),
|
|
45
|
+
PinterestAds.name: (PinterestAds, None),
|
|
46
|
+
SearchAds360.name: (SearchAds360, None),
|
|
47
|
+
SearchConsole.name: (SearchConsole, None),
|
|
48
|
+
SnapchatAds.name: (SnapchatAds, None),
|
|
49
|
+
Teads.name: (Teads, None),
|
|
50
|
+
TheTradeDesk.name: (TheTradeDesk, None),
|
|
51
|
+
TiktokAds.name: (TiktokAds, None),
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_source_and_config(id: str) -> tuple[il.SourceDefinition, type[il.Config] | None]:
|
|
56
|
+
"""Get a source definition and its config type by source type ID.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
id: Source type identifier (e.g. FacebookAds.name, DemoSource.name)
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Tuple of (SourceDefinition, ConfigType or None)
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
ValueError: If the source ID is not found in the registry
|
|
66
|
+
"""
|
|
67
|
+
if id not in SOURCE_REGISTRY:
|
|
68
|
+
raise SourceError(f"Unknown source ID: {id}")
|
|
69
|
+
return SOURCE_REGISTRY[id]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_all_sources() -> dict[str, tuple[il.SourceDefinition, type[il.Config] | None]]:
|
|
73
|
+
"""Get all registered sources.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Dictionary mapping source type IDs to (SourceDefinition, ConfigType) tuples
|
|
77
|
+
"""
|
|
78
|
+
return dict(SOURCE_REGISTRY)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
__all__ = [
|
|
82
|
+
"SOURCE_REGISTRY",
|
|
83
|
+
"get_all_sources",
|
|
84
|
+
"get_source_and_config",
|
|
85
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from interloper_assets.adservice.schemas.campaigns import Campaigns
|
|
2
|
+
from interloper_assets.adservice.schemas.campaigns_by_browser import CampaignsByBrowser
|
|
3
|
+
from interloper_assets.adservice.schemas.campaigns_by_city import CampaignsByCity
|
|
4
|
+
from interloper_assets.adservice.schemas.campaigns_by_device_type import CampaignsByDeviceType
|
|
5
|
+
from interloper_assets.adservice.schemas.conversions import ConversionsReport
|
|
6
|
+
from interloper_assets.adservice.schemas.conversions_by_time_of_day import ConversionsByTimeOfDay
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Campaigns",
|
|
10
|
+
"CampaignsByCity",
|
|
11
|
+
"CampaignsByDeviceType",
|
|
12
|
+
"CampaignsByBrowser",
|
|
13
|
+
"ConversionsReport",
|
|
14
|
+
"ConversionsByTimeOfDay",
|
|
15
|
+
]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
|
|
3
|
+
from interloper.schema import AssetSchema
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Campaigns(AssetSchema):
|
|
8
|
+
"""
|
|
9
|
+
The Campaigns report provides insights into the performance and financial outcomes of advertising campaigns.
|
|
10
|
+
It includes key metrics such as click rates, conversion rates, revenue from various client activities such as
|
|
11
|
+
clicks, impressions, leads, and sales, as well as campaign and media information.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
agent_id: int = Field(description="The unique identifier for the agent")
|
|
15
|
+
camp_id: int = Field(description="The unique identifier for the campaign")
|
|
16
|
+
camp_title: str = Field(description="The title of the campaign")
|
|
17
|
+
campaign_manager: str = Field(description="The name of the campaign manager")
|
|
18
|
+
campaign_manager_id: int = Field(description="The unique identifier for the campaign manager")
|
|
19
|
+
click_nun: int = Field(description="The number of clicks from unique visitors")
|
|
20
|
+
click_un: int = Field(description="The number of clicks from unique sources")
|
|
21
|
+
client_click_rev: float = Field(description="Revenue generated from client clicks")
|
|
22
|
+
client_impr_rev: float = Field(description="Revenue generated from client impressions")
|
|
23
|
+
client_lead_price: float = Field(description="Price of leads for the client")
|
|
24
|
+
client_lead_rev: float = Field(description="Revenue generated from client leads")
|
|
25
|
+
client_sale_rev: float = Field(description="Revenue generated from client sales")
|
|
26
|
+
client_subtotal: float = Field(description="Total revenue generated from client activities")
|
|
27
|
+
company_name: str = Field(description="The name of the company")
|
|
28
|
+
cpc: float = Field(description="Cost per click")
|
|
29
|
+
cr: float = Field(description="Conversion rate")
|
|
30
|
+
currency: str = Field(description="The currency used for transactions")
|
|
31
|
+
currency_code: str = Field(description="The currency code used")
|
|
32
|
+
currency_id: int = Field(description="The unique identifier for the currency")
|
|
33
|
+
currency_rate: float = Field(description="The exchange rate of the currency")
|
|
34
|
+
date: dt.date = Field(description="The date of the record")
|
|
35
|
+
date_from: dt.date = Field(description="The starting date for a time period")
|
|
36
|
+
date_max: dt.date = Field(description="The maximum date in a time period")
|
|
37
|
+
date_min: dt.date = Field(description="The minimum date in a time period")
|
|
38
|
+
date_to: dt.date = Field(description="The ending date for a time period")
|
|
39
|
+
default_banner: str = Field(description="The default banner for the campaign")
|
|
40
|
+
from_date: dt.date = Field(description="The starting date of an event or activity")
|
|
41
|
+
leads: int = Field(description="The number of leads generated")
|
|
42
|
+
media_id: int = Field(description="The unique identifier for the media")
|
|
43
|
+
medianame: str = Field(description="The name of the media")
|
|
44
|
+
mediatype: str = Field(description="The type of media")
|
|
45
|
+
monthyear: str = Field(description="The combination of month and year")
|
|
46
|
+
pcr: float = Field(description="Partial conversion rate")
|
|
47
|
+
pending_rev: float = Field(description="Revenue that is pending or not yet realized")
|
|
48
|
+
primary_category: int = Field(description="The primary category identifier")
|
|
49
|
+
primary_category_name: str = Field(description="The name of the primary category")
|
|
50
|
+
publisher_manager: str = Field(description="The name of the publisher manager")
|
|
51
|
+
publisher_manager_id: int = Field(description="The unique identifier for the publisher manager")
|
|
52
|
+
sales: float = Field(description="The number of sales")
|
|
53
|
+
sales_amount: float = Field(description="The total amount of sales")
|
|
54
|
+
stamp: dt.date = Field(description="The timestamp of the record")
|
|
55
|
+
to_date: dt.date = Field(description="The ending date of an event or activity")
|
|
56
|
+
week_to: dt.date = Field(description="The ending week of a time period")
|
|
57
|
+
weekyear: str = Field(description="The combination of week and year")
|
|
58
|
+
year: dt.date = Field(description="The year of the record")
|
|
59
|
+
year_from: dt.date = Field(description="The starting year of a time period")
|
|
60
|
+
year_to: dt.date = Field(description="The ending year of a time period")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from interloper.schema import AssetSchema
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CampaignsByBrowser(AssetSchema):
|
|
6
|
+
"""
|
|
7
|
+
The Campaigns by Browser report provides insights into campaign performance based on the user's browser usage.
|
|
8
|
+
It includes key metrics such as conversion rates, the number of conversions, and user demographics such as
|
|
9
|
+
city, country, device model, device type, and operating system.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
agent_id: int = Field(description="The ID of the agent")
|
|
13
|
+
browser: str = Field(description="The browser used by the user")
|
|
14
|
+
camp_id: int = Field(description="The ID of the campaign")
|
|
15
|
+
camp_title: str = Field(description="The title of the campaign")
|
|
16
|
+
city: str = Field(description="The city where the user is located")
|
|
17
|
+
conversion_pct: int = Field(description="The percentage of conversions")
|
|
18
|
+
conversions: int = Field(description="The number of conversions")
|
|
19
|
+
country: str = Field(description="The country where the user is located")
|
|
20
|
+
device_model: str = Field(description="The model of the device used by the user")
|
|
21
|
+
device_type: str = Field(description="The type of device used by the user")
|
|
22
|
+
os: str = Field(description="The operating system used by the user")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from interloper.schema import AssetSchema
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CampaignsByCity(AssetSchema):
|
|
6
|
+
"""
|
|
7
|
+
The Campaigns by City report provides insights into campaign performance segmented by cities.
|
|
8
|
+
It includes key metrics such as conversion rates, the number of conversions, and user demographics
|
|
9
|
+
such as browser usage, device type, operating system, and geographical coordinates (latitude and longitude).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
agent_id: int = Field(description="The ID of the agent")
|
|
13
|
+
browser: str = Field(description="The browser used")
|
|
14
|
+
camp_id: int = Field(description="The ID of the campaign")
|
|
15
|
+
camp_title: str = Field(description="The title of the campaign")
|
|
16
|
+
city: str = Field(description="The city")
|
|
17
|
+
conversion_pct: int = Field(description="The conversion percentage")
|
|
18
|
+
conversions: int = Field(description="The number of conversions")
|
|
19
|
+
coordinates_lat: float = Field(description="The latitude coordinates")
|
|
20
|
+
coordinates_lng: float = Field(description="The longitude coordinates")
|
|
21
|
+
country: str = Field(description="The country")
|
|
22
|
+
device_model: str = Field(description="The device model")
|
|
23
|
+
device_type: str = Field(description="The device type")
|
|
24
|
+
os: str = Field(description="The operating system")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from interloper.schema import AssetSchema
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CampaignsByDeviceType(AssetSchema):
|
|
6
|
+
"""
|
|
7
|
+
The Campaigns by Device Type report provides insights into campaign performance
|
|
8
|
+
based on the type of device used by users. It includes key metrics such as
|
|
9
|
+
conversion rates, the number of conversions, and user demographics such as
|
|
10
|
+
browser usage, operating system, city, and country.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
agent_id: int = Field(description="The ID of the agent")
|
|
14
|
+
browser: str = Field(description="The browser used")
|
|
15
|
+
camp_id: int = Field(description="The ID of the campaign")
|
|
16
|
+
camp_title: str = Field(description="The title of the campaign")
|
|
17
|
+
city: str = Field(description="The city where the campaign was run")
|
|
18
|
+
conversion_pct: int = Field(description="The percentage of conversions")
|
|
19
|
+
conversions: int = Field(description="The number of conversions")
|
|
20
|
+
country: str = Field(description="The country where the campaign was run")
|
|
21
|
+
device_model: str = Field(description="The model of the device")
|
|
22
|
+
device_type: str = Field(description="The type of the device")
|
|
23
|
+
os: str = Field(description="The operating system used")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from interloper.schema import AssetSchema
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ConversionsReport(AssetSchema):
|
|
6
|
+
"""
|
|
7
|
+
The Conversions report provides insights on conversion events tracked within campaigns.
|
|
8
|
+
It includes key metrics such as the amount of conversions, conversion time, currency, IP geolocation data,
|
|
9
|
+
media information, order details, and user device information such as browser, device, and operating system.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
agent_id: int = Field(description="Agent ID")
|
|
13
|
+
amount: str = Field(description="Amount")
|
|
14
|
+
camp_id: int = Field(description="Campaign ID")
|
|
15
|
+
camp_title: str = Field(description="Campaign Title")
|
|
16
|
+
cart_id: int = Field(description="Cart ID")
|
|
17
|
+
click_ref_id: int = Field(description="Click Reference ID")
|
|
18
|
+
click_stamp: int = Field(description="Click Stamp")
|
|
19
|
+
coid: int = Field(description="COID")
|
|
20
|
+
company_name: str = Field(description="Company Name")
|
|
21
|
+
conversion_time: int = Field(description="Conversion Time")
|
|
22
|
+
currency: str = Field(description="Currency")
|
|
23
|
+
id: int = Field(description="ID")
|
|
24
|
+
ip_city: str = Field(description="IP City")
|
|
25
|
+
ip_country_geoname_id: int = Field(description="IP Country Geoname ID")
|
|
26
|
+
ip_country_iso_code: str = Field(description="IP Country ISO Code")
|
|
27
|
+
ip_country_names_de: str = Field(description="IP Country Names (German)")
|
|
28
|
+
ip_country_names_en: str = Field(description="IP Country Names (English)")
|
|
29
|
+
ip_country_names_es: str = Field(description="IP Country Names (Spanish)")
|
|
30
|
+
ip_country_names_fr: str = Field(description="IP Country Names (French)")
|
|
31
|
+
ip_country_names_ja: str = Field(description="IP Country Names (Japanese)")
|
|
32
|
+
ip_country_names_pt_br: str = Field(description="IP Country Names (Portuguese - Brazil)")
|
|
33
|
+
ip_country_names_ru: str = Field(description="IP Country Names (Russian)")
|
|
34
|
+
ip_country_names_zh_cn: str = Field(description="IP Country Names (Chinese - Simplified)")
|
|
35
|
+
leaddata: str = Field(description="Lead Data")
|
|
36
|
+
media_id: int = Field(description="Media ID")
|
|
37
|
+
media_url: int = Field(description="Media URL")
|
|
38
|
+
medianame: str = Field(description="Media Name")
|
|
39
|
+
order_id: str = Field(description="Order ID")
|
|
40
|
+
price: str = Field(description="Price")
|
|
41
|
+
pricevariable: str = Field(description="Price Variable")
|
|
42
|
+
reject_reason: int = Field(description="Reject Reason")
|
|
43
|
+
result: str = Field(description="Result")
|
|
44
|
+
sensitive_data: int = Field(description="Sensitive Data")
|
|
45
|
+
stamp: str = Field(description="Stamp")
|
|
46
|
+
status: str = Field(description="Status")
|
|
47
|
+
user_agent: str = Field(description="User Agent")
|
|
48
|
+
user_browser: int = Field(description="User Browser")
|
|
49
|
+
user_device: int = Field(description="User Device")
|
|
50
|
+
user_os: int = Field(description="User OS")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from interloper.schema import AssetSchema
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ConversionsByTimeOfDay(AssetSchema):
|
|
6
|
+
"""
|
|
7
|
+
The Conversions by Time of Day report provides insights into conversion patterns based on the day of the week
|
|
8
|
+
and hour of the day. It includes key metrics such as the number of conversions and revenue generated within each
|
|
9
|
+
time segment.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
conversions: int = Field(description="Number of conversions")
|
|
13
|
+
day: str = Field(description="Day of the week")
|
|
14
|
+
hour: int = Field(description="Hour of the day")
|
|
15
|
+
revenue: float = Field(description="Revenue generated")
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import httpx
|
|
5
|
+
import interloper as il
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from pydantic_settings import SettingsConfigDict
|
|
8
|
+
|
|
9
|
+
from interloper_assets.adservice import schemas
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AdserviceConfig(il.Config):
|
|
15
|
+
api_key: str
|
|
16
|
+
|
|
17
|
+
model_config = SettingsConfigDict(env_prefix="adservice_")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@il.source(
|
|
21
|
+
config=AdserviceConfig,
|
|
22
|
+
tags=["Advertising"],
|
|
23
|
+
)
|
|
24
|
+
class Adservice:
|
|
25
|
+
"""Adservice advertising platform integration."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, config: AdserviceConfig) -> None:
|
|
28
|
+
base_url = "https://api.adservice.com/v2/client"
|
|
29
|
+
auth = httpx.BasicAuth(username="api", password=config.api_key)
|
|
30
|
+
self.client = il.RESTClient(base_url, auth)
|
|
31
|
+
self.base_url = base_url
|
|
32
|
+
|
|
33
|
+
def get_report(
|
|
34
|
+
self,
|
|
35
|
+
start_date: dt.date,
|
|
36
|
+
end_date: dt.date,
|
|
37
|
+
report_type: str,
|
|
38
|
+
group_by: str | None = None,
|
|
39
|
+
end_group: str | None = None,
|
|
40
|
+
sales_amount: int | None = None,
|
|
41
|
+
) -> dict:
|
|
42
|
+
response = self.client.get(
|
|
43
|
+
url=f"{self.base_url}/{report_type}",
|
|
44
|
+
params={
|
|
45
|
+
"from_date": start_date.isoformat(),
|
|
46
|
+
"to_date": end_date.isoformat(),
|
|
47
|
+
"sales_amount": sales_amount,
|
|
48
|
+
"group_by": group_by,
|
|
49
|
+
"end_group": end_group,
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
response.raise_for_status()
|
|
53
|
+
return response.json()
|
|
54
|
+
|
|
55
|
+
@il.asset(
|
|
56
|
+
schema=schemas.Campaigns,
|
|
57
|
+
partitioning=il.TimePartitionConfig(column="date"),
|
|
58
|
+
)
|
|
59
|
+
def campaigns(self, context: il.ExecutionContext) -> pd.DataFrame:
|
|
60
|
+
"""Campaign performance statistics with metrics like impressions, clicks, and conversions."""
|
|
61
|
+
|
|
62
|
+
response = self.get_report(
|
|
63
|
+
start_date=context.partition_date,
|
|
64
|
+
end_date=context.partition_date,
|
|
65
|
+
report_type="statistics",
|
|
66
|
+
group_by="stamp,camp_id",
|
|
67
|
+
end_group="stamp",
|
|
68
|
+
sales_amount=1,
|
|
69
|
+
)
|
|
70
|
+
data = response["data"]["rows"]
|
|
71
|
+
return pd.DataFrame(data)
|
|
72
|
+
|
|
73
|
+
@il.asset(
|
|
74
|
+
schema=schemas.ConversionsReport,
|
|
75
|
+
partitioning=il.TimePartitionConfig(column="date"),
|
|
76
|
+
)
|
|
77
|
+
def conversions(self, context: il.ExecutionContext) -> pd.DataFrame:
|
|
78
|
+
"""Conversion events and attribution data."""
|
|
79
|
+
response = self.get_report(
|
|
80
|
+
start_date=context.partition_date,
|
|
81
|
+
end_date=context.partition_date,
|
|
82
|
+
report_type="conversions",
|
|
83
|
+
)
|
|
84
|
+
data = response["data"]
|
|
85
|
+
return pd.DataFrame(data)
|
|
86
|
+
|
|
87
|
+
@il.asset(
|
|
88
|
+
schema=schemas.ConversionsByTimeOfDay,
|
|
89
|
+
partitioning=il.TimePartitionConfig(column="date"),
|
|
90
|
+
)
|
|
91
|
+
def conversions_time_of_day(self, context: il.ExecutionContext) -> pd.DataFrame:
|
|
92
|
+
"""Conversion events broken down by time of day."""
|
|
93
|
+
|
|
94
|
+
response = self.get_report(
|
|
95
|
+
start_date=context.partition_date,
|
|
96
|
+
end_date=context.partition_date,
|
|
97
|
+
report_type="statistics/conversions/timeofday",
|
|
98
|
+
)
|
|
99
|
+
data = response["data"]
|
|
100
|
+
return pd.DataFrame(data)
|
|
101
|
+
|
|
102
|
+
@il.asset(
|
|
103
|
+
schema=schemas.CampaignsByCity,
|
|
104
|
+
partitioning=il.TimePartitionConfig(column="date"),
|
|
105
|
+
)
|
|
106
|
+
def campaigns_by_city(self, context: il.ExecutionContext) -> pd.DataFrame:
|
|
107
|
+
"""Campaign performance segmented by city."""
|
|
108
|
+
|
|
109
|
+
response = self.get_report(
|
|
110
|
+
start_date=context.partition_date,
|
|
111
|
+
end_date=context.partition_date,
|
|
112
|
+
report_type="statistics/devicedetails",
|
|
113
|
+
group_by="city",
|
|
114
|
+
)
|
|
115
|
+
data = response["data"]
|
|
116
|
+
return pd.DataFrame(data)
|
|
117
|
+
|
|
118
|
+
@il.asset(
|
|
119
|
+
schema=schemas.CampaignsByBrowser,
|
|
120
|
+
partitioning=il.TimePartitionConfig(column="date"),
|
|
121
|
+
)
|
|
122
|
+
def campaigns_by_browser(self, context: il.ExecutionContext) -> pd.DataFrame:
|
|
123
|
+
"""Campaign performance segmented by browser."""
|
|
124
|
+
|
|
125
|
+
response = self.get_report(
|
|
126
|
+
start_date=context.partition_date,
|
|
127
|
+
end_date=context.partition_date,
|
|
128
|
+
report_type="statistics/devicedetails",
|
|
129
|
+
group_by="browser",
|
|
130
|
+
)
|
|
131
|
+
data = response["data"]
|
|
132
|
+
return pd.DataFrame(data)
|
|
133
|
+
|
|
134
|
+
@il.asset(
|
|
135
|
+
schema=schemas.CampaignsByDeviceType,
|
|
136
|
+
partitioning=il.TimePartitionConfig(column="date"),
|
|
137
|
+
)
|
|
138
|
+
def campaigns_by_device_type(self, context: il.ExecutionContext) -> pd.DataFrame:
|
|
139
|
+
"""Campaign performance segmented by device type."""
|
|
140
|
+
|
|
141
|
+
response = self.get_report(
|
|
142
|
+
start_date=context.partition_date,
|
|
143
|
+
end_date=context.partition_date,
|
|
144
|
+
report_type="statistics/devicedetails",
|
|
145
|
+
group_by="device_type",
|
|
146
|
+
)
|
|
147
|
+
data = response["data"]
|
|
148
|
+
return pd.DataFrame(data)
|
|
File without changes
|