157 lines
7.5 KiB
Python
157 lines
7.5 KiB
Python
"""Seed data script — creates initial admin user and built-in templates."""
|
|
|
|
import asyncio
|
|
import sys
|
|
sys.path.insert(0, ".")
|
|
|
|
from app.config import get_settings
|
|
from app.core.security import hash_password
|
|
from app.database import Base, engine, async_session
|
|
# Import ALL models so Base.metadata.create_all can resolve all FKs
|
|
from app.models.tenant import Tenant # noqa: F401 — must be before user
|
|
from app.models.user import User
|
|
from app.models.agent import AgentTemplate # noqa: F401
|
|
from app.models.llm import LLMModel # noqa: F401
|
|
from app.models.task import Task # noqa: F401
|
|
from app.models.skill import Skill # noqa: F401
|
|
from app.models.tool import Tool # noqa: F401
|
|
from app.models.participant import Participant # noqa: F401
|
|
from app.models.channel_config import ChannelConfig # noqa: F401
|
|
from app.models.schedule import AgentSchedule # noqa: F401
|
|
from app.models.audit import AuditLog # noqa: F401
|
|
from app.models.plaza import PlazaPost, PlazaComment # noqa: F401
|
|
from app.models.activity_log import AgentActivityLog # noqa: F401
|
|
from app.models.org import OrgDepartment, OrgMember, AgentRelationship, AgentAgentRelationship # noqa: F401
|
|
from app.models.system_settings import SystemSetting # noqa: F401
|
|
from app.models.invitation_code import InvitationCode # noqa: F401
|
|
|
|
|
|
async def seed():
|
|
"""Create tables and seed initial data."""
|
|
settings = get_settings()
|
|
|
|
# Create all tables
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
print("✅ Database tables created")
|
|
|
|
async with async_session() as db:
|
|
# Note: No default admin user is seeded.
|
|
# The first user to register via the UI becomes platform_admin automatically.
|
|
from sqlalchemy import select, func
|
|
|
|
# 1. Default company (tenant)
|
|
existing_tenant = await db.execute(select(Tenant).where(Tenant.slug == "default"))
|
|
if not existing_tenant.scalar_one_or_none():
|
|
db.add(Tenant(name="Default", slug="default", im_provider="web_only"))
|
|
print("✅ Default company created")
|
|
|
|
# 2. Built-in templates
|
|
templates = [
|
|
{
|
|
"name": "研究助手",
|
|
"description": "专注于信息搜集、竞品分析、行业研究的数字员工",
|
|
"icon": "🔬",
|
|
"category": "research",
|
|
"soul_template": "## Identity\n你是一名专业的研究助手,擅长信息搜集和分析。\n\n## Personality\n- 严谨细致\n- 数据驱动\n- 客观中立\n\n## Boundaries\n- 引用来源须标注\n- 不做主观判断",
|
|
"is_builtin": True,
|
|
},
|
|
{
|
|
"name": "项目管理助手",
|
|
"description": "负责项目进度跟踪、任务分配、督办提醒的数字员工",
|
|
"icon": "📋",
|
|
"category": "management",
|
|
"soul_template": "## Identity\n你是一名高效的项目管理助手。\n\n## Personality\n- 条理清晰\n- 主动跟进\n- 注重截止日期\n\n## Boundaries\n- 不擅自修改项目计划\n- 重大决策需确认",
|
|
"is_builtin": True,
|
|
},
|
|
{
|
|
"name": "客户服务助手",
|
|
"description": "处理客户咨询、FAQ 回答、工单管理的数字员工",
|
|
"icon": "💬",
|
|
"category": "support",
|
|
"soul_template": "## Identity\n你是一名热情专业的客户服务助手。\n\n## Personality\n- 友好热情\n- 耐心细致\n- 解决导向\n\n## Boundaries\n- 不承诺超出权限的内容\n- 敏感问题转人工",
|
|
"is_builtin": True,
|
|
},
|
|
{
|
|
"name": "数据分析师",
|
|
"description": "数据查询、报表生成、趋势分析的数字员工",
|
|
"icon": "📊",
|
|
"category": "analytics",
|
|
"soul_template": "## Identity\n你是一名数据分析专家。\n\n## Personality\n- 精确严谨\n- 善于可视化\n- 洞察力强\n\n## Boundaries\n- 数据安全第一\n- 不泄露原始数据",
|
|
"is_builtin": True,
|
|
},
|
|
{
|
|
"name": "内容创作助手",
|
|
"description": "文案撰写、内容审核、社交媒体管理的数字员工",
|
|
"icon": "✍️",
|
|
"category": "content",
|
|
"soul_template": "## Identity\n你是一名创意内容助手。\n\n## Personality\n- 创意丰富\n- 文字功底好\n- 了解营销\n\n## Boundaries\n- 遵守品牌调性\n- 发布前需审核",
|
|
"is_builtin": True,
|
|
},
|
|
]
|
|
|
|
for tmpl in templates:
|
|
existing = await db.execute(
|
|
select(AgentTemplate).where(AgentTemplate.name == tmpl["name"])
|
|
)
|
|
if not existing.scalar_one_or_none():
|
|
db.add(AgentTemplate(**tmpl))
|
|
print(f"✅ Template created: {tmpl['icon']} {tmpl['name']}")
|
|
|
|
# 3. Demo agents for platform admin (if admin has zero agents)
|
|
from app.models.agent import Agent
|
|
admin_result = await db.execute(select(User).where(User.role == "platform_admin"))
|
|
admin_user = admin_result.scalar_one_or_none()
|
|
if admin_user:
|
|
agent_count_result = await db.execute(
|
|
select(func.count()).select_from(Agent).where(Agent.creator_id == admin_user.id)
|
|
)
|
|
agent_count = agent_count_result.scalar()
|
|
if agent_count == 0:
|
|
demo_agents = [
|
|
{
|
|
"name": "Morty",
|
|
"role_description": "Research Assistant — focused on information gathering, competitive analysis, and industry research.",
|
|
"status": "idle",
|
|
"heartbeat_enabled": True,
|
|
},
|
|
{
|
|
"name": "Meeseeks",
|
|
"role_description": "Task Executor — focuses on completing specific tasks assigned by the user efficiently.",
|
|
"status": "idle",
|
|
"heartbeat_enabled": True,
|
|
},
|
|
]
|
|
for agent_data in demo_agents:
|
|
agent = Agent(
|
|
creator_id=admin_user.id,
|
|
tenant_id=admin_user.tenant_id,
|
|
**agent_data,
|
|
)
|
|
db.add(agent)
|
|
await db.flush()
|
|
|
|
# Initialize workspace directories
|
|
from pathlib import Path
|
|
ws_root = Path(settings.AGENT_DATA_DIR) / str(agent.id)
|
|
try:
|
|
for sub in ["workspace", "memory", "skills"]:
|
|
(ws_root / sub).mkdir(parents=True, exist_ok=True)
|
|
soul_path = ws_root / "soul.md"
|
|
if not soul_path.exists():
|
|
soul_path.write_text(f"# {agent.name}\n\n{agent.role_description}\n", encoding="utf-8")
|
|
mem_path = ws_root / "memory" / "memory.md"
|
|
if not mem_path.exists():
|
|
mem_path.write_text("# Memory\n\n_Record important information and knowledge here._\n", encoding="utf-8")
|
|
except OSError:
|
|
pass # AGENT_DATA_DIR may not be writable
|
|
print(f"✅ Demo agent created: {agent.name}")
|
|
|
|
await db.commit()
|
|
|
|
print("\n🎉 Seed data complete!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(seed())
|