Spaces:
Sleeping
Sleeping
| // DistractIQ deterministic prediction engine | |
| // Implements the spec formulas exactly. | |
| export interface FocusInputs { | |
| study_hours: number; | |
| phone_hours: number; | |
| social_hours: number; | |
| sleep_hours: number; | |
| stress_level: number; // 1-10 | |
| notifications: number; | |
| } | |
| export interface FocusOutputs { | |
| distraction_score: number; | |
| productivity: number; | |
| focus_score: number; | |
| risk: "HIGH" | "LOW"; | |
| risk_reasons: string[]; | |
| xp_gained: number; | |
| deep_focus_hours: number; | |
| advisories: string[]; | |
| persona: { title: string; caption: string; emoji: string }; | |
| } | |
| const clamp = (v: number, min: number, max: number) => Math.max(min, Math.min(max, v)); | |
| export function computeDistraction(i: FocusInputs): number { | |
| const raw = i.phone_hours * 8 + i.social_hours * 12 + i.notifications / 10 + i.stress_level * 5; | |
| return Math.round(clamp(raw, 0, 100)); | |
| } | |
| export function computeProductivity(i: FocusInputs): number { | |
| const raw = i.study_hours * 15 + i.sleep_hours * 5 - (i.phone_hours * 4 + i.social_hours * 6 + i.stress_level * 8) + 30; | |
| return Math.round(clamp(raw, 0, 100)); | |
| } | |
| export function computeFocusScore(distraction: number, productivity: number): number { | |
| // Half-doughnut: invert distraction, weight productivity | |
| return Math.round(clamp(productivity * 0.6 + (100 - distraction) * 0.4, 0, 100)); | |
| } | |
| export function computeRisk(i: FocusInputs, distraction: number): { risk: "HIGH" | "LOW"; reasons: string[] } { | |
| const reasons: string[] = []; | |
| if (i.phone_hours > 6 && i.study_hours < 3) reasons.push("Phone use exceeds 6h with under 3h of study"); | |
| if (i.social_hours > 4) reasons.push("Social media exceeds 4h"); | |
| if (i.stress_level > 8 && i.sleep_hours < 5) reasons.push("High stress combined with sleep deprivation"); | |
| if (distraction > 65) reasons.push("Distraction Score above critical threshold (65)"); | |
| return { risk: reasons.length > 0 ? "HIGH" : "LOW", reasons }; | |
| } | |
| export function computeAdvisories(i: FocusInputs): string[] { | |
| const out: string[] = []; | |
| if (i.stress_level > 7) out.push("Stress is blocking your deep work capacity."); | |
| if (i.sleep_hours < 6) out.push("Sleep deprivation is a hidden productivity killer."); | |
| if (i.notifications > 150) out.push("Your notification density is triggering severe context-switching."); | |
| if (i.phone_hours > 6) out.push("Excessive phone time is fragmenting your attention."); | |
| if (i.social_hours > 4) out.push("Social media is the leading cause of dopamine loops today."); | |
| return out; | |
| } | |
| export function derivePersona(focus: number, productivity: number, distraction: number): { title: string; caption: string; emoji: string } { | |
| if (focus >= 80) return { title: "Deep Work Ninja", emoji: "🥷", caption: "Silent. Focused. Untouchable. You operate in flow others only read about." }; | |
| if (focus >= 65) return { title: "Momentum Maker", emoji: "🚀", caption: "Solid rhythm — protect your peak hours and you'll hit elite tier." }; | |
| if (productivity >= 50 && distraction < 50) return { title: "Balanced Builder", emoji: "⚖️", caption: "You're stitching focus and rest together — keep refining the edges." }; | |
| if (distraction >= 70) return { title: "Scroll Hostage", emoji: "🪤", caption: "The feed is winning. Time to reclaim the next 25 minutes." }; | |
| if (productivity < 35) return { title: "Drift Mode", emoji: "🌫️", caption: "Low signal day. One small block of deep work resets the whole week." }; | |
| return { title: "Focus Apprentice", emoji: "🎯", caption: "Building the habit. Small, repeatable wins compound fast." }; | |
| } | |
| export function computeAll(i: FocusInputs): FocusOutputs { | |
| const distraction = computeDistraction(i); | |
| const productivity = computeProductivity(i); | |
| const focus = computeFocusScore(distraction, productivity); | |
| const { risk, reasons } = computeRisk(i, distraction); | |
| const xp = Math.max(0, Math.round(productivity / 3)); | |
| return { | |
| distraction_score: distraction, | |
| productivity, | |
| focus_score: focus, | |
| risk, | |
| risk_reasons: reasons, | |
| xp_gained: xp, | |
| deep_focus_hours: Math.round(i.study_hours * (productivity / 100) * 10) / 10, | |
| advisories: computeAdvisories(i), | |
| persona: derivePersona(focus, productivity, distraction), | |
| }; | |
| } | |
| // Constraint validation | |
| export function validateConstraints(i: FocusInputs): string[] { | |
| const errors: string[] = []; | |
| if (i.study_hours + i.phone_hours + i.sleep_hours > 24) { | |
| errors.push("Study + Phone + Sleep cannot exceed 24 hours."); | |
| } | |
| if (i.social_hours > i.phone_hours) { | |
| errors.push("Social media hours cannot exceed total phone hours."); | |
| } | |
| return errors; | |
| } | |
| // XP / level helpers | |
| export const XP_PER_LEVEL = 500; | |
| export const levelFromXp = (xp: number) => Math.floor(xp / XP_PER_LEVEL) + 1; | |
| export const xpInLevel = (xp: number) => xp % XP_PER_LEVEL; | |
| export function isNightMode(): boolean { | |
| const hour = new Date().getHours(); | |
| return hour >= 22 || hour < 5; | |
| } | |