From 7197f0d21cb19fd0e63412c05fceb41133f04eb5 Mon Sep 17 00:00:00 2001 From: barbara79 Date: Sun, 1 Mar 2026 18:21:51 +0100 Subject: [PATCH 1/2] chore: remove API keys from tracking --- .gitignore | 2 +- README.md | 2 +- env.example | 4 + env.local | 2 - package-lock.json | 10 ++ package.json | 1 + src/app/api/generate/route.ts | 24 ++-- src/app/job-application/page.tsx | 81 ++++++++++++ src/app/job-comparison/page.tsx | 94 +++++++++++++ src/app/marketplace/page.tsx | 124 ++++++++++++++++++ src/app/page.tsx | 72 ++++++---- src/components/ComparisonView.tsx | 90 +++++++++++++ src/components/EngineResult.tsx | 39 ++++++ src/engine/core/content.ts | 5 + src/engine/core/engine.ts | 7 +- src/engine/core/registry.ts | 4 +- src/engine/core/request.ts | 44 ++++--- src/engine/core/types.ts | 35 +++-- .../modes/{comparison.ts => jobComparison.ts} | 5 +- src/engine/runner/engineRunner.ts | 3 - src/engine/runner/factory.ts | 33 +++++ src/engine/runner/geminiRunner.ts | 21 +++ src/engine/runner/groqRunner.ts | 31 +++++ src/engine/runner/openAIRunner.ts | 3 +- src/engine/runner/types.ts | 3 + tests/api/generate.test.ts | 2 +- tests/engine/jobComparison.test.ts | 77 +++++++++++ tsconfig.json | 21 ++- 28 files changed, 750 insertions(+), 89 deletions(-) create mode 100644 env.example delete mode 100644 env.local create mode 100644 src/app/job-application/page.tsx create mode 100644 src/app/job-comparison/page.tsx create mode 100644 src/app/marketplace/page.tsx create mode 100644 src/components/ComparisonView.tsx create mode 100644 src/components/EngineResult.tsx rename src/engine/modes/{comparison.ts => jobComparison.ts} (91%) delete mode 100644 src/engine/runner/engineRunner.ts create mode 100644 src/engine/runner/factory.ts create mode 100644 src/engine/runner/geminiRunner.ts create mode 100644 src/engine/runner/groqRunner.ts create mode 100644 tests/engine/jobComparison.test.ts diff --git a/.gitignore b/.gitignore index e8eb7fb..5408a11 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,4 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts -.env.local +env.local diff --git a/README.md b/README.md index 0ee428b..493d549 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The engine is built on a "Decoupled Orchestration" model: | :--- | :--- | :--- | | **Job Application** | Cover Letters & Resume Summaries | Self-critique of tone and skill alignment. | | **Marketplace** | Product titles, descriptions & SEO tags | Automatic extraction of selling points and SEO optimization. | -| **Comparison** | Job Description vs. Resume analysis | Semantic gap analysis with ✅/❌ match reporting. | +| **Job Comparison** | Job Description vs. Resume analysis | Semantic gap analysis with ✅/❌ match reporting. | --- diff --git a/env.example b/env.example new file mode 100644 index 0000000..c6944a4 --- /dev/null +++ b/env.example @@ -0,0 +1,4 @@ +USE_AI=true +GEMINI_API_KEY=your_api_key_here +GROQ_API_KEY=your_groq_key_here +OPENAI_API_KEY=your_openai_key_here \ No newline at end of file diff --git a/env.local b/env.local deleted file mode 100644 index f9e2deb..0000000 --- a/env.local +++ /dev/null @@ -1,2 +0,0 @@ -OPENAI_API_KEY=your_sk_key_here -USE_OPENAI=true \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8cdb533..c579b2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "hybrid-text-engine", "version": "0.1.0", "dependencies": { + "@google/generative-ai": "^0.24.1", "next": "16.1.4", "node-fetch": "^3.3.2", "react": "19.2.3", @@ -686,6 +687,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@google/generative-ai": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", + "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", diff --git a/package.json b/package.json index 0f745f5..ac4e38d 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "test:watch": "jest --watch" }, "dependencies": { + "@google/generative-ai": "^0.24.1", "next": "16.1.4", "node-fetch": "^3.3.2", "react": "19.2.3", diff --git a/src/app/api/generate/route.ts b/src/app/api/generate/route.ts index acf6fd1..f636e95 100644 --- a/src/app/api/generate/route.ts +++ b/src/app/api/generate/route.ts @@ -1,31 +1,27 @@ import { NextRequest, NextResponse } from "next/server" import { runEngine } from "@/engine/core/engine" import { EngineRequest } from "@/engine/core/request" -import { OpenAIRunner } from "../../../engine/runner/openAIRunner"; -import { FakeRunner } from "@/engine/runner/fakeRunner" import { MODE_REGISTRY } from "@/engine/core/registry" +import { getRunner } from "@/engine/runner/factory"; + export async function POST(req: NextRequest) { try { - - const body: EngineRequest = await req.json(); + const modeLogic = MODE_REGISTRY[body.mode]; + + if (!modeLogic) { + return NextResponse.json({ error: "Invalid mode" }, { status: 400 }); + } - const mode = MODE_REGISTRY[body.mode]; - if (!mode) { - return NextResponse.json({ error: "Invalid mode" }, { status: 400 }); - } - - const runner = - process.env.USE_OPENAI === "true" - ? new OpenAIRunner({apiKey: process.env.OPENAI_API_KEY}) - : new FakeRunner(); + const runner = getRunner(body.provider); - const result = await runEngine(mode, body, runner); + const result = await runEngine(modeLogic, body, runner); return NextResponse.json(result); } catch (err) { console.error("API Error:", err); + return NextResponse.json( { error: err instanceof Error ? err.message : "Internal Server Error" }, { status: 500 } diff --git a/src/app/job-application/page.tsx b/src/app/job-application/page.tsx new file mode 100644 index 0000000..6934a49 --- /dev/null +++ b/src/app/job-application/page.tsx @@ -0,0 +1,81 @@ +"use client"; + +import { useState } from "react"; +import Link from "next/link"; + +import { Audience, EngineContext, EngineModeId, Provider, Tone } from "@/engine/core/types"; + +export default function JobApplicationPage() { + const [formData, setFormData] = useState({ resume: "", jd: "" }); + const [result, setResult] = useState(null); + const [loading, setLoading] = useState(false); + + const handleGenerate = async () => { + setLoading(true); + // Note: This uses the 'job-application' mode in your registry + const res = await fetch("/api/generate", { + method: "POST", + body: JSON.stringify({ + mode: EngineModeId.JOB_APPLICATION, + provider: Provider.GEMINI, + context: EngineContext.JOB, + tone: Tone.PROFESSIONAL, + audience: Audience.RECRUITERS, + content: { + resume: formData.resume, + jd: formData.jd + } + }), + }); + const data = await res.json(); + setResult(data); + setLoading(false); + }; + + return ( +
+ ← BACK + +
+
+

Application Writer

+

Generate a custom cover letter based on your experience.

+ +