InnerVoice / backend /seed_data.py
E5K7's picture
feat: implement JWT auth and voice calibration onboarding
7004388
"""
Seed the database with 30 days of realistic mock data for demo mode.
Run: python seed_data.py
"""
import sys
import os
import uuid
import random
from datetime import datetime, timedelta
from dotenv import load_dotenv
load_dotenv()
sys.path.insert(0, os.path.dirname(__file__))
from models.database import init_db, SessionLocal, User, VoiceEntry, MoodAlert, ChatMessage
DEMO_USER_EMAIL = "demo@innervoice.app"
DEMO_USER_NAME = "Alex (Demo)"
EMOTIONS = ["happy", "neutral", "sad", "anxious", "fearful", "angry"]
EMOTION_WEIGHTS = [0.30, 0.28, 0.18, 0.12, 0.07, 0.05]
TRANSCRIPTIONS = {
"happy": [
"Today was actually really good. I feel like things are finally clicking into place and I'm excited about what's ahead.",
"I had a great time with friends this evening. Laughed a lot. Really needed that connection.",
"Finished a project I've been working on for weeks. Feels so satisfying to see it done.",
"Went for a long walk this morning and the sunshine just lifted everything. Feeling grateful.",
],
"neutral": [
"It's been a regular day. Nothing spectacular, nothing bad. Just steady.",
"Work was fine. Meetings ran long but got through it. Feeling okay overall.",
"Pretty normal Tuesday. Had lunch outside which was nice. Mostly just going through the motions.",
"No major feelings today. I'm present, just... existing. That's okay too.",
],
"sad": [
"I don't really know how to explain it. Just feel a heaviness today that I can't shake.",
"Missing some people today. Feeling a bit disconnected from everything.",
"Things feel harder than they should. I'm trying but motivation is low.",
"Cried a little this evening and I'm not even sure why. Just needed to let it out.",
],
"anxious": [
"My mind keeps racing about things I can't control. Hard to focus on the present.",
"Feeling that familiar chest tightness again. Too many things on my plate.",
"The week ahead feels overwhelming. I'm trying to take it one thing at a time.",
"Lots of uncertainty right now and my nervous system is definitely feeling it.",
],
"fearful": [
"Something doesn't feel right but I can't name it. Just uneasy.",
"Woke up with a sense of dread this morning. Trying to ground myself.",
"Scared about some changes happening in my life. Trying to trust the process.",
],
"angry": [
"Really frustrated today. Feel like I'm not being heard or seen.",
"Had a tense situation at work. Hard not to carry that home.",
"Some things happened today that felt unfair and I'm still processing the anger.",
],
}
def generate_entry(user_id: str, days_ago: int) -> VoiceEntry:
# Generate a realistic mood arc (dip in middle, recovery)
progress = days_ago / 30.0 # 0 = most recent, 1 = oldest
base_mood_shift = int(20 * (0.5 - abs(progress - 0.6))) # dip 18 days ago
emotion = random.choices(EMOTIONS, weights=EMOTION_WEIGHTS)[0]
confidence = round(random.uniform(0.60, 0.95), 3)
from services.mood_calculator import calculate_mood_scores
pitch_mean = random.uniform(100, 200)
pitch_std = random.uniform(10, 60)
energy = random.uniform(0.005, 0.04)
tempo = random.uniform(60, 120)
avg_pause = random.uniform(0.1, 0.8)
filler_rate = random.uniform(0.01, 0.08)
scores = calculate_mood_scores(
emotion=emotion,
confidence=confidence,
pitch_mean=pitch_mean,
pitch_std=pitch_std,
energy=energy,
tempo=tempo,
avg_pause=avg_pause,
filler_rate=filler_rate,
)
# Apply arc shift
for key in scores:
scores[key] = max(0, min(100, scores[key] + base_mood_shift + random.randint(-5, 5)))
transcription_options = TRANSCRIPTIONS.get(emotion, TRANSCRIPTIONS["neutral"])
transcription = random.choice(transcription_options)
created_at = datetime.utcnow() - timedelta(days=days_ago, hours=random.randint(6, 22))
return VoiceEntry(
id=str(uuid.uuid4()),
user_id=user_id,
created_at=created_at,
audio_url=None,
duration_seconds=round(random.uniform(30, 65), 1),
transcription=transcription,
primary_emotion=emotion,
emotion_confidence=confidence,
energy_score=scores["energy"],
calmness_score=scores["calmness"],
mood_score=scores["mood"],
clarity_score=scores["clarity"],
pitch_mean=round(pitch_mean, 2),
pitch_std=round(pitch_std, 2),
energy_raw=round(energy, 6),
speech_rate=round(tempo, 2),
pause_count=random.randint(2, 15),
avg_pause_duration=round(avg_pause, 3),
filler_rate=round(filler_rate, 4),
mfcc_features=[round(random.uniform(-50, 50), 2) for _ in range(13)],
)
def seed():
init_db()
db = SessionLocal()
try:
# Create or get demo user
user = db.query(User).filter(User.email == DEMO_USER_EMAIL).first()
if not user:
from routes.auth import get_password_hash
hashed_pwd = get_password_hash("password")
user = User(
id=str(uuid.uuid4()),
email=DEMO_USER_EMAIL,
name=DEMO_USER_NAME,
password_hash=hashed_pwd,
baseline_pitch=150.0,
baseline_energy=0.03,
baseline_speech_rate=100.0,
)
db.add(user)
db.commit()
db.refresh(user)
print(f"[Seed] Created demo user: {user.id}")
else:
print(f"[Seed] Demo user exists: {user.id}")
# Clear old entries
db.query(VoiceEntry).filter(VoiceEntry.user_id == user.id).delete()
db.query(MoodAlert).filter(MoodAlert.user_id == user.id).delete()
db.query(ChatMessage).filter(ChatMessage.user_id == user.id).delete()
db.commit()
# Generate 30 days of entries (skip ~20% of days for realism)
entries = []
for days_ago in range(30, 0, -1):
if random.random() < 0.80: # 80% check-in rate
entry = generate_entry(user.id, days_ago)
db.add(entry)
entries.append(entry)
db.commit()
print(f"[Seed] Created {len(entries)} voice entries.")
# Create sample alerts
alerts = [
MoodAlert(
id=str(uuid.uuid4()),
user_id=user.id,
created_at=datetime.utcnow() - timedelta(days=2),
alert_type="mood_decline",
severity="warning",
message="Your mood has declined 24% this week compared to last week.",
suggested_action="Try scheduling something enjoyable today, even something small.",
is_read=False,
),
MoodAlert(
id=str(uuid.uuid4()),
user_id=user.id,
created_at=datetime.utcnow() - timedelta(days=1),
alert_type="low_energy",
severity="concern",
message="Your energy has been consistently low for the past 5 days.",
suggested_action="Even a 10-minute walk can shift your energy. Try it today.",
is_read=False,
),
]
for alert in alerts:
db.add(alert)
# Create sample chat messages
chats = [
ChatMessage(
id=str(uuid.uuid4()),
user_id=user.id,
created_at=datetime.utcnow() - timedelta(hours=3),
role="user",
content="I'm fine, just tired.",
),
ChatMessage(
id=str(uuid.uuid4()),
user_id=user.id,
created_at=datetime.utcnow() - timedelta(hours=3, seconds=-5),
role="assistant",
content="I hear you — and 'tired' can mean so many things. Your voice this week has been a little lower in energy than usual. Is there something specific weighing on you, or is it more of a general fatigue?",
),
ChatMessage(
id=str(uuid.uuid4()),
user_id=user.id,
created_at=datetime.utcnow() - timedelta(hours=2),
role="user",
content="Why have I been feeling off lately?",
),
ChatMessage(
id=str(uuid.uuid4()),
user_id=user.id,
created_at=datetime.utcnow() - timedelta(hours=2, seconds=-5),
role="assistant",
content="Looking at your last two weeks, your mood started dipping around 18 days ago and your energy has been below your baseline since then. That sometimes happens during seasonal changes or when routines get disrupted. Does anything stand out from around that time?",
),
]
for chat in chats:
db.add(chat)
db.commit()
print(f"[Seed] Created {len(alerts)} alerts and {len(chats)} chat messages.")
print(f"[Seed] Demo user ID: {user.id}")
print(f"[Seed] Seeding complete ✓")
return user.id
finally:
db.close()
if __name__ == "__main__":
user_id = seed()
print(f"\nDemo user ID: {user_id}")
print("Use this ID in Demo Mode or set NEXT_PUBLIC_DEMO_USER_ID in frontend/.env.local")