Files
gogo-telefon/gogo/seed.py
Senad Uka 0d0838e6e2 M2: agent logic in text mode
- LLMProvider interface: AnthropicLLM + ScriptedLLM test fake
- System prompt composition from super-admin template + structured tenant
  data only (§6.3); auto-generated greetings with recording disclosure,
  out-of-hours variant, chat variant
- Agent tools (§6.5): get_salon_info, check_availability (≤8 slots to model,
  agent offers ≤3), submit_booking_request (caller-ID fallback, hallucinated
  service-id guard), take_message
- Conversation loop with tool dispatch, round-limit guard, transcript capture,
  outcome classification (request_created/message_taken/info_only/abandoned)
- Terminal playground (python -m gogo.agent.cli) + demo seed (python -m gogo.seed)
- Deterministic loop tests (ScriptedLLM) + Appendix A golden-scenario
  acceptance tests against a real LLM (skipped without an API key)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 09:53:08 +02:00

118 lines
3.8 KiB
Python

"""Seed demo data: the fictional 'Salon Merima' (Appendix A) + super-admin.
Usage: python -m gogo.seed [--partner]
"""
from __future__ import annotations
import asyncio
import sys
from sqlalchemy import select
from gogo.crypto import encrypt
from gogo.db import Base, get_engine, get_sessionmaker
from gogo.models import Admin, ProviderConfig, Service, Tenant, User
def hash_password(plain: str) -> str:
import bcrypt
return bcrypt.hashpw(plain.encode(), bcrypt.gensalt()).decode()
MERIMA_HOURS = {
"mon": [["09:00", "18:00"]],
"tue": [["09:00", "18:00"]],
"wed": [["09:00", "18:00"]],
"thu": [["09:00", "18:00"]],
"fri": [["09:00", "18:00"]],
"sat": [["09:00", "14:00"]],
"sun": [],
}
MERIMA_SERVICES = [
# name, duration, price_min, price_max, home_visit, note
("Šišanje i feniranje", 45, 25, 35, False, ""),
("Farbanje cijele dužine", 90, 60, 90, False, "cijena zavisi od dužine kose"),
("Pramenovi", 120, 80, 120, False, ""),
("Keratinski tretman", 90, 70, 100, False, "za oštećenu kosu"),
("Dubinska njega", 45, 30, 40, False, "za oštećenu kosu"),
("Manikir", 45, 20, 25, False, ""),
("Gel nokti", 90, 50, 70, False, ""),
("Pedikir", 60, 30, 30, True, "moguć dolazak na kućnu adresu"),
("Depilacija nogu", 30, 15, 20, False, ""),
]
async def seed(partner: bool = False) -> None:
engine = get_engine()
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async with get_sessionmaker()() as session:
existing = (
await session.execute(select(Tenant).where(Tenant.slug == "salon-merima"))
).scalar_one_or_none()
if existing:
print("salon-merima already seeded")
return
tenant = Tenant(
name="Salon Merima",
slug="salon-merima",
address="Ulica Veselina Masleše 12",
city="Banja Luka",
phone="+38751123456",
working_hours=MERIMA_HOURS,
scheduling_provider="partner_api" if partner else "mock",
notify_emails=["vlasnica@salon-merima.ba"],
agent_notes="Parking iza zgrade. Ne primamo djecu ispod 7 godina.",
price_mode="range",
)
session.add(tenant)
await session.flush()
for name, dur, pmin, pmax, home, note in MERIMA_SERVICES:
session.add(
Service(
tenant_id=tenant.id, name=name, duration_min=dur,
price_min=pmin, price_max=pmax, home_visit=home, agent_note=note,
)
)
if partner:
session.add(
ProviderConfig(
tenant_id=tenant.id,
provider_type="partner_api",
config={
"base_url": "http://localhost:9100",
"api_key_encrypted": encrypt("test-partner-key"),
"webhook_secret_encrypted": encrypt("test-webhook-secret"),
"catalog_sync": False,
"email_to_owner": True,
"polling_fallback": False,
},
)
)
session.add(
User(
tenant_id=tenant.id,
email="vlasnica@salon-merima.ba",
password_hash=hash_password("merima123"),
)
)
session.add(
Admin(email="admin@gogotelefon.ba", password_hash=hash_password("admin123"))
)
await session.commit()
print(f"seeded tenant {tenant.slug} ({tenant.id})")
print("owner login: vlasnica@salon-merima.ba / merima123")
print("super-admin: admin@gogotelefon.ba / admin123")
if __name__ == "__main__":
asyncio.run(seed(partner="--partner" in sys.argv))