├── 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 |

64 |
React Audio Recorder
65 |
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 | 
33 |
34 | 
35 |
36 | 
37 |
38 | 
39 |
40 | 
41 |
42 | 
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 | [](https://rajeshportfolio.me/)
60 | [](https://www.linkedin.com/in/rajesh-kanugu-aba8a3254/)
61 | [](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 |
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 |
114 | ) : null}
115 |
116 |
117 | );
118 | };
119 |
120 | export default AudioRecorder;
121 |
--------------------------------------------------------------------------------