Catchup airline (#31)

* chore: update provider and pricing snitch with agnostic system

* cloning pipelines per mode instance

* updating airline hero section

* fix: must keep airflow secretkey

* fix: fixture update to hotel not shop

* chore: refactored to factory design pattern of pipelines

* chore: clean up definition of composite class of providers
This commit is contained in:
Daniel Alves Rösel
2025-12-11 21:56:12 +01:00
committed by GitHub
parent d45b344264
commit ef98141ca8
10 changed files with 384 additions and 55 deletions

View File

@@ -131,7 +131,7 @@ if __name__ == '__main__':
# example run
context = PipelineContext(
provider=HistoricalProvider(),
store_mode='hotel',
store_mode='airline',
)
product_features, prices = full_pipeline(context)

View File

@@ -18,10 +18,17 @@ class SupabaseProvider(DataProvider):
self.supabase: Client = create_client(self.supabase_url, self.supabase_key)
def fetch_products(self, store_mode: str) -> pd.DataFrame:
resp = self.supabase.table(f'{store_mode}_products').select(
"id, room_type, date_index, metadata, availability"
).execute()
return pd.DataFrame(resp.data) if resp.data else pd.DataFrame()
# hotel uses room_type, airline uses flight_type; select all and normalize
resp = self.supabase.table(f'{store_mode}_products').select("*").execute()
if not resp.data:
return pd.DataFrame()
df = pd.DataFrame(resp.data)
# normalize type column: hotel has room_type, airline has flight_type
if 'room_type' in df.columns:
df['product_type'] = df['room_type']
elif 'flight_type' in df.columns:
df['product_type'] = df['flight_type']
return df
def fetch_experiments(self, experiment_ids: List[str]) -> pd.DataFrame:
if not experiment_ids:

View File

@@ -2,7 +2,7 @@ import pandas as pd
from procesing.steps.base import BaseContextStep
class FetchInteractionsStep(BaseContextStep):
"""Fetch raw interaction data from Kafka topic with optional time filtering"""
"""Fetch raw interaction data from Kafka topic with optional time and store_mode filtering"""
def __init__(self, context, lookback: str = None):
super().__init__(context)
@@ -24,6 +24,10 @@ class FetchInteractionsStep(BaseContextStep):
# drop all where page has /admin/
df = df[~df['page'].str.contains('/admin/', na=False)]
# filter by store_mode from context
if 'storeMode' in df.columns:
df = df[df['storeMode'] == self.context.store_mode]
# Remap dateIndex if present
if 'metadata_dateIndex' in df.columns:
df['dateIndex'] = df['metadata_dateIndex'].astype('Int64')
@@ -38,7 +42,7 @@ class FetchInteractionsStep(BaseContextStep):
class FetchPriceLogsStep(BaseContextStep):
"""Fetch price log data from Kafka topic with optional time filtering"""
"""Fetch price log data from Kafka topic with optional time and store_mode filtering"""
def __init__(self, context, lookback: str = None):
super().__init__(context)
@@ -50,6 +54,10 @@ class FetchPriceLogsStep(BaseContextStep):
if df.empty:
return df
# filter by store_mode from context
if 'storeMode' in df.columns:
df = df[df['storeMode'] == self.context.store_mode]
# Apply time filtering if lookback specified
if self.lookback and 'ts' in df.columns:
df['ts'] = pd.to_datetime(df['ts'])

View File

@@ -144,7 +144,7 @@ def mock_price_logs_raw_kafka():
'price': 162.47,
'sessionId': 'd423ce8a-77aa-4c9a-94d4-d1adddcc3472',
'experimentId': '53aefd07-f66a-4d7f-ba8b-7ea1fc562d35',
'storeMode': 'shop',
'storeMode': 'hotel',
'ts': '2025-11-25T21:05:57.967Z'
}
}
@@ -157,7 +157,7 @@ def mock_price_logs_raw_kafka():
'price': 743.49,
'sessionId': 'd423ce8a-77aa-4c9a-94d4-d1adddcc3472',
'experimentId': '53aefd07-f66a-4d7f-ba8b-7ea1fc562d35',
'storeMode': 'shop',
'storeMode': 'hotel',
'ts': '2025-11-25T21:05:57.993Z'
}
}
@@ -170,7 +170,7 @@ def mock_price_logs_raw_kafka():
'price': 163.87,
'sessionId': 'd423ce8a-77aa-4c9a-94d4-d1adddcc3472',
'experimentId': '53aefd07-f66a-4d7f-ba8b-7ea1fc562d35',
'storeMode': 'shop',
'storeMode': 'hotel',
'ts': '2025-11-25T21:05:58.009Z'
}
}
@@ -183,7 +183,7 @@ def mock_price_logs_raw_kafka():
'price': 397.46,
'sessionId': 'd423ce8a-77aa-4c9a-94d4-d1adddcc3472',
'experimentId': '53aefd07-f66a-4d7f-ba8b-7ea1fc562d35',
'storeMode': 'shop',
'storeMode': 'hotel',
'ts': '2025-11-25T21:05:58.049Z'
}
}
@@ -196,7 +196,7 @@ def mock_price_logs_raw_kafka():
'price': 401.66,
'sessionId': 'd423ce8a-77aa-4c9a-94d4-d1adddcc3472',
'experimentId': '53aefd07-f66a-4d7f-ba8b-7ea1fc562d35',
'storeMode': 'shop',
'storeMode': 'hotel',
'ts': '2025-11-25T21:06:08.864Z'
}
}
@@ -222,7 +222,7 @@ def mock_experiments():
'created_at': pd.to_datetime(['2025-11-25T20:00:00Z', '2025-11-26T10:00:00Z']),
'subject_name': ['Session A', 'Session B'],
'xp_human_only': [True, False],
'xp_market_mode': ['hotel', 'shop'],
'xp_market_mode': ['hotel', 'airline'],
'xp_task_id': [None, None]
})