forked from sagnik/Project_Velocity
feat: Ipad app production readiness, Colony orchestration, Social posting
This commit is contained in:
@@ -13,6 +13,7 @@ import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import uuid
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
@@ -29,6 +30,7 @@ except ModuleNotFoundError: # pragma: no cover - exercised by operator environm
|
||||
SEED_SOURCE = "velocity_ipad_investor_demo_2026_04"
|
||||
DEFAULT_OPERATOR_EMAIL = "sayan@desineuron.in"
|
||||
NAMESPACE = uuid.uuid5(uuid.NAMESPACE_URL, "https://desineuron.in/project-velocity/ipad-investor-demo")
|
||||
DEMO_CLIENT_TARGET_COUNT = 50
|
||||
|
||||
|
||||
def _load_env() -> None:
|
||||
@@ -73,6 +75,7 @@ def _expected_counts() -> dict[str, int]:
|
||||
"leads": len(DEMO_CLIENTS),
|
||||
"projects": len(PROJECTS),
|
||||
"properties": len(PROJECTS),
|
||||
"property_media": len(PROJECTS) * 2,
|
||||
"interests": len(DEMO_CLIENTS),
|
||||
"opportunities": len(DEMO_CLIENTS),
|
||||
"scores": len(DEMO_CLIENTS) * 3,
|
||||
@@ -80,6 +83,10 @@ def _expected_counts() -> dict[str, int]:
|
||||
"edge_events": len(DEMO_CLIENTS),
|
||||
"reminders": len(DEMO_CLIENTS),
|
||||
"calendar_events": len(DEMO_CLIENTS),
|
||||
"insight_recommendations": len(DEMO_CLIENTS),
|
||||
"comms_threads": len(DEMO_CLIENTS),
|
||||
"comms_messages": len(DEMO_CLIENTS) * 3,
|
||||
"comms_call_logs": len(DEMO_CLIENTS),
|
||||
"import_batches": 1,
|
||||
"import_proposals": 3,
|
||||
}
|
||||
@@ -304,6 +311,201 @@ PROJECTS = {
|
||||
},
|
||||
}
|
||||
|
||||
PROJECTS.update(
|
||||
{
|
||||
"Emaar Palm Heights Dubai": {
|
||||
"developer": "Emaar Properties",
|
||||
"micro_market": "Dubai Hills Estate",
|
||||
"address": "Dubai Hills Estate, Dubai, UAE",
|
||||
"property_type": "penthouse",
|
||||
"location": {"city": "Dubai", "district": "Dubai Hills", "lat": 25.1132, "lng": 55.2477},
|
||||
"price_bands": [
|
||||
{"unitType": "4BR Sky Penthouse", "minUSD": 3200000, "maxUSD": 5200000},
|
||||
{"unitType": "3BR Residence", "minUSD": 1800000, "maxUSD": 2600000},
|
||||
],
|
||||
"unit_mix": [{"bedrooms": 4, "count": 16, "sizeSqft": 5200}, {"bedrooms": 3, "count": 42, "sizeSqft": 3100}],
|
||||
},
|
||||
"Sobha Hartland Estates": {
|
||||
"developer": "Sobha Realty",
|
||||
"micro_market": "Mohammed Bin Rashid City",
|
||||
"address": "Sobha Hartland, MBR City, Dubai, UAE",
|
||||
"property_type": "villa",
|
||||
"location": {"city": "Dubai", "district": "MBR City", "lat": 25.1763, "lng": 55.3067},
|
||||
"price_bands": [
|
||||
{"unitType": "5BR Waterfront Villa", "minUSD": 4500000, "maxUSD": 7800000},
|
||||
{"unitType": "4BR Garden Villa", "minUSD": 2900000, "maxUSD": 4200000},
|
||||
],
|
||||
"unit_mix": [{"bedrooms": 5, "count": 12, "sizeSqft": 8100}, {"bedrooms": 4, "count": 24, "sizeSqft": 5900}],
|
||||
},
|
||||
"Emaar Urban Oasis Gurugram": {
|
||||
"developer": "Emaar India",
|
||||
"micro_market": "Golf Course Extension",
|
||||
"address": "Sector 62, Gurugram, India",
|
||||
"property_type": "apartment",
|
||||
"location": {"city": "Gurugram", "district": "Golf Course Extension", "lat": 28.4059, "lng": 77.0964},
|
||||
"price_bands": [
|
||||
{"unitType": "4BHK Signature", "minINR": 95000000, "maxINR": 155000000},
|
||||
{"unitType": "Penthouse", "minINR": 180000000, "maxINR": 290000000},
|
||||
],
|
||||
"unit_mix": [{"bedrooms": 4, "count": 44, "sizeSqft": 4200}, {"bedrooms": 5, "count": 10, "sizeSqft": 6200}],
|
||||
},
|
||||
"Sobha Neopolis Presidential": {
|
||||
"developer": "Sobha Limited",
|
||||
"micro_market": "Panathur",
|
||||
"address": "Panathur Main Road, Bengaluru, India",
|
||||
"property_type": "apartment",
|
||||
"location": {"city": "Bengaluru", "district": "Panathur", "lat": 12.9357, "lng": 77.7037},
|
||||
"price_bands": [
|
||||
{"unitType": "4BHK Presidential", "minINR": 85000000, "maxINR": 140000000},
|
||||
{"unitType": "3BHK Luxury", "minINR": 42000000, "maxINR": 68000000},
|
||||
],
|
||||
"unit_mix": [{"bedrooms": 4, "count": 30, "sizeSqft": 3600}, {"bedrooms": 3, "count": 72, "sizeSqft": 2400}],
|
||||
},
|
||||
"Emaar Ocean Crown Abu Dhabi": {
|
||||
"developer": "Emaar Properties",
|
||||
"micro_market": "Saadiyat Island",
|
||||
"address": "Saadiyat Cultural District, Abu Dhabi, UAE",
|
||||
"property_type": "branded_residence",
|
||||
"location": {"city": "Abu Dhabi", "district": "Saadiyat Island", "lat": 24.5442, "lng": 54.4332},
|
||||
"price_bands": [
|
||||
{"unitType": "Royal Beachfront Penthouse", "minUSD": 6200000, "maxUSD": 11000000},
|
||||
{"unitType": "3BR Beach Residence", "minUSD": 2400000, "maxUSD": 3900000},
|
||||
],
|
||||
"unit_mix": [{"bedrooms": 5, "count": 6, "sizeSqft": 9200}, {"bedrooms": 3, "count": 28, "sizeSqft": 3400}],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
PROPERTY_MEDIA_URLS = [
|
||||
"https://images.unsplash.com/photo-1600585154340-be6161a56a0c",
|
||||
"https://images.unsplash.com/photo-1600607687939-ce8a6c25118c",
|
||||
"https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3",
|
||||
"https://images.unsplash.com/photo-1600585154526-990dced4db0d",
|
||||
"https://images.unsplash.com/photo-1613490493576-7fde63acd811",
|
||||
"https://images.unsplash.com/photo-1600607687644-aac4c3eac7f4",
|
||||
"https://images.unsplash.com/photo-1600566752355-35792bedcfea",
|
||||
"https://images.unsplash.com/photo-1600607687920-4e2a09cf159d",
|
||||
]
|
||||
|
||||
|
||||
def _media_url(seed_index: int, *, width: int, height: int) -> str:
|
||||
base = PROPERTY_MEDIA_URLS[seed_index % len(PROPERTY_MEDIA_URLS)]
|
||||
return f"{base}?auto=format&fit=crop&w={width}&h={height}&q=82"
|
||||
|
||||
|
||||
def _project_media_assets(project_name: str, project: dict[str, Any], index: int) -> list[dict[str, Any]]:
|
||||
slug = re.sub(r"[^a-z0-9]+", "-", project_name.lower()).strip("-")
|
||||
location = project["location"]
|
||||
return [
|
||||
{
|
||||
"key": f"{slug}:hero",
|
||||
"media_type": "image",
|
||||
"url": _media_url(index, width=1600, height=1000),
|
||||
"thumbnail_url": _media_url(index, width=640, height=420),
|
||||
"sort_order": 0,
|
||||
"metadata": {
|
||||
"seed_source": SEED_SOURCE,
|
||||
"demo_asset_kind": "property_hero",
|
||||
"project_name": project_name,
|
||||
"developer": project["developer"],
|
||||
"city": location["city"],
|
||||
"district": location["district"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"key": f"{slug}:floorplan",
|
||||
"media_type": "floorplan",
|
||||
"url": _media_url(index + 3, width=1600, height=1000),
|
||||
"thumbnail_url": _media_url(index + 3, width=640, height=420),
|
||||
"sort_order": 1,
|
||||
"metadata": {
|
||||
"seed_source": SEED_SOURCE,
|
||||
"demo_asset_kind": "floor_plan_reference",
|
||||
"project_name": project_name,
|
||||
"unit_mix": project["unit_mix"],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def _phone_for(index: int, country: str) -> str:
|
||||
if country == "UAE":
|
||||
return f"+971-50-{7200000 + index:07d}"
|
||||
return f"+91-98{30000000 + index:08d}"[:14]
|
||||
|
||||
|
||||
def _expand_demo_clients(seed_clients: list[dict[str, Any]], target_count: int) -> list[dict[str, Any]]:
|
||||
if len(seed_clients) >= target_count:
|
||||
return seed_clients
|
||||
|
||||
first_names = [
|
||||
"Aarav", "Ishaan", "Kabir", "Reyansh", "Vihaan", "Anika", "Aanya", "Kiara",
|
||||
"Navya", "Rhea", "Omar", "Mariam", "Zayed", "Leila", "Farah", "Aditya",
|
||||
"Naina", "Rohan", "Tara", "Samaira", "Armaan", "Dev", "Saanvi", "Ayesha",
|
||||
]
|
||||
last_names = [
|
||||
"Mehta", "Kapoor", "Khanna", "Bhatia", "Sarin", "Al Maktoum", "Al Futtaim",
|
||||
"Al Habtoor", "Nair", "Menon", "Reddy", "Pillai", "Chopra", "Raheja",
|
||||
"Jindal", "Goenka", "Dalmia", "Merchant", "Saxena", "Bose",
|
||||
]
|
||||
buyer_types = ["hni_end_user", "nri_investor", "family_office", "founder_buyer", "investor"]
|
||||
statuses = ["qualified", "site_visit_scheduled", "site_visited", "negotiation", "booking_initiated", "contacted"]
|
||||
stages = ["qualified", "proposal", "site_visit", "negotiation", "booking"]
|
||||
urgencies = ["medium", "high", "critical"]
|
||||
project_names = list(PROJECTS.keys())
|
||||
expanded = list(seed_clients)
|
||||
|
||||
for index in range(len(seed_clients), target_count):
|
||||
first = first_names[index % len(first_names)]
|
||||
last = last_names[(index * 3) % len(last_names)]
|
||||
project_name = project_names[index % len(project_names)]
|
||||
project = PROJECTS[project_name]
|
||||
city = project["location"]["city"]
|
||||
is_uae = city in {"Dubai", "Abu Dhabi"}
|
||||
country = "UAE" if is_uae else "India"
|
||||
buyer_type = buyer_types[index % len(buyer_types)]
|
||||
urgency = urgencies[index % len(urgencies)]
|
||||
high_value_usd = 1_150_000 + (index % 9) * 425_000
|
||||
value = high_value_usd if is_uae else 82_000_000 + (index % 11) * 17_500_000
|
||||
budget_label = f"${high_value_usd / 1_000_000:.1f}-${(high_value_usd + 950_000) / 1_000_000:.1f}M" if is_uae else f"{int(value / 10_000_000)}-{int(value / 10_000_000) + 4} Cr"
|
||||
configuration = project["unit_mix"][0]["bedrooms"]
|
||||
unit_label = "Royal penthouse stack" if value >= (4_000_000 if is_uae else 180_000_000) else "High-floor signature residence"
|
||||
full_name = f"{first} {last}"
|
||||
key = re.sub(r"[^a-z0-9]+", "-", full_name.lower()).strip("-") + f"-{index:02d}"
|
||||
expanded.append(
|
||||
{
|
||||
"key": key,
|
||||
"name": full_name,
|
||||
"email": f"{key}@demo.desineuron.in",
|
||||
"phone": _phone_for(index, country),
|
||||
"buyer_type": buyer_type,
|
||||
"city": city,
|
||||
"nationality": "Emirati" if is_uae and index % 3 == 0 else "Indian",
|
||||
"persona": [buyer_type, "tier_1_developer_pitch", "high_value_pipeline"],
|
||||
"budget": budget_label,
|
||||
"urgency": urgency,
|
||||
"status": statuses[index % len(statuses)],
|
||||
"project": project_name,
|
||||
"configuration": f"{configuration}BR Signature Residence",
|
||||
"unit": unit_label,
|
||||
"budget_min": int(value * 0.88),
|
||||
"budget_max": int(value * 1.22),
|
||||
"stage": stages[index % len(stages)],
|
||||
"value": value,
|
||||
"probability": min(92, 48 + (index * 7) % 43),
|
||||
"next_action": f"Prepare developer-grade commercial deck for {project_name} and schedule executive walkthrough.",
|
||||
"scores": (
|
||||
round(0.68 + ((index * 7) % 28) / 100, 2),
|
||||
round(0.64 + ((index * 5) % 30) / 100, 2),
|
||||
round(0.62 + ((index * 11) % 35) / 100, 2),
|
||||
),
|
||||
}
|
||||
)
|
||||
return expanded
|
||||
|
||||
|
||||
DEMO_CLIENTS = _expand_demo_clients(DEMO_CLIENTS, DEMO_CLIENT_TARGET_COUNT)
|
||||
|
||||
|
||||
async def seed(conn: asyncpg.Connection, tenant_id: str, operator_user_id: str | None, dry_run: bool = False) -> dict[str, int]:
|
||||
now = datetime.now(timezone.utc)
|
||||
@@ -313,6 +515,7 @@ async def seed(conn: asyncpg.Connection, tenant_id: str, operator_user_id: str |
|
||||
"leads": 0,
|
||||
"projects": 0,
|
||||
"properties": 0,
|
||||
"property_media": 0,
|
||||
"interests": 0,
|
||||
"opportunities": 0,
|
||||
"scores": 0,
|
||||
@@ -320,6 +523,10 @@ async def seed(conn: asyncpg.Connection, tenant_id: str, operator_user_id: str |
|
||||
"edge_events": 0,
|
||||
"reminders": 0,
|
||||
"calendar_events": 0,
|
||||
"insight_recommendations": 0,
|
||||
"comms_threads": 0,
|
||||
"comms_messages": 0,
|
||||
"comms_call_logs": 0,
|
||||
"import_batches": 0,
|
||||
"import_proposals": 0,
|
||||
}
|
||||
@@ -327,7 +534,7 @@ async def seed(conn: asyncpg.Connection, tenant_id: str, operator_user_id: str |
|
||||
return counts
|
||||
|
||||
project_ids: dict[str, str] = {}
|
||||
for name, project in PROJECTS.items():
|
||||
for project_index, (name, project) in enumerate(PROJECTS.items()):
|
||||
project_id = _stable_uuid(tenant_id, f"project:{name}")
|
||||
project_ids[name] = project_id
|
||||
await conn.execute(
|
||||
@@ -336,8 +543,8 @@ async def seed(conn: asyncpg.Connection, tenant_id: str, operator_user_id: str |
|
||||
project_id, project_name, developer_name, city, micro_market, address,
|
||||
total_units, project_status, location_json, amenities_json, metadata_json
|
||||
) VALUES (
|
||||
$1::uuid, $2, $3, 'Kolkata', $4, $5, $6, 'active',
|
||||
$7::jsonb, $8::jsonb, $9::jsonb
|
||||
$1::uuid, $2, $3, $4, $5, $6, $7, 'active',
|
||||
$8::jsonb, $9::jsonb, $10::jsonb
|
||||
)
|
||||
ON CONFLICT (project_name) DO UPDATE SET
|
||||
developer_name = EXCLUDED.developer_name,
|
||||
@@ -353,6 +560,7 @@ async def seed(conn: asyncpg.Connection, tenant_id: str, operator_user_id: str |
|
||||
project_id,
|
||||
name,
|
||||
project["developer"],
|
||||
project["location"]["city"],
|
||||
project["micro_market"],
|
||||
project["address"],
|
||||
sum(item["count"] for item in project["unit_mix"]),
|
||||
@@ -399,6 +607,36 @@ async def seed(conn: asyncpg.Connection, tenant_id: str, operator_user_id: str |
|
||||
)
|
||||
counts["properties"] += 1
|
||||
|
||||
for media in _project_media_assets(name, project, project_index):
|
||||
media_asset_id = _stable_uuid(tenant_id, f"inventory-media:{media['key']}")
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO inventory_media_assets (
|
||||
media_asset_id, property_id, tenant_id, media_type, url,
|
||||
thumbnail_url, sort_order, metadata, uploaded_by, created_at
|
||||
) VALUES (
|
||||
$1::uuid, $2::uuid, $3, $4, $5, $6, $7, $8::jsonb, $9, NOW()
|
||||
)
|
||||
ON CONFLICT (media_asset_id) DO UPDATE SET
|
||||
media_type = EXCLUDED.media_type,
|
||||
url = EXCLUDED.url,
|
||||
thumbnail_url = EXCLUDED.thumbnail_url,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
metadata = inventory_media_assets.metadata || EXCLUDED.metadata,
|
||||
uploaded_by = EXCLUDED.uploaded_by
|
||||
""",
|
||||
media_asset_id,
|
||||
property_id,
|
||||
tenant_id,
|
||||
media["media_type"],
|
||||
media["url"],
|
||||
media["thumbnail_url"],
|
||||
media["sort_order"],
|
||||
_json(media["metadata"]),
|
||||
owner_user_ref,
|
||||
)
|
||||
counts["property_media"] += 1
|
||||
|
||||
for index, client in enumerate(DEMO_CLIENTS):
|
||||
person_id = _stable_uuid(tenant_id, f"person:{client['key']}")
|
||||
lead_id = _stable_uuid(tenant_id, f"lead:{client['key']}")
|
||||
@@ -707,6 +945,142 @@ async def seed(conn: asyncpg.Connection, tenant_id: str, operator_user_id: str |
|
||||
)
|
||||
counts["calendar_events"] += 1
|
||||
|
||||
recommendation_id = _stable_uuid(tenant_id, f"insight:{client['key']}")
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO insight_recommendations (
|
||||
recommendation_id, tenant_id, lead_id, source_event_id,
|
||||
recommendation_type, summary, suggested_action, target_system,
|
||||
status, confidence, created_at, updated_at
|
||||
) VALUES (
|
||||
$1::uuid, $2, $3, $4::uuid, $5, $6, $7, $8,
|
||||
'pending', $9, NOW() - ($10::int * INTERVAL '8 minutes'), NOW()
|
||||
)
|
||||
ON CONFLICT (recommendation_id) DO UPDATE SET
|
||||
source_event_id = EXCLUDED.source_event_id,
|
||||
recommendation_type = EXCLUDED.recommendation_type,
|
||||
summary = EXCLUDED.summary,
|
||||
suggested_action = EXCLUDED.suggested_action,
|
||||
target_system = EXCLUDED.target_system,
|
||||
status = 'pending',
|
||||
confidence = EXCLUDED.confidence,
|
||||
updated_at = NOW()
|
||||
""",
|
||||
recommendation_id,
|
||||
tenant_id,
|
||||
lead_id,
|
||||
edge_event_id,
|
||||
"schedule_meeting" if client["urgency"] in {"high", "critical"} else "send_property_info",
|
||||
f"{client['name']} is showing strong buying intent for {client['project']}.",
|
||||
client["next_action"],
|
||||
"calendar" if client["urgency"] in {"high", "critical"} else "whatsapp",
|
||||
min(0.98, float(client["scores"][0]) + 0.04),
|
||||
index,
|
||||
)
|
||||
counts["insight_recommendations"] += 1
|
||||
|
||||
thread_id = _stable_uuid(tenant_id, f"comms-thread:{client['key']}")
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO comms_threads (
|
||||
thread_id, provider, external_thread_id, person_id, phone_e164,
|
||||
display_name, channel, status, assigned_user_id, last_message_at,
|
||||
unread_count, metadata_json, created_at, updated_at
|
||||
) VALUES (
|
||||
$1::uuid, 'waha', $2, $3::uuid, $4, $5, 'whatsapp',
|
||||
'open', $6::uuid, $7, 1, $8::jsonb, NOW() - INTERVAL '3 days', NOW()
|
||||
)
|
||||
ON CONFLICT (thread_id) DO UPDATE SET
|
||||
person_id = EXCLUDED.person_id,
|
||||
phone_e164 = EXCLUDED.phone_e164,
|
||||
display_name = EXCLUDED.display_name,
|
||||
assigned_user_id = EXCLUDED.assigned_user_id,
|
||||
last_message_at = EXCLUDED.last_message_at,
|
||||
unread_count = EXCLUDED.unread_count,
|
||||
metadata_json = comms_threads.metadata_json || EXCLUDED.metadata_json,
|
||||
updated_at = NOW()
|
||||
""",
|
||||
thread_id,
|
||||
f"{SEED_SOURCE}:{client['key']}",
|
||||
person_id,
|
||||
client["phone"],
|
||||
client["name"],
|
||||
operator_user_id,
|
||||
now - timedelta(minutes=18 + index * 9),
|
||||
_json({"seed_source": SEED_SOURCE, "investor_demo": True, "project": client["project"]}),
|
||||
)
|
||||
counts["comms_threads"] += 1
|
||||
|
||||
message_bodies = [
|
||||
("inbound", f"Can you send the latest floor stack and payment plan for {client['project']}?"),
|
||||
("outbound", f"Sharing the executive deck now. I also reserved a walkthrough slot for {client['configuration']}."),
|
||||
("inbound", f"Please proceed. Budget is aligned around {client['budget']} if the view and handover schedule work."),
|
||||
]
|
||||
for message_index, (direction, body) in enumerate(message_bodies):
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO comms_messages (
|
||||
message_id, thread_id, provider, external_message_id, direction,
|
||||
message_type, body, delivery_status, sent_at, delivered_at,
|
||||
raw_payload, created_at
|
||||
) VALUES (
|
||||
$1::uuid, $2::uuid, 'waha', $3, $4, 'text', $5,
|
||||
'delivered', $6, $6, $7::jsonb, NOW()
|
||||
)
|
||||
ON CONFLICT (message_id) DO UPDATE SET
|
||||
body = EXCLUDED.body,
|
||||
delivery_status = EXCLUDED.delivery_status,
|
||||
sent_at = EXCLUDED.sent_at,
|
||||
delivered_at = EXCLUDED.delivered_at,
|
||||
raw_payload = EXCLUDED.raw_payload
|
||||
""",
|
||||
_stable_uuid(tenant_id, f"comms-message:{client['key']}:{message_index}"),
|
||||
thread_id,
|
||||
f"{SEED_SOURCE}:{client['key']}:{message_index}",
|
||||
direction,
|
||||
body,
|
||||
now - timedelta(minutes=46 - message_index * 14 + index * 3),
|
||||
_json({"seed_source": SEED_SOURCE, "investor_demo": True}),
|
||||
)
|
||||
counts["comms_messages"] += 1
|
||||
|
||||
call_id = _stable_uuid(tenant_id, f"comms-call:{client['key']}")
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO comms_call_logs (
|
||||
call_id, thread_id, person_id, provider, external_call_id,
|
||||
phone_e164, direction, status, started_at, ended_at,
|
||||
duration_seconds, recording_url, transcript_text, raw_payload,
|
||||
created_at
|
||||
) VALUES (
|
||||
$1::uuid, $2::uuid, $3::uuid, 'waha', $4, $5, 'outbound',
|
||||
'completed', $6, $7, $8, $9, $10, $11::jsonb, NOW()
|
||||
)
|
||||
ON CONFLICT (call_id) DO UPDATE SET
|
||||
thread_id = EXCLUDED.thread_id,
|
||||
person_id = EXCLUDED.person_id,
|
||||
status = EXCLUDED.status,
|
||||
started_at = EXCLUDED.started_at,
|
||||
ended_at = EXCLUDED.ended_at,
|
||||
duration_seconds = EXCLUDED.duration_seconds,
|
||||
recording_url = EXCLUDED.recording_url,
|
||||
transcript_text = EXCLUDED.transcript_text,
|
||||
raw_payload = EXCLUDED.raw_payload
|
||||
""",
|
||||
call_id,
|
||||
thread_id,
|
||||
person_id,
|
||||
f"{SEED_SOURCE}:call:{client['key']}",
|
||||
client["phone"],
|
||||
now - timedelta(hours=2 + index),
|
||||
now - timedelta(hours=2 + index) + timedelta(minutes=7, seconds=30),
|
||||
450,
|
||||
f"s3://velocity-demo-media/{SEED_SOURCE}/calls/{client['key']}.m4a",
|
||||
f"Discussed {client['project']}, {client['configuration']}, budget {client['budget']}, and next action: {client['next_action']}",
|
||||
_json({"seed_source": SEED_SOURCE, "investor_demo": True}),
|
||||
)
|
||||
counts["comms_call_logs"] += 1
|
||||
|
||||
batch_id = _stable_uuid(tenant_id, "workflow-import-batch:investor-demo")
|
||||
await conn.execute(
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user