Initial commit: Inner OS v1

Full-stack inner development operating system built on Next.js 16 + Prisma 7 + PostgreSQL + OpenAI + Clerk.
Generates personalized daily mental training tasks, collects reflection, updates user state, and provides internal reward feedback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jackyu66git
2026-05-20 12:11:27 +08:00
co-authored by Claude Opus 4.6
commit cef29d40bd
49 changed files with 4723 additions and 0 deletions
+191
View File
@@ -0,0 +1,191 @@
import OpenAI from "openai";
import { prisma } from "@/lib/prisma";
import { keywordCheck, llmSafetyCheck, type SafetyResult } from "@/lib/safety";
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
interface WeekData {
sessions: {
taskType: string;
taskDescription: string;
focusScore: number | null;
emotionScore: number | null;
notes: string | null;
durationSeconds: number;
createdAt: Date;
}[];
state: {
attentionLevel: number;
emotionStability: number;
stressLevel: number;
practiceStage: number;
consistencyScore: number;
streakDays: number;
totalSessionsCompleted: number;
};
}
interface GeneratedSummary {
summary: string;
safety: SafetyResult;
}
// ---------------------------------------------------------------------------
// LLM summary generation (LLM #3)
// ---------------------------------------------------------------------------
const SUMMARY_PROMPT = `You are a wise, warm inner development coach writing a weekly practice summary. Your tone is grounded, encouraging, and specific — never generic or saccharine.
You will receive data about the user's practice this week: sessions completed, task types, focus/emotion scores, reflections, and their current state metrics (attention, emotional stability, stress, consistency, streak, stage).
Write a 3-4 paragraph summary that:
1. Opens by acknowledging their commitment this week — be specific about what they practiced and how many sessions
2. Highlights patterns you notice: which types of practice led to better focus? Did their emotional awareness deepen? Were there difficult days they pushed through?
3. Notes changes in their state metrics from what you can infer — are they trending in a good direction?
4. Closes with gentle encouragement for the week ahead, grounded in what they've actually demonstrated (not empty motivation)
Voice rules:
- Be specific. Reference actual task types and patterns. "Your two attention training sessions showed stronger focus than your stress regulation work" is good. "Great job this week!" is not.
- Be honest. If it was a light week with only 1-2 sessions, acknowledge that without judgment.
- Never diagnose, never claim medical benefits, never use self-help clichés.
- Write in second person ("you").
- Keep it to 3-4 paragraphs, 200-300 words total.`;
export async function generateWeeklySummary(
userId: string,
openai: OpenAI
): Promise<GeneratedSummary> {
// Gather week data
const weekAgo = new Date();
weekAgo.setDate(weekAgo.getDate() - 7);
const [sessions, userState] = await Promise.all([
prisma.session.findMany({
where: {
userId,
createdAt: { gte: weekAgo },
completed: true,
},
orderBy: { createdAt: "asc" },
select: {
taskType: true,
taskDescription: true,
focusScore: true,
emotionScore: true,
notes: true,
durationSeconds: true,
createdAt: true,
},
}),
prisma.userState.findUnique({ where: { userId } }),
]);
if (!userState || sessions.length === 0) {
return {
summary:
"No completed practice sessions this week. Every week is a fresh start — your practice is here when you're ready.",
safety: { safe: true },
};
}
const weekData: WeekData = {
sessions,
state: {
attentionLevel: userState.attentionLevel,
emotionStability: userState.emotionStability,
stressLevel: userState.stressLevel,
practiceStage: userState.practiceStage,
consistencyScore: userState.consistencyScore,
streakDays: userState.streakDays,
totalSessionsCompleted: userState.totalSessionsCompleted,
},
};
try {
const response = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: SUMMARY_PROMPT },
{
role: "user",
content: JSON.stringify(weekData),
},
],
temperature: 0.7,
max_tokens: 500,
});
const summary = response.choices[0]?.message?.content?.trim();
if (!summary || summary.length < 50) throw new Error("Summary too short");
// Safety check
const keywordResult = keywordCheck(summary);
if (!keywordResult.safe) {
return { summary: "Your practice summary for this week.", safety: keywordResult };
}
const llmSafety = await llmSafetyCheck(summary, openai as any);
// Persist the summary (upsert — one per user per week)
const weekStart = new Date(weekAgo);
weekStart.setHours(0, 0, 0, 0);
await prisma.weeklySummary.upsert({
where: { userId },
create: {
userId,
summary: llmSafety.safe ? summary : "Your practice summary for this week.",
weekStart,
},
update: {
summary: llmSafety.safe ? summary : "Your practice summary for this week.",
weekStart,
},
});
return {
summary: llmSafety.safe ? summary : "Your practice summary for this week.",
safety: llmSafety,
};
} catch {
const fallback = `You completed ${sessions.length} practice session${sessions.length === 1 ? "" : "s"} this week. Showing up consistently is the foundation everything else is built on. Your current streak is ${userState.streakDays} day${userState.streakDays === 1 ? "" : "s"}. See you next week.`;
return { summary: fallback, safety: { safe: true } };
}
}
// ---------------------------------------------------------------------------
// Cron handler — generates summaries for all active users
// ---------------------------------------------------------------------------
export async function generateAllWeeklySummaries(
openai: OpenAI
): Promise<{ userId: string; success: boolean }[]> {
// Find users who had sessions in the last 7 days
const weekAgo = new Date();
weekAgo.setDate(weekAgo.getDate() - 7);
const activeUsers = await prisma.session.findMany({
where: {
createdAt: { gte: weekAgo },
completed: true,
},
select: { userId: true },
distinct: ["userId"],
});
const results: { userId: string; success: boolean }[] = [];
for (const { userId } of activeUsers) {
try {
await generateWeeklySummary(userId, openai);
results.push({ userId, success: true });
} catch {
results.push({ userId, success: false });
}
}
return results;
}