@@ -509,6 +517,123 @@ routes.get("/", (c) => {
}));
});
+// ── Meeting Intelligence knowledge page ──
+
+routes.get("/meeting-intelligence", async (c) => {
+ const space = c.req.param("space") || "demo";
+ const base = `/${escapeHtml(space)}/rmeets`;
+ const prefix = encodeURIComponent(space + "_");
+
+ // Fetch space-scoped meetings from MI API
+ const result = await miApiFetch(`/meetings?limit=50&sort=-created_at&conference_prefix=${prefix}`);
+
+ let meetingCards = "";
+ let aggregateHtml = "";
+
+ if (!result.ok) {
+ meetingCards = miUnavailableHtml();
+ } else {
+ const meetings = Array.isArray(result.data) ? result.data : (result.data?.meetings ?? result.data?.items ?? []);
+
+ if (meetings.length === 0) {
+ meetingCards = `
No meetings recorded yet for this space. Start a meeting and enable recording to see it here.
`;
+ } else {
+ // Build meeting cards
+ meetingCards = `
`;
+
+ // Aggregate knowledge from completed meetings with summaries
+ const readyMeetings = meetings.filter((m: any) => (m.status === "completed" || m.has_summary));
+ if (readyMeetings.length > 0) {
+ // Fetch summaries for up to 10 completed meetings
+ const summaryPromises = readyMeetings.slice(0, 10).map((m: any) =>
+ miApiFetch(`/meetings/${m.id}/summary`).then(r => r.ok ? r.data : null)
+ );
+ const summaries = (await Promise.all(summaryPromises)).filter(Boolean);
+
+ const allActionItems: string[] = [];
+ const allDecisions: string[] = [];
+ const allTopics: string[] = [];
+
+ for (const s of summaries) {
+ const actions = s.action_items ?? s.actionItems ?? [];
+ for (const a of actions) {
+ const text = typeof a === "string" ? a : (a.task || a.text || a.description || "");
+ if (text) allActionItems.push(text);
+ }
+ const decisions = s.decisions ?? [];
+ for (const d of decisions) {
+ const text = typeof d === "string" ? d : (d.text || d.description || "");
+ if (text) allDecisions.push(text);
+ }
+ const topics = s.topics ?? [];
+ for (const t of topics) {
+ const text = typeof t === "string" ? t : (t.name || t.topic || t.text || "");
+ if (text) allTopics.push(text);
+ }
+ }
+
+ if (allActionItems.length > 0 || allDecisions.length > 0 || allTopics.length > 0) {
+ aggregateHtml = `
`;
+ if (allActionItems.length > 0) {
+ aggregateHtml += `
Action Items
${allActionItems.map(a => `- ${escapeHtml(a)}
`).join("")}
`;
+ }
+ if (allDecisions.length > 0) {
+ aggregateHtml += `
Decisions
${allDecisions.map(d => `- ${escapeHtml(d)}
`).join("")}
`;
+ }
+ if (allTopics.length > 0) {
+ aggregateHtml += `
Topics
${allTopics.map(t => `${escapeHtml(t)}`).join("")}
`;
+ }
+ aggregateHtml += `
`;
+ }
+ }
+ }
+ }
+
+ const extraStyles = ``;
+
+ return c.html(renderShell({
+ title: `Meeting Intelligence — rMeets | rSpace`,
+ moduleId: "rmeets",
+ spaceSlug: space,
+ modules: getModuleInfoList(),
+ styles: MI_STYLES + extraStyles,
+ body: `
+
Meeting Intelligence
+
Knowledge objects, action items, and insights across all meetings
+
+ ${aggregateHtml ? `
Aggregate Knowledge
${aggregateHtml}` : ""}
+
Meetings
+ ${meetingCards}
+
`,
+ }));
+});
+
// ── Room embed (catch-all — must be LAST so /meet, /recordings, /search match first) ──
routes.get("/:room", (c) => {
@@ -543,7 +668,7 @@ routes.get("/:room", (c) => {
}
// Default: clean full-screen Jitsi — no rSpace shell, mobile-friendly
- const jitsiRoom = encodeURIComponent(room);
+ const jitsiRoom = encodeURIComponent(space + "_" + room);
const meetsBase = `/${escapeHtml(space)}/rmeets`;
return c.html(`
@@ -585,6 +710,7 @@ routes.get("/:room", (c) => {
+
🧠 Meeting Intelligence
🎥 Recordings
🔍 Search Transcripts
@@ -629,7 +755,7 @@ routes.get("/:room", (c) => {
"raisehand","tileview","toggle-camera",
"fullscreen","chat","settings",
"participants-pane","select-background",
- "sharedvideo",
+ "sharedvideo","shareaudio","meetingintelligence",
],
},
interfaceConfigOverwrite: {