hemangjain17
feat: gemini/ollama integration, test code for hf space(static)
34f7311
"""Pydantic models for the GTM Strategy Optimizer environment."""
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field, model_validator
import json
from openenv.core.env_server import Action, Observation, State
# ── Sub-models for structured metrics ──────────────────────────────────────
class ChannelMetrics(BaseModel):
"""Performance metrics for a single marketing channel."""
impressions: int = 0
clicks: int = 0
conversions: int = 0
spend: float = 0.0
ctr: float = 0.0
cvr: float = 0.0
roi: float = 0.0
class FunnelMetrics(BaseModel):
"""Funnel-level metrics across all channels."""
visitors: int = 0
signups: int = 0
activations: int = 0
retained_users: int = 0
signup_rate: float = 0.0
activation_rate: float = 0.0
retention_rate: float = 0.0
class SegmentMetrics(BaseModel):
"""Performance metrics for a customer segment."""
conversion_rate: float = 0.0
engagement_score: float = 0.0
churn_rate: float = 0.0
revenue: float = 0.0
class ExperimentResult(BaseModel):
"""Result of a completed experiment."""
experiment_type: str
uplift_estimate: float
confidence: float
recommendation: str
# ── Action ─────────────────────────────────────────────────────────────────
class GTMAction(Action):
"""Agent's weekly GTM decisions.
All allocation dicts map names to fractions (0.0-1.0).
Fractions in budget_allocation should sum to <= 1.0.
Fractions in segment_targeting and messaging should each sum to ~1.0.
"""
budget_allocation: Dict[str, float] = Field(
default_factory=dict,
description="Channel name -> fraction of weekly budget to allocate",
)
segment_targeting: Dict[str, float] = Field(
default_factory=dict,
description="Segment name -> targeting weight (should sum to ~1.0)",
)
messaging: Dict[str, float] = Field(
default_factory=dict,
description="Messaging dimension -> emphasis weight. Dimensions: cost_savings, performance, reliability, innovation, ease_of_use, security",
)
experiment: Optional[str] = Field(
default=None,
description="Experiment to launch: 'ab_test_landing', 'ab_test_pricing', 'ab_test_creative', 'run_survey', 'competitor_analysis', or null",
)
@model_validator(mode="before")
@classmethod
def parse_stringified_json(cls, data: Any) -> Any:
if isinstance(data, dict):
for field in ["budget_allocation", "segment_targeting", "messaging"]:
if field in data and isinstance(data[field], str):
try:
data[field] = json.loads(data[field])
except json.JSONDecodeError:
pass
return data
pricing_action: Optional[str] = Field(
default=None,
description="Pricing change: 'discount_10', 'discount_20', 'raise_5', 'add_free_trial', or null",
)
# ── Observation ────────────────────────────────────────────────────────────
class GTMObservation(Observation):
"""What the agent observes after each week of GTM activity."""
week: int = 0
total_weeks: int = 12
budget_remaining: float = 0.0
weekly_budget: float = 0.0
channel_metrics: Dict[str, ChannelMetrics] = Field(default_factory=dict)
funnel: FunnelMetrics = Field(default_factory=FunnelMetrics)
segment_performance: Dict[str, SegmentMetrics] = Field(default_factory=dict)
experiment_result: Optional[ExperimentResult] = None
brand_score: float = 50.0
total_revenue: float = 0.0
total_conversions: int = 0
average_cac: float = 0.0
available_channels: List[str] = Field(default_factory=list)
available_segments: List[str] = Field(default_factory=list)
available_experiments: List[str] = Field(default_factory=list)
available_pricing_actions: List[str] = Field(default_factory=list)
messaging_dimensions: List[str] = Field(default_factory=list)
message: str = ""
# ── State ──────────────────────────────────────────────────────────────────
class GTMState(State):
"""Internal environment state (includes hidden ground truth)."""
task_id: str = "channel_optimizer"
difficulty: str = "easy"
true_brand_strength: float = 50.0
true_market_demand: float = 1.0
total_revenue: float = 0.0
total_spend: float = 0.0
total_conversions: int = 0
compliance_violations: int = 0
experiments_run: int = 0
useful_experiments: int = 0