pdf-quiz-generator/backend/app/services/reminder_service.py
Daniel 47ba213ae3 Major platform update: pgvector search, multi-provider TTS, settings page, CLI
Features:
- Hybrid semantic + keyword quiz search (pgvector HNSW + PostgreSQL ILIKE)
- AWS Bedrock Titan Embed V2 embeddings via LiteLLM proxy (0.71 cosine sim)
- Multi-provider TTS: OpenAI, AWS Polly (neural), ElevenLabs, Google Cloud TTS
- Unified Settings page (profile, theme, Nextcloud integration, admin shortcuts)
- Good morning/afternoon greeting on dashboard
- manage.py CLI: reset-password, list-users, reembed
- Email verification enforced: register no longer returns JWT for unverified users
- Quiz search with debounced input, semantic/keyword/title modes, highlighted snippets
- TTS button: loading/playing states, voice selector locked during playback
- TTS auto-stops when navigating between questions
- Footer added; mobile quiz nav overflow fixed; markdown theme body selector fixed
- OpenAI Alloy as default TTS voice; favicon added
- SMTP configured via smtp2go; password reset rate limiting (3/hour)
- PostgreSQL upgraded to pgvector/pgvector:pg16

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 18:03:10 +02:00

61 lines
1.9 KiB
Python

from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from app.models.reminder import ReminderSchedule
# SM-2 simplified intervals in days
INTERVALS = [1, 3, 7, 14, 30]
def update_reminder_schedule(
db: Session,
user_id: int,
quiz_id: int,
score_percentage: float,
):
"""Update or create a reminder schedule based on quiz performance."""
reminder = db.query(ReminderSchedule).filter(
ReminderSchedule.user_id == user_id,
ReminderSchedule.quiz_id == quiz_id,
).first()
if not reminder:
reminder = ReminderSchedule(
user_id=user_id,
quiz_id=quiz_id,
performance_score=score_percentage,
interval_days=INTERVALS[0],
next_reminder_at=datetime.utcnow() + timedelta(days=INTERVALS[0]),
is_active=True,
)
db.add(reminder)
else:
reminder.performance_score = score_percentage
reminder.is_active = True
# Find current interval index
current_idx = 0
for i, interval in enumerate(INTERVALS):
if reminder.interval_days <= interval:
current_idx = i
break
if score_percentage < 75:
# Below threshold: reset to shortest interval
new_idx = 0
elif score_percentage < 90:
# Decent performance: advance one step
new_idx = min(current_idx + 1, len(INTERVALS) - 1)
else:
# Excellent performance: advance or deactivate
if current_idx >= len(INTERVALS) - 1:
reminder.is_active = False
db.commit()
return
new_idx = min(current_idx + 2, len(INTERVALS) - 1)
reminder.interval_days = INTERVALS[new_idx]
reminder.next_reminder_at = datetime.utcnow() + timedelta(days=INTERVALS[new_idx])
db.commit()