@rimori/client 1.4.0 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +77 -71
  2. package/dist/cli/scripts/init/dev-registration.d.ts +1 -1
  3. package/dist/cli/scripts/init/dev-registration.js +4 -4
  4. package/dist/cli/scripts/init/main.js +1 -1
  5. package/dist/cli/scripts/init/package-setup.d.ts +1 -1
  6. package/dist/cli/scripts/init/package-setup.js +3 -3
  7. package/dist/cli/scripts/init/router-transformer.js +19 -12
  8. package/dist/cli/scripts/init/vite-config.d.ts +2 -2
  9. package/dist/cli/scripts/init/vite-config.js +2 -2
  10. package/dist/cli/scripts/release/release-config-upload.js +9 -9
  11. package/dist/cli/scripts/release/release-db-update.d.ts +1 -1
  12. package/dist/cli/scripts/release/release-db-update.js +9 -9
  13. package/dist/cli/scripts/release/release-file-upload.js +1 -1
  14. package/dist/cli/scripts/release/release.js +2 -2
  15. package/dist/components/CRUDModal.d.ts +1 -1
  16. package/dist/components/CRUDModal.js +3 -3
  17. package/dist/components/MarkdownEditor.js +16 -16
  18. package/dist/components/Spinner.js +2 -2
  19. package/dist/components/ai/Assistant.js +7 -8
  20. package/dist/components/ai/Avatar.d.ts +2 -2
  21. package/dist/components/ai/Avatar.js +10 -5
  22. package/dist/components/ai/EmbeddedAssistent/AudioInputField.js +5 -6
  23. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +1 -1
  24. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -2
  25. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +1 -2
  26. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +4 -2
  27. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +2 -3
  28. package/dist/components/audio/Playbutton.js +10 -7
  29. package/dist/components/components/ContextMenu.d.ts +1 -1
  30. package/dist/components/components/ContextMenu.js +19 -16
  31. package/dist/components.d.ts +10 -10
  32. package/dist/components.js +10 -10
  33. package/dist/core/controller/AIController.d.ts +2 -2
  34. package/dist/core/controller/AIController.js +12 -12
  35. package/dist/core/controller/ExerciseController.d.ts +2 -2
  36. package/dist/core/controller/ExerciseController.js +2 -2
  37. package/dist/core/controller/ObjectController.js +5 -5
  38. package/dist/core/controller/SettingsController.d.ts +22 -7
  39. package/dist/core/controller/SettingsController.js +73 -8
  40. package/dist/core/controller/SharedContentController.d.ts +3 -3
  41. package/dist/core/controller/SharedContentController.js +38 -20
  42. package/dist/core/controller/VoiceController.js +6 -4
  43. package/dist/core/core.d.ts +15 -15
  44. package/dist/core/core.js +7 -7
  45. package/dist/fromRimori/EventBus.js +23 -23
  46. package/dist/fromRimori/PluginTypes.d.ts +4 -4
  47. package/dist/hooks/UseChatHook.d.ts +3 -3
  48. package/dist/hooks/UseChatHook.js +9 -3
  49. package/dist/index.d.ts +10 -10
  50. package/dist/index.js +9 -9
  51. package/dist/plugin/AccomplishmentHandler.d.ts +5 -5
  52. package/dist/plugin/AccomplishmentHandler.js +31 -27
  53. package/dist/plugin/AudioController.d.ts +1 -1
  54. package/dist/plugin/AudioController.js +6 -6
  55. package/dist/plugin/Logger.js +15 -13
  56. package/dist/plugin/PluginController.d.ts +7 -1
  57. package/dist/plugin/PluginController.js +32 -27
  58. package/dist/plugin/RimoriClient.d.ts +17 -18
  59. package/dist/plugin/RimoriClient.js +31 -31
  60. package/dist/plugin/StandaloneClient.d.ts +1 -1
  61. package/dist/plugin/StandaloneClient.js +35 -16
  62. package/dist/plugin/ThemeSetter.js +4 -4
  63. package/dist/providers/PluginProvider.js +44 -14
  64. package/dist/utils/Language.js +57 -57
  65. package/dist/utils/PluginUtils.js +3 -3
  66. package/dist/utils/difficultyConverter.d.ts +1 -1
  67. package/dist/utils/difficultyConverter.js +1 -1
  68. package/dist/utils/endpoint.js +2 -2
  69. package/dist/worker/WorkerSetup.d.ts +1 -1
  70. package/dist/worker/WorkerSetup.js +6 -6
  71. package/example/docs/devdocs.md +50 -40
  72. package/example/docs/overview.md +1 -1
  73. package/example/docs/userdocs.md +4 -1
  74. package/example/rimori.config.ts +51 -49
  75. package/example/worker/vite.config.ts +3 -3
  76. package/example/worker/worker.ts +2 -2
  77. package/package.json +14 -8
  78. package/prettier.config.js +1 -1
  79. package/src/cli/scripts/init/dev-registration.ts +5 -8
  80. package/src/cli/scripts/init/env-setup.ts +1 -1
  81. package/src/cli/scripts/init/file-operations.ts +1 -1
  82. package/src/cli/scripts/init/html-cleaner.ts +2 -5
  83. package/src/cli/scripts/init/main.ts +16 -13
  84. package/src/cli/scripts/init/package-setup.ts +11 -15
  85. package/src/cli/scripts/init/router-transformer.ts +40 -37
  86. package/src/cli/scripts/init/tailwind-config.ts +17 -26
  87. package/src/cli/scripts/init/vite-config.ts +3 -3
  88. package/src/cli/scripts/release/release-config-upload.ts +11 -11
  89. package/src/cli/scripts/release/release-db-update.ts +12 -12
  90. package/src/cli/scripts/release/release-file-upload.ts +2 -2
  91. package/src/cli/scripts/release/release.ts +4 -4
  92. package/src/cli/types/DatabaseTypes.ts +2 -10
  93. package/src/components/CRUDModal.tsx +64 -48
  94. package/src/components/MarkdownEditor.tsx +58 -27
  95. package/src/components/Spinner.tsx +24 -17
  96. package/src/components/ai/Assistant.tsx +70 -70
  97. package/src/components/ai/Avatar.tsx +17 -14
  98. package/src/components/ai/EmbeddedAssistent/AudioInputField.tsx +63 -54
  99. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +14 -5
  100. package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +75 -74
  101. package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +3 -4
  102. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +109 -94
  103. package/src/components/ai/utils.ts +4 -4
  104. package/src/components/audio/Playbutton.tsx +101 -93
  105. package/src/components/components/ContextMenu.tsx +47 -35
  106. package/src/components.ts +10 -10
  107. package/src/core/controller/AIController.ts +29 -19
  108. package/src/core/controller/ExerciseController.ts +16 -23
  109. package/src/core/controller/ObjectController.ts +15 -10
  110. package/src/core/controller/SettingsController.ts +89 -16
  111. package/src/core/controller/SharedContentController.ts +80 -44
  112. package/src/core/controller/VoiceController.ts +10 -8
  113. package/src/core/core.ts +15 -16
  114. package/src/fromRimori/EventBus.ts +76 -47
  115. package/src/fromRimori/PluginTypes.ts +26 -17
  116. package/src/fromRimori/readme.md +2 -2
  117. package/src/hooks/UseChatHook.ts +25 -15
  118. package/src/index.ts +10 -10
  119. package/src/plugin/AccomplishmentHandler.ts +53 -35
  120. package/src/plugin/AudioController.ts +18 -12
  121. package/src/plugin/Logger.ts +28 -21
  122. package/src/plugin/PluginController.ts +60 -44
  123. package/src/plugin/RimoriClient.ts +102 -72
  124. package/src/plugin/StandaloneClient.ts +51 -24
  125. package/src/plugin/ThemeSetter.ts +5 -5
  126. package/src/providers/PluginProvider.tsx +90 -36
  127. package/src/style.scss +3 -3
  128. package/src/utils/Language.ts +58 -58
  129. package/src/utils/PluginUtils.ts +16 -20
  130. package/src/utils/difficultyConverter.ts +2 -2
  131. package/src/utils/endpoint.ts +3 -2
  132. package/src/worker/WorkerSetup.ts +8 -9
  133. package/tsconfig.json +2 -4
@@ -58,14 +58,14 @@ function detectRouteComponents(content) {
58
58
  componentNames.add(componentName);
59
59
  }
60
60
  // For each component, find its corresponding import statement
61
- componentNames.forEach(componentName => {
61
+ componentNames.forEach((componentName) => {
62
62
  const importInfo = findImportForComponent(content, componentName);
63
63
  if (importInfo) {
64
64
  routeComponents.push({
65
65
  componentName,
66
66
  importStatement: importInfo.importStatement,
67
67
  importPath: importInfo.importPath,
68
- isDefaultImport: importInfo.isDefaultImport
68
+ isDefaultImport: importInfo.isDefaultImport,
69
69
  });
70
70
  }
71
71
  });
@@ -86,19 +86,19 @@ function findImportForComponent(content, componentName) {
86
86
  return {
87
87
  importStatement: defaultMatch[0],
88
88
  importPath: defaultMatch[1],
89
- isDefaultImport: true
89
+ isDefaultImport: true,
90
90
  };
91
91
  }
92
92
  // Check for named import: import { ComponentName } from "path"
93
93
  const namedImportRegex = /import\s*\{\s*([^}]*)\s*\}\s*from\s*["']([^"']+)["'];?/g;
94
94
  let namedMatch;
95
95
  while ((namedMatch = namedImportRegex.exec(content)) !== null) {
96
- const imports = namedMatch[1].split(',').map(imp => imp.trim());
96
+ const imports = namedMatch[1].split(',').map((imp) => imp.trim());
97
97
  if (imports.includes(componentName)) {
98
98
  return {
99
99
  importStatement: namedMatch[0],
100
100
  importPath: namedMatch[2],
101
- isDefaultImport: false
101
+ isDefaultImport: false,
102
102
  };
103
103
  }
104
104
  }
@@ -142,16 +142,17 @@ function addLazyImport(content) {
142
142
  if (reactImportMatch) {
143
143
  // React import exists, add lazy to it
144
144
  const existingImports = reactImportMatch[1] || '';
145
- const importList = existingImports.split(',').map(imp => imp.trim()).filter(Boolean);
145
+ const importList = existingImports
146
+ .split(',')
147
+ .map((imp) => imp.trim())
148
+ .filter(Boolean);
146
149
  if (!importList.includes('lazy')) {
147
150
  importList.push('lazy');
148
151
  }
149
152
  if (!importList.includes('Suspense')) {
150
153
  importList.push('Suspense');
151
154
  }
152
- const newImport = importList.length > 0
153
- ? `import React, { ${importList.join(', ')} } from "react";`
154
- : `import React from "react";`;
155
+ const newImport = importList.length > 0 ? `import React, { ${importList.join(', ')} } from "react";` : `import React from "react";`;
155
156
  return content.replace(reactImportMatch[0], newImport);
156
157
  }
157
158
  else {
@@ -221,7 +222,10 @@ function transformImports(content) {
221
222
  else {
222
223
  // Update existing @rimori/client import to include PluginProvider
223
224
  content = content.replace(/import\s*{\s*([^}]*)\s*}\s*from\s*["']@rimori\/client["'];?/, (match, imports) => {
224
- const importList = imports.split(',').map((imp) => imp.trim()).filter(Boolean);
225
+ const importList = imports
226
+ .split(',')
227
+ .map((imp) => imp.trim())
228
+ .filter(Boolean);
225
229
  if (!importList.includes('PluginProvider')) {
226
230
  importList.push('PluginProvider');
227
231
  }
@@ -230,8 +234,11 @@ function transformImports(content) {
230
234
  }
231
235
  // Transform react-router-dom import: replace BrowserRouter with HashRouter
232
236
  content = content.replace(/import\s*{\s*([^}]*)\s*}\s*from\s*["']react-router-dom["'];?/, (match, imports) => {
233
- const importList = imports.split(',').map((imp) => imp.trim()).filter(Boolean);
234
- const updatedImports = importList.map((imp) => imp === 'BrowserRouter' ? 'HashRouter' : imp);
237
+ const importList = imports
238
+ .split(',')
239
+ .map((imp) => imp.trim())
240
+ .filter(Boolean);
241
+ const updatedImports = importList.map((imp) => (imp === 'BrowserRouter' ? 'HashRouter' : imp));
235
242
  return `import { ${updatedImports.join(', ')} } from "react-router-dom";`;
236
243
  });
237
244
  return content;
@@ -5,7 +5,7 @@
5
5
  * @param param.configPath - Path to the vite.config.ts file (defaults to './vite.config.ts')
6
6
  * @throws {Error} if vite.config.ts file is not found or cannot be modified.
7
7
  */
8
- export declare function updateViteConfigBase({ basePath, configPath }?: {
8
+ export declare function updateViteConfigBase({ basePath, configPath, }?: {
9
9
  basePath?: string;
10
10
  configPath?: string;
11
11
  }): void;
@@ -15,6 +15,6 @@ export declare function updateViteConfigBase({ basePath, configPath }?: {
15
15
  * @param param.configPath - Path to the vite.config.ts file (defaults to './vite.config.ts')
16
16
  * @returns The current base value or null if not found.
17
17
  */
18
- export declare function getCurrentViteBase({ configPath }?: {
18
+ export declare function getCurrentViteBase({ configPath, }?: {
19
19
  configPath?: string;
20
20
  }): string | null;
@@ -7,7 +7,7 @@ import * as path from 'path';
7
7
  * @param param.configPath - Path to the vite.config.ts file (defaults to './vite.config.ts')
8
8
  * @throws {Error} if vite.config.ts file is not found or cannot be modified.
9
9
  */
10
- export function updateViteConfigBase({ basePath = './', configPath = './vite.config.ts' } = {}) {
10
+ export function updateViteConfigBase({ basePath = './', configPath = './vite.config.ts', } = {}) {
11
11
  const viteConfigPath = path.resolve(configPath);
12
12
  if (!fs.existsSync(viteConfigPath)) {
13
13
  throw new Error(`vite.config.ts not found at ${viteConfigPath}`);
@@ -43,7 +43,7 @@ export function updateViteConfigBase({ basePath = './', configPath = './vite.con
43
43
  * @param param.configPath - Path to the vite.config.ts file (defaults to './vite.config.ts')
44
44
  * @returns The current base value or null if not found.
45
45
  */
46
- export function getCurrentViteBase({ configPath = './vite.config.ts' } = {}) {
46
+ export function getCurrentViteBase({ configPath = './vite.config.ts', } = {}) {
47
47
  const viteConfigPath = path.resolve(configPath);
48
48
  if (!fs.existsSync(viteConfigPath)) {
49
49
  return null;
@@ -31,7 +31,7 @@ export function sendConfiguration(config) {
31
31
  // Transpile TypeScript to JavaScript
32
32
  const result = ts.transpile(configContent, {
33
33
  target: ts.ScriptTarget.ES2020,
34
- module: ts.ModuleKind.ES2020
34
+ module: ts.ModuleKind.ES2020,
35
35
  });
36
36
  // Create a temporary file to import the transpiled code
37
37
  const tempFile = path.join(process.cwd(), 'temp_config.js');
@@ -67,7 +67,7 @@ export function sendConfiguration(config) {
67
67
  method: 'POST',
68
68
  headers: {
69
69
  'Content-Type': 'application/json',
70
- 'Authorization': `Bearer ${config.token}`
70
+ Authorization: `Bearer ${config.token}`,
71
71
  },
72
72
  body: JSON.stringify(requestBody),
73
73
  });
@@ -87,8 +87,8 @@ export function sendConfiguration(config) {
87
87
  }
88
88
  }
89
89
  catch (e) {
90
- console.log("error", e);
91
- throw new Error("Error sending configuration");
90
+ console.log('error', e);
91
+ throw new Error('Error sending configuration');
92
92
  }
93
93
  }
94
94
  catch (error) {
@@ -103,14 +103,14 @@ export function releasePlugin(config, release_id) {
103
103
  method: 'POST',
104
104
  headers: {
105
105
  'Content-Type': 'application/json',
106
- 'Authorization': `Bearer ${config.token}`
106
+ Authorization: `Bearer ${config.token}`,
107
107
  },
108
- body: JSON.stringify({ plugin_id: config.plugin_id })
108
+ body: JSON.stringify({ plugin_id: config.plugin_id }),
109
109
  });
110
110
  if (!response.ok) {
111
- console.log("Response:", yield response.text());
112
- throw new Error("Failed to release plugin");
111
+ console.log('Response:', yield response.text());
112
+ throw new Error('Failed to release plugin');
113
113
  }
114
- console.log("✅ Plugin released successfully");
114
+ console.log('✅ Plugin released successfully');
115
115
  });
116
116
  }
@@ -1,4 +1,4 @@
1
- import { Config } from "./release";
1
+ import { Config } from './release';
2
2
  /**
3
3
  * Read and send the database configuration to the release endpoint
4
4
  * @param config - Configuration object
@@ -32,7 +32,7 @@ export default function dbUpdate(config, release_id) {
32
32
  // Transpile TypeScript to JavaScript
33
33
  const result = ts.transpile(dbConfigContent, {
34
34
  target: ts.ScriptTarget.ES2020,
35
- module: ts.ModuleKind.ES2020
35
+ module: ts.ModuleKind.ES2020,
36
36
  });
37
37
  // Create a temporary file to import the transpiled code
38
38
  const tempFile = path.join(process.cwd(), 'temp_db_config.js');
@@ -66,30 +66,30 @@ export default function dbUpdate(config, release_id) {
66
66
  method: 'POST',
67
67
  headers: {
68
68
  'Content-Type': 'application/json',
69
- 'Authorization': `Bearer ${config.token}`
69
+ Authorization: `Bearer ${config.token}`,
70
70
  },
71
71
  body: JSON.stringify(requestBody),
72
72
  }).catch((e) => {
73
- console.log("error", e);
74
- throw new Error("Error sending database configuration");
73
+ console.log('error', e);
74
+ throw new Error('Error sending database configuration');
75
75
  });
76
76
  try {
77
77
  const responseText = yield response.text().catch((e) => {
78
- console.log("error", e);
79
- throw new Error("Error sending database configuration");
78
+ console.log('error', e);
79
+ throw new Error('Error sending database configuration');
80
80
  });
81
81
  const responseData = JSON.parse(responseText);
82
82
  if (response.ok) {
83
83
  console.log('✅ Database configuration deployed successfully!');
84
84
  }
85
85
  else {
86
- console.log("responseData", responseData);
86
+ console.log('responseData', responseData);
87
87
  throw new Error(responseData.message);
88
88
  }
89
89
  }
90
90
  catch (e) {
91
- console.log("error", e);
92
- throw new Error("Error sending database configuration");
91
+ console.log('error', e);
92
+ throw new Error('Error sending database configuration');
93
93
  }
94
94
  }
95
95
  catch (error) {
@@ -65,7 +65,7 @@ export function uploadDirectory(config, release_id) {
65
65
  // Upload to the release endpoint
66
66
  const response = yield fetch(`${config.domain}/release/${release_id}/files`, {
67
67
  method: 'POST',
68
- headers: { 'Authorization': `Bearer ${config.token}` },
68
+ headers: { Authorization: `Bearer ${config.token}` },
69
69
  body: formData,
70
70
  });
71
71
  if (response.ok) {
@@ -43,7 +43,7 @@ const config = {
43
43
  release_channel: releaseChannel,
44
44
  plugin_id: pluginId,
45
45
  token: RIMORI_TOKEN,
46
- domain: process.env.RIMORI_BACKEND_URL || "https://api.rimori.se",
46
+ domain: process.env.RIMORI_BACKEND_URL || 'https://api.rimori.se',
47
47
  rimori_client_version: packageJson.dependencies['@rimori/client'].replace('^', ''),
48
48
  };
49
49
  /**
@@ -62,7 +62,7 @@ function releaseProcess() {
62
62
  yield releasePlugin(config, release_id);
63
63
  }
64
64
  catch (error) {
65
- console.log("❌ Error:", error.message);
65
+ console.log('❌ Error:', error.message);
66
66
  process.exit(1);
67
67
  }
68
68
  });
@@ -13,5 +13,5 @@ interface ActionButton {
13
13
  onClick: () => void;
14
14
  closeModal?: boolean;
15
15
  }
16
- export declare function CRUDModal({ actionbuttons, children, title, buttonText, className, closeAble, show, onClose }: Props): import("react/jsx-runtime").JSX.Element;
16
+ export declare function CRUDModal({ actionbuttons, children, title, buttonText, className, closeAble, show, onClose, }: Props): import("react/jsx-runtime").JSX.Element;
17
17
  export {};
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useRef } from "react";
3
- export function CRUDModal({ actionbuttons, children, title, buttonText, className, closeAble = true, show = false, onClose }) {
2
+ import { useEffect, useRef } from 'react';
3
+ export function CRUDModal({ actionbuttons, children, title, buttonText, className, closeAble = true, show = false, onClose, }) {
4
4
  const dialogRef = useRef(null);
5
5
  useEffect(() => {
6
6
  var _a, _b;
@@ -16,7 +16,7 @@ export function CRUDModal({ actionbuttons, children, title, buttonText, classNam
16
16
  (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.close();
17
17
  onClose === null || onClose === void 0 ? void 0 : onClose();
18
18
  };
19
- return (_jsxs(_Fragment, { children: [!!buttonText && _jsx("button", { className: className, onClick: () => { var _a; return (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.showModal(); }, children: buttonText }), _jsxs("dialog", { ref: dialogRef, className: "bg-gray-400 rounded-lg font-normal", onClose: handleClose, children: [_jsxs("div", { className: "bg-gray-500 text-xl flex flex-row justify-between p-3 items-start font-bold", children: [_jsx("h2", { children: title }), closeAble && _jsx("button", { onClick: handleClose, children: "\u00D7" })] }), _jsx("div", { className: "modal-body p-2", children: children }), _jsx("div", { className: "modal-footer px-2 py-2 flex flex-row gap-2 border-t-2", children: actionbuttons.map(({ onClick, text, closeModal = true }, index) => (_jsx("button", { className: "bg-blue-500 hover:bg-blue-600 dark:border-gray-900 rounded-md py-2 px-4 dark:text-white font-bold", onClick: () => {
19
+ return (_jsxs(_Fragment, { children: [!!buttonText && (_jsx("button", { className: className, onClick: () => { var _a; return (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.showModal(); }, children: buttonText })), _jsxs("dialog", { ref: dialogRef, className: "bg-gray-400 rounded-lg font-normal", onClose: handleClose, children: [_jsxs("div", { className: "bg-gray-500 text-xl flex flex-row justify-between p-3 items-start font-bold", children: [_jsx("h2", { children: title }), closeAble && _jsx("button", { onClick: handleClose, children: "\u00D7" })] }), _jsx("div", { className: "modal-body p-2", children: children }), _jsx("div", { className: "modal-footer px-2 py-2 flex flex-row gap-2 border-t-2", children: actionbuttons.map(({ onClick, text, closeModal = true }, index) => (_jsx("button", { className: "bg-blue-500 hover:bg-blue-600 dark:border-gray-900 rounded-md py-2 px-4 dark:text-white font-bold", onClick: () => {
20
20
  if (closeModal)
21
21
  handleClose();
22
22
  onClick();
@@ -1,48 +1,48 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Markdown } from 'tiptap-markdown';
3
- import StarterKit from "@tiptap/starter-kit";
4
- import { PiCodeBlock } from "react-icons/pi";
5
- import { TbBlockquote } from "react-icons/tb";
6
- import { GoListOrdered } from "react-icons/go";
7
- import { AiOutlineUnorderedList } from "react-icons/ai";
8
- import { EditorProvider, useCurrentEditor } from "@tiptap/react";
9
- import { LuHeading1, LuHeading2, LuHeading3 } from "react-icons/lu";
10
- import { FaBold, FaCode, FaItalic, FaParagraph, FaStrikethrough } from "react-icons/fa";
3
+ import StarterKit from '@tiptap/starter-kit';
4
+ import { PiCodeBlock } from 'react-icons/pi';
5
+ import { TbBlockquote } from 'react-icons/tb';
6
+ import { GoListOrdered } from 'react-icons/go';
7
+ import { AiOutlineUnorderedList } from 'react-icons/ai';
8
+ import { EditorProvider, useCurrentEditor } from '@tiptap/react';
9
+ import { LuHeading1, LuHeading2, LuHeading3 } from 'react-icons/lu';
10
+ import { FaBold, FaCode, FaItalic, FaParagraph, FaStrikethrough } from 'react-icons/fa';
11
11
  const EditorButton = ({ action, isActive, label, disabled }) => {
12
12
  const { editor } = useCurrentEditor();
13
13
  if (!editor) {
14
14
  return null;
15
15
  }
16
- if (action.includes("heading")) {
16
+ if (action.includes('heading')) {
17
17
  const level = parseInt(action[action.length - 1]);
18
- return (_jsx("button", { onClick: () => editor.chain().focus().toggleHeading({ level: level }).run(), className: `pl-2 ${isActive ? "is-active" : ""}`, children: label }));
18
+ return (_jsx("button", { onClick: () => editor.chain().focus().toggleHeading({ level: level }).run(), className: `pl-2 ${isActive ? 'is-active' : ''}`, children: label }));
19
19
  }
20
- return (_jsx("button", { onClick: () => editor.chain().focus()[action]().run(), disabled: disabled ? !editor.can().chain().focus()[action]().run() : false, className: `pl-2 ${isActive ? "is-active" : ""}`, children: label }));
20
+ return (_jsx("button", { onClick: () => editor.chain().focus()[action]().run(), disabled: disabled ? !editor.can().chain().focus()[action]().run() : false, className: `pl-2 ${isActive ? 'is-active' : ''}`, children: label }));
21
21
  };
22
22
  const MenuBar = () => {
23
23
  const { editor } = useCurrentEditor();
24
24
  if (!editor) {
25
25
  return null;
26
26
  }
27
- return (_jsxs("div", { className: "bg-gray-400 dark:bg-gray-800 dark:text-white text-lg flex flex-row flex-wrap items-center p-1", children: [_jsx(EditorButton, { action: "toggleBold", isActive: editor.isActive("bold"), label: _jsx(FaBold, {}), disabled: true }), _jsx(EditorButton, { action: "toggleItalic", isActive: editor.isActive("italic"), label: _jsx(FaItalic, {}), disabled: true }), _jsx(EditorButton, { action: "toggleStrike", isActive: editor.isActive("strike"), label: _jsx(FaStrikethrough, {}), disabled: true }), _jsx(EditorButton, { action: "toggleCode", isActive: editor.isActive("code"), label: _jsx(FaCode, {}), disabled: true }), _jsx(EditorButton, { action: "setParagraph", isActive: editor.isActive("paragraph"), label: _jsx(FaParagraph, {}) }), _jsx(EditorButton, { action: 'setHeading1', isActive: editor.isActive("heading", { level: 1 }), label: _jsx(LuHeading1, { size: "24px" }) }), _jsx(EditorButton, { action: 'setHeading2', isActive: editor.isActive("heading", { level: 2 }), label: _jsx(LuHeading2, { size: "24px" }) }), _jsx(EditorButton, { action: 'setHeading3', isActive: editor.isActive("heading", { level: 3 }), label: _jsx(LuHeading3, { size: "24px" }) }), _jsx(EditorButton, { action: "toggleBulletList", isActive: editor.isActive("bulletList"), label: _jsx(AiOutlineUnorderedList, { size: "24px" }) }), _jsx(EditorButton, { action: "toggleOrderedList", isActive: editor.isActive("orderedList"), label: _jsx(GoListOrdered, { size: "24px" }) }), _jsx(EditorButton, { action: "toggleCodeBlock", isActive: editor.isActive("codeBlock"), label: _jsx(PiCodeBlock, { size: "24px" }) }), _jsx(EditorButton, { action: "toggleBlockquote", isActive: editor.isActive("blockquote"), label: _jsx(TbBlockquote, { size: "24px" }) })] }));
27
+ return (_jsxs("div", { className: "bg-gray-400 dark:bg-gray-800 dark:text-white text-lg flex flex-row flex-wrap items-center p-1", children: [_jsx(EditorButton, { action: "toggleBold", isActive: editor.isActive('bold'), label: _jsx(FaBold, {}), disabled: true }), _jsx(EditorButton, { action: "toggleItalic", isActive: editor.isActive('italic'), label: _jsx(FaItalic, {}), disabled: true }), _jsx(EditorButton, { action: "toggleStrike", isActive: editor.isActive('strike'), label: _jsx(FaStrikethrough, {}), disabled: true }), _jsx(EditorButton, { action: "toggleCode", isActive: editor.isActive('code'), label: _jsx(FaCode, {}), disabled: true }), _jsx(EditorButton, { action: "setParagraph", isActive: editor.isActive('paragraph'), label: _jsx(FaParagraph, {}) }), _jsx(EditorButton, { action: "setHeading1", isActive: editor.isActive('heading', { level: 1 }), label: _jsx(LuHeading1, { size: '24px' }) }), _jsx(EditorButton, { action: "setHeading2", isActive: editor.isActive('heading', { level: 2 }), label: _jsx(LuHeading2, { size: '24px' }) }), _jsx(EditorButton, { action: "setHeading3", isActive: editor.isActive('heading', { level: 3 }), label: _jsx(LuHeading3, { size: '24px' }) }), _jsx(EditorButton, { action: "toggleBulletList", isActive: editor.isActive('bulletList'), label: _jsx(AiOutlineUnorderedList, { size: '24px' }) }), _jsx(EditorButton, { action: "toggleOrderedList", isActive: editor.isActive('orderedList'), label: _jsx(GoListOrdered, { size: '24px' }) }), _jsx(EditorButton, { action: "toggleCodeBlock", isActive: editor.isActive('codeBlock'), label: _jsx(PiCodeBlock, { size: '24px' }) }), _jsx(EditorButton, { action: "toggleBlockquote", isActive: editor.isActive('blockquote'), label: _jsx(TbBlockquote, { size: '24px' }) })] }));
28
28
  };
29
29
  const extensions = [
30
30
  StarterKit.configure({
31
31
  bulletList: {
32
32
  HTMLAttributes: {
33
- class: "list-disc list-inside dark:text-white p-1 mt-1 [&_li]:mb-1 [&_p]:inline m-0",
33
+ class: 'list-disc list-inside dark:text-white p-1 mt-1 [&_li]:mb-1 [&_p]:inline m-0',
34
34
  },
35
35
  },
36
36
  orderedList: {
37
37
  HTMLAttributes: {
38
- className: "list-decimal list-inside dark:text-white p-1 mt-1 [&_li]:mb-1 [&_p]:inline m-0",
38
+ className: 'list-decimal list-inside dark:text-white p-1 mt-1 [&_li]:mb-1 [&_p]:inline m-0',
39
39
  },
40
40
  },
41
41
  }),
42
42
  Markdown,
43
43
  ];
44
44
  export const MarkdownEditor = (props) => {
45
- return (_jsx("div", { className: "text-md border border-gray-800 overflow-hidden " + props.className, style: { borderWidth: props.editable ? 1 : 0 }, children: _jsx(EditorProvider, { slotBefore: props.editable ? _jsx(MenuBar, {}) : null, extensions: extensions, content: props.content, editable: props.editable, onUpdate: (e) => {
45
+ return (_jsx("div", { className: 'text-md border border-gray-800 overflow-hidden ' + props.className, style: { borderWidth: props.editable ? 1 : 0 }, children: _jsx(EditorProvider, { slotBefore: props.editable ? _jsx(MenuBar, {}) : null, extensions: extensions, content: props.content, editable: props.editable, onUpdate: (e) => {
46
46
  props.onUpdate && props.onUpdate(e.editor.storage.markdown.getMarkdown());
47
- } }, (props.editable ? "editable" : "readonly") + props.content) }));
47
+ } }, (props.editable ? 'editable' : 'readonly') + props.content) }));
48
48
  };
@@ -1,4 +1,4 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export const Spinner = ({ text, className, size = "30px" }) => {
3
- return (_jsxs("div", { className: "flex items-center space-x-2 " + className, children: [_jsxs("svg", { style: { width: size, height: size }, className: "animate-spin -ml-1 mr-3 h-5 w-5 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }), text && _jsx("span", { className: "", children: text })] }));
2
+ export const Spinner = ({ text, className, size = '30px' }) => {
3
+ return (_jsxs("div", { className: 'flex items-center space-x-2 ' + className, children: [_jsxs("svg", { style: { width: size, height: size }, className: "animate-spin -ml-1 mr-3 h-5 w-5 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }), text && _jsx("span", { className: "", children: text })] }));
4
4
  };
@@ -36,24 +36,23 @@ export function AssistantChat({ avatarImageUrl, voiceId, onComplete, autoStartCo
36
36
  }, [messages, isLoading]);
37
37
  const lastMessage = messages[messages.length - 1];
38
38
  useEffect(() => {
39
- console.log("lastMessage", lastMessage);
39
+ console.log('lastMessage', lastMessage);
40
40
  const toolInvocations = lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.toolCalls;
41
41
  if (toolInvocations && toolInvocations.length > 0) {
42
- console.log("toolInvocations", toolInvocations);
42
+ console.log('toolInvocations', toolInvocations);
43
43
  onComplete(toolInvocations[0].args);
44
44
  }
45
45
  }, [lastMessage]);
46
46
  if ((lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.toolCalls) && lastMessage.toolCalls.length > 0) {
47
- console.log("lastMessage test2", lastMessage);
47
+ console.log('lastMessage test2', lastMessage);
48
48
  const args = lastMessage.toolCalls[0].args;
49
- const success = args.explanationUnderstood === "TRUE" || args.studentKnowsTopic === "TRUE";
50
- return _jsxs("div", { className: "px-5 pt-5 overflow-y-auto text-center", style: { height: "478px" }, children: [_jsx("h1", { className: 'text-center mt-5 mb-5', children: success ? "Great job!" : "You failed" }), _jsx("p", { children: args.improvementHints })] });
49
+ const success = args.explanationUnderstood === 'TRUE' || args.studentKnowsTopic === 'TRUE';
50
+ return (_jsxs("div", { className: "px-5 pt-5 overflow-y-auto text-center", style: { height: '478px' }, children: [_jsx("h1", { className: "text-center mt-5 mb-5", children: success ? 'Great job!' : 'You failed' }), _jsx("p", { children: args.improvementHints })] }));
51
51
  }
52
- return (_jsxs("div", { children: [oralCommunication && _jsx(CircleAudioAvatar, { imageUrl: avatarImageUrl, className: 'mx-auto my-10' }), _jsx("div", { className: "w-full", children: lastAssistantMessage && _jsx("div", { className: "px-5 pt-5 overflow-y-auto remirror-theme", style: { height: "4k78px" }, children: _jsx(Markdown, { children: lastAssistantMessage }) }) }), _jsx(AudioInputField, { blockSubmission: isLoading, onSubmit: message => {
52
+ return (_jsxs("div", { children: [oralCommunication && _jsx(CircleAudioAvatar, { imageUrl: avatarImageUrl, className: "mx-auto my-10" }), _jsx("div", { className: "w-full", children: lastAssistantMessage && (_jsx("div", { className: "px-5 pt-5 overflow-y-auto remirror-theme", style: { height: '4k78px' }, children: _jsx(Markdown, { children: lastAssistantMessage }) })) }), _jsx(AudioInputField, { blockSubmission: isLoading, onSubmit: (message) => {
53
53
  append([{ role: 'user', content: message, id: messages.length.toString() }]);
54
- }, onAudioControl: voice => {
54
+ }, onAudioControl: (voice) => {
55
55
  setOralCommunication(voice);
56
56
  sender.setVolume(voice ? 1 : 0);
57
57
  } })] }));
58
58
  }
59
- ;
@@ -1,7 +1,7 @@
1
1
  import { Tool } from '../../fromRimori/PluginTypes';
2
2
  import { FirstMessages } from './utils';
3
3
  interface Props {
4
- voiceId: any;
4
+ voiceId: string;
5
5
  agentTools: Tool[];
6
6
  avatarImageUrl: string;
7
7
  circleSize?: string;
@@ -10,5 +10,5 @@ interface Props {
10
10
  autoStartConversation?: FirstMessages;
11
11
  className?: string;
12
12
  }
13
- export declare function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversation, children, isDarkTheme, circleSize, className }: Props): import("react/jsx-runtime").JSX.Element;
13
+ export declare function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversation, children, isDarkTheme, circleSize, className, }: Props): import("react/jsx-runtime").JSX.Element;
14
14
  export {};
@@ -6,14 +6,14 @@ import { CircleAudioAvatar } from './EmbeddedAssistent/CircleAudioAvatar';
6
6
  import { useChat } from '../../hooks/UseChatHook';
7
7
  import { useRimori } from '../../components';
8
8
  import { getFirstMessages } from './utils';
9
- export function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversation, children, isDarkTheme = false, circleSize = "300px", className }) {
9
+ export function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversation, children, isDarkTheme = false, circleSize = '300px', className, }) {
10
10
  const { ai, event } = useRimori();
11
11
  const [agentReplying, setAgentReplying] = useState(false);
12
12
  const [isProcessingMessage, setIsProcessingMessage] = useState(false);
13
13
  const sender = useMemo(() => new MessageSender(ai.getVoice, voiceId), [voiceId]);
14
14
  const { messages, append, isLoading, lastMessage, setMessages } = useChat(agentTools);
15
15
  useEffect(() => {
16
- console.log("messages", messages);
16
+ console.log('messages', messages);
17
17
  }, [messages]);
18
18
  useEffect(() => {
19
19
  if (!isLoading)
@@ -46,9 +46,14 @@ export function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversat
46
46
  }
47
47
  }
48
48
  }, [lastMessage, isLoading]);
49
- return (_jsxs("div", { className: `md:pb-8 ${className || ''}`, children: [_jsx(CircleAudioAvatar, { width: circleSize, className: 'mx-auto', imageUrl: avatarImageUrl, isDarkTheme: isDarkTheme }), children, _jsx(VoiceRecorder, { iconSize: '30', className: 'w-16 h-16 shadow-lg rounded-full bg-gray-400 dark:bg-gray-800', disabled: agentReplying, loading: isProcessingMessage, enablePushToTalk: true, onVoiceRecorded: (message) => {
49
+ return (_jsxs("div", { className: `md:pb-8 ${className || ''}`, children: [_jsx(CircleAudioAvatar, { width: circleSize, className: "mx-auto", imageUrl: avatarImageUrl, isDarkTheme: isDarkTheme }), children, _jsx(VoiceRecorder, { iconSize: "30", className: "w-16 h-16 shadow-lg rounded-full bg-gray-400 dark:bg-gray-800", disabled: agentReplying, loading: isProcessingMessage, enablePushToTalk: true, onVoiceRecorded: (message) => {
50
50
  setAgentReplying(true);
51
- append([{ role: 'user', content: "Message(" + Math.floor((messages.length + 1) / 2) + "): " + message, id: messages.length.toString() }]);
51
+ append([
52
+ {
53
+ role: 'user',
54
+ content: 'Message(' + Math.floor((messages.length + 1) / 2) + '): ' + message,
55
+ id: messages.length.toString(),
56
+ },
57
+ ]);
52
58
  }, onRecordingStatusChange: (running) => !running && setIsProcessingMessage(true) })] }));
53
59
  }
54
- ;
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { VoiceRecorder } from './VoiceRecoder';
4
- import { BiSolidRightArrow } from "react-icons/bi";
5
- import { HiMiniSpeakerXMark, HiMiniSpeakerWave } from "react-icons/hi2";
4
+ import { BiSolidRightArrow } from 'react-icons/bi';
5
+ import { HiMiniSpeakerXMark, HiMiniSpeakerWave } from 'react-icons/hi2';
6
6
  export function AudioInputField({ onSubmit, onAudioControl, blockSubmission = false }) {
7
7
  const [text, setText] = useState('');
8
8
  const [audioEnabled, setAudioEnabled] = useState(true);
@@ -27,12 +27,11 @@ export function AudioInputField({ onSubmit, onAudioControl, blockSubmission = fa
27
27
  handleSubmit();
28
28
  }
29
29
  };
30
- return (_jsxs("div", { className: "flex items-center bg-gray-600 pt-2 pb-2 p-2", children: [onAudioControl && _jsx("button", { onClick: () => {
30
+ return (_jsxs("div", { className: "flex items-center bg-gray-600 pt-2 pb-2 p-2", children: [onAudioControl && (_jsx("button", { onClick: () => {
31
31
  onAudioControl(!audioEnabled);
32
32
  setAudioEnabled(!audioEnabled);
33
- }, className: "cursor-default", children: audioEnabled ? _jsx(HiMiniSpeakerWave, { className: 'w-9 h-9 cursor-pointer' }) : _jsx(HiMiniSpeakerXMark, { className: 'w-9 h-9 cursor-pointer' }) }), _jsx(VoiceRecorder, { onRecordingStatusChange: () => { }, onVoiceRecorded: (m) => {
33
+ }, className: "cursor-default", children: audioEnabled ? (_jsx(HiMiniSpeakerWave, { className: "w-9 h-9 cursor-pointer" })) : (_jsx(HiMiniSpeakerXMark, { className: "w-9 h-9 cursor-pointer" })) })), _jsx(VoiceRecorder, { onRecordingStatusChange: () => { }, onVoiceRecorded: (m) => {
34
34
  console.log('onVoiceRecorded', m);
35
35
  handleSubmit(m);
36
- } }), _jsx("textarea", { value: text, onChange: (e) => setText(e.target.value), onKeyDown: handleKeyDown, className: "flex-1 border-none rounded-lg p-2 text-gray-800 focus::outline-none", placeholder: 'Type a message...', disabled: blockSubmission }), _jsx("button", { onClick: () => handleSubmit(), className: "cursor-default", disabled: blockSubmission, children: _jsx(BiSolidRightArrow, { className: 'w-9 h-10 cursor-pointer' }) })] }));
36
+ } }), _jsx("textarea", { value: text, onChange: (e) => setText(e.target.value), onKeyDown: handleKeyDown, className: "flex-1 border-none rounded-lg p-2 text-gray-800 focus::outline-none", placeholder: "Type a message...", disabled: blockSubmission }), _jsx("button", { onClick: () => handleSubmit(), className: "cursor-default", disabled: blockSubmission, children: _jsx(BiSolidRightArrow, { className: "w-9 h-10 cursor-pointer" }) })] }));
37
37
  }
38
- ;
@@ -4,5 +4,5 @@ interface CircleAudioAvatarProps {
4
4
  className?: string;
5
5
  isDarkTheme?: boolean;
6
6
  }
7
- export declare function CircleAudioAvatar({ imageUrl, className, isDarkTheme, width }: CircleAudioAvatarProps): import("react/jsx-runtime").JSX.Element;
7
+ export declare function CircleAudioAvatar({ imageUrl, className, isDarkTheme, width, }: CircleAudioAvatarProps): import("react/jsx-runtime").JSX.Element;
8
8
  export {};
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useRef } from 'react';
3
3
  import { EventBus } from '../../../fromRimori/EventBus';
4
- export function CircleAudioAvatar({ imageUrl, className, isDarkTheme = false, width = "150px" }) {
4
+ export function CircleAudioAvatar({ imageUrl, className, isDarkTheme = false, width = '150px', }) {
5
5
  const canvasRef = useRef(null);
6
6
  const currentLoudnessRef = useRef(0);
7
7
  const targetLoudnessRef = useRef(0);
@@ -77,4 +77,3 @@ export function CircleAudioAvatar({ imageUrl, className, isDarkTheme = false, wi
77
77
  };
78
78
  return _jsx("canvas", { ref: canvasRef, className: className, width: 500, height: 500, style: { width } });
79
79
  }
80
- ;
@@ -4,9 +4,8 @@ export declare class MessageSender {
4
4
  private fetchedSentences;
5
5
  private lastLoading;
6
6
  private voice;
7
- private model;
8
7
  private voiceBackend;
9
- constructor(voiceBackend: VoiceBackend, voice?: string, model?: string);
8
+ constructor(voiceBackend: VoiceBackend, voice: string);
10
9
  private getCompletedSentences;
11
10
  handleNewText(currentText: string | undefined, isLoading: boolean): Promise<void>;
12
11
  private generateSpeech;
@@ -9,13 +9,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { ChunkedAudioPlayer } from './Player';
11
11
  export class MessageSender {
12
- constructor(voiceBackend, voice = 'alloy', model = 'openai') {
12
+ constructor(voiceBackend, voice) {
13
13
  this.player = new ChunkedAudioPlayer();
14
14
  this.fetchedSentences = new Set();
15
15
  this.lastLoading = false;
16
+ if ((voice === null || voice === void 0 ? void 0 : voice.split('_').length) !== 2) {
17
+ throw new Error("Invalid voice id format '" + voice + "'. Voice id needs to look like <provider>_<voice_id>");
18
+ }
16
19
  this.voiceBackend = voiceBackend;
17
20
  this.voice = voice;
18
- this.model = model;
19
21
  }
20
22
  getCompletedSentences(currentText, isLoading) {
21
23
  // Split the text based on the following characters: .,?!
@@ -12,7 +12,7 @@ import { useRimori } from '../../../components';
12
12
  import { FaMicrophone, FaSpinner } from 'react-icons/fa6';
13
13
  import { AudioController } from '../../../plugin/AudioController';
14
14
  import { useState, useRef, forwardRef, useImperativeHandle, useEffect } from 'react';
15
- export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className, disabled, loading, onRecordingStatusChange, enablePushToTalk = false }, ref) => {
15
+ export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className, disabled, loading, onRecordingStatusChange, enablePushToTalk = false, }, ref) => {
16
16
  const [isRecording, setIsRecording] = useState(false);
17
17
  const [internalIsProcessing, setInternalIsProcessing] = useState(false);
18
18
  const audioControllerRef = useRef(null);
@@ -91,6 +91,5 @@ export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className,
91
91
  window.removeEventListener('keyup', handleKeyUp);
92
92
  };
93
93
  }, [enablePushToTalk]);
94
- return (_jsx("button", { className: "flex flex-row justify-center items-center rounded-full mx-auto disabled:opacity-50 " + className, onClick: isRecording ? stopRecording : startRecording, disabled: disabled || loading || internalIsProcessing, children: loading || internalIsProcessing ? _jsx(FaSpinner, { className: "animate-spin" }) :
95
- _jsx(FaMicrophone, { size: iconSize, className: (isRecording ? "text-red-600" : "") }) }));
94
+ return (_jsx("button", { className: 'flex flex-row justify-center items-center rounded-full mx-auto disabled:opacity-50 ' + className, onClick: isRecording ? stopRecording : startRecording, disabled: disabled || loading || internalIsProcessing, children: loading || internalIsProcessing ? (_jsx(FaSpinner, { className: "animate-spin" })) : (_jsx(FaMicrophone, { size: iconSize, className: isRecording ? 'text-red-600' : '' })) }));
96
95
  });
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { useState, useEffect } from 'react';
12
- import { FaPlayCircle, FaStopCircle } from "react-icons/fa";
13
- import { useRimori } from "../../providers/PluginProvider";
12
+ import { FaPlayCircle, FaStopCircle } from 'react-icons/fa';
13
+ import { useRimori } from '../../providers/PluginProvider';
14
14
  import { Spinner } from '../Spinner';
15
15
  import { EventBus } from '../../fromRimori/EventBus';
16
16
  export const AudioPlayOptions = [0.8, 0.9, 1.0, 1.1, 1.2, 1.5];
@@ -35,7 +35,7 @@ export const AudioPlayer = ({ text, voice, language, hide, playListenerEvent, in
35
35
  // Function to generate audio from text using API
36
36
  const generateAudio = () => __awaiter(void 0, void 0, void 0, function* () {
37
37
  setIsLoading(true);
38
- const blob = yield ai.getVoice(text, voice || (language ? "aws_default" : "openai_alloy"), 1, language);
38
+ const blob = yield ai.getVoice(text, voice || (language ? 'aws_default' : 'openai_alloy'), 1, language);
39
39
  setAudioUrl(URL.createObjectURL(blob));
40
40
  setIsLoading(false);
41
41
  });
@@ -45,13 +45,16 @@ export const AudioPlayer = ({ text, voice, language, hide, playListenerEvent, in
45
45
  return;
46
46
  const audio = new Audio(audioUrl);
47
47
  audio.playbackRate = speed;
48
- audio.play().then(() => {
48
+ audio
49
+ .play()
50
+ .then(() => {
49
51
  audio.onended = () => {
50
52
  setIsPlaying(false);
51
53
  isFetchingAudio = false;
52
54
  };
53
- }).catch(e => {
54
- console.warn("Error playing audio:", e);
55
+ })
56
+ .catch((e) => {
57
+ console.warn('Error playing audio:', e);
55
58
  setIsPlaying(false);
56
59
  });
57
60
  return () => {
@@ -73,5 +76,5 @@ export const AudioPlayer = ({ text, voice, language, hide, playListenerEvent, in
73
76
  // console.log("playOnMount", playOnMount);
74
77
  togglePlayback();
75
78
  }, [playOnMount]);
76
- return (_jsx("div", { className: "group relative", children: _jsxs("div", { className: 'flex flex-row items-end', children: [!hide && _jsx("button", { className: "text-gray-500", onClick: togglePlayback, disabled: isLoading, children: isLoading ? _jsx(Spinner, {}) : isPlaying ? _jsx(FaStopCircle, { size: "25px" }) : _jsx(FaPlayCircle, { size: "25px" }) }), enableSpeedAdjustment && (_jsxs("div", { className: "ml-1 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-row text-sm text-gray-500", children: [_jsx("span", { className: 'pr-1', children: "Speed: " }), _jsx("select", { value: speed, className: 'appearance-none cursor-pointer pr-0 p-0 rounded shadow leading-tight focus:outline-none focus:bg-gray-800 focus:ring bg-transparent border-0', onChange: (e) => setSpeed(parseFloat(e.target.value)), disabled: isLoading, children: AudioPlayOptions.map((s) => (_jsx("option", { value: s, children: s }, s))) })] }))] }) }));
79
+ return (_jsx("div", { className: "group relative", children: _jsxs("div", { className: "flex flex-row items-end", children: [!hide && (_jsx("button", { className: "text-gray-500", onClick: togglePlayback, disabled: isLoading, children: isLoading ? _jsx(Spinner, {}) : isPlaying ? _jsx(FaStopCircle, { size: '25px' }) : _jsx(FaPlayCircle, { size: '25px' }) })), enableSpeedAdjustment && (_jsxs("div", { className: "ml-1 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-row text-sm text-gray-500", children: [_jsx("span", { className: "pr-1", children: "Speed: " }), _jsx("select", { value: speed, className: "appearance-none cursor-pointer pr-0 p-0 rounded shadow leading-tight focus:outline-none focus:bg-gray-800 focus:ring bg-transparent border-0", onChange: (e) => setSpeed(parseFloat(e.target.value)), disabled: isLoading, children: AudioPlayOptions.map((s) => (_jsx("option", { value: s, children: s }, s))) })] }))] }) }));
77
80
  };