diff --git a/.gitignore b/.gitignore index d6d1bdc3..351176e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ **/.DS_Store - -.env \ No newline at end of file +.env +.env.local +**/.next/ +**/node_modules/ diff --git a/README.md b/README.md index 5d62c270..cd06f42d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@

Stack to Build Reliable AI Agents


-

Opensource SDK ♦️ Collaborative Studio ♦️ Serverless Deployment

+

Opensource SDK • Collaborative Studio • Serverless Deployment

Website | Docs| Join Slack community

@@ -73,29 +73,30 @@ Deploy intelligent AI agents in minutes with enterprise-grade security, scalable ### 📦 Available Kits -Explore ready-to-deploy agent kits and templates built on Lamatic’s AgentKit framework. +Explore ready-to-deploy agent kits and templates built on Lamatic's AgentKit framework. Each kit includes configuration instructions, environment variables/lamatic-config.json, and a 1-click Vercel deploy button. | Kit Name | Description | Status | Live Demo | Path | |-----------|--------------|--------|--------------|------| -| **🧠 Agentic Kits** | Advanced self-directed, reasoning agents for goal-driven operations | | | [`/kits/agentic`](./kits/agentic) | +| **🤖 Agentic Kits** | Advanced self-directed, reasoning agents for goal-driven operations | | | [`/kits/agentic`](./kits/agentic) | | **Deep Search Agent** | A Next.js starter kit for goal-driven reasoning agents using Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-reasoning.vercel.app) | [`/kits/agentic/deep-search`](./kits/agentic/deep-search) | | **Generation Agent** | A Next.js starter kit for generating text/json/image content using Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-generation.vercel.app) | [`/kits/agentic/generation`](./kits/agentic/generation) | || -| **🤖 Automation Kits** | Automate complex business processes with robust and flexible agent workflows | | | [`/kits/automation`](./kits/automation) | +| **⚙️ Automation Kits** | Automate complex business processes with robust and flexible agent workflows | | | [`/kits/automation`](./kits/automation) | | **Hiring Automation** | A Next.js starter kit for hiring automation using Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-hiring.vercel.app) | [`/kits/automation/hiring`](./kits/automation/hiring) | || | **🧑‍💼 Assistant Kits** | Create context-aware helpers for users, customers, and team members | | | [`/kits/assistant`](./kits/assistant) | -| **Grammar Assistant** | A chrome extension to check grammar corrections across your selection. | Available | | [`/kits/assistant/grammar-extension`](./kits/assistant/grammar-extension) | +| **Grammar Assistant** | A Chrome extension to check grammar corrections across your selection. | Available | | [`/kits/assistant/grammar-extension`](./kits/assistant/grammar-extension) | || | **💬 Embed Kits** | Seamlessly integrate AI agents into apps, websites, and workflows | | | [`/kits/embed`](./kits/embed) | | **Chatbot** | A Next.js starter kit for chatbot using Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-embedded-chat.vercel.app) | [`/kits/embed/chat`](./kits/embed/chat) | | **Search** | A Next.js starter kit for searchbot Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-embedded-chat.vercel.app) | [`/kits/embed/search`](./kits/embed/search) | | **Sheets** | A Next.js starter kit for sheets using Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-sheets.vercel.app) | [`/kits/embed/sheets`](./kits/embed/sheets) | +| **Meeting Intelligence Copilot** | Transforms raw meeting transcripts into structured insights (summary, action items, risks) and delivers them to Slack via an embedded Lamatic chat widget. | Available | | [`/kits/embed/meeting-intelligence`](./kits/embed/meeting-intelligence) | > 💡 Each kit folder includes its own README with specific setup steps, required keys, and example Lamatic flows. -## 🏛️ Architecture Overview +## 🏗️ Architecture Overview - **Agent Engine**: Multi-agent system enabling advanced reasoning and planning - **Templates & Kits**: Pre-designed packs for popular use-cases and enterprise workflows @@ -160,7 +161,7 @@ We welcome your ideas and improvements! See [CONTRIBUTING.md](./CONTRIBUTING.md) *** -## ⭐ Related Links +## 🔗 Related Links - [Lamatic.ai](https://lamatic.ai) - [Lamatic University](https://lamatic.ai/university) diff --git a/kits/embed/chat/README.md b/kits/embed/chat/README.md index 040cf917..f4cc2393 100644 --- a/kits/embed/chat/README.md +++ b/kits/embed/chat/README.md @@ -1,4 +1,4 @@ -# Agent Kit Embedded Chat by Lamatic.ai +# Agent Kit Embedded Chat by Lamatic.ai

@@ -22,8 +22,8 @@ Before running this project, you must build and deploy the flow in Lamatic, then Pre: Build in Lamatic 1. Sign in or sign up at https://lamatic.ai -2. Create a project (if you don’t have one yet) -3. Click “+ New Flow” and select "Templates" +2. Create a project (if you donΓÇÖt have one yet) +3. Click ΓÇ£+ New FlowΓÇ¥ and select "Templates" 4. Select the 'Embed Chat' agent kit 5. Configure providers/tools/inputs as prompted 6. Deploy the kit in Lamatic and obtain your .env keys @@ -35,22 +35,22 @@ Post: Wire into this repo - npm install - npm run dev 3. Deploy (Vercel recommended): - - Import your repo, set the project’s Root Directory (if applicable) + - Import your repo, set the projectΓÇÖs Root Directory (if applicable) - Add env vars in Vercel (same as your .env) - Deploy and test your live URL Notes -- Coming soon: single-click export and “Connect Git” in Lamatic to push config directly to your repo. +- Coming soon: single-click export and ΓÇ£Connect GitΓÇ¥ in Lamatic to push config directly to your repo. --- -## 🔑 Setup +## ≡ƒöæ Setup ## Required Keys and Config -You’ll need two things to run this project locally: +YouΓÇÖll need two things to run this project locally: -1. **.env Keys** → get it from your [Lamatic account](https://lamatic.ai) post kit deployment. -2. Vercel Blob Token – Required for uploaded file storage. Each deployment needs its own Blob token. You can generate it from your Vercel project after the first deploy (see instructions below). +1. **.env Keys** ΓåÆ get it from your [Lamatic account](https://lamatic.ai) post kit deployment. +2. Vercel Blob Token ΓÇô Required for uploaded file storage. Each deployment needs its own Blob token. You can generate it from your Vercel project after the first deploy (see instructions below). | Item | Purpose | Where to Get It | @@ -86,7 +86,7 @@ npm run dev ### 3. Deploy Instructions (Vercel) -Click the “Deploy with Vercel” button. +Click the ΓÇ£Deploy with VercelΓÇ¥ button. Fill in .env Keys from lamatic (required). @@ -96,43 +96,43 @@ After deployment, generate your own Blob token: vercel storage blob token create ``` -Add/Replace it in Vercel Dashboard → Environment Variables → BLOB_READ_WRITE_TOKEN and redeploy. +Add/Replace it in Vercel Dashboard ΓåÆ Environment Variables ΓåÆ BLOB_READ_WRITE_TOKEN and redeploy. --- -## 📂 Repo Structure +## ≡ƒôé Repo Structure ``` /actions - └── orchestrate.ts # Lamatic workflow orchestration + ΓööΓöÇΓöÇ orchestrate.ts # Lamatic workflow orchestration /app - ├── page.tsx # Main upload/indexation UI - ├── chat - │ └── page.tsx # Chat interface with documents - └── api - ├── index # PDF indexation endpoint - ├── index-webpages # Webpage indexation endpoint - ├── delete # PDF deletion endpoint - ├── delete-resource # Resource deletion endpoint - └── check-workflow-status # Async workflow polling + Γö£ΓöÇΓöÇ page.tsx # Main upload/indexation UI + Γö£ΓöÇΓöÇ chat + Γöé ΓööΓöÇΓöÇ page.tsx # Chat interface with documents + ΓööΓöÇΓöÇ api + Γö£ΓöÇΓöÇ index # PDF indexation endpoint + Γö£ΓöÇΓöÇ index-webpages # Webpage indexation endpoint + Γö£ΓöÇΓöÇ delete # PDF deletion endpoint + Γö£ΓöÇΓöÇ delete-resource # Resource deletion endpoint + ΓööΓöÇΓöÇ check-workflow-status # Async workflow polling /lib - └── lamatic-client.ts # Lamatic SDK client + ΓööΓöÇΓöÇ lamatic-client.ts # Lamatic SDK client /public - └── images - ├── lamatic-logo.png # Lamatic branding - └── *.png # Data source icons + ΓööΓöÇΓöÇ images + Γö£ΓöÇΓöÇ lamatic-logo.png # Lamatic branding + ΓööΓöÇΓöÇ *.png # Data source icons /flows - └── ... # Lamatic Flows + ΓööΓöÇΓöÇ ... # Lamatic Flows /package.json # Dependencies & scripts ``` --- -## 🤝 Contributing +## ≡ƒñ¥ Contributing We welcome contributions! Open an issue or PR in this repo. --- -## 📜 License +## ≡ƒô£ License -MIT License – see [LICENSE](../../../LICENSE). +MIT License ΓÇô see [LICENSE](../../../LICENSE). diff --git a/kits/embed/chat/app/globals.css b/kits/embed/chat/app/globals.css index 0a808b09..aa6fd283 100644 --- a/kits/embed/chat/app/globals.css +++ b/kits/embed/chat/app/globals.css @@ -10,7 +10,6 @@ --card-foreground: oklch(0.15 0.02 270); --popover: oklch(1 0 0); --popover-foreground: oklch(0.15 0.02 270); - /* Updated primary to purple for buttons and accents */ --primary: oklch(0.55 0.18 270); --primary-foreground: oklch(0.98 0.01 270); --secondary: oklch(0.96 0.01 270); @@ -24,7 +23,6 @@ --border: oklch(0.92 0.01 270); --input: oklch(0.92 0.01 270); --ring: oklch(0.55 0.18 270); - /* Updated chart colors to purple/blue theme */ --chart-1: oklch(0.55 0.18 270); --chart-2: oklch(0.6 0.15 240); --chart-3: oklch(0.65 0.12 210); @@ -48,7 +46,6 @@ --card-foreground: oklch(0.95 0.01 270); --popover: oklch(0.12 0.02 270); --popover-foreground: oklch(0.95 0.01 270); - /* Updated dark mode primary to brighter purple */ --primary: oklch(0.65 0.2 270); --primary-foreground: oklch(0.08 0.02 270); --secondary: oklch(0.18 0.02 270); @@ -62,7 +59,6 @@ --border: oklch(0.18 0.02 270); --input: oklch(0.18 0.02 270); --ring: oklch(0.65 0.2 270); - /* Updated dark mode chart colors */ --chart-1: oklch(0.65 0.2 270); --chart-2: oklch(0.7 0.18 240); --chart-3: oklch(0.75 0.15 210); @@ -122,8 +118,24 @@ @layer base { * { @apply border-border outline-ring/50; + box-sizing: border-box; } + + html { + scroll-behavior: smooth; + } + body { @apply bg-background text-foreground; + margin: 0; + } + + a { + color: inherit; + text-decoration: none; + } + + button { + font: inherit; } } diff --git a/kits/embed/meeting-intelligence/.env.example b/kits/embed/meeting-intelligence/.env.example new file mode 100644 index 00000000..440a1314 --- /dev/null +++ b/kits/embed/meeting-intelligence/.env.example @@ -0,0 +1,3 @@ +NEXT_PUBLIC_LAMATIC_PROJECT_ID=your_project_id_here +NEXT_PUBLIC_LAMATIC_FLOW_ID=your_flow_id_here +NEXT_PUBLIC_LAMATIC_API_URL=https://your-project.lamatic.dev diff --git a/kits/embed/meeting-intelligence/.gitignore b/kits/embed/meeting-intelligence/.gitignore new file mode 100644 index 00000000..f4d3bba1 --- /dev/null +++ b/kits/embed/meeting-intelligence/.gitignore @@ -0,0 +1,3 @@ +.env.local +.next/ +node_modules/ diff --git a/kits/embed/meeting-intelligence/README.md b/kits/embed/meeting-intelligence/README.md new file mode 100644 index 00000000..02e914b1 --- /dev/null +++ b/kits/embed/meeting-intelligence/README.md @@ -0,0 +1,162 @@ +# 🧠 AI Meeting Intelligence Copilot + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits/embed/meeting-intelligence&env=NEXT_PUBLIC_LAMATIC_PROJECT_ID,NEXT_PUBLIC_LAMATIC_FLOW_ID,NEXT_PUBLIC_LAMATIC_API_URL&envDescription=Get%20these%20from%20Lamatic%20Studio) + +> Turn raw meeting transcripts into structured, actionable intelligence — delivered automatically to Slack. + +Part of the [Lamatic AgentKit](https://github.com/Lamatic/AgentKit) · Built by [Vijayshree Vaibhav](https://github.com/vijayshreepathak) + +--- + +## 🎯 Problem Statement + +Teams walk out of meetings with scattered notes, untracked action items, and unclear ownership. This kit solves it in one step: paste a transcript → receive a structured summary, action items, risks, next steps, and a follow-up email draft — all sent to Slack automatically. + +--- + +## ✨ What This Kit Does + +| Input | Output | +|---|---| +| Raw meeting transcript | Executive summary | +| Any format, any length | Action items with owners & priority | +| | Risks & blockers | +| | Suggested next steps | +| | Follow-up email draft | +| | Overall sentiment | +| | Slack notification ⚡ | + +--- + +## 🏗️ Architecture + +``` +User pastes transcript + ↓ +Next.js Frontend (TranscriptPlayground) + ↓ +Lamatic Chat Widget (chat-v2 embedded) + ↓ +Chat Trigger → Generate Text (LLM) → Generate JSON + ↙ ↘ + Slack API Chat Response + (webhook) (streamed to UI) +``` + +--- + +## 📸 Screenshots + +### Web App — Transcript Input & Structured Output +![Web App](app/Screenshots/FromwebPage-With%20Followup%20mail-Running.png) + +### Lamatic Studio — Flow Execution & Preview +![Lamatic Flow](app/Screenshots/fromLamatic-Running.png) + +### Slack Integration — Auto-delivered Insights +![Slack](app/Screenshots/Slack_integrated-Summarizer.png) + +### Landing Page +![Landing](app/Screenshots/1.png) + +--- + +## 📂 Structure + +``` +kits/embed/meeting-intelligence/ +├── app/ +│ ├── page.js # Landing page (Server Component) +│ ├── layout.js # Root layout with Geist fonts + Analytics +│ ├── globals.css # Tailwind v4 theme + CSS variables +│ └── Screenshots/ # Demo screenshots +├── components/ +│ ├── LamaticChat.js # Widget bootstrap + lifecycle manager +│ ├── HeroActions.jsx # CTA buttons (Client Component) +│ ├── TranscriptPlayground.jsx # Transcript input + Analyze button +│ └── ui/ # shadcn/ui primitives (button, badge, card, textarea) +├── flows/ +│ └── meeting-intelligence-chatbot/ +│ ├── config.json # Lamatic flow configuration +│ ├── meta.json # Flow metadata +│ ├── inputs.json # Configurable inputs (model, Slack URL) +│ └── README.md # Flow setup guide +├── lib/ +│ └── utils.ts # cn() utility +├── .env.example # Environment variable template +├── .gitignore +├── components.json # shadcn/ui config +├── next.config.mjs +├── package.json +├── postcss.config.mjs +└── tsconfig.json +``` + +--- + +## ⚙️ Setup + +### 1. Prerequisites + +- [Lamatic account](https://lamatic.ai) with the meeting intelligence flow deployed +- A Slack incoming webhook URL + +### 2. Build the Lamatic flow + +1. Sign in to [Lamatic Studio](https://studio.lamatic.ai) +2. Create a new flow and import `flows/meeting-intelligence-chatbot/config.json` +3. Set your LLM credentials (Gemini, GPT-4o, or Claude) +4. Replace `YOUR_SLACK_WEBHOOK_URL` in the API node with your Slack webhook +5. In the Chat Trigger node, add `*` to Allowed Domains +6. Click **Save** → **Deploy** +7. Copy your Project ID, Flow ID, and API URL + +### 3. Install and run locally + +```bash +cd kits/embed/meeting-intelligence +npm install +``` + +Create `.env.local`: + +```env +NEXT_PUBLIC_LAMATIC_PROJECT_ID=your_project_id +NEXT_PUBLIC_LAMATIC_FLOW_ID=your_flow_id +NEXT_PUBLIC_LAMATIC_API_URL=https://your-project.lamatic.dev +``` + +```bash +npm run dev +# → http://localhost:3000 +``` + +### 4. Deploy to Vercel + +Click the **Deploy with Vercel** button at the top, or: + +```bash +vercel --root kits/embed/meeting-intelligence +``` + +Add your production domain to the Chat Trigger's Allowed Domains in Lamatic Studio, then redeploy the flow. + +--- + +## 🛠️ Tech Stack + +| Layer | Technology | +|---|---| +| Frontend | Next.js 14 (App Router) | +| UI | Tailwind CSS v4 + shadcn/ui | +| AI Workflow | Lamatic Studio | +| LLM | Gemini 2.5 Flash (swappable) | +| Chat Widget | Lamatic `chat-v2` | +| Integration | Slack Incoming Webhooks | +| Deployment | Vercel | + +--- + +## 📜 License + +MIT — see [LICENSE](../../LICENSE). diff --git a/kits/embed/meeting-intelligence/app/Screenshots/1.png b/kits/embed/meeting-intelligence/app/Screenshots/1.png new file mode 100644 index 00000000..516838b1 Binary files /dev/null and b/kits/embed/meeting-intelligence/app/Screenshots/1.png differ diff --git a/kits/embed/meeting-intelligence/app/Screenshots/FromwebPage-With Followup mail-Running.png b/kits/embed/meeting-intelligence/app/Screenshots/FromwebPage-With Followup mail-Running.png new file mode 100644 index 00000000..645fb5b8 Binary files /dev/null and b/kits/embed/meeting-intelligence/app/Screenshots/FromwebPage-With Followup mail-Running.png differ diff --git a/kits/embed/meeting-intelligence/app/Screenshots/Slack_integrated-Summarizer.png b/kits/embed/meeting-intelligence/app/Screenshots/Slack_integrated-Summarizer.png new file mode 100644 index 00000000..90f99128 Binary files /dev/null and b/kits/embed/meeting-intelligence/app/Screenshots/Slack_integrated-Summarizer.png differ diff --git a/kits/embed/meeting-intelligence/app/Screenshots/fromLamatic-Running.png b/kits/embed/meeting-intelligence/app/Screenshots/fromLamatic-Running.png new file mode 100644 index 00000000..fc9555e5 Binary files /dev/null and b/kits/embed/meeting-intelligence/app/Screenshots/fromLamatic-Running.png differ diff --git a/kits/embed/meeting-intelligence/app/globals.css b/kits/embed/meeting-intelligence/app/globals.css new file mode 100644 index 00000000..2b457eba --- /dev/null +++ b/kits/embed/meeting-intelligence/app/globals.css @@ -0,0 +1,141 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +:root { + --background: oklch(0.98 0.01 270); + --foreground: oklch(0.15 0.02 270); + --card: oklch(1 0 0); + --card-foreground: oklch(0.15 0.02 270); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.15 0.02 270); + --primary: oklch(0.55 0.18 270); + --primary-foreground: oklch(0.98 0.01 270); + --secondary: oklch(0.96 0.01 270); + --secondary-foreground: oklch(0.15 0.02 270); + --muted: oklch(0.96 0.01 270); + --muted-foreground: oklch(0.45 0.02 270); + --accent: oklch(0.96 0.01 270); + --accent-foreground: oklch(0.15 0.02 270); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.98 0.01 270); + --border: oklch(0.92 0.01 270); + --input: oklch(0.92 0.01 270); + --ring: oklch(0.55 0.18 270); + --chart-1: oklch(0.55 0.18 270); + --chart-2: oklch(0.6 0.15 240); + --chart-3: oklch(0.65 0.12 210); + --chart-4: oklch(0.7 0.1 180); + --chart-5: oklch(0.5 0.2 300); + --radius: 0.75rem; + --sidebar: oklch(0.98 0.01 270); + --sidebar-foreground: oklch(0.15 0.02 270); + --sidebar-primary: oklch(0.55 0.18 270); + --sidebar-primary-foreground: oklch(0.98 0.01 270); + --sidebar-accent: oklch(0.96 0.01 270); + --sidebar-accent-foreground: oklch(0.15 0.02 270); + --sidebar-border: oklch(0.92 0.01 270); + --sidebar-ring: oklch(0.55 0.18 270); +} + +.dark { + --background: oklch(0.08 0.02 270); + --foreground: oklch(0.95 0.01 270); + --card: oklch(0.12 0.02 270); + --card-foreground: oklch(0.95 0.01 270); + --popover: oklch(0.12 0.02 270); + --popover-foreground: oklch(0.95 0.01 270); + --primary: oklch(0.65 0.2 270); + --primary-foreground: oklch(0.08 0.02 270); + --secondary: oklch(0.18 0.02 270); + --secondary-foreground: oklch(0.95 0.01 270); + --muted: oklch(0.18 0.02 270); + --muted-foreground: oklch(0.65 0.02 270); + --accent: oklch(0.18 0.02 270); + --accent-foreground: oklch(0.95 0.01 270); + --destructive: oklch(0.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.18 0.02 270); + --input: oklch(0.18 0.02 270); + --ring: oklch(0.65 0.2 270); + --chart-1: oklch(0.65 0.2 270); + --chart-2: oklch(0.7 0.18 240); + --chart-3: oklch(0.75 0.15 210); + --chart-4: oklch(0.8 0.12 180); + --chart-5: oklch(0.6 0.22 300); + --sidebar: oklch(0.12 0.02 270); + --sidebar-foreground: oklch(0.95 0.01 270); + --sidebar-primary: oklch(0.65 0.2 270); + --sidebar-primary-foreground: oklch(0.08 0.02 270); + --sidebar-accent: oklch(0.18 0.02 270); + --sidebar-accent-foreground: oklch(0.95 0.01 270); + --sidebar-border: oklch(0.18 0.02 270); + --sidebar-ring: oklch(0.65 0.2 270); +} + +@theme inline { + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +@layer base { + * { + @apply border-border outline-ring/50; + box-sizing: border-box; + } + + html { + scroll-behavior: smooth; + } + + body { + @apply bg-background text-foreground; + margin: 0; + } + + a { + color: inherit; + text-decoration: none; + } + + button { + font: inherit; + } +} diff --git a/kits/embed/meeting-intelligence/app/layout.tsx b/kits/embed/meeting-intelligence/app/layout.tsx new file mode 100644 index 00000000..60311eb4 --- /dev/null +++ b/kits/embed/meeting-intelligence/app/layout.tsx @@ -0,0 +1,22 @@ +import type { Metadata } from "next"; +import { GeistSans } from "geist/font/sans"; +import { GeistMono } from "geist/font/mono"; +import { Analytics } from "@vercel/analytics/next"; +import { Suspense } from "react"; +import "./globals.css"; + +export const metadata: Metadata = { + title: "AI Meeting Intelligence Copilot", + description: "Turn meeting transcripts into actionable insights instantly.", +}; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + + + ); +} diff --git a/kits/embed/meeting-intelligence/app/page.tsx b/kits/embed/meeting-intelligence/app/page.tsx new file mode 100644 index 00000000..29eea80a --- /dev/null +++ b/kits/embed/meeting-intelligence/app/page.tsx @@ -0,0 +1,217 @@ +import LamaticChat from "@/components/LamaticChat"; +import HeroActions from "@/components/HeroActions"; +import TranscriptPlayground from "@/components/TranscriptPlayground"; +import { Badge } from "@/components/ui/badge"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; + +const features = [ + "Extract action items automatically", + "Identify risks and blockers", + "Generate follow-up summaries", + "Send insights to Slack", +]; + +const transcript = [ + "Maya: Enterprise onboarding is taking too long because legal review starts late in the cycle.", + "Jordan: We can shorten turnaround if customer success collects the security questionnaire before kickoff.", + "Priya: Slack alerts should notify the account team whenever a deal slips past the implementation target date.", + "Alex: Let's send a concise follow-up summary with owners, due dates, and unresolved blockers after every client meeting.", +]; + +const actionItems = [ + "Customer Success to collect the security questionnaire before kickoff.", + "Operations to add Slack alerts for delayed implementation milestones.", + "Account team to send a post-meeting summary with owners and deadlines.", +]; + +const risks = [ + "Late legal review is extending onboarding timelines.", + "No proactive alerting exists when implementation targets slip.", +]; + +export default function Home() { + const lamaticConfig = { + projectId: process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID ?? "", + flowId: process.env.NEXT_PUBLIC_LAMATIC_FLOW_ID ?? "", + apiUrl: process.env.NEXT_PUBLIC_LAMATIC_API_URL ?? "", + }; + + const missingEnvVars = ( + Object.entries({ + NEXT_PUBLIC_LAMATIC_PROJECT_ID: lamaticConfig.projectId, + NEXT_PUBLIC_LAMATIC_FLOW_ID: lamaticConfig.flowId, + NEXT_PUBLIC_LAMATIC_API_URL: lamaticConfig.apiUrl, + }) as [string, string][] + ) + .filter(([, value]) => !value) + .map(([key]) => key); + + const isLamaticReady = missingEnvVars.length === 0; + + return ( + <> +
+
+
+
+
+
+ AI Powered + Slack Integrated ⚡ +
+ +

+ AI Meeting Intelligence Copilot +

+

+ Turn meeting transcripts into actionable insights instantly +

+ + + +

+ {isLamaticReady ? "Lamatic assistant ready" : "Add Lamatic env vars to enable the assistant"} +

+
+ +
+ + + Core capabilities + + +
    + {features.map((feature) => ( +
  • + {feature} +
  • + ))} +
+
+
+ + + + Widget status + + +
+

+ {isLamaticReady ? "Configuration complete" : "Configuration required"} +

+

+ {isLamaticReady + ? "Open Copilot from the button in the bottom-right." + : "Set the required Lamatic variables in `.env.local` before the widget can render."} +

+
+ + {!isLamaticReady && ( +
+

Missing environment variables

+
    + {missingEnvVars.map((envVar) => ( +
  • + {envVar} +
  • + ))} +
+
+ )} +
+
+
+
+
+ +
+
+
+

Demo Preview

+

+ See how meeting insights are structured +

+

+ Capture raw discussion on the left and instantly convert it into an executive-ready summary on the right. +

+
+ +
+ +
+ +
+
+
+

Example Input

+ + Meeting Transcript + +
+
+ {transcript.map((line) => ( +
+ {line} +
+ ))} +
+
+ +
+
+

Example Output

+ + Generated Insights + +
+ +
+
+

Summary

+

+ The team identified delayed legal review as the primary cause of slow onboarding and aligned on + collecting security materials earlier, adding Slack alerts for slippage, and standardizing + follow-up summaries after customer meetings. +

+
+ +
+
+

Action Items

+
    + {actionItems.map((item) => ( +
  • + {item} +
  • + ))} +
+
+ +
+

+ Risks & Blockers +

+
    + {risks.map((item) => ( +
  • + {item} +
  • + ))} +
+
+
+
+
+
+
+
+ +
+ Built by Vijayshree +
+
+ + + + ); +} diff --git a/kits/embed/meeting-intelligence/components.json b/kits/embed/meeting-intelligence/components.json new file mode 100644 index 00000000..4ee62ee1 --- /dev/null +++ b/kits/embed/meeting-intelligence/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} diff --git a/kits/embed/meeting-intelligence/components/HeroActions.tsx b/kits/embed/meeting-intelligence/components/HeroActions.tsx new file mode 100644 index 00000000..0dd00466 --- /dev/null +++ b/kits/embed/meeting-intelligence/components/HeroActions.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { Button } from "@/components/ui/button"; + +interface HeroActionsProps { + isLamaticReady: boolean; +} + +export default function HeroActions({ isLamaticReady }: HeroActionsProps) { + return ( +
+ + + +
+ ); +} diff --git a/kits/embed/meeting-intelligence/components/LamaticChat.tsx b/kits/embed/meeting-intelligence/components/LamaticChat.tsx new file mode 100644 index 00000000..11f605b1 --- /dev/null +++ b/kits/embed/meeting-intelligence/components/LamaticChat.tsx @@ -0,0 +1,159 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Button } from "@/components/ui/button"; + +// --------------------------------------------------------------------------- +// Config — NEXT_PUBLIC_ vars are inlined by the Next.js bundler at build time. +// --------------------------------------------------------------------------- +const PROJECT_ID = process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID ?? ""; +const FLOW_ID = process.env.NEXT_PUBLIC_LAMATIC_FLOW_ID ?? ""; +const API_URL = process.env.NEXT_PUBLIC_LAMATIC_API_URL ?? ""; + +const ROOT_ID = "lamatic-chat-root"; +const SCRIPT_ID = "lamatic-chat-script"; + +type LamaticWindow = Window & { + LamaticChatWidget?: { open?: () => void; close?: () => void }; +}; + +// Module-level guard — survives React Fast Refresh so we never double-inject. +let didBootstrap = false; + +// --------------------------------------------------------------------------- +// bootstrapWidget — mirrors the official Lamatic-generated embed script. +// +// Called on mount (not on button click) so the widget fetches chatConfig and +// creates an IndexedDB session BEFORE the user sends the first message. +// This prevents the "unexpected error" on first send. +// --------------------------------------------------------------------------- +function bootstrapWidget(): void { + if (didBootstrap) return; + didBootstrap = true; + + if (!PROJECT_ID || !FLOW_ID || !API_URL) { + if (process.env.NODE_ENV === "development") { + console.warn("[LamaticChat] Missing env vars — widget disabled.", { + PROJECT_ID: PROJECT_ID || "MISSING", + FLOW_ID: FLOW_ID || "MISSING", + API_URL: API_URL || "MISSING", + }); + } + return; + } + + // 1. Root div — appended directly to body (official Lamatic pattern). + if (!document.getElementById(ROOT_ID)) { + const root = document.createElement("div"); + root.id = ROOT_ID; + root.dataset.apiUrl = API_URL; + root.dataset.flowId = FLOW_ID; + root.dataset.projectId = PROJECT_ID; + document.body.appendChild(root); + if (process.env.NODE_ENV === "development") { + console.log("[LamaticChat] root mounted ✓", { API_URL, FLOW_ID, PROJECT_ID }); + } + } + + // 2. Script — injected once (matches official Lamatic embed). + if (!document.getElementById(SCRIPT_ID)) { + const script = document.createElement("script"); + script.id = SCRIPT_ID; + script.type = "module"; + script.async = true; + script.src = `https://widget.lamatic.ai/chat-v2?projectId=${encodeURIComponent(PROJECT_ID)}`; + script.onload = () => { + if (process.env.NODE_ENV === "development") { + console.log("[LamaticChat] widget script loaded ✓"); + } + }; + script.onerror = () => { + // Reset the guard so a subsequent mount can retry injection. + didBootstrap = false; + document.getElementById(SCRIPT_ID)?.remove(); + console.error("[LamaticChat] widget script failed to load"); + }; + document.body.appendChild(script); + } +} + +interface LamaticChatProps { + disabled?: boolean; +} + +export default function LamaticChat({ disabled = false }: LamaticChatProps) { + const [isOpen, setIsOpen] = useState(false); + const [isWidgetReady, setIsWidgetReady] = useState(false); + const isConfigured = Boolean(PROJECT_ID && FLOW_ID && API_URL); + + // Bootstrap immediately on first client render. + useEffect(() => { + if (disabled || !isConfigured) return; + bootstrapWidget(); + + const handleReady = () => { + if (process.env.NODE_ENV === "development") { + console.log("[LamaticChat] lamaticChatWidgetReady ✓"); + } + setIsWidgetReady(true); + }; + window.addEventListener("lamaticChatWidgetReady", handleReady, { once: true }); + return () => window.removeEventListener("lamaticChatWidgetReady", handleReady); + }, [disabled, isConfigured]); + + // Sync open / close with the Lamatic widget JS API. + // Deferred until the widget signals it is ready to prevent silent no-ops. + useEffect(() => { + if (!isConfigured || disabled || !isWidgetReady) return; + try { + const w = window as LamaticWindow; + if (isOpen) w.LamaticChatWidget?.open?.(); + else w.LamaticChatWidget?.close?.(); + } catch (e) { + console.warn("[LamaticChat] toggle error", e); + } + }, [disabled, isConfigured, isOpen, isWidgetReady]); + + // External event bus (used by HeroActions and TranscriptPlayground). + useEffect(() => { + if (disabled) return; + const open = () => setIsOpen(true); + const close = () => setIsOpen(false); + const toggle = () => setIsOpen((v) => !v); + window.addEventListener("lamatic:open", open); + window.addEventListener("lamatic:close", close); + window.addEventListener("lamatic:toggle", toggle); + return () => { + window.removeEventListener("lamatic:open", open); + window.removeEventListener("lamatic:close", close); + window.removeEventListener("lamatic:toggle", toggle); + }; + }, [disabled]); + + // NOTE: #lamatic-chat-root is intentionally NOT removed on unmount. + // Removing and re-adding it causes "ConstraintError: Key already exists" + // in the widget's IndexedDB session store. + + if (!isConfigured || disabled) { + return ( +
+ +
+ ); + } + + return ( +
+ +
+ ); +} diff --git a/kits/embed/meeting-intelligence/components/TranscriptPlayground.tsx b/kits/embed/meeting-intelligence/components/TranscriptPlayground.tsx new file mode 100644 index 00000000..cdf3e4da --- /dev/null +++ b/kits/embed/meeting-intelligence/components/TranscriptPlayground.tsx @@ -0,0 +1,177 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Textarea } from "@/components/ui/textarea"; +import { Badge } from "@/components/ui/badge"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; + +const SAMPLE_TRANSCRIPT = + "Team discussed Q4 product launch. Rahul handles frontend. Priya backend. Budget concerns raised. Deadline next Friday."; + +// These IDs must match the Lamatic chat widget's internal DOM structure. +// If the widget updates, verify these selectors still work. +const INPUT_ID = "lam-chat-message-input"; +const SEND_BTN_ID = "lam-chat-send-button"; +const MAX_ATTEMPTS = 20; +const MIN_TRANSCRIPT_LENGTH = 12; + +// --------------------------------------------------------------------------- +// Zod schema — single source of truth for validation. +// --------------------------------------------------------------------------- +const transcriptSchema = z.object({ + transcript: z + .string() + .min(MIN_TRANSCRIPT_LENGTH + 1, `Transcript must be at least ${MIN_TRANSCRIPT_LENGTH + 1} characters.`), +}); + +type TranscriptFormValues = z.infer; + +// --------------------------------------------------------------------------- +// fillAndSend — polls until the widget input is available, then injects the +// value and triggers the send button. Uses an instanceof check to select the +// correct prototype setter so we never call a textarea setter on an input +// receiver (which throws "Illegal invocation"). +// --------------------------------------------------------------------------- +function fillAndSend( + value: string, + attempt = 0, + isCancelled: () => boolean = () => false, + onDone?: () => void, +): void { + if (isCancelled()) { + onDone?.(); + return; + } + + const input = document.getElementById(INPUT_ID) as HTMLInputElement | HTMLTextAreaElement | null; + + if (!input) { + if (attempt < MAX_ATTEMPTS) { + setTimeout(() => fillAndSend(value, attempt + 1, isCancelled, onDone), 100); + } else { + console.warn("[TranscriptPlayground] Widget input not found after retries"); + onDone?.(); + } + return; + } + + const nativeSetter = + input instanceof window.HTMLTextAreaElement + ? Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value")?.set + : Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set; + + if (nativeSetter) nativeSetter.call(input, value); + else input.value = value; + + input.dispatchEvent(new Event("input", { bubbles: true })); + + const sendBtn = document.getElementById(SEND_BTN_ID) as HTMLButtonElement | null; + if (sendBtn) sendBtn.click(); + + onDone?.(); +} + +// --------------------------------------------------------------------------- +// Component +// --------------------------------------------------------------------------- +interface TranscriptPlaygroundProps { + isLamaticReady?: boolean; +} + +export default function TranscriptPlayground({ isLamaticReady = true }: TranscriptPlaygroundProps) { + const cancelledRef = useRef(false); + const [isAnalyzing, setIsAnalyzing] = useState(false); + + const form = useForm({ + resolver: zodResolver(transcriptSchema), + defaultValues: { transcript: SAMPLE_TRANSCRIPT }, + }); + + // Cancel any in-flight retries when the component unmounts. + useEffect(() => { + cancelledRef.current = false; + return () => { + cancelledRef.current = true; + }; + }, []); + + const onSubmit = (data: TranscriptFormValues) => { + if (isAnalyzing) return; + setIsAnalyzing(true); + + window.dispatchEvent(new Event("lamatic:open")); + + // Give the widget a moment to open, then poll for its input. + setTimeout(() => { + fillAndSend(data.transcript, 0, () => cancelledRef.current, () => { + setIsAnalyzing(false); + }); + }, 300); + }; + + return ( + + +
+ Test your meeting copilot + Slack Integrated ⚡ +
+ Paste a transcript, get structured insights +
+ +
+ + ( + + Meeting transcript + +