Expand AI insight: fix broken competitor query, add continuity, 30-day horizon, holidays

- Fix gather_competitor_data() tier filter: it queried tier IN ('primary','secondary'),
  values that never exist (real values are 'own'/'competitor'/'market'), so the
  cheapest-competitor comparison has always silently returned nothing.
- Feed the previous insight back into the prompt so the model can note what's
  changed/resolved instead of repeating itself.
- Extend forecast horizon from 14 to 30 days; add a per-day revenue table
  alongside the existing occupancy table.
- Annotate the occupancy table with UK (England) bank holidays.
- Add a same-channel market-movement section (B.com vs B.com, rack vs rack)
  diffing rates against the last insight's snapshot, threshold £3.
- Add a parsed headline field + insight history list on the Dashboard,
  collapsed to headline/age and expandable to full content.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-24 18:03:31 +00:00
parent 2f5349bd1c
commit 2a7ee1d6b8
9 changed files with 381 additions and 83 deletions

View file

@ -28,7 +28,7 @@ async def get_latest_insight(
"""Get the most recent AI insight for the dashboard card."""
result = await db.execute(
text("""
SELECT id, generated_at, insight_type, content, model,
SELECT id, generated_at, insight_type, headline, content, model,
input_tokens, output_tokens, triggered_by
FROM ai_insights
ORDER BY generated_at DESC
@ -43,6 +43,7 @@ async def get_latest_insight(
"id": row.id,
"generated_at": row.generated_at.isoformat(),
"insight_type": row.insight_type,
"headline": row.headline,
"content": row.content,
"model": row.model,
"input_tokens": row.input_tokens,
@ -61,7 +62,7 @@ async def get_insight_history(
"""Get historical AI insights with pagination."""
result = await db.execute(
text("""
SELECT id, generated_at, insight_type, content, model,
SELECT id, generated_at, insight_type, headline, content, model,
input_tokens, output_tokens, triggered_by
FROM ai_insights
ORDER BY generated_at DESC
@ -79,6 +80,7 @@ async def get_insight_history(
"id": row.id,
"generated_at": row.generated_at.isoformat(),
"insight_type": row.insight_type,
"headline": row.headline,
"content": row.content,
"model": row.model,
"input_tokens": row.input_tokens,
@ -166,6 +168,7 @@ async def generate_insight_manual(
return {
"success": True,
"content": result["content"],
"headline": result.get("headline"),
"input_tokens": result["input_tokens"],
"output_tokens": result["output_tokens"],
"model": result["model"],

View file

@ -1223,7 +1223,7 @@ class AIInsightsSettingsResponse(BaseModel):
api_key_set: bool = False
model: str = "claude-haiku-4-5-20251001"
schedule_time: str = "07:15"
daily_token_budget: int = 5000
daily_token_budget: int = 12000
class AIInsightsSettingsUpdate(BaseModel):
@ -1258,7 +1258,7 @@ async def get_ai_insights_settings(
api_key_set=config.get('_api_key_set', False),
model=config.get('ai_insights_model', 'claude-haiku-4-5-20251001'),
schedule_time=config.get('ai_insights_schedule_time', '07:15'),
daily_token_budget=int(config.get('ai_insights_daily_token_budget', '5000')),
daily_token_budget=int(config.get('ai_insights_daily_token_budget', '12000')),
)