zouhairk commited on
Commit
cba7fd1
·
1 Parent(s): ae9b179

add front et requirements

Browse files
front/.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
front/.gitignore copy 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?
front/eslint.config copy.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ );
front/index copy.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>MSA TRANSLATE</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
front/package copy.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "voice-chat-translation-app",
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
+ "@microsoft/fetch-event-source": "^2.0.1",
14
+ "lucide-react": "^0.344.0",
15
+ "react": "^18.3.1",
16
+ "react-dom": "^18.3.1",
17
+ "react-router-dom": "^6.22.3"
18
+ },
19
+ "devDependencies": {
20
+ "@eslint/js": "^9.9.1",
21
+ "@types/react": "^18.3.5",
22
+ "@types/react-dom": "^18.3.0",
23
+ "@vitejs/plugin-react": "^4.3.1",
24
+ "autoprefixer": "^10.4.18",
25
+ "eslint": "^9.9.1",
26
+ "eslint-plugin-react-hooks": "^5.1.0-rc.0",
27
+ "eslint-plugin-react-refresh": "^0.4.11",
28
+ "globals": "^15.9.0",
29
+ "postcss": "^8.4.35",
30
+ "tailwindcss": "^3.4.1",
31
+ "typescript": "^5.5.3",
32
+ "typescript-eslint": "^8.3.0",
33
+ "vite": "^5.4.2"
34
+ }
35
+ }
front/package-lock copy.json ADDED
The diff for this file is too large to render. See raw diff
 
front/postcss.config copy.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
front/src/App.tsx CHANGED
@@ -15,12 +15,12 @@ function App() {
15
  <div className="container mx-auto flex items-center justify-between">
16
  <Link to="/" className="flex items-center space-x-2">
17
  <Globe2 className="h-6 w-6 text-blue-600" />
18
- <span className="text-xl font-semibold">MSA Translator</span>
19
  </Link>
20
  <div className="flex space-x-4">
21
- <Link to="/" className="px-4 py-2 rounded hover:bg-gray-100">Home</Link>
22
- <Link to="/arabic" className="px-4 py-2 rounded hover:bg-gray-100">Arabic Chat</Link>
23
- <Link to="/french" className="px-4 py-2 rounded hover:bg-gray-100">French Chat</Link>
24
  </div>
25
  </div>
26
  </nav>
 
15
  <div className="container mx-auto flex items-center justify-between">
16
  <Link to="/" className="flex items-center space-x-2">
17
  <Globe2 className="h-6 w-6 text-blue-600" />
18
+ <span className="text-xl font-semibold">MSA Translate</span>
19
  </Link>
20
  <div className="flex space-x-4">
21
+ <Link to="/" className="px-4 py-2 rounded hover:bg-gray-100">Choix langue</Link>
22
+ <Link to="/arabic" className="px-4 py-2 rounded hover:bg-gray-100">Adherent</Link>
23
+ <Link to="/french" className="px-4 py-2 rounded hover:bg-gray-100">Agent</Link>
24
  </div>
25
  </div>
26
  </nav>
front/src/context/ChatContext.tsx CHANGED
@@ -3,6 +3,7 @@ import React, { createContext, useContext, useState } from 'react';
3
  interface Message {
4
  id: number;
5
  text: string;
 
6
  isArabic?: boolean;
7
  isFrench?: boolean;
8
  timestamp: Date;
@@ -18,8 +19,43 @@ const ChatContext = createContext<ChatContextType | undefined>(undefined);
18
  export function ChatProvider({ children }: { children: React.ReactNode }) {
19
  const [messages, setMessages] = useState<Message[]>([]);
20
 
21
- const addMessage = (message: Message) => {
22
- setMessages(prev => [...prev, message]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  };
24
 
25
  return (
 
3
  interface Message {
4
  id: number;
5
  text: string;
6
+ translatedText?: string;
7
  isArabic?: boolean;
8
  isFrench?: boolean;
9
  timestamp: Date;
 
19
  export function ChatProvider({ children }: { children: React.ReactNode }) {
20
  const [messages, setMessages] = useState<Message[]>([]);
21
 
22
+ const translateText = async (text: string, from: string, to: string) => {
23
+ try {
24
+ // Utilisation de l'API Google Translate via RapidAPI
25
+ const response = await fetch('https://translate.googleapis.com/translate_a/single?client=gtx&sl=' + from + '&tl=' + to + '&dt=t&q=' + encodeURI(text));
26
+
27
+ if (!response.ok) {
28
+ throw new Error('Translation failed');
29
+ }
30
+
31
+ const data = await response.json();
32
+ // La traduction se trouve dans le premier élément du premier tableau
33
+ const translatedText = data[0][0][0];
34
+
35
+ return translatedText;
36
+ } catch (error) {
37
+ console.error('Translation error:', error);
38
+ return text;
39
+ }
40
+ };
41
+
42
+ const addMessage = async (message: Message) => {
43
+ const from = message.isArabic ? 'ar' : 'fr';
44
+ const to = message.isArabic ? 'fr' : 'ar';
45
+
46
+ try {
47
+ const translatedText = await translateText(message.text, from, to);
48
+
49
+ const messageWithTranslation = {
50
+ ...message,
51
+ translatedText,
52
+ };
53
+
54
+ setMessages(prev => [...prev, messageWithTranslation]);
55
+ } catch (error) {
56
+ console.error('Error in message translation:', error);
57
+ setMessages(prev => [...prev, message]);
58
+ }
59
  };
60
 
61
  return (
front/src/pages/ArabicChat.tsx CHANGED
@@ -1,17 +1,17 @@
1
  import React, { useState, useRef } from 'react';
2
- import { Mic, Play, Square } from 'lucide-react';
3
  import { useChat } from '../context/ChatContext';
4
 
5
  const ArabicChat = () => {
6
  const { messages, addMessage } = useChat();
7
  const [isRecording, setIsRecording] = useState(false);
 
8
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
9
  const chunksRef = useRef<Blob[]>([]);
10
  const recognitionRef = useRef<SpeechRecognition | null>(null);
11
 
12
  const startRecording = async () => {
13
  try {
14
- // Initialize speech recognition
15
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
16
  const recognition = new SpeechRecognition();
17
  recognitionRef.current = recognition;
@@ -39,7 +39,6 @@ const ArabicChat = () => {
39
  recognition.start();
40
  setIsRecording(true);
41
 
42
- // Also start audio recording for WAV file
43
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
44
  const mediaRecorder = new MediaRecorder(stream);
45
  mediaRecorderRef.current = mediaRecorder;
@@ -67,28 +66,42 @@ const ArabicChat = () => {
67
  }
68
  };
69
 
70
- const speakText = (text: string, isArabic: boolean) => {
71
  if ('speechSynthesis' in window) {
72
- window.speechSynthesis.cancel();
 
73
 
74
  const utterance = new SpeechSynthesisUtterance(text);
75
- utterance.lang = isArabic ? 'ar-SA' : 'fr-FR';
76
- utterance.rate = 1.0;
77
  utterance.pitch = 1.0;
78
  utterance.volume = 1.0;
79
 
 
 
 
 
 
 
 
 
80
  window.speechSynthesis.speak(utterance);
81
  }
82
  };
83
 
 
 
 
 
 
84
  return (
85
- <div className="container mx-auto p-4 max-w-2xl">
86
  <div className="bg-white rounded-lg shadow-md h-[calc(100vh-12rem)] flex flex-col">
87
  <div className="flex-1 overflow-y-auto p-4">
88
  {messages.map((message) => (
89
  <div
90
  key={message.id}
91
- className={`flex ${message.isArabic ? 'justify-end' : 'justify-start'} mb-4`}
92
  >
93
  <div
94
  className={`rounded-lg p-3 max-w-[70%] ${
@@ -97,14 +110,20 @@ const ArabicChat = () => {
97
  : 'bg-white border border-gray-300'
98
  }`}
99
  >
100
- <p dir={message.isArabic ? 'rtl' : 'ltr'}>{message.text}</p>
 
 
101
  {!message.isArabic && (
102
  <button
103
  className="mt-2 p-2 bg-gray-100 rounded-full hover:bg-gray-200 transition-colors"
104
- onClick={() => speakText(message.text, false)}
105
- title="Écouter la traduction"
106
  >
107
- <Play className="h-4 w-4" />
 
 
 
 
108
  </button>
109
  )}
110
  </div>
@@ -113,7 +132,7 @@ const ArabicChat = () => {
113
  </div>
114
 
115
  <div className="border-t p-4">
116
- <div className="flex items-center justify-center space-x-4">
117
  <button
118
  onClick={isRecording ? stopRecording : startRecording}
119
  className="relative p-4 rounded-full bg-blue-500 hover:bg-blue-600 text-white"
@@ -127,7 +146,7 @@ const ArabicChat = () => {
127
  <div className="absolute inset-0 animate-ping rounded-full bg-blue-400 opacity-75"></div>
128
  )}
129
  </button>
130
- <p className="text-gray-600 text-right" dir="rtl">انقر ثم تحدث</p>
131
  </div>
132
  </div>
133
  </div>
 
1
  import React, { useState, useRef } from 'react';
2
+ import { Mic, Play, Square, StopCircle } from 'lucide-react';
3
  import { useChat } from '../context/ChatContext';
4
 
5
  const ArabicChat = () => {
6
  const { messages, addMessage } = useChat();
7
  const [isRecording, setIsRecording] = useState(false);
8
+ const [isPlaying, setIsPlaying] = useState(false);
9
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
10
  const chunksRef = useRef<Blob[]>([]);
11
  const recognitionRef = useRef<SpeechRecognition | null>(null);
12
 
13
  const startRecording = async () => {
14
  try {
 
15
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
16
  const recognition = new SpeechRecognition();
17
  recognitionRef.current = recognition;
 
39
  recognition.start();
40
  setIsRecording(true);
41
 
 
42
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
43
  const mediaRecorder = new MediaRecorder(stream);
44
  mediaRecorderRef.current = mediaRecorder;
 
66
  }
67
  };
68
 
69
+ const speakText = (text: string) => {
70
  if ('speechSynthesis' in window) {
71
+ window.speechSynthesis.cancel(); // Arrête toute lecture en cours
72
+ setIsPlaying(true);
73
 
74
  const utterance = new SpeechSynthesisUtterance(text);
75
+ utterance.lang = 'ar-SA';
76
+ utterance.rate = 0.9;
77
  utterance.pitch = 1.0;
78
  utterance.volume = 1.0;
79
 
80
+ utterance.onend = () => {
81
+ setIsPlaying(false);
82
+ };
83
+
84
+ utterance.onerror = () => {
85
+ setIsPlaying(false);
86
+ };
87
+
88
  window.speechSynthesis.speak(utterance);
89
  }
90
  };
91
 
92
+ const stopSpeaking = () => {
93
+ window.speechSynthesis.cancel();
94
+ setIsPlaying(false);
95
+ };
96
+
97
  return (
98
+ <div className="container mx-auto p-4 max-w-2xl" dir="rtl">
99
  <div className="bg-white rounded-lg shadow-md h-[calc(100vh-12rem)] flex flex-col">
100
  <div className="flex-1 overflow-y-auto p-4">
101
  {messages.map((message) => (
102
  <div
103
  key={message.id}
104
+ className={`flex ${message.isArabic ? 'justify-start' : 'justify-end'} mb-4`}
105
  >
106
  <div
107
  className={`rounded-lg p-3 max-w-[70%] ${
 
110
  : 'bg-white border border-gray-300'
111
  }`}
112
  >
113
+ <p className="text-right" style={{ direction: 'rtl' }}>
114
+ {message.isArabic ? message.text : message.translatedText}
115
+ </p>
116
  {!message.isArabic && (
117
  <button
118
  className="mt-2 p-2 bg-gray-100 rounded-full hover:bg-gray-200 transition-colors"
119
+ onClick={() => isPlaying ? stopSpeaking() : speakText(message.translatedText || '')}
120
+ title={isPlaying ? 'إيقاف الاستماع' : 'الاستماع إلى الرسالة'}
121
  >
122
+ {isPlaying ? (
123
+ <StopCircle className="h-4 w-4 text-red-500" />
124
+ ) : (
125
+ <Play className="h-4 w-4" />
126
+ )}
127
  </button>
128
  )}
129
  </div>
 
132
  </div>
133
 
134
  <div className="border-t p-4">
135
+ <div className="flex items-center justify-center space-x-4 flex-row-reverse">
136
  <button
137
  onClick={isRecording ? stopRecording : startRecording}
138
  className="relative p-4 rounded-full bg-blue-500 hover:bg-blue-600 text-white"
 
146
  <div className="absolute inset-0 animate-ping rounded-full bg-blue-400 opacity-75"></div>
147
  )}
148
  </button>
149
+ <p className="text-gray-600">انقر ثم تحدث</p>
150
  </div>
151
  </div>
152
  </div>
front/src/pages/FrenchChat.tsx CHANGED
@@ -1,17 +1,17 @@
1
  import React, { useState, useRef } from 'react';
2
- import { Mic, Play, Square } from 'lucide-react';
3
  import { useChat } from '../context/ChatContext';
4
 
5
  const FrenchChat = () => {
6
  const { messages, addMessage } = useChat();
7
  const [isRecording, setIsRecording] = useState(false);
 
8
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
9
  const chunksRef = useRef<Blob[]>([]);
10
  const recognitionRef = useRef<SpeechRecognition | null>(null);
11
 
12
  const startRecording = async () => {
13
  try {
14
- // Initialize speech recognition
15
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
16
  const recognition = new SpeechRecognition();
17
  recognitionRef.current = recognition;
@@ -39,7 +39,6 @@ const FrenchChat = () => {
39
  recognition.start();
40
  setIsRecording(true);
41
 
42
- // Also start audio recording for WAV file
43
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
44
  const mediaRecorder = new MediaRecorder(stream);
45
  mediaRecorderRef.current = mediaRecorder;
@@ -67,20 +66,34 @@ const FrenchChat = () => {
67
  }
68
  };
69
 
70
- const speakText = (text: string, isFrench: boolean) => {
71
  if ('speechSynthesis' in window) {
72
- window.speechSynthesis.cancel();
 
73
 
74
  const utterance = new SpeechSynthesisUtterance(text);
75
- utterance.lang = isFrench ? 'fr-FR' : 'ar-SA';
76
- utterance.rate = 1.0;
77
  utterance.pitch = 1.0;
78
  utterance.volume = 1.0;
79
 
 
 
 
 
 
 
 
 
80
  window.speechSynthesis.speak(utterance);
81
  }
82
  };
83
 
 
 
 
 
 
84
  return (
85
  <div className="container mx-auto p-4 max-w-2xl">
86
  <div className="bg-white rounded-lg shadow-md h-[calc(100vh-12rem)] flex flex-col">
@@ -97,14 +110,18 @@ const FrenchChat = () => {
97
  : 'bg-white border border-gray-300'
98
  }`}
99
  >
100
- <p>{message.text}</p>
101
  {!message.isFrench && (
102
  <button
103
  className="mt-2 p-2 bg-gray-100 rounded-full hover:bg-gray-200 transition-colors"
104
- onClick={() => speakText(message.text, false)}
105
- title="Écouter le message"
106
  >
107
- <Play className="h-4 w-4" />
 
 
 
 
108
  </button>
109
  )}
110
  </div>
 
1
  import React, { useState, useRef } from 'react';
2
+ import { Mic, Play, Square, StopCircle } from 'lucide-react';
3
  import { useChat } from '../context/ChatContext';
4
 
5
  const FrenchChat = () => {
6
  const { messages, addMessage } = useChat();
7
  const [isRecording, setIsRecording] = useState(false);
8
+ const [isPlaying, setIsPlaying] = useState(false);
9
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
10
  const chunksRef = useRef<Blob[]>([]);
11
  const recognitionRef = useRef<SpeechRecognition | null>(null);
12
 
13
  const startRecording = async () => {
14
  try {
 
15
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
16
  const recognition = new SpeechRecognition();
17
  recognitionRef.current = recognition;
 
39
  recognition.start();
40
  setIsRecording(true);
41
 
 
42
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
43
  const mediaRecorder = new MediaRecorder(stream);
44
  mediaRecorderRef.current = mediaRecorder;
 
66
  }
67
  };
68
 
69
+ const speakText = (text: string) => {
70
  if ('speechSynthesis' in window) {
71
+ window.speechSynthesis.cancel(); // Arrête toute lecture en cours
72
+ setIsPlaying(true);
73
 
74
  const utterance = new SpeechSynthesisUtterance(text);
75
+ utterance.lang = 'fr-FR';
76
+ utterance.rate = 0.9;
77
  utterance.pitch = 1.0;
78
  utterance.volume = 1.0;
79
 
80
+ utterance.onend = () => {
81
+ setIsPlaying(false);
82
+ };
83
+
84
+ utterance.onerror = () => {
85
+ setIsPlaying(false);
86
+ };
87
+
88
  window.speechSynthesis.speak(utterance);
89
  }
90
  };
91
 
92
+ const stopSpeaking = () => {
93
+ window.speechSynthesis.cancel();
94
+ setIsPlaying(false);
95
+ };
96
+
97
  return (
98
  <div className="container mx-auto p-4 max-w-2xl">
99
  <div className="bg-white rounded-lg shadow-md h-[calc(100vh-12rem)] flex flex-col">
 
110
  : 'bg-white border border-gray-300'
111
  }`}
112
  >
113
+ <p>{message.isFrench ? message.text : message.translatedText}</p>
114
  {!message.isFrench && (
115
  <button
116
  className="mt-2 p-2 bg-gray-100 rounded-full hover:bg-gray-200 transition-colors"
117
+ onClick={() => isPlaying ? stopSpeaking() : speakText(message.translatedText || '')}
118
+ title={isPlaying ? 'Arrêter la lecture' : 'Écouter le message'}
119
  >
120
+ {isPlaying ? (
121
+ <StopCircle className="h-4 w-4 text-red-500" />
122
+ ) : (
123
+ <Play className="h-4 w-4" />
124
+ )}
125
  </button>
126
  )}
127
  </div>
front/src/pages/LanguageSelection.tsx CHANGED
@@ -8,22 +8,22 @@ const LanguageSelection = () => {
8
  {
9
  name: 'Bulgarian',
10
  nativeName: 'Говоря български',
11
- flag: 'https://images.unsplash.com/photo-1607427293702-036707fc51c0?auto=format&fit=crop&w=64&h=64',
12
  },
13
  {
14
  name: 'Arabic',
15
  nativeName: 'أتحدث العربية',
16
- flag: 'https://images.unsplash.com/photo-1607427293702-036707fc51c0?auto=format&fit=crop&w=64&h=64',
17
  },
18
  {
19
  name: 'Spanish',
20
  nativeName: 'Hablo español',
21
- flag: 'https://images.unsplash.com/photo-1607427293702-036707fc51c0?auto=format&fit=crop&w=64&h=64',
22
  },
23
  {
24
  name: 'Romanian',
25
  nativeName: 'Vorbesc română',
26
- flag: 'https://images.unsplash.com/photo-1607427293702-036707fc51c0?auto=format&fit=crop&w=64&h=64',
27
  },
28
  ];
29
 
@@ -32,9 +32,9 @@ const LanguageSelection = () => {
32
  <div className="max-w-2xl mx-auto">
33
  <div className="flex justify-center mb-8">
34
  <img
35
- src="https://images.unsplash.com/photo-1607427293702-036707fc51c0?auto=format&fit=crop&w=200&h=100"
36
  alt="MSA Logo"
37
- className="h-24"
38
  />
39
  </div>
40
 
@@ -48,10 +48,10 @@ const LanguageSelection = () => {
48
  <img
49
  src={lang.flag}
50
  alt={`${lang.name} flag`}
51
- className="w-12 h-12 rounded-full"
52
  />
53
  <div className="text-left">
54
- <p className="text-sm text-gray-600">Je parle</p>
55
  <p className="text-lg font-semibold">{lang.nativeName}</p>
56
  </div>
57
  </button>
 
8
  {
9
  name: 'Bulgarian',
10
  nativeName: 'Говоря български',
11
+ flag: 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Flag_of_Bulgaria.svg/langfr-2560px-Flag_of_Bulgaria.svg.png',
12
  },
13
  {
14
  name: 'Arabic',
15
  nativeName: 'أتحدث العربية',
16
+ flag: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Flag_of_Morocco.svg/langfr-1920px-Flag_of_Morocco.svg.png',
17
  },
18
  {
19
  name: 'Spanish',
20
  nativeName: 'Hablo español',
21
+ flag: 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Flag_of_Spain.svg/langfr-1920px-Flag_of_Spain.svg.png',
22
  },
23
  {
24
  name: 'Romanian',
25
  nativeName: 'Vorbesc română',
26
+ flag: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Flag_of_Romania.svg/langfr-1920px-Flag_of_Romania.svg.png',
27
  },
28
  ];
29
 
 
32
  <div className="max-w-2xl mx-auto">
33
  <div className="flex justify-center mb-8">
34
  <img
35
+ src="https://upload.wikimedia.org/wikipedia/fr/1/18/Mutualite_sociale_agricole_logo.svg"
36
  alt="MSA Logo"
37
+ className="h-16"
38
  />
39
  </div>
40
 
 
48
  <img
49
  src={lang.flag}
50
  alt={`${lang.name} flag`}
51
+ className="w-12 shadow-md border-solid"
52
  />
53
  <div className="text-left">
54
+
55
  <p className="text-lg font-semibold">{lang.nativeName}</p>
56
  </div>
57
  </button>
front/tailwind.config copy.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
4
+ theme: {
5
+ extend: {},
6
+ },
7
+ plugins: [],
8
+ };
front/tsconfig copy.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
front/tsconfig.app copy.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
front/tsconfig.node copy.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
front/vite.config copy.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
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
+ });
requirements.txt CHANGED
@@ -7,4 +7,5 @@ huggingface-hub
7
  tiktoken
8
  blobfile
9
  protobuf
10
- sentencepiece
 
 
7
  tiktoken
8
  blobfile
9
  protobuf
10
+ sentencepiece
11
+ torchaudio