├── react-avatar-app ├── src │ ├── vite-env.d.ts │ ├── utils │ │ └── cn.ts │ ├── main.tsx │ ├── components │ │ ├── ui │ │ │ ├── textarea.tsx │ │ │ ├── input.tsx │ │ │ └── button.tsx │ │ └── ThemeProvider.tsx │ ├── index.css │ ├── assets │ │ └── react.svg │ ├── App.css │ └── App.tsx ├── postcss.config.js ├── tsconfig.json ├── .gitignore ├── vite.config.ts ├── index.html ├── tsconfig.node.json ├── utils │ └── logger.js ├── tsconfig.app.json ├── eslint.config.js ├── package.json ├── public │ └── vite.svg ├── tailwind.config.js └── README.md ├── server ├── favicon.ico ├── .env.sample ├── .gitignore ├── routes │ ├── chatRouter.js │ └── personaRoutes.js ├── .prettierrc ├── config │ └── config.js ├── package.json ├── server.js ├── utils │ ├── persona.js │ └── logger.js ├── services │ ├── heygenService.js │ └── aiService.js ├── controllers │ ├── chatController.js │ ├── personaController.js │ └── heygenController.js ├── soham_bot.js ├── README.md └── package-lock.json └── README.md /react-avatar-app/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /server/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiehSt/Streaming-Avatar/HEAD/server/favicon.ico -------------------------------------------------------------------------------- /server/.env.sample: -------------------------------------------------------------------------------- 1 | HEYGEN_APIKEY= 2 | HEYGEN_SERVER_URL=https://api.heygen.com 3 | GEMINI_APIKEY= 4 | PORT=3000 -------------------------------------------------------------------------------- /react-avatar-app/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } -------------------------------------------------------------------------------- /react-avatar-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | .vscode 4 | .env 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | dist/ 9 | coverage/ 10 | .DS_Store 11 | *.log 12 | *.pid 13 | *.seed 14 | *.pid.lock -------------------------------------------------------------------------------- /server/routes/chatRouter.js: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import { AIChatResponse, InitializeBot } from '../controllers/chatController.js'; 3 | const chatRouter = Router(); 4 | 5 | chatRouter.post('/complete', AIChatResponse); 6 | chatRouter.post('/', InitializeBot); 7 | export default chatRouter; 8 | -------------------------------------------------------------------------------- /react-avatar-app/src/utils/cn.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | /** 5 | * Combines multiple class names using clsx and optimizes them with tailwind-merge 6 | */ 7 | export function cn(...inputs: ClassValue[]) { 8 | return twMerge(clsx(inputs)); 9 | } -------------------------------------------------------------------------------- /react-avatar-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /react-avatar-app/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import { ThemeProvider } from './components/ThemeProvider.tsx' 5 | import './index.css' 6 | 7 | ReactDOM.createRoot(document.getElementById('root')!).render( 8 | 9 | 10 | 11 | 12 | , 13 | ) 14 | -------------------------------------------------------------------------------- /react-avatar-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | server: { 8 | proxy: { 9 | '/persona': { 10 | target: 'http://localhost:3000', 11 | changeOrigin: true, 12 | }, 13 | '/openai': { 14 | target: 'http://localhost:3000', 15 | changeOrigin: true, 16 | } 17 | } 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /server/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": false, 4 | "trailingComma": "all", 5 | "printWidth": 100, 6 | "useTabs": false, 7 | "tabWidth": 2, 8 | "semi": true, 9 | "quoteProps": "as-needed", 10 | "bracketSpacing": true, 11 | "bracketSameLine": false, 12 | "arrowParens": "always", 13 | "singleAttributePerLine": false, 14 | "overrides": [ 15 | { 16 | "files": ".prettierrc", 17 | "options": { "parser": "json" } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /server/config/config.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | dotenv.config(); 3 | 4 | export const config = { 5 | heygen: { 6 | apiKey: process.env.HEYGEN_APIKEY, 7 | serverUrl: process.env.HEYGEN_SERVER_URL, 8 | defaultQuality: 'low', 9 | }, 10 | gemini: { 11 | apiKey: process.env.GEMINI_APIKEY, 12 | model: 'gemini-2.0-flash', 13 | config: { 14 | temperature: 0.9, 15 | topP: 0.1, 16 | topK: 16, 17 | maxOutputTokens: 2048, 18 | candidateCount: 1, 19 | stopSequences: [], 20 | }, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "streamingavatar", 3 | "version": "1.0.0", 4 | "description": "## Pre-Requisites", 5 | "type": "module", 6 | "main": "server.js", 7 | "keywords": [], 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "cors": "^2.8.5", 12 | "dotenv": "^16.5.0", 13 | "express": "^4.21.2", 14 | "mime-types": "^3.0.1" 15 | }, 16 | "scripts": { 17 | "start": "node server.js", 18 | "dev": "nodemon server.js", 19 | "test": "echo \"Error: no test specified\" && exit 1", 20 | "lint": "eslint .", 21 | "format": "prettier --write ." 22 | }, 23 | "devDependencies": { 24 | "prettier": "^3.2.4" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /react-avatar-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Streaming Avatar 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /react-avatar-app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import path from 'path'; 3 | import { fileURLToPath } from 'url'; 4 | import { logger } from './utils/logger.js'; 5 | import personaRouter from './routes/personaRoutes.js'; 6 | import chatRouter from './routes/chatRouter.js'; 7 | import dotenv from 'dotenv'; 8 | import cors from 'cors'; 9 | dotenv.config(); 10 | 11 | const __filename = fileURLToPath(import.meta.url); 12 | const __dirname = path.dirname(__filename); 13 | 14 | const app = express(); 15 | app.use(express.json()); 16 | app.use(cors()); 17 | 18 | app.use('/persona', personaRouter); 19 | app.use('/openai', chatRouter); 20 | 21 | app.listen(process.env.PORT, () => { 22 | logger.info('Server', `Server running at http://localhost:${process.env.PORT}`); 23 | }); 24 | -------------------------------------------------------------------------------- /react-avatar-app/utils/logger.js: -------------------------------------------------------------------------------- 1 | export const logger = { 2 | debug: (module, message, meta = {}) => { 3 | const timestamp = new Date().toISOString(); 4 | console.debug(`[${timestamp}] [DEBUG] [${module}]`, message, meta); 5 | }, 6 | info: (module, message, meta = {}) => { 7 | const timestamp = new Date().toISOString(); 8 | console.info(`[${timestamp}] [INFO] [${module}]`, message, meta); 9 | }, 10 | warn: (module, message, meta = {}) => { 11 | const timestamp = new Date().toISOString(); 12 | console.warn(`[${timestamp}] [WARN] [${module}]`, message, meta); 13 | }, 14 | error: (module, message, meta = {}) => { 15 | const timestamp = new Date().toISOString(); 16 | console.error(`[${timestamp}] [ERROR] [${module}]`, message, meta); 17 | } 18 | }; -------------------------------------------------------------------------------- /react-avatar-app/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true 24 | }, 25 | "include": ["src"] 26 | } 27 | -------------------------------------------------------------------------------- /react-avatar-app/src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cn } from "../../utils/cn" 3 | 4 | export interface TextareaProps 5 | extends React.TextareaHTMLAttributes {} 6 | 7 | const Textarea = React.forwardRef( 8 | ({ className, ...props }, ref) => { 9 | return ( 10 |