From 3b51f8b2857e1a7d6e05c7a9707c99a5bc7c9b52 Mon Sep 17 00:00:00 2001 From: srijita22 <163577688+srijita22@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:21:45 +0530 Subject: [PATCH 1/3] feat: Add resumeFit AgentKit --- kits/agentic/resumeFit/.env.example | 4 + kits/agentic/resumeFit/.gitignore | 28 + kits/agentic/resumeFit/README.md | 106 + kits/agentic/resumeFit/actions/config.ts | 12 + kits/agentic/resumeFit/actions/orchestrate.ts | 128 + kits/agentic/resumeFit/app/globals.css | 127 + kits/agentic/resumeFit/app/layout.tsx | 45 + kits/agentic/resumeFit/app/page.tsx | 265 + kits/agentic/resumeFit/components.json | 21 + kits/agentic/resumeFit/components/header.tsx | 56 + .../resumeFit/components/theme-provider.tsx | 11 + .../resumeFit/components/ui/accordion.tsx | 66 + .../resumeFit/components/ui/alert-dialog.tsx | 157 + .../agentic/resumeFit/components/ui/alert.tsx | 66 + .../resumeFit/components/ui/aspect-ratio.tsx | 11 + .../resumeFit/components/ui/avatar.tsx | 53 + .../agentic/resumeFit/components/ui/badge.tsx | 46 + .../resumeFit/components/ui/breadcrumb.tsx | 109 + .../resumeFit/components/ui/button-group.tsx | 83 + .../resumeFit/components/ui/button.tsx | 60 + .../resumeFit/components/ui/calendar.tsx | 213 + kits/agentic/resumeFit/components/ui/card.tsx | 92 + .../resumeFit/components/ui/carousel.tsx | 241 + .../agentic/resumeFit/components/ui/chart.tsx | 353 + .../resumeFit/components/ui/checkbox.tsx | 32 + .../resumeFit/components/ui/collapsible.tsx | 33 + .../resumeFit/components/ui/command.tsx | 184 + .../resumeFit/components/ui/context-menu.tsx | 252 + .../resumeFit/components/ui/dialog.tsx | 143 + .../resumeFit/components/ui/drawer.tsx | 135 + .../resumeFit/components/ui/dropdown-menu.tsx | 257 + .../agentic/resumeFit/components/ui/empty.tsx | 104 + .../agentic/resumeFit/components/ui/field.tsx | 244 + kits/agentic/resumeFit/components/ui/form.tsx | 167 + .../resumeFit/components/ui/hover-card.tsx | 44 + .../resumeFit/components/ui/input-group.tsx | 169 + .../resumeFit/components/ui/input-otp.tsx | 77 + .../agentic/resumeFit/components/ui/input.tsx | 21 + kits/agentic/resumeFit/components/ui/item.tsx | 193 + kits/agentic/resumeFit/components/ui/kbd.tsx | 28 + .../agentic/resumeFit/components/ui/label.tsx | 24 + .../resumeFit/components/ui/menubar.tsx | 276 + .../components/ui/navigation-menu.tsx | 166 + .../resumeFit/components/ui/pagination.tsx | 127 + .../resumeFit/components/ui/popover.tsx | 48 + .../resumeFit/components/ui/progress.tsx | 31 + .../resumeFit/components/ui/radio-group.tsx | 45 + .../resumeFit/components/ui/resizable.tsx | 56 + .../resumeFit/components/ui/scroll-area.tsx | 58 + .../resumeFit/components/ui/select.tsx | 185 + .../resumeFit/components/ui/separator.tsx | 28 + .../agentic/resumeFit/components/ui/sheet.tsx | 139 + .../resumeFit/components/ui/sidebar.tsx | 726 ++ .../resumeFit/components/ui/skeleton.tsx | 13 + .../resumeFit/components/ui/slider.tsx | 63 + .../resumeFit/components/ui/sonner.tsx | 25 + .../resumeFit/components/ui/spinner.tsx | 16 + .../resumeFit/components/ui/switch.tsx | 31 + .../agentic/resumeFit/components/ui/table.tsx | 116 + kits/agentic/resumeFit/components/ui/tabs.tsx | 66 + .../resumeFit/components/ui/textarea.tsx | 18 + .../agentic/resumeFit/components/ui/toast.tsx | 129 + .../resumeFit/components/ui/toaster.tsx | 35 + .../resumeFit/components/ui/toggle-group.tsx | 73 + .../resumeFit/components/ui/toggle.tsx | 47 + .../resumeFit/components/ui/tooltip.tsx | 61 + .../resumeFit/components/ui/use-mobile.tsx | 19 + .../resumeFit/components/ui/use-toast.ts | 191 + kits/agentic/resumeFit/config.json | 22 + .../resumeFit/flows/resume-fit-flow/README.md | 62 + .../flows/resume-fit-flow/config.json | 435 ++ .../flows/resume-fit-flow/inputs.json | 170 + .../resumeFit/flows/resume-fit-flow/meta.json | 9 + kits/agentic/resumeFit/hooks/use-mobile.ts | 19 + kits/agentic/resumeFit/hooks/use-toast.ts | 191 + kits/agentic/resumeFit/lib/lamatic-client.ts | 24 + kits/agentic/resumeFit/lib/utils.ts | 6 + kits/agentic/resumeFit/next.config.mjs | 11 + kits/agentic/resumeFit/package-lock.json | 6170 +++++++++++++++++ kits/agentic/resumeFit/package.json | 84 + kits/agentic/resumeFit/postcss.config.js | 6 + kits/agentic/resumeFit/tailwind.config.js | 11 + kits/agentic/resumeFit/tsconfig.json | 38 + 83 files changed, 14506 insertions(+) create mode 100644 kits/agentic/resumeFit/.env.example create mode 100644 kits/agentic/resumeFit/.gitignore create mode 100644 kits/agentic/resumeFit/README.md create mode 100644 kits/agentic/resumeFit/actions/config.ts create mode 100644 kits/agentic/resumeFit/actions/orchestrate.ts create mode 100644 kits/agentic/resumeFit/app/globals.css create mode 100644 kits/agentic/resumeFit/app/layout.tsx create mode 100644 kits/agentic/resumeFit/app/page.tsx create mode 100644 kits/agentic/resumeFit/components.json create mode 100644 kits/agentic/resumeFit/components/header.tsx create mode 100644 kits/agentic/resumeFit/components/theme-provider.tsx create mode 100644 kits/agentic/resumeFit/components/ui/accordion.tsx create mode 100644 kits/agentic/resumeFit/components/ui/alert-dialog.tsx create mode 100644 kits/agentic/resumeFit/components/ui/alert.tsx create mode 100644 kits/agentic/resumeFit/components/ui/aspect-ratio.tsx create mode 100644 kits/agentic/resumeFit/components/ui/avatar.tsx create mode 100644 kits/agentic/resumeFit/components/ui/badge.tsx create mode 100644 kits/agentic/resumeFit/components/ui/breadcrumb.tsx create mode 100644 kits/agentic/resumeFit/components/ui/button-group.tsx create mode 100644 kits/agentic/resumeFit/components/ui/button.tsx create mode 100644 kits/agentic/resumeFit/components/ui/calendar.tsx create mode 100644 kits/agentic/resumeFit/components/ui/card.tsx create mode 100644 kits/agentic/resumeFit/components/ui/carousel.tsx create mode 100644 kits/agentic/resumeFit/components/ui/chart.tsx create mode 100644 kits/agentic/resumeFit/components/ui/checkbox.tsx create mode 100644 kits/agentic/resumeFit/components/ui/collapsible.tsx create mode 100644 kits/agentic/resumeFit/components/ui/command.tsx create mode 100644 kits/agentic/resumeFit/components/ui/context-menu.tsx create mode 100644 kits/agentic/resumeFit/components/ui/dialog.tsx create mode 100644 kits/agentic/resumeFit/components/ui/drawer.tsx create mode 100644 kits/agentic/resumeFit/components/ui/dropdown-menu.tsx create mode 100644 kits/agentic/resumeFit/components/ui/empty.tsx create mode 100644 kits/agentic/resumeFit/components/ui/field.tsx create mode 100644 kits/agentic/resumeFit/components/ui/form.tsx create mode 100644 kits/agentic/resumeFit/components/ui/hover-card.tsx create mode 100644 kits/agentic/resumeFit/components/ui/input-group.tsx create mode 100644 kits/agentic/resumeFit/components/ui/input-otp.tsx create mode 100644 kits/agentic/resumeFit/components/ui/input.tsx create mode 100644 kits/agentic/resumeFit/components/ui/item.tsx create mode 100644 kits/agentic/resumeFit/components/ui/kbd.tsx create mode 100644 kits/agentic/resumeFit/components/ui/label.tsx create mode 100644 kits/agentic/resumeFit/components/ui/menubar.tsx create mode 100644 kits/agentic/resumeFit/components/ui/navigation-menu.tsx create mode 100644 kits/agentic/resumeFit/components/ui/pagination.tsx create mode 100644 kits/agentic/resumeFit/components/ui/popover.tsx create mode 100644 kits/agentic/resumeFit/components/ui/progress.tsx create mode 100644 kits/agentic/resumeFit/components/ui/radio-group.tsx create mode 100644 kits/agentic/resumeFit/components/ui/resizable.tsx create mode 100644 kits/agentic/resumeFit/components/ui/scroll-area.tsx create mode 100644 kits/agentic/resumeFit/components/ui/select.tsx create mode 100644 kits/agentic/resumeFit/components/ui/separator.tsx create mode 100644 kits/agentic/resumeFit/components/ui/sheet.tsx create mode 100644 kits/agentic/resumeFit/components/ui/sidebar.tsx create mode 100644 kits/agentic/resumeFit/components/ui/skeleton.tsx create mode 100644 kits/agentic/resumeFit/components/ui/slider.tsx create mode 100644 kits/agentic/resumeFit/components/ui/sonner.tsx create mode 100644 kits/agentic/resumeFit/components/ui/spinner.tsx create mode 100644 kits/agentic/resumeFit/components/ui/switch.tsx create mode 100644 kits/agentic/resumeFit/components/ui/table.tsx create mode 100644 kits/agentic/resumeFit/components/ui/tabs.tsx create mode 100644 kits/agentic/resumeFit/components/ui/textarea.tsx create mode 100644 kits/agentic/resumeFit/components/ui/toast.tsx create mode 100644 kits/agentic/resumeFit/components/ui/toaster.tsx create mode 100644 kits/agentic/resumeFit/components/ui/toggle-group.tsx create mode 100644 kits/agentic/resumeFit/components/ui/toggle.tsx create mode 100644 kits/agentic/resumeFit/components/ui/tooltip.tsx create mode 100644 kits/agentic/resumeFit/components/ui/use-mobile.tsx create mode 100644 kits/agentic/resumeFit/components/ui/use-toast.ts create mode 100644 kits/agentic/resumeFit/config.json create mode 100644 kits/agentic/resumeFit/flows/resume-fit-flow/README.md create mode 100644 kits/agentic/resumeFit/flows/resume-fit-flow/config.json create mode 100644 kits/agentic/resumeFit/flows/resume-fit-flow/inputs.json create mode 100644 kits/agentic/resumeFit/flows/resume-fit-flow/meta.json create mode 100644 kits/agentic/resumeFit/hooks/use-mobile.ts create mode 100644 kits/agentic/resumeFit/hooks/use-toast.ts create mode 100644 kits/agentic/resumeFit/lib/lamatic-client.ts create mode 100644 kits/agentic/resumeFit/lib/utils.ts create mode 100644 kits/agentic/resumeFit/next.config.mjs create mode 100644 kits/agentic/resumeFit/package-lock.json create mode 100644 kits/agentic/resumeFit/package.json create mode 100644 kits/agentic/resumeFit/postcss.config.js create mode 100644 kits/agentic/resumeFit/tailwind.config.js create mode 100644 kits/agentic/resumeFit/tsconfig.json diff --git a/kits/agentic/resumeFit/.env.example b/kits/agentic/resumeFit/.env.example new file mode 100644 index 00000000..a943bef2 --- /dev/null +++ b/kits/agentic/resumeFit/.env.example @@ -0,0 +1,4 @@ +RESUME_FIT_FLOW="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/agentic/resumeFit/.gitignore b/kits/agentic/resumeFit/.gitignore new file mode 100644 index 00000000..3c35968e --- /dev/null +++ b/kits/agentic/resumeFit/.gitignore @@ -0,0 +1,28 @@ +# 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* +!.env.example + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts \ No newline at end of file diff --git a/kits/agentic/resumeFit/README.md b/kits/agentic/resumeFit/README.md new file mode 100644 index 00000000..5943f657 --- /dev/null +++ b/kits/agentic/resumeFit/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/agentic/resumeFit/actions/config.ts b/kits/agentic/resumeFit/actions/config.ts new file mode 100644 index 00000000..ba5e1024 --- /dev/null +++ b/kits/agentic/resumeFit/actions/config.ts @@ -0,0 +1,12 @@ +export const config = { + flows: { + resumeFit: { + name: "Resume Fit Flow", + workflowId: process.env.AGENTIC_GENERATE_CONTENT, + inputSchema: { + instructions: "string", + mode: "string" + } + } + } +} \ No newline at end of file diff --git a/kits/agentic/resumeFit/actions/orchestrate.ts b/kits/agentic/resumeFit/actions/orchestrate.ts new file mode 100644 index 00000000..34921240 --- /dev/null +++ b/kits/agentic/resumeFit/actions/orchestrate.ts @@ -0,0 +1,128 @@ +"use server" + +import { lamaticClient } from "../lib/lamatic-client" +import { config } from "./config" + +type InputType = "text" | "image" | "json" + +export async function evaluateResume( + 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 res = await fetch(process.env.LAMATIC_API_URL!, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${process.env.LAMATIC_API_KEY}`, + "x-project-id": process.env.LAMATIC_PROJECT_ID!, + }, + body: JSON.stringify({ + query: ` + query ExecuteWorkflow($workflowId: String!, $payload: JSON!) { + executeWorkflow(workflowId: $workflowId, payload: $payload) { + status + result + } + } + `, + variables: { + workflowId: flow.workflowId, + payload: { + chatMessage: instructions, // πŸ‘ˆ map your input here + mode: inputType, // optional depending on your flow + }, + }, + }), +}) + +console.log("STATUS:", res.status) +console.log("CONTENT TYPE:", res.headers.get("content-type")) + + const resData = await res.json() +console.log("FULL RESPONSE:", JSON.stringify(resData, null, 2)) + + // Parse the answer from resData?.output.answer + +const exec = resData?.data?.executeWorkflow + +if (!exec) { + throw new Error("Invalid response structure") +} + +if (exec.status !== "success") { + throw new Error("Workflow execution failed") +} + +// βœ… FIX: extract content instead of answer +const answer = + exec?.result?.content || + exec?.result?.answer || // fallback if structure changes + exec?.result + +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/agentic/resumeFit/app/globals.css b/kits/agentic/resumeFit/app/globals.css new file mode 100644 index 00000000..edfe99e2 --- /dev/null +++ b/kits/agentic/resumeFit/app/globals.css @@ -0,0 +1,127 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + + +@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; + } + body { + @apply bg-white text-black; + } +} \ No newline at end of file diff --git a/kits/agentic/resumeFit/app/layout.tsx b/kits/agentic/resumeFit/app/layout.tsx new file mode 100644 index 00000000..4489638d --- /dev/null +++ b/kits/agentic/resumeFit/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/agentic/resumeFit/app/page.tsx b/kits/agentic/resumeFit/app/page.tsx new file mode 100644 index 00000000..5c9aed9c --- /dev/null +++ b/kits/agentic/resumeFit/app/page.tsx @@ -0,0 +1,265 @@ +"use client" + +import { useState } from "react" +import { Button } from "../components/ui/button" +import { Textarea } from "../components/ui/textarea" +import { Card } from "../components/ui/card" +import { Loader2, Sparkles, Copy, Check, Home } from "lucide-react" +import { evaluateResume } from "../actions/orchestrate" +import { Header } from "../components/header" + +export default function ResumeScreener() { + const [resume, setResume] = useState("") + const [jobDesc, setJobDesc] = useState("") + const [isLoading, setIsLoading] = useState(false) + const [result, setResult] = useState(null) + const [error, setError] = useState("") + const [copied, setCopied] = useState(false) + + const handleSubmit = async (e: any) => { + e.preventDefault() + + if (!resume || !jobDesc) { + setError("Please provide both resume and job description") + return + } + + setIsLoading(true) + setError("") + setResult(null) + + try { + const combinedInput = ` + RESUME: + ${resume} + + JOB DESCRIPTION: + ${jobDesc} + ` + + const response = await evaluateResume("text", combinedInput) + + if (response.success) { + try { + let raw = response.data + + if (typeof raw === "string") { + + + raw = raw.replace(/```json|```/g, "").trim() + + + const match = raw.match(/\{[\s\S]*\}/) + + if (!match) { + throw new Error("No valid JSON found in response") + } + + const parsed = JSON.parse(match[0]) + + const formatted = { + decision: parsed.decision, + summary: parsed.summary, + score: Number(parsed.fscore || 0), + strengths: parsed.strengths + ? parsed.strengths.split(",").map((s: string) => s.trim()) + : [], + weaknesses: parsed.weaknesses + ? parsed.weaknesses.split(",").map((s: string) => s.trim()) + : [], +} + +setResult(formatted) + + } else { + // Already JSON + setResult(raw) + } + + } catch (err) { + console.error("Parsing error:", err) + setError("Failed to parse AI response") + } +} + } catch (err: any) { + setError(err.message) + } finally { + setIsLoading(false) + } + } + + const handleCopy = async () => { + await navigator.clipboard.writeText(JSON.stringify(result, null, 2)) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } + + const handleReset = () => { + setResult(null) + setResume("") + setJobDesc("") + setError("") + } + + const decision = result?.decision +const summary = result?.summary +const score = result?.score +const strengths = result?.strengths || [] +const weaknesses = result?.weaknesses || [] + + return ( +
+
+ +
+ + {/* HERO */} + {!result && ( + <> +
+

+ AI Resume Screener +

+

+ Instantly evaluate candidates based on job requirements +

+
+ + + +
+ + {/* RESUME */} +
+ +