From 2ddc48801dfda51c5efb0e7b3694a3d40c947fc5 Mon Sep 17 00:00:00 2001 From: d-pamneja Date: Mon, 6 Apr 2026 14:03:34 +0530 Subject: [PATCH 1/3] refactor: POC unified filesystem structure (1 kit + 1 bundle + 1 template) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proof-of-concept migration of three entries to the new unified filesystem spec (RFC v0.3.0). All entries now live under kits// with flat flow files, lamatic.config.ts, constitutions, and prompts. Migrated entries: - Template: kits/rag-chatbot/ (from templates/rag-chatbot/) - Bundle: kits/knowledge-chatbot/ (from bundles/knowledge-chatbot/) - Kit: kits/content-generation/ (from kits/sample/content-generation/) Key structural changes demonstrated: - config.json → lamatic.config.ts (typed project config) - flows//config.json → flows/.ts (flat files, not folders) - Inline prompts → prompts/system.md (externalized) - New: constitutions/default.md, flows/flows.md Old locations are NOT deleted — this is additive for review purposes. Co-Authored-By: Claude Opus 4.6 (1M context) --- kits/content-generation/.env.example | 4 + kits/content-generation/.gitignore | 27 + kits/content-generation/README.md | 106 +++ .../content-generation/actions/orchestrate.ts | 84 ++ kits/content-generation/app/globals.css | 125 +++ kits/content-generation/app/layout.tsx | 45 ++ kits/content-generation/app/page.tsx | 229 ++++++ kits/content-generation/components.json | 21 + kits/content-generation/components/header.tsx | 47 ++ .../components/theme-provider.tsx | 11 + .../components/ui/accordion.tsx | 66 ++ .../components/ui/alert-dialog.tsx | 157 ++++ .../components/ui/alert.tsx | 66 ++ .../components/ui/aspect-ratio.tsx | 11 + .../components/ui/avatar.tsx | 53 ++ .../components/ui/badge.tsx | 46 ++ .../components/ui/breadcrumb.tsx | 109 +++ .../components/ui/button-group.tsx | 83 ++ .../components/ui/button.tsx | 60 ++ .../components/ui/calendar.tsx | 213 +++++ .../content-generation/components/ui/card.tsx | 92 +++ .../components/ui/carousel.tsx | 241 ++++++ .../components/ui/chart.tsx | 353 +++++++++ .../components/ui/checkbox.tsx | 32 + .../components/ui/collapsible.tsx | 33 + .../components/ui/command.tsx | 184 +++++ .../components/ui/context-menu.tsx | 252 ++++++ .../components/ui/dialog.tsx | 143 ++++ .../components/ui/drawer.tsx | 135 ++++ .../components/ui/dropdown-menu.tsx | 257 +++++++ .../components/ui/empty.tsx | 104 +++ .../components/ui/field.tsx | 244 ++++++ .../content-generation/components/ui/form.tsx | 167 ++++ .../components/ui/hover-card.tsx | 44 ++ .../components/ui/input-group.tsx | 169 ++++ .../components/ui/input-otp.tsx | 77 ++ .../components/ui/input.tsx | 21 + .../content-generation/components/ui/item.tsx | 193 +++++ kits/content-generation/components/ui/kbd.tsx | 28 + .../components/ui/label.tsx | 24 + .../components/ui/menubar.tsx | 276 +++++++ .../components/ui/navigation-menu.tsx | 166 ++++ .../components/ui/pagination.tsx | 127 +++ .../components/ui/popover.tsx | 48 ++ .../components/ui/progress.tsx | 31 + .../components/ui/radio-group.tsx | 45 ++ .../components/ui/resizable.tsx | 56 ++ .../components/ui/scroll-area.tsx | 58 ++ .../components/ui/select.tsx | 185 +++++ .../components/ui/separator.tsx | 28 + .../components/ui/sheet.tsx | 139 ++++ .../components/ui/sidebar.tsx | 726 ++++++++++++++++++ .../components/ui/skeleton.tsx | 13 + .../components/ui/slider.tsx | 63 ++ .../components/ui/sonner.tsx | 25 + .../components/ui/spinner.tsx | 16 + .../components/ui/switch.tsx | 31 + .../components/ui/table.tsx | 116 +++ .../content-generation/components/ui/tabs.tsx | 66 ++ .../components/ui/textarea.tsx | 18 + .../components/ui/toast.tsx | 129 ++++ .../components/ui/toaster.tsx | 35 + .../components/ui/toggle-group.tsx | 73 ++ .../components/ui/toggle.tsx | 47 ++ .../components/ui/tooltip.tsx | 61 ++ .../components/ui/use-mobile.tsx | 19 + .../components/ui/use-toast.ts | 191 +++++ .../constitutions/default.md | 17 + .../agentic-generate-content.inputs.json | 66 ++ .../flows/agentic-generate-content.meta.json | 12 + .../flows/agentic-generate-content.ts | 333 ++++++++ kits/content-generation/flows/flows.md | 15 + kits/content-generation/hooks/use-mobile.ts | 19 + kits/content-generation/hooks/use-toast.ts | 191 +++++ kits/content-generation/lamatic.config.ts | 33 + kits/content-generation/next.config.mjs | 11 + kits/knowledge-chatbot/.env.example | 3 + kits/knowledge-chatbot/.gitignore | 4 + kits/knowledge-chatbot/README.md | 70 ++ .../constitutions/default.md | 17 + .../flows/crawling-indexation.inputs.json | 42 + .../flows/crawling-indexation.meta.json | 17 + .../flows/crawling-indexation.ts | 359 +++++++++ kits/knowledge-chatbot/flows/flows.md | 19 + .../flows/gdrive.inputs.json | 87 +++ kits/knowledge-chatbot/flows/gdrive.meta.json | 13 + kits/knowledge-chatbot/flows/gdrive.ts | 205 +++++ .../flows/gsheet.inputs.json | 98 +++ kits/knowledge-chatbot/flows/gsheet.meta.json | 13 + kits/knowledge-chatbot/flows/gsheet.ts | 177 +++++ .../flows/knowledge-chatbot.inputs.json | 42 + .../flows/knowledge-chatbot.meta.json | 13 + .../flows/knowledge-chatbot.ts | 126 +++ .../flows/onedrive.inputs.json | 62 ++ .../flows/onedrive.meta.json | 13 + kits/knowledge-chatbot/flows/onedrive.ts | 215 ++++++ .../flows/postgres.inputs.json | 87 +++ .../flows/postgres.meta.json | 13 + kits/knowledge-chatbot/flows/postgres.ts | 175 +++++ kits/knowledge-chatbot/flows/s3.inputs.json | 71 ++ kits/knowledge-chatbot/flows/s3.meta.json | 13 + kits/knowledge-chatbot/flows/s3.ts | 270 +++++++ .../flows/scraping-indexation.inputs.json | 56 ++ .../flows/scraping-indexation.meta.json | 17 + .../flows/scraping-indexation.ts | 359 +++++++++ .../flows/sharepoint.inputs.json | 75 ++ .../flows/sharepoint.meta.json | 13 + kits/knowledge-chatbot/flows/sharepoint.ts | 216 ++++++ kits/knowledge-chatbot/lamatic.config.ts | 44 ++ kits/rag-chatbot/.gitignore | 4 + kits/rag-chatbot/README.md | 36 + kits/rag-chatbot/constitutions/default.md | 17 + kits/rag-chatbot/flows/flows.md | 20 + .../rag-chatbot/flows/rag-chatbot.inputs.json | 1 + kits/rag-chatbot/flows/rag-chatbot.meta.json | 10 + kits/rag-chatbot/flows/rag-chatbot.ts | 89 +++ kits/rag-chatbot/lamatic.config.ts | 30 + kits/rag-chatbot/prompts/system.md | 1 + 118 files changed, 11053 insertions(+) create mode 100644 kits/content-generation/.env.example create mode 100644 kits/content-generation/.gitignore create mode 100644 kits/content-generation/README.md create mode 100644 kits/content-generation/actions/orchestrate.ts create mode 100644 kits/content-generation/app/globals.css create mode 100644 kits/content-generation/app/layout.tsx create mode 100644 kits/content-generation/app/page.tsx create mode 100644 kits/content-generation/components.json create mode 100644 kits/content-generation/components/header.tsx create mode 100644 kits/content-generation/components/theme-provider.tsx create mode 100644 kits/content-generation/components/ui/accordion.tsx create mode 100644 kits/content-generation/components/ui/alert-dialog.tsx create mode 100644 kits/content-generation/components/ui/alert.tsx create mode 100644 kits/content-generation/components/ui/aspect-ratio.tsx create mode 100644 kits/content-generation/components/ui/avatar.tsx create mode 100644 kits/content-generation/components/ui/badge.tsx create mode 100644 kits/content-generation/components/ui/breadcrumb.tsx create mode 100644 kits/content-generation/components/ui/button-group.tsx create mode 100644 kits/content-generation/components/ui/button.tsx create mode 100644 kits/content-generation/components/ui/calendar.tsx create mode 100644 kits/content-generation/components/ui/card.tsx create mode 100644 kits/content-generation/components/ui/carousel.tsx create mode 100644 kits/content-generation/components/ui/chart.tsx create mode 100644 kits/content-generation/components/ui/checkbox.tsx create mode 100644 kits/content-generation/components/ui/collapsible.tsx create mode 100644 kits/content-generation/components/ui/command.tsx create mode 100644 kits/content-generation/components/ui/context-menu.tsx create mode 100644 kits/content-generation/components/ui/dialog.tsx create mode 100644 kits/content-generation/components/ui/drawer.tsx create mode 100644 kits/content-generation/components/ui/dropdown-menu.tsx create mode 100644 kits/content-generation/components/ui/empty.tsx create mode 100644 kits/content-generation/components/ui/field.tsx create mode 100644 kits/content-generation/components/ui/form.tsx create mode 100644 kits/content-generation/components/ui/hover-card.tsx create mode 100644 kits/content-generation/components/ui/input-group.tsx create mode 100644 kits/content-generation/components/ui/input-otp.tsx create mode 100644 kits/content-generation/components/ui/input.tsx create mode 100644 kits/content-generation/components/ui/item.tsx create mode 100644 kits/content-generation/components/ui/kbd.tsx create mode 100644 kits/content-generation/components/ui/label.tsx create mode 100644 kits/content-generation/components/ui/menubar.tsx create mode 100644 kits/content-generation/components/ui/navigation-menu.tsx create mode 100644 kits/content-generation/components/ui/pagination.tsx create mode 100644 kits/content-generation/components/ui/popover.tsx create mode 100644 kits/content-generation/components/ui/progress.tsx create mode 100644 kits/content-generation/components/ui/radio-group.tsx create mode 100644 kits/content-generation/components/ui/resizable.tsx create mode 100644 kits/content-generation/components/ui/scroll-area.tsx create mode 100644 kits/content-generation/components/ui/select.tsx create mode 100644 kits/content-generation/components/ui/separator.tsx create mode 100644 kits/content-generation/components/ui/sheet.tsx create mode 100644 kits/content-generation/components/ui/sidebar.tsx create mode 100644 kits/content-generation/components/ui/skeleton.tsx create mode 100644 kits/content-generation/components/ui/slider.tsx create mode 100644 kits/content-generation/components/ui/sonner.tsx create mode 100644 kits/content-generation/components/ui/spinner.tsx create mode 100644 kits/content-generation/components/ui/switch.tsx create mode 100644 kits/content-generation/components/ui/table.tsx create mode 100644 kits/content-generation/components/ui/tabs.tsx create mode 100644 kits/content-generation/components/ui/textarea.tsx create mode 100644 kits/content-generation/components/ui/toast.tsx create mode 100644 kits/content-generation/components/ui/toaster.tsx create mode 100644 kits/content-generation/components/ui/toggle-group.tsx create mode 100644 kits/content-generation/components/ui/toggle.tsx create mode 100644 kits/content-generation/components/ui/tooltip.tsx create mode 100644 kits/content-generation/components/ui/use-mobile.tsx create mode 100644 kits/content-generation/components/ui/use-toast.ts create mode 100644 kits/content-generation/constitutions/default.md create mode 100644 kits/content-generation/flows/agentic-generate-content.inputs.json create mode 100644 kits/content-generation/flows/agentic-generate-content.meta.json create mode 100644 kits/content-generation/flows/agentic-generate-content.ts create mode 100644 kits/content-generation/flows/flows.md create mode 100644 kits/content-generation/hooks/use-mobile.ts create mode 100644 kits/content-generation/hooks/use-toast.ts create mode 100644 kits/content-generation/lamatic.config.ts create mode 100644 kits/content-generation/next.config.mjs create mode 100644 kits/knowledge-chatbot/.env.example create mode 100644 kits/knowledge-chatbot/.gitignore create mode 100644 kits/knowledge-chatbot/README.md create mode 100644 kits/knowledge-chatbot/constitutions/default.md create mode 100644 kits/knowledge-chatbot/flows/crawling-indexation.inputs.json create mode 100644 kits/knowledge-chatbot/flows/crawling-indexation.meta.json create mode 100644 kits/knowledge-chatbot/flows/crawling-indexation.ts create mode 100644 kits/knowledge-chatbot/flows/flows.md create mode 100644 kits/knowledge-chatbot/flows/gdrive.inputs.json create mode 100644 kits/knowledge-chatbot/flows/gdrive.meta.json create mode 100644 kits/knowledge-chatbot/flows/gdrive.ts create mode 100644 kits/knowledge-chatbot/flows/gsheet.inputs.json create mode 100644 kits/knowledge-chatbot/flows/gsheet.meta.json create mode 100644 kits/knowledge-chatbot/flows/gsheet.ts create mode 100644 kits/knowledge-chatbot/flows/knowledge-chatbot.inputs.json create mode 100644 kits/knowledge-chatbot/flows/knowledge-chatbot.meta.json create mode 100644 kits/knowledge-chatbot/flows/knowledge-chatbot.ts create mode 100644 kits/knowledge-chatbot/flows/onedrive.inputs.json create mode 100644 kits/knowledge-chatbot/flows/onedrive.meta.json create mode 100644 kits/knowledge-chatbot/flows/onedrive.ts create mode 100644 kits/knowledge-chatbot/flows/postgres.inputs.json create mode 100644 kits/knowledge-chatbot/flows/postgres.meta.json create mode 100644 kits/knowledge-chatbot/flows/postgres.ts create mode 100644 kits/knowledge-chatbot/flows/s3.inputs.json create mode 100644 kits/knowledge-chatbot/flows/s3.meta.json create mode 100644 kits/knowledge-chatbot/flows/s3.ts create mode 100644 kits/knowledge-chatbot/flows/scraping-indexation.inputs.json create mode 100644 kits/knowledge-chatbot/flows/scraping-indexation.meta.json create mode 100644 kits/knowledge-chatbot/flows/scraping-indexation.ts create mode 100644 kits/knowledge-chatbot/flows/sharepoint.inputs.json create mode 100644 kits/knowledge-chatbot/flows/sharepoint.meta.json create mode 100644 kits/knowledge-chatbot/flows/sharepoint.ts create mode 100644 kits/knowledge-chatbot/lamatic.config.ts create mode 100644 kits/rag-chatbot/.gitignore create mode 100644 kits/rag-chatbot/README.md create mode 100644 kits/rag-chatbot/constitutions/default.md create mode 100644 kits/rag-chatbot/flows/flows.md create mode 100644 kits/rag-chatbot/flows/rag-chatbot.inputs.json create mode 100644 kits/rag-chatbot/flows/rag-chatbot.meta.json create mode 100644 kits/rag-chatbot/flows/rag-chatbot.ts create mode 100644 kits/rag-chatbot/lamatic.config.ts create mode 100644 kits/rag-chatbot/prompts/system.md diff --git a/kits/content-generation/.env.example b/kits/content-generation/.env.example new file mode 100644 index 00000000..2483cbdf --- /dev/null +++ b/kits/content-generation/.env.example @@ -0,0 +1,4 @@ +AGENTIC_GENERATE_CONTENT="AGENTIC_GENERATE_CONTENT Flow ID" +LAMATIC_API_URL="LAMATIC_API_URL" +LAMATIC_PROJECT_ID="LAMATIC_PROJECT_ID" +LAMATIC_API_KEY="LAMATIC_API_KEY" \ No newline at end of file diff --git a/kits/content-generation/.gitignore b/kits/content-generation/.gitignore new file mode 100644 index 00000000..b28ea810 --- /dev/null +++ b/kits/content-generation/.gitignore @@ -0,0 +1,27 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules + +# next.js +/.next/ +/out/ + +# production +/build + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files +.env + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts \ No newline at end of file diff --git a/kits/content-generation/README.md b/kits/content-generation/README.md new file mode 100644 index 00000000..5943f657 --- /dev/null +++ b/kits/content-generation/README.md @@ -0,0 +1,106 @@ +# Agent Kit Generation by Lamatic.ai + +

+ + Live Demo + +

+ + +**Agent Kit Generation** is an AI-powered content generation system built with [Lamatic.ai](https://lamatic.ai). It uses intelligent workflows to generate text, images, and JSON content through a modern Next.js interface with markdown rendering support. + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits/agentic/generation&env=AGENTIC_GENERATE_CONTENT,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY&envDescription=Your%20Lamatic%20Generation%20keys%20are%20required.&envLink=https://lamatic.ai/templates/agentkits/agentic/agent-kit-generation) + +--- + +## Lamatic Setup (Pre and Post) + +Before running this project, you must build and deploy the flow in Lamatic, then wire its config into this codebase. + +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" +4. Select the 'Generation' agent kit +5. Configure providers/tools/inputs as prompted +6. Deploy the kit in Lamatic and obtain your .env keys +7. Copy the keys from your studio + +Post: Wire into this repo +1. Create a .env file and set the keys +2. Install and run locally: + - npm install + - npm run dev +3. Deploy (Vercel recommended): + - 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. + +--- + +## 🔑 Setup +## Required Keys and Config + +You’ll need these things to run this project locally: + +1. **.env Keys** → get it from your [Lamatic account](https://lamatic.ai) post kit deployment. + + +| Item | Purpose | Where to Get It | +| ----------------- | -------------------------------------------- | ----------------------------------------------- | +| .env Key | Authentication for Lamatic AI APIs and Orchestration | [lamatic.ai](https://lamatic.ai) | + +### 1. Environment Variables + +Create `.env.local` with: + +```bash +# Lamatic +AGENTIC_GENERATE_CONTENT = "AGENTIC_GENERATE_CONTENT Flow ID" +LAMATIC_API_URL = "LAMATIC_API_URL" +LAMATIC_PROJECT_ID = "LAMATIC_PROJECT_ID" +LAMATIC_API_KEY = "LAMATIC_API_KEY" +``` + +### 2. Install & Run + +```bash +npm install +npm run dev +# Open http://localhost:3000 +``` +--- + +## 📂 Repo Structure + +``` +/actions + └── orchestrate.ts # Lamatic workflow orchestration +/app + └── page.tsx # Main generation form UI +/components + ├── header.tsx # Header component with navigation + └── ui # shadcn/ui components +/lib + └── lamatic-client.ts # Lamatic SDK client +/public + └── lamatic-logo.png # Lamatic branding +/flows + └── ... # Lamatic Flows +/package.json # Dependencies & scripts +``` + +--- + +## 🤝 Contributing + +We welcome contributions! Open an issue or PR in this repo. + +--- + +## 📜 License + +MIT License – see [LICENSE](../../../LICENSE). diff --git a/kits/content-generation/actions/orchestrate.ts b/kits/content-generation/actions/orchestrate.ts new file mode 100644 index 00000000..78bd9438 --- /dev/null +++ b/kits/content-generation/actions/orchestrate.ts @@ -0,0 +1,84 @@ +"use server" + +import { lamaticClient } from "@/lib/lamatic-client" +import {config} from "../orchestrate.js" + +type InputType = "text" | "image" | "json" + +export async function generateContent( + inputType: InputType, + instructions: string, +): Promise<{ + success: boolean + data?: any + error?: string +}> { + try { + console.log("[v0] Generating content with:", { inputType, instructions }) + + // Get the first workflow from the config + const flows = config.flows + const firstFlowKey = Object.keys(flows)[0] + + if (!firstFlowKey) { + throw new Error("No workflows found in configuration") + } + + // Fix: Add index signature to make TypeScript happy about accessing flows[firstFlowKey] + const flow = flows[firstFlowKey as keyof typeof flows] as (typeof flows)[keyof typeof flows]; + console.log("[v0] Using workflow:", flow.name, flow.workflowId); + + // Prepare inputs based on the flow's input schema + const inputs: Record = { + mode: inputType, + instructions, + } + + // Map to schema if needed + for (const inputKey of Object.keys(flow.inputSchema || {})) { + if (inputKey === "inputType" || inputKey === "type") { + inputs[inputKey] = inputType + } else if (inputKey === "instructions" || inputKey === "query") { + inputs[inputKey] = instructions + } + } + + console.log("[v0] Sending inputs:", inputs) + + if(!flow.workflowId){ + throw Error("Workflow not found in config.") + } + const resData = await lamaticClient.executeFlow(flow.workflowId, inputs) + console.log("[v0] Raw response:", resData) + + // Parse the answer from resData?.output.answer + const answer = resData?.result?.answer + + if (!answer) { + throw new Error("No answer found in response") + } + + return { + success: true, + data: answer, + } + } catch (error) { + console.error("[v0] Generation error:", error) + + let errorMessage = "Unknown error occurred" + if (error instanceof Error) { + errorMessage = error.message + if (error.message.includes("fetch failed")) { + errorMessage = + "Network error: Unable to connect to the service. Please check your internet connection and try again." + } else if (error.message.includes("API key")) { + errorMessage = "Authentication error: Please check your API configuration." + } + } + + return { + success: false, + error: errorMessage, + } + } +} diff --git a/kits/content-generation/app/globals.css b/kits/content-generation/app/globals.css new file mode 100644 index 00000000..dc2aea17 --- /dev/null +++ b/kits/content-generation/app/globals.css @@ -0,0 +1,125 @@ +@import 'tailwindcss'; +@import 'tw-animate-css'; + +@custom-variant dark (&:is(.dark *)); + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.145 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.985 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.269 0 0); + --input: oklch(0.269 0 0); + --ring: oklch(0.439 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(0.269 0 0); + --sidebar-ring: oklch(0.439 0 0); +} + +@theme inline { + --font-sans: 'Geist', 'Geist Fallback'; + --font-mono: 'Geist Mono', 'Geist Mono Fallback'; + --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; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/kits/content-generation/app/layout.tsx b/kits/content-generation/app/layout.tsx new file mode 100644 index 00000000..4489638d --- /dev/null +++ b/kits/content-generation/app/layout.tsx @@ -0,0 +1,45 @@ +import type { Metadata } from 'next' +import { Geist, Geist_Mono } from 'next/font/google' +import { Analytics } from '@vercel/analytics/next' +import './globals.css' + +const _geist = Geist({ subsets: ["latin"] }); +const _geistMono = Geist_Mono({ subsets: ["latin"] }); + +export const metadata: Metadata = { + title: 'v0 App', + description: 'Created with v0', + generator: 'v0.app', + icons: { + icon: [ + { + url: '/icon-light-32x32.png', + media: '(prefers-color-scheme: light)', + }, + { + url: '/icon-dark-32x32.png', + media: '(prefers-color-scheme: dark)', + }, + { + url: '/icon.svg', + type: 'image/svg+xml', + }, + ], + apple: '/apple-icon.png', + }, +} + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + + {children} + + + + ) +} diff --git a/kits/content-generation/app/page.tsx b/kits/content-generation/app/page.tsx new file mode 100644 index 00000000..461848d7 --- /dev/null +++ b/kits/content-generation/app/page.tsx @@ -0,0 +1,229 @@ +"use client" + +import type React from "react" + +import { useState } from "react" +import { Button } from "@/components/ui/button" +import { Textarea } from "@/components/ui/textarea" +import { Card } from "@/components/ui/card" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" +import { Loader2, Sparkles, FileText, Copy, Check, Home } from "lucide-react" +import { generateContent } from "@/actions/orchestrate" +import ReactMarkdown from "react-markdown" +import { Header } from "@/components/header" + +type InputType = "text" | "image" | "json" + +export default function GenerationPage() { + const [inputType, setInputType] = useState("text") + const [instructions, setInstructions] = useState("") + const [isLoading, setIsLoading] = useState(false) + const [result, setResult] = useState(null) + const [error, setError] = useState("") + const [copied, setCopied] = useState(false) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + + if (!instructions.trim()) { + setError("Please provide instructions") + return + } + + setIsLoading(true) + setError("") + setResult(null) + setCopied(false) + + try { + const response = await generateContent(inputType, instructions) + + if (response.success) { + setResult(response.data) + } else { + setError(response.error || "Generation failed") + } + } catch (err) { + setError(err instanceof Error ? err.message : "An error occurred") + } finally { + setIsLoading(false) + } + } + + const handleReset = () => { + setResult(null) + setInstructions("") + setError("") + setCopied(false) + } + + const handleCopy = async () => { + const textToCopy = typeof result === "object" ? JSON.stringify(result, null, 2) : String(result) + + try { + await navigator.clipboard.writeText(textToCopy) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } catch (err) { + console.error("Failed to copy:", err) + } + } + + const isImageUrl = (value: any): boolean => { + if (typeof value !== "string") return false + return ( + /^https?:\/\/.+\.(jpg|jpeg|png|gif|webp|svg)$/i.test(value) || + (/^https?:\/\/.+/.test(value) && (value.includes("image") || value.includes("img"))) + ) + } + + const renderResult = () => { + if (!result) return null + + // Check if it's an image URL + if (isImageUrl(result)) { + return ( +
+ Generated content +

{result}

+
+ ) + } + + // Check if it's an object/JSON + if (typeof result === "object" && result !== null) { + return
{JSON.stringify(result, null, 2)}
+ } + + // If input type is text, render as markdown + if (inputType === "text" && typeof result === "string") { + return ( +
+ {result} +
+ ) + } + + // Otherwise, it's plain text + return

{result}

+ } + + return ( +
+
+ +
+ {!result && ( +
+
+
+

Generate Content

+

+ Select input type and provide instructions for content generation +

+
+ + +
+
+ + +
+ +
+ +