rahul036 commited on
Commit
7a249ac
·
verified ·
1 Parent(s): 8aa1e92

Upload 11 files

Browse files
Files changed (11) hide show
  1. .env.local +1 -0
  2. .gitignore +24 -0
  3. App.tsx +99 -0
  4. README.md +14 -3
  5. index.html +49 -0
  6. index.tsx +16 -0
  7. metadata.json +7 -0
  8. package.json +21 -0
  9. tsconfig.json +30 -0
  10. types.ts +14 -0
  11. vite.config.ts +17 -0
.env.local ADDED
@@ -0,0 +1 @@
 
 
1
+ GEMINI_API_KEY=PLACEHOLDER_API_KEY
.gitignore ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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?
App.tsx ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import React, { useState, useEffect } from 'react';
3
+ import ChatInterface from './components/ChatInterface';
4
+ import { LanguageProvider } from './contexts/LanguageContext';
5
+ import LanguageSelector from './components/LanguageSelector';
6
+ import FeedbackPage from './components/FeedbackPage';
7
+ import UserFeedbackAnalysisPage from './components/UserFeedbackAnalysisPage';
8
+ import { Review } from './types';
9
+
10
+ function App() {
11
+ const [page, setPage] = useState<'chat' | 'feedback' | 'userexperience'>('chat');
12
+
13
+ // Initialize reviews from localStorage
14
+ const [reviews, setReviews] = useState<Review[]>(() => {
15
+ try {
16
+ const storedReviews = window.localStorage.getItem('emotimate-reviews');
17
+ return storedReviews ? JSON.parse(storedReviews) : [];
18
+ } catch (error) {
19
+ console.error("Error reading reviews from localStorage", error);
20
+ return [];
21
+ }
22
+ });
23
+
24
+ // Save reviews to localStorage whenever they change
25
+ useEffect(() => {
26
+ try {
27
+ window.localStorage.setItem('emotimate-reviews', JSON.stringify(reviews));
28
+ } catch (error) {
29
+ console.error("Error saving reviews to localStorage", error);
30
+ }
31
+ }, [reviews]);
32
+
33
+ const handleAddReview = (review: Omit<Review, 'id' | 'date'>) => {
34
+ const newReview: Review = {
35
+ ...review,
36
+ id: `User-${Math.random().toString(36).substr(2, 4).toUpperCase()}`,
37
+ date: new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }),
38
+ };
39
+ setReviews(prev => [...prev, newReview]);
40
+ };
41
+
42
+ const handleDeleteReview = (reviewId: string) => {
43
+ setReviews(prev => prev.filter(review => review.id !== reviewId));
44
+ };
45
+
46
+ const buttonClasses = "text-sm sm:text-base text-slate-600 hover:text-blue-600 font-medium transition-colors px-3 py-2 rounded-lg hover:bg-slate-200";
47
+
48
+ return (
49
+ <LanguageProvider>
50
+ <div className="flex flex-col h-screen bg-slate-100 font-sans">
51
+ <header className="w-full bg-white shadow-md px-4 py-3 sm:p-4 z-10">
52
+ <div className="max-w-4xl mx-auto flex justify-between items-center">
53
+ <h1 className="text-xl sm:text-2xl font-bold bg-gradient-to-r from-blue-500 to-violet-500 text-transparent bg-clip-text">EmotiMate</h1>
54
+ <div className="flex items-center gap-2 sm:gap-4">
55
+ {page === 'chat' && (
56
+ <>
57
+ <LanguageSelector />
58
+ <button onClick={() => setPage('feedback')} className={buttonClasses} aria-label="Go to feedback page">
59
+ Feedback
60
+ </button>
61
+ <button onClick={() => setPage('userexperience')} className={buttonClasses} aria-label="Go to user experience page">
62
+ User Experience
63
+ </button>
64
+ </>
65
+ )}
66
+ {page === 'feedback' && (
67
+ <>
68
+ <button onClick={() => setPage('userexperience')} className={buttonClasses} aria-label="Go to user experience page">
69
+ User Experience
70
+ </button>
71
+ <button onClick={() => setPage('chat')} className={buttonClasses} aria-label="Go back to home page">
72
+ Home
73
+ </button>
74
+ </>
75
+ )}
76
+ {page === 'userexperience' && (
77
+ <>
78
+ <button onClick={() => setPage('feedback')} className={buttonClasses} aria-label="Go to feedback page">
79
+ Feedback
80
+ </button>
81
+ <button onClick={() => setPage('chat')} className={buttonClasses} aria-label="Go back to home page">
82
+ Home
83
+ </button>
84
+ </>
85
+ )}
86
+ </div>
87
+ </div>
88
+ </header>
89
+ <main className="flex-grow overflow-auto custom-scrollbar">
90
+ {page === 'chat' && <ChatInterface />}
91
+ {page === 'feedback' && <FeedbackPage onGoHome={() => setPage('chat')} onAddReview={handleAddReview} />}
92
+ {page === 'userexperience' && <UserFeedbackAnalysisPage reviews={reviews} onDeleteReview={handleDeleteReview} />}
93
+ </main>
94
+ </div>
95
+ </LanguageProvider>
96
+ );
97
+ }
98
+
99
+ export default App;
README.md CHANGED
@@ -1,3 +1,14 @@
1
- ---
2
- license: gemma
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Run and deploy your AI Studio app
2
+
3
+ This contains everything you need to run your app locally.
4
+
5
+ ## Run Locally
6
+
7
+ **Prerequisites:** Node.js
8
+
9
+
10
+ 1. Install dependencies:
11
+ `npm install`
12
+ 2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
13
+ 3. Run the app:
14
+ `npm run dev`
index.html ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>EmotiMate</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <style>
10
+ /* For custom scrollbar styling */
11
+ .custom-scrollbar::-webkit-scrollbar {
12
+ width: 8px;
13
+ }
14
+ .custom-scrollbar::-webkit-scrollbar-track {
15
+ background: #f1f5f9; /* slate-100 */
16
+ }
17
+ .custom-scrollbar::-webkit-scrollbar-thumb {
18
+ background: #94a3b8; /* slate-400 */
19
+ border-radius: 10px;
20
+ }
21
+ .custom-scrollbar::-webkit-scrollbar-thumb:hover {
22
+ background: #64748b; /* slate-500 */
23
+ }
24
+ /* Utility to permanently hide scrollbars */
25
+ .hide-scrollbar::-webkit-scrollbar {
26
+ display: none;
27
+ }
28
+ .hide-scrollbar {
29
+ -ms-overflow-style: none; /* IE and Edge */
30
+ scrollbar-width: none; /* Firefox */
31
+ }
32
+ </style>
33
+ <script type="importmap">
34
+ {
35
+ "imports": {
36
+ "react-dom/": "https://esm.sh/react-dom@^19.1.0/",
37
+ "react/": "https://esm.sh/react@^19.1.0/",
38
+ "react": "https://esm.sh/react@^19.1.0",
39
+ "@google/genai": "https://esm.sh/@google/genai@^1.11.0"
40
+ }
41
+ }
42
+ </script>
43
+ <link rel="stylesheet" href="/index.css">
44
+ </head>
45
+ <body class="bg-slate-100">
46
+ <div id="root"></div>
47
+ <script type="module" src="/index.tsx"></script>
48
+ </body>
49
+ </html>
index.tsx ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import React from 'react';
3
+ import ReactDOM from 'react-dom/client';
4
+ import App from './App';
5
+
6
+ const rootElement = document.getElementById('root');
7
+ if (!rootElement) {
8
+ throw new Error("Could not find root element to mount to");
9
+ }
10
+
11
+ const root = ReactDOM.createRoot(rootElement);
12
+ root.render(
13
+ <React.StrictMode>
14
+ <App />
15
+ </React.StrictMode>
16
+ );
metadata.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "EmotiMate",
3
+ "description": "An emotionally intelligent AI assistant for supportive and empathetic conversations. Engage via voice or text to receive supportive suggestions and mindfulness exercises in a safe, non-judgmental space.",
4
+ "requestFramePermissions": [
5
+ "microphone"
6
+ ]
7
+ }
package.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "emotimate",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "react-dom": "^19.1.0",
13
+ "react": "^19.1.0",
14
+ "@google/genai": "^1.11.0"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^22.14.0",
18
+ "typescript": "~5.7.2",
19
+ "vite": "^6.2.0"
20
+ }
21
+ }
tsconfig.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "experimentalDecorators": true,
5
+ "useDefineForClassFields": false,
6
+ "module": "ESNext",
7
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "isolatedModules": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+ "allowJs": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "noFallthroughCasesInSwitch": true,
24
+ "noUncheckedSideEffectImports": true,
25
+
26
+ "paths": {
27
+ "@/*" : ["./*"]
28
+ }
29
+ }
30
+ }
types.ts ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export interface Message {
2
+ id: string;
3
+ text: string;
4
+ sender: 'user' | 'ai';
5
+ suggestions?: string[];
6
+ }
7
+
8
+ export interface Review {
9
+ id: string;
10
+ date: string;
11
+ lang: string;
12
+ rating: number;
13
+ comments: string;
14
+ }
vite.config.ts ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import path from 'path';
2
+ import { defineConfig, loadEnv } from 'vite';
3
+
4
+ export default defineConfig(({ mode }) => {
5
+ const env = loadEnv(mode, '.', '');
6
+ return {
7
+ define: {
8
+ 'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY),
9
+ 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY)
10
+ },
11
+ resolve: {
12
+ alias: {
13
+ '@': path.resolve(__dirname, '.'),
14
+ }
15
+ }
16
+ };
17
+ });