Initial commit: VoIdeaAI - voice-first AI idea assistant
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
"""Seed data for VoIdeaAI.
|
||||
|
||||
Called from app lifespan when DB tables are empty.
|
||||
Creates default tariff plans and sets system owner by email.
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.models.agent import AgentConfig
|
||||
from app.models.tariff import TariffPlan
|
||||
from app.services.user_service import UserService
|
||||
|
||||
settings = get_settings()
|
||||
|
||||
_AGENT_VERSIONS_FILE = Path(__file__).resolve().parent.parent.parent / "AGENT_VERSIONS.json"
|
||||
|
||||
|
||||
def _load_agent_versions() -> dict[str, str]:
|
||||
try:
|
||||
return json.loads(_AGENT_VERSIONS_FILE.read_text(encoding="utf-8"))
|
||||
except (FileNotFoundError, json.JSONDecodeError, OSError):
|
||||
return {}
|
||||
|
||||
|
||||
AGENT_DESCRIPTIONS: dict[str, str] = {
|
||||
"conductor": "Дирижёр — оркестратор, единственная точка входа. Маршрутизирует запросы к ролевым агентам, верифицирует ответы.",
|
||||
"business_analyst": "Бизнес-аналитик — оценивает бизнес-метрики, ROI, конкурентную среду, окупаемость идеи.",
|
||||
"task_organizer": "Организатор задач — разбивает идею на конкретные шаги реализации с оценкой сроков.",
|
||||
"lawyer": "Юрист — проверяет идею на соответствие законодательству РФ (44-ФЗ, 152-ФЗ, 223-ФЗ).",
|
||||
"financial_consultant": "Финансовый консультант — бюджет, прогноз выручки, точка безубыточности.",
|
||||
"solution_architect": "Архитектор решений — предлагает 2 варианта архитектуры: монолит и микросервисы.",
|
||||
"tester": "Тестировщик — описывает сценарии тестирования (позитивные и негативные кейсы).",
|
||||
"ui_designer": "UI-дизайнер — предлагает 2 варианта визуального дизайна интерфейса.",
|
||||
"smm_specialist": "SMM-специалист — разрабатывает контент-план для соцсетей.",
|
||||
"life_coach": "Лайф-коуч — ставит SMART-цели, поквартальные вехи развития.",
|
||||
"accessibility_expert": "Эксперт по доступности — проверяет на WCAG 2.1 AA соответствие.",
|
||||
"critic": "Критик — конструктивная критика, поиск «слепых зон» идеи.",
|
||||
"copywriter": "Копирайтер — упаковывает идею в продающий текст для разных аудиторий.",
|
||||
"keeper": "Хранитель — сохраняет проработанную идею в базу данных.",
|
||||
"doc_agent": "DocAgent — автоматическая генерация и обновление документации.",
|
||||
"backlog_agent": "BacklogAgent — управление бэклогом, приоритизация задач.",
|
||||
"spec_agent": "SpecAgent — написание формальных спецификаций и требований.",
|
||||
"audit_agent": "AuditAgent — аудит кода, архитектуры, безопасности.",
|
||||
"observer_agent": "ObserverAgent — мониторинг системы, сбор метрик, алерты.",
|
||||
"evolution_agent": "EvolutionAgent — автоматическое улучшение кода, рефакторинг.",
|
||||
"security_agent": "SecurityAgent — проверка безопасности, уязвимости, OWASP.",
|
||||
"qa_tester_agent": "QATesterAgent — автоматизированное тестирование, регресс.",
|
||||
"fix_agent": "FixAgent — автоматическое исправление ошибок на основе логов.",
|
||||
"ui_test_agent": "UITestAgent — тестирование UI/UX, скриншотные тесты.",
|
||||
"rollout_agent": "RolloutAgent — управление релизами, миграции, откаты.",
|
||||
}
|
||||
|
||||
|
||||
async def seed_database(db: AsyncSession) -> None:
|
||||
"""Seed initial data if tables are empty."""
|
||||
await _seed_tariff_plans(db)
|
||||
await _seed_agent_descriptions(db)
|
||||
await _seed_owner(db)
|
||||
|
||||
|
||||
async def _seed_tariff_plans(db: AsyncSession) -> None:
|
||||
"""Create default Free tariff plan if none exist."""
|
||||
result = await db.execute(select(TariffPlan).limit(1))
|
||||
if result.scalar_one_or_none():
|
||||
return
|
||||
|
||||
free_plan = TariffPlan(
|
||||
name="Бесплатно",
|
||||
code="free",
|
||||
description="Базовый доступ ко всем функциям. Сейчас всё бесплатно 🎉",
|
||||
price_monthly=0,
|
||||
features={
|
||||
"limit_ideas": None,
|
||||
"limit_sessions_per_day": None,
|
||||
"limit_agents": None,
|
||||
"limit_team_members": None,
|
||||
"limit_storage_mb": 100,
|
||||
"has_voice": True,
|
||||
"has_voice_commands": True,
|
||||
"has_drive": True,
|
||||
"has_advanced_analytics": True,
|
||||
"has_api_access": True,
|
||||
"has_priority_support": True,
|
||||
"has_custom_branding": True,
|
||||
"_promo": True,
|
||||
},
|
||||
is_active=True,
|
||||
sort_order=0,
|
||||
)
|
||||
db.add(free_plan)
|
||||
await db.commit()
|
||||
|
||||
|
||||
async def _seed_agent_descriptions(db: AsyncSession) -> None:
|
||||
"""Fill empty agent descriptions and update versions from AGENT_VERSIONS.json."""
|
||||
agent_versions = _load_agent_versions()
|
||||
result = await db.execute(select(AgentConfig))
|
||||
agents = result.scalars().all()
|
||||
updated = False
|
||||
for agent in agents:
|
||||
name = agent.agent_name.lower()
|
||||
if name in AGENT_DESCRIPTIONS and (not agent.description or agent.description == ""):
|
||||
agent.description = AGENT_DESCRIPTIONS[name]
|
||||
updated = True
|
||||
|
||||
name_lower = agent.agent_name.lower()
|
||||
expected_version = agent_versions.get(name_lower) or agent_versions.get(agent.agent_name)
|
||||
if expected_version and agent.version != expected_version:
|
||||
agent.version = expected_version
|
||||
updated = True
|
||||
|
||||
if updated:
|
||||
await db.commit()
|
||||
|
||||
|
||||
async def _seed_owner(db: AsyncSession) -> None:
|
||||
"""Set system owner by SYSTEM_OWNER_EMAIL if configured."""
|
||||
if not settings.system_owner_email:
|
||||
return
|
||||
svc = UserService(db)
|
||||
await svc.set_owner_by_email(settings.system_owner_email)
|
||||
Reference in New Issue
Block a user