A reusable, embeddable chatbot widget for personal CV/portfolio websites. Built with Vite, React, TypeScript, and Tailwind CSS.
- π― Floating Chat Widget - Bottom-right corner button that opens a chat panel
- π¬ AI-Powered Conversations - Answers questions about your CV using Google Gemini 2.0 Flash (via OpenAI-compatible API)
- π Demo Mode - Works out of the box without any API key using local fallback responses
- β‘ Quick Actions - Predefined topic buttons for common questions
- π± Responsive Design - Works seamlessly on desktop and mobile
- π¨ Clean UI - Modern, minimal design with Tailwind CSS
- π§ Fully Configurable - Easy to customize CV data, tone, and behavior
cv-assistant/
βββ src/
β βββ components/
β β βββ CvChatbot/
β β βββ CvChatbot.tsx # Main chatbot component
β β βββ ChatWindow.tsx # Chat panel wrapper
β β βββ MessageList.tsx # Message bubbles
β β βββ MessageInput.tsx # Input + send button
β β βββ QuickActions.tsx # Quick action buttons
β β βββ index.ts # Exports
β βββ config/
β β βββ cvData.ts # CV data configuration
β β βββ systemPrompt.ts # System prompt generator
β β βββ quickActions.ts # Quick action buttons config
β βββ lib/
β β βββ openai.ts # Gemini API helper function (OpenAI-compatible)
β βββ types/
β β βββ chat.ts # Chat message types
β β βββ cv.ts # CV data types
β βββ App.tsx # Main app component
β βββ main.tsx # Entry point
β βββ index.css # Global styles
βββ .env # Environment variables (create this)
βββ .env.example # Example environment variables
βββ index.html # HTML entry point
βββ package.json
βββ tsconfig.json
βββ vite.config.ts
- Node.js 18 or higher
- npm or yarn
npm installThe app works out of the box in demo mode without any configuration! You can skip this step if you just want to try it.
Demo Mode (Default - No API Key Required):
- The chatbot works immediately without any
.envfile - Uses local fallback responder based on CV data
- No network calls, no API keys needed
- Perfect for testing and demos
AI Mode (Optional - Requires API Key): If you want to use real AI responses from Google Gemini:
- Create a
.envfile in the root directory (you can copy from.env.example) - Add the following:
VITE_USE_LLM=true
VITE_GOOGLE_API_KEY=your-gemini-api-key-here
VITE_LLM_MODEL=gemini-2.0-flashNote:
VITE_USE_LLMmust be set to"true"(as a string) to enable AI modeVITE_LLM_MODELis optional and defaults togemini-2.0-flashif not provided- If
VITE_USE_LLMis not set or"false", the app runs in demo mode regardless of API key
npm run devThe app will open at http://localhost:3000 (or another port if 3000 is busy).
npm run buildThe production build will be in the dist directory. You can preview it with:
npm run previewEdit src/config/cvData.ts to replace the example data with your own:
- Personal Info:
name,title,summary - Experience: Add your work history in
experiences[] - Projects: List your projects in
projects[] - Skills: Organize your technical skills in
skills - Current Work: What you're working on, learning, goals
- Links: Contact information and social links
To use your own photo in the hero section:
- Place a file called
image.pngin thepublic/folder - The hero avatar will automatically use
/image.png - Recommended size: Square image (e.g., 400x400px or larger) for best quality
- The image will be displayed as a circular avatar with a blue border
Example:
export const cvData: CvData = {
name: 'Your Name',
title: 'Your Title',
summary: 'Your professional summary...',
experiences: [
{
company: 'Company Name',
position: 'Your Position',
period: '2020 - Present',
description: ['Achievement 1', 'Achievement 2'],
technologies: ['React', 'TypeScript'],
},
],
// ... rest of your data
}Edit src/config/systemPrompt.ts to change the assistant's tone, behavior, or instructions. The function createSystemPrompt(cvData) generates the system message for the LLM.
You can modify:
- The tone (friendly, professional, casual, etc.)
- Response style (concise, detailed, etc.)
- Rules and constraints
- How the CV data is formatted in the prompt
Edit src/config/quickActions.ts to modify the quick action buttons:
export const quickActions: QuickAction[] = [
{ label: 'Who is Arzu?', topic: 'profile' },
{ label: 'Experience', topic: 'experience' },
{ label: 'Projects', topic: 'projects' },
// Add more actions...
]The topic values are used to provide context-specific instructions to the LLM when a quick action is clicked.
In src/App.tsx, customize the CvChatbot props:
<CvChatbot
cvData={cvData}
quickActions={quickActions}
title="CV Assistant" // Change the chat window title
placeholder="Ask me anything..." // Change input placeholder
buttonLabel="CV Assistant" // Change floating button label
/>-
Component Architecture: The
CvChatbotcomponent manages the chat state and UI. It's completely decoupled from the LLM implementation. -
Response Generation: The component calls
sendChatMessage()fromsrc/lib/openai.ts, which:- Demo Mode (default): Uses local fallback responder based on CV data (no API calls, no key required)
- AI Mode (when
VITE_USE_LLM=trueand API key is set):- Builds a system prompt using your CV data
- Formats the conversation history
- Calls Google Gemini's OpenAI-compatible Chat Completions API
- Returns the assistant's response
-
Message Flow:
- User types a message or clicks a quick action
- Message is added to local state
- In demo mode: Local fallback responder generates response from CV data
- In AI mode: Gemini API is called with conversation history
- Assistant response is appended to messages
-
First-Time Greeting: When the chat opens for the first time, an automatic greeting message is displayed.
All components use Tailwind CSS. You can customize colors, spacing, and layout by modifying the className props in:
src/components/CvChatbot/CvChatbot.tsx(floating button)src/components/CvChatbot/ChatWindow.tsx(chat panel)src/components/CvChatbot/MessageList.tsx(message bubbles)src/components/CvChatbot/MessageInput.tsx(input area)
To use a different LLM provider (e.g., OpenAI, Anthropic, local model), modify src/lib/openai.ts:
- Replace the Gemini API endpoint with your provider's API
- Adjust the request/response format as needed
- Update environment variables accordingly
The chatbot widget is designed to be portable:
- Copy the
src/components/CvChatbot/directory - Copy the
src/types/directory - Copy
src/lib/openai.ts(or your custom LLM integration) - Copy
src/config/directory and customize the files - Ensure your environment variables are set
- Import and use:
<CvChatbot cvData={...} quickActions={...} />
- Vite 6 - Fast build tool and dev server
- React 18 - UI library
- TypeScript - Type safety
- Tailwind CSS 4 - Utility-first styling
- lucide-react - Icon library
- Google Gemini 2.0 Flash - LLM integration via OpenAI-compatible API (configurable)
| Variable | Description | Required | Default |
|---|---|---|---|
VITE_USE_LLM |
Enable AI mode (set to "true" to use Gemini API) |
No | "false" (demo mode) |
VITE_GOOGLE_API_KEY |
Your Google Gemini API key | Only if VITE_USE_LLM=true |
- |
VITE_LLM_MODEL |
Gemini model to use | No | gemini-2.0-flash |
Important: Since this uses Vite, all environment variables must be prefixed with VITE_ to be accessible in the browser.
Demo Mode (Default):
- No environment variables needed
- Works immediately after
npm installandnpm run dev - Uses local fallback responder based on CV data
- No network calls, no API keys, no errors
- Perfect for testing, demos, and templates
- Shows "Demo Mode" badge in the chat header
AI Mode (Optional):
- Set
VITE_USE_LLM=truein.env - Set
VITE_GOOGLE_API_KEYwith your Gemini API key - Makes real API calls to Google Gemini
- Falls back to demo mode if key is missing or invalid
- Shows "AI Mode" badge in the chat header
Note on Model Selection:
gemini-2.0-flashmay not be available on all plans (especially free tier)- If you encounter quota/rate limit errors, try these alternatives:
gemini-1.5-flash(faster, widely available on free tier)gemini-1.5-pro(more capable, available on free tier)gemini-pro(older but widely available)
- Check model availability: https://ai.google.dev/gemini-api/docs/models
- Monitor your usage: https://ai.dev/usage?tab=rate-limit
This project is designed to be turned into a commercial template. Customize and use as needed.
For issues or questions, please refer to the code comments or adjust the implementation to fit your needs.