├── test.txt ├── src ├── vite-env.d.ts ├── main.tsx ├── index.css ├── components │ ├── Navbar.tsx │ └── ShazamRecommend.tsx └── App.tsx ├── postcss.config.js ├── tsconfig.json ├── vite.config.ts ├── .gitignore ├── index.html ├── tsconfig.node.json ├── tailwind.config.js ├── tsconfig.app.json ├── eslint.config.js ├── package.json └── README.md /test.txt: -------------------------------------------------------------------------------- 1 | hello git remote test -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /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 | optimizeDeps: { 8 | exclude: ['lucide-react'], 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import App from './App.tsx'; 4 | import './index.css'; 5 | 6 | createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: { 6 | scale: { 7 | '102': '1.02', 8 | '103': '1.03', 9 | }, 10 | animation: { 11 | 'spin': 'spin 1s linear infinite', 12 | 'pulse': 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite', 13 | 'float': 'float 3s ease-in-out infinite', 14 | }, 15 | backgroundImage: { 16 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 17 | }, 18 | }, 19 | }, 20 | plugins: [], 21 | }; -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @keyframes fade-in { 6 | from { 7 | opacity: 0; 8 | transform: translateY(10px); 9 | } 10 | to { 11 | opacity: 1; 12 | transform: translateY(0); 13 | } 14 | } 15 | 16 | .animate-fade-in { 17 | animation: fade-in 0.5s ease-out forwards; 18 | } 19 | 20 | @keyframes float { 21 | 0% { 22 | transform: translateY(0px); 23 | } 24 | 50% { 25 | transform: translateY(-5px); 26 | } 27 | 100% { 28 | transform: translateY(0px); 29 | } 30 | } 31 | 32 | .animate-float { 33 | animation: float 3s ease-in-out infinite; 34 | } -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 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 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import globals from 'globals'; 3 | import reactHooks from 'eslint-plugin-react-hooks'; 4 | import reactRefresh from 'eslint-plugin-react-refresh'; 5 | import tseslint from 'typescript-eslint'; 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'react-refresh/only-export-components': [ 23 | 'warn', 24 | { allowConstantExport: true }, 25 | ], 26 | }, 27 | } 28 | ); 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-react-typescript-starter", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "axios": "^1.9.0", 14 | "lucide-react": "^0.344.0", 15 | "react": "^18.3.1", 16 | "react-dom": "^18.3.1" 17 | }, 18 | "devDependencies": { 19 | "@eslint/js": "^9.9.1", 20 | "@types/react": "^18.3.5", 21 | "@types/react-dom": "^18.3.0", 22 | "@vitejs/plugin-react": "^4.3.1", 23 | "autoprefixer": "^10.4.18", 24 | "eslint": "^9.9.1", 25 | "eslint-plugin-react-hooks": "^5.1.0-rc.0", 26 | "eslint-plugin-react-refresh": "^0.4.11", 27 | "globals": "^15.9.0", 28 | "postcss": "^8.4.35", 29 | "tailwindcss": "^3.4.1", 30 | "typescript": "^5.5.3", 31 | "typescript-eslint": "^8.3.0", 32 | "vite": "^5.4.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Audio Monk - Music Genre Classification Setup Guide 2 | 3 | ## Project Description 4 | 5 | **Audio Monk** is an advanced music genre classification system that leverages deep learning techniques and the Spotify Web API to provide intelligent music discovery and recommendation services. 6 | 7 | ### Overview 8 | Genre classification is crucial for simplifying music discovery, organizing digital music libraries, and customizing streaming services. With the exponential growth of available music data, there's an increasing demand for automated systems that can classify songs by genre through audio characteristics analysis. 9 | 10 | ### Technical Approach 11 | This project utilizes cutting-edge deep learning techniques, specifically Convolutional Neural Networks (CNNs), to extract spatial features directly from audio signals. The system employs sophisticated audio preprocessing techniques including: 12 | 13 | - **Spectrogram Creation**: Converting raw audio files into time-frequency representations 14 | - **Short-Time Fourier Transform (STFT)**: Transforming audio signals for CNN processing 15 | - **Pattern Recognition**: Identifying complex audio patterns that traditional feature-based methods cannot capture 16 | 17 | ### Key Features 18 | - **Real-time Genre Classification**: Instant audio analysis and genre prediction 19 | - **Spotify Integration**: Automatic recommendations based on classified genres 20 | - **User-Friendly Interface**: Upload audio files and receive immediate feedback 21 | - **Dynamic Music Discovery**: Enhanced user engagement through intelligent recommendations 22 | 23 | ### Problem Statement 24 | The music streaming industry faces significant challenges with existing classification systems that rely on manual tagging and metadata-based approaches. These methods often fail to capture the true essence of musical content, leading to poor recommendation accuracy. Audio Monk addresses these limitations by analyzing actual audio patterns and characteristics. 25 | 26 | ### Demo/Overview 27 | 28 | Screenshot 2025-06-13 at 1 26 23 AM 29 | 30 | Screenshot 2025-06-13 at 1 26 31 AM 31 | 32 | Screenshot 2025-06-13 at 1 29 13 AM 33 | 34 | Screenshot 2025-06-13 at 1 29 27 AM 35 | 36 | Screenshot 2025-06-13 at 1 29 58 AM 37 | 38 | Screenshot 2025-06-13 at 1 30 06 AM 39 | 40 | Screenshot 2025-06-13 at 1 30 16 AM 41 | 42 | 43 | Screenshot 2025-06-13 at 1 30 24 AM 44 | 45 | --- 46 | 47 | ## Prerequisites 48 | 49 | Before starting, ensure you have the following installed: 50 | 51 | - **Node.js** (version 16 or higher) 52 | - **npm** or **yarn** package manager 53 | - **Git** for version control 54 | - **Spotify Developer Account** (for API credentials) 55 | 56 | --- 57 | 58 | ## Step-by-Step Setup Instructions 59 | 60 | ### 1. Initialize React Project 61 | 62 | ```bash 63 | # Create a new React application 64 | npx create-react-app audio-monk 65 | cd audio-monk 66 | 67 | # Install additional dependencies 68 | npm install axios react-router-dom styled-components 69 | npm install @tensorflow/tfjs @tensorflow/tfjs-node 70 | npm install web-audio-api wavefile 71 | npm install react-dropzone react-player 72 | npm install chart.js react-chartjs-2 73 | npm install @material-ui/core @material-ui/icons 74 | npm install dotenv 75 | ``` 76 | 77 | ### 2. Project Structure Setup 78 | 79 | ```bash 80 | # Create directory structure 81 | mkdir src/components 82 | mkdir src/pages 83 | mkdir src/services 84 | mkdir src/utils 85 | mkdir src/hooks 86 | mkdir src/models 87 | mkdir src/assets 88 | mkdir src/styles 89 | mkdir public/models 90 | ``` 91 | 92 | ### 3. Environment Configuration 93 | 94 | Create a `.env` file in the root directory: 95 | 96 | ```bash 97 | # Create environment file 98 | touch .env 99 | ``` 100 | 101 | Add the following content to `.env`: 102 | 103 | ```env 104 | # Spotify API Credentials 105 | REACT_APP_SPOTIFY_CLIENT_ID=your_spotify_client_id_here 106 | REACT_APP_SPOTIFY_CLIENT_SECRET=your_spotify_client_secret_here 107 | REACT_APP_SPOTIFY_REDIRECT_URI=http://localhost:3000/callback 108 | 109 | # Shazam API (Optional) 110 | REACT_APP_SHAZAM_API_KEY=your_shazam_api_key_here 111 | 112 | # Application Settings 113 | REACT_APP_API_BASE_URL=http://localhost:3000 114 | REACT_APP_ENVIRONMENT=development 115 | ``` 116 | 117 | ### 4. Spotify Developer Setup 118 | 119 | 1. **Create Spotify App**: 120 | - Go to [Spotify Developer Dashboard](https://developer.spotify.com/dashboard) 121 | - Click "Create App" 122 | - Fill in app details: 123 | - App Name: "Audio Monk" 124 | - App Description: "Music Genre Classification System" 125 | - Redirect URI: `http://localhost:3000/callback` 126 | 127 | 2. **Get Credentials**: 128 | - Copy Client ID and Client Secret 129 | - Replace placeholders in `.env` file 130 | 131 | ### 5. Install Additional ML Dependencies 132 | 133 | ```bash 134 | # TensorFlow.js for machine learning 135 | npm install @tensorflow/tfjs-react-native 136 | npm install @tensorflow/tfjs-platform-react-native 137 | 138 | # Audio processing libraries 139 | npm install tone 140 | npm install audiomotion-analyzer 141 | npm install meyda 142 | 143 | # UI and styling 144 | npm install @emotion/react @emotion/styled 145 | npm install @mui/material @mui/icons-material 146 | npm install framer-motion 147 | ``` 148 | 149 | ### 6. Development Scripts 150 | 151 | Add these scripts to `package.json`: 152 | 153 | ```json 154 | { 155 | "scripts": { 156 | "start": "react-scripts start", 157 | "build": "react-scripts build", 158 | "test": "react-scripts test", 159 | "eject": "react-scripts eject", 160 | "dev": "npm start", 161 | "build:prod": "NODE_ENV=production npm run build", 162 | "serve": "serve -s build -l 5000", 163 | "analyze": "npm run build && npx webpack-bundle-analyzer build/static/js/*.js" 164 | } 165 | } 166 | ``` 167 | 168 | ### 7. Git Repository Setup 169 | 170 | ```bash 171 | # Initialize Git repository 172 | git init 173 | 174 | # Create .gitignore 175 | echo "node_modules/ 176 | .env 177 | .env.local 178 | .env.development.local 179 | .env.test.local 180 | .env.production.local 181 | npm-debug.log* 182 | yarn-debug.log* 183 | yarn-error.log* 184 | .DS_Store 185 | build/ 186 | dist/ 187 | *.log" > .gitignore 188 | 189 | # Initial commit 190 | git add . 191 | git commit -m "Initial commit: Audio Monk setup" 192 | ``` 193 | 194 | ### 8. Environment Variables Template 195 | 196 | Create `.env.example` for team collaboration: 197 | 198 | ```bash 199 | # Spotify API Credentials (Required) 200 | REACT_APP_SPOTIFY_CLIENT_ID=your_spotify_client_id_here 201 | REACT_APP_SPOTIFY_CLIENT_SECRET=your_spotify_client_secret_here 202 | REACT_APP_SPOTIFY_REDIRECT_URI=http://localhost:3000/callback 203 | 204 | # Optional APIs 205 | REACT_APP_SHAZAM_API_KEY=your_shazam_api_key_here 206 | 207 | # Application Configuration 208 | REACT_APP_API_BASE_URL=http://localhost:3000 209 | REACT_APP_ENVIRONMENT=development 210 | ``` 211 | 212 | ### 9. Start Development Server 213 | 214 | ```bash 215 | # Start the development server 216 | npm start 217 | 218 | # The application will open at http://localhost:3000 219 | ``` 220 | 221 | ### 10. Testing Spotify Integration 222 | 223 | Create a simple test component to verify Spotify API connection: 224 | 225 | ```bash 226 | # Create test file 227 | touch src/components/SpotifyTest.js 228 | ``` 229 | 230 | ### 11. Build and Deployment Preparation 231 | 232 | ```bash 233 | # Create production build 234 | npm run build 235 | 236 | # Test production build locally 237 | npm install -g serve 238 | serve -s build -l 5000 239 | ``` 240 | 241 | --- 242 | 243 | ## Important Configuration Notes 244 | 245 | ### Spotify API Credentials Setup 246 | 247 | **Important**: Replace the placeholder values in your `.env` file with your actual Spotify credentials: 248 | 249 | ```env 250 | # Replace these with your actual Spotify app credentials 251 | REACT_APP_SPOTIFY_CLIENT_ID=1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p 252 | REACT_APP_SPOTIFY_CLIENT_SECRET=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0 253 | ``` 254 | 255 | ### Security Considerations 256 | 257 | 1. **Never commit `.env` file** to version control 258 | 2. **Use environment variables** for all sensitive data 259 | 3. **Implement proper CORS** configuration 260 | 4. **Use HTTPS** in production 261 | 5. **Validate all API inputs** 262 | 263 | --- 264 | 265 | ## Next Steps 266 | 267 | After completing the setup: 268 | 269 | 1. **Implement Core Components**: 270 | - Audio upload interface 271 | - Genre classification engine 272 | - Spotify integration service 273 | - Results dashboard 274 | 275 | 2. **Train ML Model**: 276 | - Prepare audio dataset 277 | - Train CNN model 278 | - Convert to TensorFlow.js format 279 | 280 | 3. **Integration Testing**: 281 | - Test Spotify API endpoints 282 | - Validate audio processing pipeline 283 | - Test recommendation system 284 | 285 | 4. **UI/UX Development**: 286 | - Design responsive interface 287 | - Implement audio visualization 288 | - Create user dashboard 289 | 290 | 5. **Deployment**: 291 | - Configure production environment 292 | - Set up CI/CD pipeline 293 | - Deploy to cloud platform 294 | 295 | --- 296 | 297 | ## Troubleshooting 298 | 299 | ### Common Issues 300 | 301 | 1. **Spotify API 401 Error**: Check client credentials 302 | 2. **CORS Issues**: Configure proxy in package.json 303 | 3. **Audio Processing**: Ensure browser supports Web Audio API 304 | 4. **Build Errors**: Check Node.js version compatibility 305 | 306 | ### Support 307 | 308 | For technical support or questions: 309 | - Check Spotify Web API documentation 310 | - Review TensorFlow.js guides 311 | - Consult React.js documentation 312 | 313 | --- 314 | 315 | ## Project Timeline 316 | 317 | - **Week 1-2**: Setup and basic React implementation 318 | - **Week 3-4**: Spotify API integration 319 | - **Week 5-6**: ML model development and integration 320 | - **Week 7-8**: UI/UX refinement and testing 321 | - **Week 9-10**: Deployment and optimization 322 | 323 | --- 324 | 325 | **Ready to build the future of music discovery! 🎵🤖** 326 | -------------------------------------------------------------------------------- /src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Music, Search, User, Play, Pause, Volume2, Heart, Shuffle, SkipForward, Headphones, Mic, Radio, TrendingUp, Zap } from 'lucide-react'; 3 | 4 | interface SpotifyTrack { 5 | id: string; 6 | name: string; 7 | artists: { name: string }[]; 8 | preview_url: string | null; 9 | external_urls: { spotify: string }; 10 | album: { 11 | images: { url: string }[]; 12 | name: string; 13 | }; 14 | } 15 | 16 | const Navbar: React.FC = () => { 17 | const [isOpen, setIsOpen] = useState(false); 18 | const [isPlaying, setIsPlaying] = useState(false); 19 | const [currentTrack, setCurrentTrack] = useState(null); 20 | const [searchQuery, setSearchQuery] = useState(''); 21 | const [searchResults, setSearchResults] = useState([]); 22 | const [isSearching, setIsSearching] = useState(false); 23 | const [showPlayer, setShowPlayer] = useState(false); 24 | const [audio, setAudio] = useState(null); 25 | const [accessToken, setAccessToken] = useState(null); 26 | 27 | // Spotify credentials 28 | const CLIENT_ID = "4d6cc08e0cca4364b2a03c72d54e7143"; 29 | const CLIENT_SECRET = "a74fbe2e08524d469703a05868fead0e"; 30 | 31 | // Get Spotify access token 32 | useEffect(() => { 33 | const getAccessToken = async () => { 34 | try { 35 | const response = await fetch('https://accounts.spotify.com/api/token', { 36 | method: 'POST', 37 | headers: { 38 | 'Content-Type': 'application/x-www-form-urlencoded', 39 | 'Authorization': `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}` 40 | }, 41 | body: 'grant_type=client_credentials' 42 | }); 43 | 44 | const data = await response.json(); 45 | setAccessToken(data.access_token); 46 | } catch (error) { 47 | console.error('Error getting access token:', error); 48 | } 49 | }; 50 | 51 | getAccessToken(); 52 | }, []); 53 | 54 | // Search Spotify tracks 55 | const searchTracks = async (query: string) => { 56 | if (!accessToken || !query.trim()) return; 57 | 58 | setIsSearching(true); 59 | try { 60 | const response = await fetch( 61 | `https://api.spotify.com/v1/search?q=${encodeURIComponent(query)}&type=track&limit=5`, 62 | { 63 | headers: { 64 | 'Authorization': `Bearer ${accessToken}` 65 | } 66 | } 67 | ); 68 | 69 | const data = await response.json(); 70 | setSearchResults(data.tracks?.items || []); 71 | } catch (error) { 72 | console.error('Error searching tracks:', error); 73 | } finally { 74 | setIsSearching(false); 75 | } 76 | }; 77 | 78 | // Play/Pause functionality 79 | const togglePlay = (track: SpotifyTrack) => { 80 | if (currentTrack?.id === track.id && audio) { 81 | if (isPlaying) { 82 | audio.pause(); 83 | setIsPlaying(false); 84 | } else { 85 | audio.play(); 86 | setIsPlaying(true); 87 | } 88 | } else { 89 | if (audio) { 90 | audio.pause(); 91 | } 92 | 93 | if (track.preview_url) { 94 | const newAudio = new Audio(track.preview_url); 95 | newAudio.addEventListener('ended', () => setIsPlaying(false)); 96 | newAudio.play(); 97 | setAudio(newAudio); 98 | setCurrentTrack(track); 99 | setIsPlaying(true); 100 | setShowPlayer(true); 101 | } 102 | } 103 | }; 104 | 105 | useEffect(() => { 106 | const delayedSearch = setTimeout(() => { 107 | if (searchQuery) { 108 | searchTracks(searchQuery); 109 | } else { 110 | setSearchResults([]); 111 | } 112 | }, 500); 113 | 114 | return () => clearTimeout(delayedSearch); 115 | }, [searchQuery, accessToken]); 116 | 117 | const menuItems = [ 118 | { name: 'Discover', icon: TrendingUp, active: true }, 119 | { name: 'Genres', icon: Music }, 120 | { name: 'Live Radio', icon: Radio }, 121 | { name: 'AI Classify', icon: Zap }, 122 | { name: 'Studio', icon: Mic } 123 | ]; 124 | 125 | return ( 126 | <> 127 | {/* Main Navbar */} 128 | 272 | 273 | {/* Mini Player */} 274 | {showPlayer && currentTrack && ( 275 |
276 |
277 |
278 | {currentTrack.album.name} 283 |
284 |

{currentTrack.name}

285 |

{currentTrack.artists[0]?.name}

286 |
287 |
288 | 289 |
290 | 293 | 299 | 302 | 308 |
309 |
310 |
311 | )} 312 | 313 | ); 314 | }; 315 | 316 | export default Navbar; -------------------------------------------------------------------------------- /src/components/ShazamRecommend.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Music, Loader2, Sparkles, Play, TrendingUp, Volume2, Heart, Share2 } from "lucide-react"; 3 | 4 | type Recommendation = { 5 | artist: string; 6 | name: string; 7 | similarity: number; 8 | }; 9 | 10 | type ApiResponse = { 11 | predicted_genre: string; 12 | recommendations: Recommendation[]; 13 | }; 14 | 15 | const ShazamRecommend: React.FC = () => { 16 | const [data, setData] = useState(null); 17 | const [loading, setLoading] = useState(false); 18 | const [error, setError] = useState(null); 19 | const [hoveredIndex, setHoveredIndex] = useState(null); 20 | const [animatedBars, setAnimatedBars] = useState([]); 21 | 22 | const fetchRecommendations = () => { 23 | setLoading(true); 24 | setError(null); 25 | setData(null); 26 | setAnimatedBars([]); 27 | 28 | fetch("http://127.0.0.1:5000/api/recommend") 29 | .then((res) => { 30 | if (!res.ok) throw new Error("Network response was not ok"); 31 | return res.json(); 32 | }) 33 | .then((newData) => { 34 | setData(newData); 35 | // Trigger bar animations after data loads 36 | setTimeout(() => { 37 | setAnimatedBars(new Array(newData.recommendations.length).fill(true)); 38 | }, 300); 39 | }) 40 | .catch(() => setError("Failed to fetch recommendations")) 41 | .finally(() => setLoading(false)); 42 | }; 43 | 44 | return ( 45 |
46 | {/* Animated Background Elements */} 47 |
48 |
49 |
50 |
51 |
52 | 53 |
54 | {/* Header Section */} 55 |
56 |
57 |
58 |
59 | 60 |
61 |
62 | 63 |

64 | Shazam Discover 65 |

66 |

67 | Unlock your musical DNA with AI-powered recommendations that feel like magic 68 |

69 | 70 | {/* Floating elements */} 71 |
72 |
73 |
74 |
75 | 76 | {/* Main Card */} 77 |
78 | {/* Animated border gradient */} 79 |
80 | 81 | {/* Action Button */} 82 |
83 | 113 |
114 | 115 | {/* Error State */} 116 | {error && ( 117 |
118 |
119 |
120 | {error} 121 |
122 |
123 | )} 124 | 125 | {/* Results Section */} 126 | {data && ( 127 |
128 | {/* Genre Header */} 129 |
130 |
131 |
132 | 133 | 134 | Your Musical DNA: 135 | 136 | 137 | {data.predicted_genre} 138 | 139 |
140 |
141 | 142 | {/* Recommendations Grid */} 143 |
144 |

145 | 146 | Your Sonic Journey 147 |

148 | 149 | {data.recommendations.map((rec, idx) => ( 150 |
setHoveredIndex(idx)} 155 | onMouseLeave={() => setHoveredIndex(null)} 156 | > 157 | {/* Hover overlay */} 158 |
159 | 160 |
161 |
162 |
163 |
164 |
165 | 166 |
167 |
168 | 169 |
170 |

171 | {rec.name} 172 |

173 |

174 | by {rec.artist} 175 |

176 |
177 |
178 | 179 |
180 | {/* Action buttons */} 181 |
182 | 185 | 188 |
189 | 190 |
191 |
192 | {rec.similarity.toFixed(1)}% 193 |
194 |
195 | Match Score 196 |
197 |
198 |
199 |
200 | 201 | {/* Horizontal Similarity Bar */} 202 |
203 |
204 | Similarity Match 205 | {rec.similarity.toFixed(1)}% 206 |
207 | 208 |
209 | {/* Animated gradient background */} 210 |
211 | 212 | {/* Progress bar */} 213 |
222 | {/* Shimmer effect on bar */} 223 |
224 | 225 | {/* Glow effect */} 226 |
227 |
228 | 229 | {/* Animated dots */} 230 |
231 |
232 |
233 |
234 |
235 |
236 | ))} 237 |
238 |
239 | )} 240 |
241 | 242 | {/* Enhanced Footer */} 243 |
244 |
245 |
246 |

Powered by quantum-enhanced AI algorithms

247 |
248 |
249 |
250 |
251 | 252 | 375 |
376 | ); 377 | }; 378 | 379 | export default ShazamRecommend; -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useCallback, useEffect } from "react"; 2 | import { 3 | Upload, 4 | AudioWaveform, 5 | Music2, 6 | Volume2, 7 | RefreshCw, 8 | Trash2, 9 | Play, 10 | ExternalLink, 11 | Sparkles, 12 | } from "lucide-react"; 13 | import Navbar from './components/Navbar'; 14 | import ShazamRecommend from './components/shazamrecommend'; 15 | const SPOTIFY_CLIENT_ID = "Add your own client id"; 16 | const SPOTIFY_CLIENT_SECRET = "Add your own client secret"; 17 | 18 | interface SpotifyTrack { 19 | id: string; 20 | name: string; 21 | artists: { name: string }[]; 22 | album: { 23 | name: string; 24 | images: { url: string }[]; 25 | }; 26 | external_urls: { 27 | spotify: string; 28 | }; 29 | preview_url: string; 30 | } 31 | 32 | function App() { 33 | const [file, setFile] = useState(null); 34 | const [analysisResult, setAnalysisResult] = useState<{ 35 | message: string; 36 | filename: string; 37 | duration: number; 38 | predicted_genre: string; 39 | } | null>(null); 40 | const [isLoading, setIsLoading] = useState(false); 41 | const [error, setError] = useState(""); 42 | const [isDragging, setIsDragging] = useState(false); 43 | const [uploadProgress, setUploadProgress] = useState(0); 44 | const [isAnalyzing, setIsAnalyzing] = useState(false); 45 | const [spotifyTracks, setSpotifyTracks] = useState([]); 46 | const [accessToken, setAccessToken] = useState(""); 47 | const [currentlyPlaying, setCurrentlyPlaying] = useState(null); 48 | const [pageLoaded, setPageLoaded] = useState(false); 49 | const [showAnalysisAnimation, setShowAnalysisAnimation] = useState(false); 50 | 51 | useEffect(() => { 52 | // Page load animation 53 | setPageLoaded(true); 54 | 55 | const getSpotifyToken = async () => { 56 | try { 57 | const response = await fetch("https://accounts.spotify.com/api/token", { 58 | method: "POST", 59 | headers: { 60 | "Content-Type": "application/x-www-form-urlencoded", 61 | Authorization: 62 | "Basic " + btoa(SPOTIFY_CLIENT_ID + ":" + SPOTIFY_CLIENT_SECRET), 63 | }, 64 | body: "grant_type=client_credentials", 65 | }); 66 | 67 | const data = await response.json(); 68 | if (data.access_token) { 69 | setAccessToken(data.access_token); 70 | } 71 | } catch (error) { 72 | console.error("Error fetching Spotify token:", error); 73 | } 74 | }; 75 | 76 | getSpotifyToken(); 77 | }, []); 78 | 79 | const fetchSpotifyRecommendations = async (genre: string) => { 80 | try { 81 | const response = await fetch( 82 | `https://api.spotify.com/v1/search?q=genre:"${genre}"&type=track&limit=40`, 83 | { 84 | headers: { 85 | Authorization: `Bearer ${accessToken}`, 86 | }, 87 | } 88 | ); 89 | 90 | const data = await response.json(); 91 | if (data.tracks?.items) { 92 | setSpotifyTracks(data.tracks.items); 93 | } 94 | } catch (error) { 95 | console.error("Error fetching Spotify recommendations:", error); 96 | } 97 | }; 98 | 99 | const handleDragOver = useCallback((e: React.DragEvent) => { 100 | e.preventDefault(); 101 | setIsDragging(true); 102 | }, []); 103 | 104 | const handleDragLeave = useCallback((e: React.DragEvent) => { 105 | e.preventDefault(); 106 | setIsDragging(false); 107 | }, []); 108 | 109 | const handleDrop = useCallback((e: React.DragEvent) => { 110 | e.preventDefault(); 111 | setIsDragging(false); 112 | const droppedFile = e.dataTransfer.files[0]; 113 | if (droppedFile?.type === "audio/wav") { 114 | setFile(droppedFile); 115 | setError(""); 116 | setAnalysisResult(null); 117 | setSpotifyTracks([]); 118 | } else { 119 | setError("Please select a WAV file"); 120 | } 121 | }, []); 122 | 123 | const handleFileChange = (event: React.ChangeEvent) => { 124 | const selectedFile = event.target.files?.[0]; 125 | if (selectedFile) { 126 | if (selectedFile.type !== "audio/wav") { 127 | setError("Please select a WAV file"); 128 | setFile(null); 129 | return; 130 | } 131 | setError(""); 132 | setFile(selectedFile); 133 | setAnalysisResult(null); 134 | setSpotifyTracks([]); 135 | } 136 | }; 137 | 138 | const clearFile = () => { 139 | setFile(null); 140 | setAnalysisResult(null); 141 | setError(""); 142 | setUploadProgress(0); 143 | setSpotifyTracks([]); 144 | }; 145 | 146 | const handleUpload = async () => { 147 | if (!file) { 148 | setError("Please select a file first."); 149 | return; 150 | } 151 | 152 | setIsLoading(true); 153 | setError(""); 154 | setUploadProgress(0); 155 | setIsAnalyzing(true); 156 | setSpotifyTracks([]); 157 | setShowAnalysisAnimation(true); 158 | 159 | const formData = new FormData(); 160 | formData.append("file", file); 161 | 162 | try { 163 | const response = await fetch("http://127.0.0.1:5000/api/predict", { 164 | method: "POST", 165 | body: formData, 166 | }); 167 | 168 | if (!response.ok) { 169 | throw new Error("Failed to process audio file"); 170 | } 171 | 172 | const duration = 2000; 173 | const interval = 100; 174 | const steps = duration / interval; 175 | let progress = 0; 176 | 177 | const progressInterval = setInterval(() => { 178 | progress += 100 / steps; 179 | if (progress >= 100) { 180 | clearInterval(progressInterval); 181 | progress = 100; 182 | } 183 | setUploadProgress(Math.min(progress, 100)); 184 | }, interval); 185 | 186 | const data = await response.json(); 187 | setAnalysisResult(data); 188 | await fetchSpotifyRecommendations(data.predicted_genre); 189 | } catch (error) { 190 | setError("Error processing the audio file. Please try again."); 191 | console.error("Error:", error); 192 | } finally { 193 | setIsLoading(false); 194 | setIsAnalyzing(false); 195 | setTimeout(() => setShowAnalysisAnimation(false), 1000); 196 | } 197 | }; 198 | 199 | const handlePlayPreview = (previewUrl: string | null, trackId: string) => { 200 | if (currentlyPlaying === trackId) { 201 | const audioElements = document.getElementsByTagName("audio"); 202 | for (const audio of audioElements) { 203 | audio.pause(); 204 | } 205 | setCurrentlyPlaying(null); 206 | } else { 207 | const audioElements = document.getElementsByTagName("audio"); 208 | for (const audio of audioElements) { 209 | audio.pause(); 210 | } 211 | if (previewUrl) { 212 | const audio = new Audio(previewUrl); 213 | audio.play(); 214 | setCurrentlyPlaying(trackId); 215 | audio.onended = () => setCurrentlyPlaying(null); 216 | } 217 | } 218 | }; 219 | 220 | // Generate audio wave animation 221 | const generateWaveElements = () => { 222 | const elements = []; 223 | for (let i = 0; i < 20; i++) { 224 | elements.push( 225 |
234 | ); 235 | } 236 | return elements; 237 | }; 238 | 239 | return ( 240 |
245 | {/* Background animated particles */} 246 |
247 | {Array.from({ length: 20 }).map((_, i) => ( 248 |
260 | ))} 261 |
262 | 263 |
268 | 269 | {/* Header with animated gradient */} 270 |
271 |
272 |
273 |
274 | 275 |
276 | 277 |
278 |
279 |
280 |

281 | AudioMonk 282 |

283 |

284 | Intelligent Song Genre Classificaton & Recommendation 285 |

286 |
287 |
288 |
289 | 290 |
291 | {/* File upload area with animations */} 292 |
300 | 372 |
373 | 374 | {error && ( 375 |
376 | {error} 377 |
378 | )} 379 | 380 | {/* Animated progress bar */} 381 | {uploadProgress > 0 && uploadProgress < 100 && ( 382 |
383 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 | )} 396 | 397 | {/* Analyze button with enhanced styling and animations */} 398 | 429 | 430 | {/* Analysis animation */} 431 | {showAnalysisAnimation && ( 432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 | {generateWaveElements().map((element, index) => ( 440 |
441 | {element} 442 |
443 | ))} 444 |
445 |
446 |
447 |

448 | Analyzing Audio 449 |

450 |

451 | Using Machine-Learning to identify the genre. 452 |

453 |
454 |
455 |
456 |
457 |
458 |
459 | )} 460 | 461 | {/* Analysis result with enhanced styling and animations */} 462 | {analysisResult && ( 463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 | 471 |

472 | Analysis Result 473 |

474 |
475 |
476 |
477 |
478 |

479 | {analysisResult.message} 480 |

481 |
482 |
483 |

484 | File 485 |

486 |

487 | {analysisResult.filename} 488 |

489 |
490 |
491 |

492 | Duration 493 |

494 |

495 | {analysisResult?.duration?.toFixed(2) ?? "N/A"} 496 |

497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 | {analysisResult.predicted_genre} 505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 | )} 513 |
514 |
515 | 516 |
517 |
518 | 519 | {/* Spotify recommendations with enhanced styling and animations */} 520 | {spotifyTracks.length > 0 && ( 521 |
522 |
523 |
524 |

525 | Spotify Recommended Tracks 526 |

527 |
528 |
529 |
530 | {spotifyTracks.map((track, index) => ( 531 |
540 |
541 | {track.album.name} 546 |
547 | {track.preview_url && ( 548 | 562 | )} 563 |
564 |
565 |
566 |

567 | {track.name} 568 |

569 |

570 | {track.artists.map((artist) => artist.name).join(", ")} 571 |

572 | 583 |
584 |
585 | ))} 586 |
587 |
588 | )} 589 |
590 | 591 | 592 | {/* Footer */} 593 |
594 |

595 | 596 | AudioMonk 597 | {" "} 598 | • AI-Powered Audio Genre Classification & Recommendation 599 |

600 |

Made with ❤ By Group F5

601 |
602 |
603 | 604 | 738 |
739 | ); 740 | } 741 | 742 | export default App; 743 | --------------------------------------------------------------------------------