Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Google AI Studio (aistudio.google.com)
GOOGLE_GENERATIVE_AI_API_KEY=your_google_ai_key

# Upstash Console (console.upstash.com)
UPSTASH_REDIS_REST_URL=https://your-instance.upstash.io
UPSTASH_REDIS_REST_TOKEN=your_upstash_token
3 changes: 3 additions & 0 deletions .github/workflows/firebase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ jobs:
run: mise run deploy
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
UPSTASH_REDIS_REST_URL: ${{ secrets.UPSTASH_REDIS_REST_URL }}
UPSTASH_REDIS_REST_TOKEN: ${{ secrets.UPSTASH_REDIS_REST_TOKEN }}
15 changes: 15 additions & 0 deletions .github/workflows/seed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Re-seed Vector Store

on:
workflow_dispatch:

jobs:
seed:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v4
- name: Run seed:reset
run: pnpm run seed:reset
env:
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
27 changes: 27 additions & 0 deletions .vibe/specs/add-ai-agent/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Plan for AI Agent Implementation

1. **Setup and Dependencies**
- Install required npm packages and dev dependencies.
- Update `package.json` with seed scripts.

2. **Data Preparation and Seeding**
- Set up Firebase Admin SDK in `src/lib/firebase.ts`.
- Create the seeding script `scripts/seed.ts` to process data files and populate Firestore with embeddings.
- Implement the query function in `src/lib/ai/queries.ts`.

3. **Backend Development**
- Implement the AI API route `src/app/api/chat/route.ts`.
- Integrate rate limiting, validation, and RAG logic.

4. **Frontend Development**
- Create the `ChatWidget` component in `src/components/chat-widget.tsx`.
- Integrate the widget into the main layout `src/app/layout.tsx`.

5. **CI/CD and Environment Configuration**
- Create the GitHub Actions workflow for seeding.
- Update `.env.local.example`.

6. **Pre-commit and Verification**
- Verify all functionalities.
- Run tests (if applicable).
- Ensure all security and performance guidelines are met.
31 changes: 31 additions & 0 deletions .vibe/specs/add-ai-agent/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Requirements for AI Agent

## Overview

Add an AI assistant to the portfolio website to answer questions about Amr Abed's experiences, skills, tools, projects, and certifications using RAG (Retrieval-Augmented Generation) with data from the project's data files.

## Technical Stack

- **Framework**: Next.js 15 (App Router)
- **AI SDK**: Vercel AI SDK (`ai`)
- **Model**: Google Gemini (`@ai-sdk/google`, model `gemma-4-27b-it`)
- **Embeddings**: `@ai-sdk/google` (model `text-embedding-004`)
- **Database/Vector Store**: Firebase Firestore (Vector Search)
- **Rate Limiting**: Upstash Redis (`@upstash/ratelimit`, `@upstash/redis`)
- **UI**: Tailwind CSS, HeroUI v3 components, Lucide icons, `react-markdown`

## Functional Requirements

- **Chat Interface**: A floating chat widget accessible from any page.
- **RAG Capability**: The agent must retrieve relevant context from the portfolio data to answer queries accurately.
- **Rate Limiting**: 10 requests per day per IP to prevent abuse.
- **Markdown Support**: AI responses should support markdown formatting.
- **Accessibility**: ARIA labels, keyboard navigation (Escape to close), and focus management.
- **Seeding**: A script to process data files, generate embeddings, and store them in Firestore.
- **CI/CD**: Automated re-seeding of the vector store on production deployments.

## Security Requirements

- Protect against reverse tabnabbing in links.
- Securely handle API keys via environment variables.
- Use Firebase Admin SDK for server-side operations.
7 changes: 7 additions & 0 deletions .vibe/specs/add-ai-agent/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Tasks - AI Agent Implementation

- [x] Task 1: Install dependencies and add scripts.
- [x] Task 2: Set up Firebase Admin and Seed script.
- [x] Task 3: Create API Route for chat.
- [x] Task 4: Create Floating Chat Widget.
- [x] Task 5: Setup GitHub Actions and Env template.
40 changes: 27 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,37 @@
"build": "next build",
"start": "next start",
"format": "prettier -w .",
"lint": "eslint ."
"lint": "eslint .",
"seed": "tsx scripts/seed.ts",
"seed:reset": "tsx scripts/seed.ts --reset"
},
"dependencies": {
"@ai-sdk/google": "^3.0.80",
"@ai-sdk/react": "^3.0.199",
"@heroicons/react": "^2.2.0",
"@heroui/react": "^3.0.5",
"@heroui/styles": "^3.0.5",
"@next/third-parties": "^16.2.6",
"@react-aria/visually-hidden": "^3.9.0",
"@heroui/react": "^3.1.0",
"@heroui/styles": "^3.1.0",
"@next/third-parties": "^16.2.7",
"@react-aria/visually-hidden": "^3.9.1",
"@tailwindcss/postcss": "^4.3.0",
"@upstash/ratelimit": "^2.0.8",
"@upstash/redis": "^1.38.0",
"@vercel/analytics": "^1.6.1",
"ai": "^6.0.197",
"axios": "^1.17.0",
"firebase-admin": "^13.10.0",
"framer-motion": "^12.40.0",
"he": "^1.2.0",
"next": "^16.2.6",
"lucide-react": "^1.17.0",
"mongoose": "^8.24.0",
"next": "^16.2.7",
"next-themes": "^0.4.6",
"react": "^19.2.6",
"react-dom": "^19.2.6",
"nodemailer": "^8.0.10",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-ga4": "^2.1.0",
"react-icons": "^5.6.0",
"react-markdown": "^10.1.0",
"react-responsive-carousel": "^3.2.23",
"react-responsive-masonry": "^2.7.2",
"react-syntax-highlighter": "^16.1.1",
Expand All @@ -34,20 +47,21 @@
},
"devDependencies": {
"@eslint/js": "9.38.0",
"@next/eslint-plugin-next": "^15.5.18",
"@next/eslint-plugin-next": "^15.5.19",
"@playwright/test": "^1.60.0",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/node": "^24.12.4",
"@types/react": "^19.2.15",
"@types/node": "^24.13.1",
"@types/react": "^19.2.17",
"autoprefixer": "^10.5.0",
"eslint": "9.38.0",
"eslint-config-next": "^16.2.6",
"eslint-config-next": "^16.2.7",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1",
"postcss": "^8.5.15",
"prettier": "^3.8.3",
"tailwindcss": "^4.3.0",
"typescript-eslint": "^8.59.4"
"tsx": "^4.22.4",
"typescript-eslint": "^8.60.1"
}
}
Loading