├── src ├── vite-env.d.ts ├── index.css ├── main.tsx ├── App.css ├── App.tsx ├── assets │ └── react.svg └── AudioRecorder.tsx ├── gitpush.bat ├── public ├── microphone.png └── vite.svg ├── postcss.config.js ├── vite.config.ts ├── tailwind.config.js ├── tsconfig.node.json ├── .gitignore ├── index.html ├── .eslintrc.cjs ├── tsconfig.json ├── package.json ├── .github └── workflows │ └── main_audio-react.yml └── README.md /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /gitpush.bat: -------------------------------------------------------------------------------- 1 | git add . 2 | git commit -m %1 3 | git push -u origin main -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /public/microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanugurajesh/Audio-Recorder/HEAD/public/microphone.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /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 | }) 8 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: [ 4 | "./index.html", 5 | "./src/**/*.{js,ts,jsx,tsx}", 6 | ], 7 | theme: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /.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 | Audio Recorder 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | ignorePatterns: ['dist', '.eslintrc.cjs'], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': [ 14 | 'warn', 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.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 | "resolveJsonModule": true, 13 | "isolatedModules": true, 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 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .animated-slide { 2 | animation-name: cursorSlide; 3 | animation-duration: 1s; 4 | animation-timing-function: ease-in-out; 5 | } 6 | 7 | .animated-click { 8 | animation-name: cursorClick; 9 | animation-duration: 0.5s; 10 | animation-timing-function: ease-in-out; 11 | } 12 | 13 | @keyframes cursorSlide { 14 | 0% { 15 | opacity: 0; 16 | transform: translateX(-100%); 17 | } 18 | 100% { 19 | opacity: 1; 20 | transform: translateX(0); 21 | } 22 | } 23 | 24 | @keyframes cursorClick { 25 | 0% { 26 | border-width: 2px; /* Initial border width */ 27 | } 28 | 50% { 29 | border-width: 10px; /* Expanded border width */ 30 | } 31 | 100% { 32 | border-width: 2px; /* Back to initial border width */ 33 | } 34 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "voice-interact-gemini", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "react-hot-toast": "^2.4.1" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^18.2.56", 19 | "@types/react-dom": "^18.2.19", 20 | "@typescript-eslint/eslint-plugin": "^7.0.2", 21 | "@typescript-eslint/parser": "^7.0.2", 22 | "@vitejs/plugin-react": "^4.2.1", 23 | "autoprefixer": "^10.4.18", 24 | "eslint": "^8.56.0", 25 | "eslint-plugin-react-hooks": "^4.6.0", 26 | "eslint-plugin-react-refresh": "^0.4.5", 27 | "postcss": "^8.4.35", 28 | "tailwindcss": "^3.4.1", 29 | "typescript": "^5.2.2", 30 | "vite": "^5.1.4" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | 3 | import "./App.css"; 4 | import { useState, useRef, useEffect } from "react"; 5 | import AudioRecorder from "./AudioRecorder"; 6 | 7 | const App = () => { 8 | const toggleRecordOption = (type) => { 9 | return () => { 10 | setRecordOption(type); 11 | }; 12 | }; 13 | 14 | const cursorRef = useRef(null); 15 | const clickRef = useRef(null); 16 | 17 | const [cursorPosition, setCursorPosition] = useState({ 18 | x: window.innerWidth / 2, 19 | y: window.innerHeight / 2, 20 | }); 21 | 22 | const handleMouseMove = (event) => { 23 | setCursorPosition({ x: event.clientX, y: event.clientY }); 24 | }; 25 | 26 | const handleClick = () => { 27 | const cursorElement = clickRef.current; 28 | cursorElement.classList.add("animated-click"); 29 | setTimeout(() => { 30 | cursorElement.classList.remove("animated-click"); 31 | }, 500); 32 | }; 33 | 34 | useEffect(() => { 35 | const cursorElement = cursorRef.current; 36 | 37 | if (cursorElement) { 38 | cursorElement.addEventListener("mousemove", handleMouseMove); 39 | cursorElement.addEventListener("click", handleClick); 40 | } 41 | return () => { 42 | if (cursorElement) { 43 | cursorElement.removeEventListener("mousemove", handleMouseMove); 44 | } 45 | }; 46 | }, []); 47 | 48 | return ( 49 |
54 |
63 | microphone 64 |

React Audio Recorder

65 |
66 | 67 |
68 |
69 | ); 70 | }; 71 | 72 | export default App; 73 | -------------------------------------------------------------------------------- /.github/workflows/main_audio-react.yml: -------------------------------------------------------------------------------- 1 | # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy 2 | # More GitHub Actions for Azure: https://github.com/Azure/actions 3 | 4 | name: Build and deploy Node.js app to Azure Web App - Audio-React 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Node.js version 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: '20.x' 23 | 24 | - name: npm install, build, and test 25 | run: | 26 | npm install 27 | npm run build --if-present 28 | npm run test --if-present 29 | 30 | - name: Zip artifact for deployment 31 | run: zip release.zip ./* -r 32 | 33 | - name: Upload artifact for deployment job 34 | uses: actions/upload-artifact@v3 35 | with: 36 | name: node-app 37 | path: release.zip 38 | 39 | deploy: 40 | runs-on: ubuntu-latest 41 | needs: build 42 | environment: 43 | name: 'Production' 44 | url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} 45 | permissions: 46 | id-token: write #This is required for requesting the JWT 47 | 48 | steps: 49 | - name: Download artifact from build job 50 | uses: actions/download-artifact@v3 51 | with: 52 | name: node-app 53 | 54 | - name: Unzip artifact for deployment 55 | run: unzip release.zip 56 | 57 | - name: Login to Azure 58 | uses: azure/login@v1 59 | with: 60 | client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_A7F96E044B6C4E478C36E5C23E3F0382 }} 61 | tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_13A23CF4AA2B448BAB7EB6A776E58C4C }} 62 | subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_95ED7C8B6B9B48E99A6B0BEABCC9244E }} 63 | 64 | - name: 'Deploy to Azure Web App' 65 | id: deploy-to-webapp 66 | uses: azure/webapps-deploy@v2 67 | with: 68 | app-name: 'Audio-React' 69 | slot-name: 'Production' 70 | package: . 71 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### 🌟 star the repo if you like it 2 | 3 |
4 | 5 |
6 | 7 | # Audio Recorder 8 | 9 | An application to record audio with the help of react and download it in mp3 format 10 | 11 | ## Features 12 | 13 | - Audio Recording 14 | - Offline Compatible 15 | - Downloadable Audio 16 | 17 | ## Project Setup 18 | 19 | ```bash 20 | # fork the repo to your github 21 | git clone https://github.com/your-username/Audio-Recorder 22 | # change your directory to the Application directory 23 | cd Audio-Recorder 24 | # install the packages 25 | npm install 26 | # Run the application 27 | npm run dev 28 | ``` 29 | 30 | ## Screenshots 31 | 32 | ![Screenshot 2024-03-05 235707](https://github.com/kanugurajesh/Audio-Recorder/assets/77529419/6fe3b3a7-6dc4-4f19-b5e1-35606cece24d) 33 | 34 | ![Screenshot 2024-03-05 235713](https://github.com/kanugurajesh/Audio-Recorder/assets/77529419/1f5bc6e3-f0a4-4f08-a4db-23acf4e63736) 35 | 36 | ![Screenshot 2024-03-05 235731](https://github.com/kanugurajesh/Audio-Recorder/assets/77529419/3565a0a0-90ee-462a-90ed-24e112c12d65) 37 | 38 | ![Screenshot 2024-03-05 235737](https://github.com/kanugurajesh/Audio-Recorder/assets/77529419/a2c8bc5c-d1c3-4e47-b0ce-34d6f4dd3422) 39 | 40 | ![Screenshot 2024-03-05 235747](https://github.com/kanugurajesh/Audio-Recorder/assets/77529419/10929506-c207-43a3-b67f-cc96d352db1f) 41 | 42 | ![Screenshot 2024-03-05 235754](https://github.com/kanugurajesh/Audio-Recorder/assets/77529419/b0fd231a-9801-43a6-afde-2ab1082d5891) 43 | 44 | ## Contribution Guidelines 45 | 46 | We welcome contributions to enhance and improve the llm app. If you have ideas or improvements, feel free to submit a pull request following our contribution guidelines. 47 | 48 | ## Feedback and Issues 49 | 50 | If you encounter any issues or have feedback, please open an issue on our [GitHub repository](https://github.com/kanugurajesh/Student-LMS/issues). We appreciate your input and strive to make our system better with each update. 51 | 52 | ## Tech Stack 53 | 54 | - React 55 | - Vite 56 | - TailwindCSS 57 | 58 | ## 🔗 Links 59 | [![portfolio](https://img.shields.io/badge/my_portfolio-000?style=for-the-badge&logo=ko-fi&logoColor=white)](https://rajeshportfolio.me/) 60 | [![linkedin](https://img.shields.io/badge/linkedin-0A66C2?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/rajesh-kanugu-aba8a3254/) 61 | [![twitter](https://img.shields.io/badge/twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/exploringengin1) 62 | 63 | ## Authors 64 | 65 | - [@kanugurajesh](https://github.com/kanugurajesh) 66 | 67 | ## Support 68 | 69 | For support, you can buy me a coffee 70 | 71 | Buy Me A Coffee 72 | 73 |
74 |
75 | 76 | # React + TypeScript + Vite 77 | 78 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 79 | 80 | Currently, two official plugins are available: 81 | 82 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 83 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 84 | 85 | ## Expanding the ESLint configuration 86 | 87 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 88 | 89 | - Configure the top-level `parserOptions` property like this: 90 | 91 | ```js 92 | export default { 93 | // other rules... 94 | parserOptions: { 95 | ecmaVersion: 'latest', 96 | sourceType: 'module', 97 | project: ['./tsconfig.json', './tsconfig.node.json'], 98 | tsconfigRootDir: __dirname, 99 | }, 100 | } 101 | ``` 102 | 103 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` 104 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked` 105 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list 106 | -------------------------------------------------------------------------------- /src/AudioRecorder.tsx: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import { useState, useRef } from "react"; 3 | import toast, { Toaster } from "react-hot-toast"; 4 | 5 | const AudioRecorder = () => { 6 | const mimeType = "audio/mp3"; 7 | const [permission, setPermission] = useState(false); 8 | const mediaRecorder = useRef(null); 9 | const [recordingStatus, setRecordingStatus] = useState("inactive"); 10 | const [stream, setStream] = useState(null); 11 | const [audioChunks, setAudioChunks] = useState([]); 12 | const [audio, setAudio] = useState(null); 13 | 14 | const getMicrophonePermission = async () => { 15 | if ("MediaRecorder" in window) { 16 | try { 17 | toast.loading("Getting Permission"); 18 | const streamData = await navigator.mediaDevices.getUserMedia({ 19 | audio: true, 20 | video: false, 21 | }); 22 | toast.dismiss(); 23 | toast.success("Permission Obtained"); 24 | setPermission(true); 25 | setStream(streamData); 26 | } catch (err) { 27 | toast.error("Permission Failed"); 28 | } 29 | } else { 30 | toast.error("The MediaRecorder API is not supported in your browser."); 31 | } 32 | }; 33 | 34 | const startRecording = async () => { 35 | setRecordingStatus("recording"); 36 | toast.loading("recording"); 37 | toast.success("recording has started start speaking") 38 | //create new Media recorder instance using the stream 39 | const media = new MediaRecorder(stream, { type: mimeType }); 40 | //set the MediaRecorder instance to the mediaRecorder ref 41 | mediaRecorder.current = media; 42 | //invokes the start method to start the recording process 43 | mediaRecorder.current.start(); 44 | let localAudioChunks = []; 45 | mediaRecorder.current.ondataavailable = (event) => { 46 | if (typeof event.data === "undefined") return; 47 | if (event.data.size === 0) return; 48 | localAudioChunks.push(event.data); 49 | }; 50 | setAudioChunks(localAudioChunks); 51 | }; 52 | 53 | const stopRecording = () => { 54 | setRecordingStatus("inactive"); 55 | //stops the recording instance 56 | mediaRecorder.current.stop(); 57 | mediaRecorder.current.onstop = () => { 58 | //creates a blob file from the audiochunks data 59 | const audioBlob = new Blob(audioChunks, { type: mimeType }); 60 | //creates a playable URL from the blob file. 61 | const audioUrl = URL.createObjectURL(audioBlob); 62 | setAudio(audioUrl); 63 | setAudioChunks([]); 64 | }; 65 | toast.dismiss(); 66 | toast.success("recording is successfull"); 67 | }; 68 | 69 | return ( 70 |
71 | 72 |
73 |
74 | {!permission ? ( 75 | 82 | ) : null} 83 | {permission && recordingStatus === "inactive" ? ( 84 | 91 | ) : null} 92 | {recordingStatus === "recording" ? ( 93 | 100 | ) : null} 101 |
102 | {audio ? ( 103 |
104 | 105 | toast.success("Recording Downloaded")} 110 | > 111 | Download Recording 112 | 113 |
114 | ) : null} 115 |
116 |
117 | ); 118 | }; 119 | 120 | export default AudioRecorder; 121 | --------------------------------------------------------------------------------