@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
@@ -1,18 +1,18 @@
1
1
  import React, { useState, useEffect } from 'react';
2
- import { FaPlayCircle, FaStopCircle } from "react-icons/fa";
3
- import { useRimori } from "../../providers/PluginProvider";
2
+ import { FaPlayCircle, FaStopCircle } from 'react-icons/fa';
3
+ import { useRimori } from '../../providers/PluginProvider';
4
4
  import { Spinner } from '../Spinner';
5
5
  import { EventBus } from '../../fromRimori/EventBus';
6
6
 
7
7
  type AudioPlayerProps = {
8
- text: string;
9
- voice?: string;
10
- language?: string;
11
- hide?: boolean;
12
- playOnMount?: boolean;
13
- initialSpeed?: number;
14
- enableSpeedAdjustment?: boolean;
15
- playListenerEvent?: string;
8
+ text: string;
9
+ voice?: string;
10
+ language?: string;
11
+ hide?: boolean;
12
+ playOnMount?: boolean;
13
+ initialSpeed?: number;
14
+ enableSpeedAdjustment?: boolean;
15
+ playListenerEvent?: string;
16
16
  };
17
17
 
18
18
  export const AudioPlayOptions = [0.8, 0.9, 1.0, 1.1, 1.2, 1.5];
@@ -21,98 +21,106 @@ export type AudioPlayOptionType = 0.8 | 0.9 | 1.0 | 1.1 | 1.2 | 1.5;
21
21
  let isFetchingAudio = false;
22
22
 
23
23
  export const AudioPlayer: React.FC<AudioPlayerProps> = ({
24
- text,
25
- voice,
26
- language,
27
- hide,
28
- playListenerEvent,
29
- initialSpeed = 1.0,
30
- playOnMount = false,
31
- enableSpeedAdjustment = false,
24
+ text,
25
+ voice,
26
+ language,
27
+ hide,
28
+ playListenerEvent,
29
+ initialSpeed = 1.0,
30
+ playOnMount = false,
31
+ enableSpeedAdjustment = false,
32
32
  }) => {
33
- const [audioUrl, setAudioUrl] = useState<string | null>(null);
34
- const [speed, setSpeed] = useState(initialSpeed);
35
- const [isPlaying, setIsPlaying] = useState(false);
36
- const [isLoading, setIsLoading] = useState(false);
37
- const { ai } = useRimori();
33
+ const [audioUrl, setAudioUrl] = useState<string | null>(null);
34
+ const [speed, setSpeed] = useState(initialSpeed);
35
+ const [isPlaying, setIsPlaying] = useState(false);
36
+ const [isLoading, setIsLoading] = useState(false);
37
+ const { ai } = useRimori();
38
38
 
39
- useEffect(() => {
40
- if (!playListenerEvent) return;
41
- EventBus.on(playListenerEvent, () => togglePlayback());
42
- }, [playListenerEvent]);
39
+ useEffect(() => {
40
+ if (!playListenerEvent) return;
41
+ EventBus.on(playListenerEvent, () => togglePlayback());
42
+ }, [playListenerEvent]);
43
43
 
44
- useEffect(() => {
45
- audioUrl && setAudioUrl(null);
46
- return () => {
47
- audioUrl && URL.revokeObjectURL(audioUrl);
48
- }
49
- }, [text]);
50
-
51
- // Function to generate audio from text using API
52
- const generateAudio = async () => {
53
- setIsLoading(true);
54
-
55
- const blob = await ai.getVoice(text, voice || (language ? "aws_default" : "openai_alloy"), 1, language);
56
- setAudioUrl(URL.createObjectURL(blob));
57
- setIsLoading(false);
44
+ useEffect(() => {
45
+ audioUrl && setAudioUrl(null);
46
+ return () => {
47
+ audioUrl && URL.revokeObjectURL(audioUrl);
58
48
  };
49
+ }, [text]);
59
50
 
60
- // Effect to play audio when audioUrl changes and play state is true
61
- useEffect(() => {
62
- if (!audioUrl || !isPlaying) return;
63
- const audio = new Audio(audioUrl);
64
- audio.playbackRate = speed;
65
- audio.play().then(() => {
66
- audio.onended = () => {
67
- setIsPlaying(false);
68
- isFetchingAudio = false;
69
- };
70
- }).catch(e => {
71
- console.warn("Error playing audio:", e);
72
- setIsPlaying(false);
73
- });
51
+ // Function to generate audio from text using API
52
+ const generateAudio = async () => {
53
+ setIsLoading(true);
74
54
 
75
- return () => {
76
- audio.pause();
55
+ const blob = await ai.getVoice(text, voice || (language ? 'aws_default' : 'openai_alloy'), 1, language);
56
+ setAudioUrl(URL.createObjectURL(blob));
57
+ setIsLoading(false);
58
+ };
59
+
60
+ // Effect to play audio when audioUrl changes and play state is true
61
+ useEffect(() => {
62
+ if (!audioUrl || !isPlaying) return;
63
+ const audio = new Audio(audioUrl);
64
+ audio.playbackRate = speed;
65
+ audio
66
+ .play()
67
+ .then(() => {
68
+ audio.onended = () => {
69
+ setIsPlaying(false);
70
+ isFetchingAudio = false;
77
71
  };
78
- }, [audioUrl, isPlaying, speed]);
72
+ })
73
+ .catch((e) => {
74
+ console.warn('Error playing audio:', e);
75
+ setIsPlaying(false);
76
+ });
79
77
 
80
- const togglePlayback = () => {
81
- if (!isPlaying && !audioUrl) {
82
- generateAudio().then(() => setIsPlaying(true));
83
- } else {
84
- setIsPlaying((prev) => !prev);
85
- }
78
+ return () => {
79
+ audio.pause();
86
80
  };
81
+ }, [audioUrl, isPlaying, speed]);
82
+
83
+ const togglePlayback = () => {
84
+ if (!isPlaying && !audioUrl) {
85
+ generateAudio().then(() => setIsPlaying(true));
86
+ } else {
87
+ setIsPlaying((prev) => !prev);
88
+ }
89
+ };
87
90
 
88
- useEffect(() => {
89
- if (!playOnMount || isFetchingAudio) return;
90
- isFetchingAudio = true;
91
- // console.log("playOnMount", playOnMount);
92
- togglePlayback();
93
- }, [playOnMount]);
91
+ useEffect(() => {
92
+ if (!playOnMount || isFetchingAudio) return;
93
+ isFetchingAudio = true;
94
+ // console.log("playOnMount", playOnMount);
95
+ togglePlayback();
96
+ }, [playOnMount]);
94
97
 
95
- return (
96
- <div className="group relative">
97
- <div className='flex flex-row items-end'>
98
- {!hide && <button className="text-gray-500" onClick={togglePlayback} disabled={isLoading}>
99
- {isLoading ? <Spinner /> : isPlaying ? <FaStopCircle size={"25px"} /> : <FaPlayCircle size={"25px"} />}
100
- </button>}
101
- {enableSpeedAdjustment && (
102
- <div className="ml-1 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-row text-sm text-gray-500">
103
- <span className='pr-1'>Speed: </span>
104
- <select
105
- value={speed}
106
- 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'
107
- onChange={(e) => setSpeed(parseFloat(e.target.value))}
108
- disabled={isLoading}>
109
- {AudioPlayOptions.map((s) => (
110
- <option key={s} value={s}>{s}</option>
111
- ))}
112
- </select>
113
- </div>
114
- )}
115
- </div>
116
- </div>
117
- );
98
+ return (
99
+ <div className="group relative">
100
+ <div className="flex flex-row items-end">
101
+ {!hide && (
102
+ <button className="text-gray-500" onClick={togglePlayback} disabled={isLoading}>
103
+ {isLoading ? <Spinner /> : isPlaying ? <FaStopCircle size={'25px'} /> : <FaPlayCircle size={'25px'} />}
104
+ </button>
105
+ )}
106
+ {enableSpeedAdjustment && (
107
+ <div className="ml-1 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-row text-sm text-gray-500">
108
+ <span className="pr-1">Speed: </span>
109
+ <select
110
+ value={speed}
111
+ 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"
112
+ onChange={(e) => setSpeed(parseFloat(e.target.value))}
113
+ disabled={isLoading}
114
+ >
115
+ {AudioPlayOptions.map((s) => (
116
+ <option key={s} value={s}>
117
+ {s}
118
+ </option>
119
+ ))}
120
+ </select>
121
+ </div>
122
+ )}
123
+ </div>
124
+ </div>
125
+ );
118
126
  };
@@ -1,12 +1,12 @@
1
- import React, { useState, useEffect, useRef } from "react";
2
- import { EventBus } from "../../fromRimori/EventBus";
3
- import { RimoriClient } from "../../plugin/RimoriClient";
4
- import { MenuEntry } from "../../fromRimori/PluginTypes";
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { EventBus } from '../../fromRimori/EventBus';
3
+ import { RimoriClient } from '../../plugin/RimoriClient';
4
+ import { MenuEntry } from '../../fromRimori/PluginTypes';
5
5
 
6
6
  export interface Position {
7
- x: number,
8
- y: number,
9
- text?: string
7
+ x: number;
8
+ y: number;
9
+ text?: string;
10
10
  }
11
11
 
12
12
  const ContextMenu = ({ client }: { client: RimoriClient }) => {
@@ -35,7 +35,7 @@ const ContextMenu = ({ client }: { client: RimoriClient }) => {
35
35
  const rect = range.getBoundingClientRect();
36
36
 
37
37
  // Center horizontally over the selected text, accounting for menu width
38
- const centerX = rect.left + (rect.width / 2) - (menuWidth / 2);
38
+ const centerX = rect.left + rect.width / 2 - menuWidth / 2;
39
39
 
40
40
  // Position 12px below where the text ends vertically
41
41
  const textEndY = rect.bottom + 12;
@@ -44,12 +44,14 @@ const ContextMenu = ({ client }: { client: RimoriClient }) => {
44
44
  };
45
45
 
46
46
  useEffect(() => {
47
- const actions = client.plugin.getPluginInfo().installedPlugins.flatMap(p => p.context_menu_actions).filter(Boolean);
47
+ const actions = client.plugin
48
+ .getPluginInfo()
49
+ .installedPlugins.flatMap((p) => p.context_menu_actions)
50
+ .filter(Boolean);
48
51
  setActions(actions);
49
52
  setOpenOnTextSelect(client.plugin.getUserInfo().context_menu_on_select);
50
53
 
51
-
52
- EventBus.on<{ actions: MenuEntry[] }>("global.contextMenu.createActions", ({ data }) => {
54
+ EventBus.on<{ actions: MenuEntry[] }>('global.contextMenu.createActions', ({ data }) => {
53
55
  setActions([...data.actions, ...actions]);
54
56
  });
55
57
  }, []);
@@ -84,10 +86,9 @@ const ContextMenu = ({ client }: { client: RimoriClient }) => {
84
86
 
85
87
  // Prevent context menu on textarea or text input selection
86
88
  const target = e.target as HTMLElement;
87
- const isTextInput = target && (
88
- (target.tagName === 'TEXTAREA') ||
89
- (target.tagName === 'INPUT' && (target as HTMLInputElement).type === 'text')
90
- );
89
+ const isTextInput =
90
+ target &&
91
+ (target.tagName === 'TEXTAREA' || (target.tagName === 'INPUT' && (target as HTMLInputElement).type === 'text'));
91
92
  if (isTextInput) {
92
93
  setIsOpen(false);
93
94
  return;
@@ -123,16 +124,16 @@ const ContextMenu = ({ client }: { client: RimoriClient }) => {
123
124
  }
124
125
  };
125
126
 
126
- document.addEventListener("mouseup", handleMouseUp);
127
- window.addEventListener("mousemove", handleMouseMove);
128
- document.addEventListener("contextmenu", handleMouseUp);
129
- document.addEventListener("selectionchange", handleSelectionChange);
127
+ document.addEventListener('mouseup', handleMouseUp);
128
+ window.addEventListener('mousemove', handleMouseMove);
129
+ document.addEventListener('contextmenu', handleMouseUp);
130
+ document.addEventListener('selectionchange', handleSelectionChange);
130
131
 
131
132
  return () => {
132
- document.removeEventListener("mouseup", handleMouseUp);
133
- window.removeEventListener("mousemove", handleMouseMove);
134
- document.removeEventListener("contextmenu", handleMouseUp);
135
- document.removeEventListener("selectionchange", handleSelectionChange);
133
+ document.removeEventListener('mouseup', handleMouseUp);
134
+ window.removeEventListener('mousemove', handleMouseMove);
135
+ document.removeEventListener('contextmenu', handleMouseUp);
136
+ document.removeEventListener('selectionchange', handleSelectionChange);
136
137
  };
137
138
  }, [openOnTextSelect, isOpen, position.text]);
138
139
 
@@ -144,24 +145,35 @@ const ContextMenu = ({ client }: { client: RimoriClient }) => {
144
145
  <div
145
146
  ref={menuRef}
146
147
  className="fixed bg-gray-400 dark:bg-gray-700 shadow-lg border border-gray-400 rounded-md overflow-hidden dark:text-white z-50"
147
- style={{ top: position.y, left: position.x }}>
148
+ style={{ top: position.y, left: position.x }}
149
+ >
148
150
  {actions.map((action, index) => (
149
- <MenuEntryItem key={index} icon={action.icon} text={action.text} onClick={() => {
150
- setIsOpen(false);
151
- window.getSelection()?.removeAllRanges();
152
- client.event.emitSidebarAction(action.plugin_id, action.action_key, position.text);
153
- }} />
151
+ <MenuEntryItem
152
+ key={index}
153
+ icon={action.icon}
154
+ text={action.text}
155
+ onClick={() => {
156
+ setIsOpen(false);
157
+ window.getSelection()?.removeAllRanges();
158
+ client.event.emitSidebarAction(action.plugin_id, action.action_key, position.text);
159
+ }}
160
+ />
154
161
  ))}
155
162
  </div>
156
163
  );
157
164
  };
158
165
 
159
- function MenuEntryItem(props: { icon: React.ReactNode, text: string, onClick: () => void }) {
160
- return <button onClick={props.onClick} className="px-4 py-2 text-left hover:bg-gray-500 dark:hover:bg-gray-600 w-full flex flex-row">
161
- <span className="flex-grow">{props.icon}</span>
162
- <span className="flex-grow">{props.text}</span>
163
- {/* <span className="text-sm">Ctrl+Shift+xxxx</span> */}
164
- </button>
166
+ function MenuEntryItem(props: { icon: React.ReactNode; text: string; onClick: () => void }) {
167
+ return (
168
+ <button
169
+ onClick={props.onClick}
170
+ className="px-4 py-2 text-left hover:bg-gray-500 dark:hover:bg-gray-600 w-full flex flex-row"
171
+ >
172
+ <span className="flex-grow">{props.icon}</span>
173
+ <span className="flex-grow">{props.text}</span>
174
+ {/* <span className="text-sm">Ctrl+Shift+xxxx</span> */}
175
+ </button>
176
+ );
165
177
  }
166
178
 
167
179
  export default ContextMenu;
package/src/components.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  // React components and hooks exports
2
- export * from "./components/ai/Assistant";
3
- export * from "./components/ai/Avatar";
4
- export * from "./components/ai/EmbeddedAssistent/VoiceRecoder";
5
- export * from "./components/audio/Playbutton";
6
- export * from "./components/CRUDModal";
7
- export * from "./components/MarkdownEditor";
8
- export * from "./components/Spinner";
9
- export * from "./hooks/UseChatHook";
10
- export * from "./plugin/ThemeSetter";
11
- export * from "./providers/PluginProvider";
2
+ export * from './components/ai/Assistant';
3
+ export * from './components/ai/Avatar';
4
+ export * from './components/ai/EmbeddedAssistent/VoiceRecoder';
5
+ export * from './components/audio/Playbutton';
6
+ export * from './components/CRUDModal';
7
+ export * from './components/MarkdownEditor';
8
+ export * from './components/Spinner';
9
+ export * from './hooks/UseChatHook';
10
+ export * from './plugin/ThemeSetter';
11
+ export * from './providers/PluginProvider';
@@ -1,4 +1,4 @@
1
- import { Tool } from "../../fromRimori/PluginTypes";
1
+ import { Tool } from '../../fromRimori/PluginTypes';
2
2
 
3
3
  export interface ToolInvocation {
4
4
  toolCallId: string;
@@ -8,7 +8,7 @@ export interface ToolInvocation {
8
8
 
9
9
  export interface Message {
10
10
  id?: string;
11
- role: "user" | "assistant" | "system"
11
+ role: 'user' | 'assistant' | 'system';
12
12
  content: string;
13
13
  toolCalls?: ToolInvocation[];
14
14
  }
@@ -17,15 +17,26 @@ export async function generateText(backendUrl: string, messages: Message[], tool
17
17
  const response = await fetch(`${backendUrl}/ai/llm`, {
18
18
  method: 'POST',
19
19
  body: JSON.stringify({ messages, tools }),
20
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
20
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
21
21
  });
22
22
 
23
23
  return await response.json();
24
24
  }
25
25
 
26
- export type OnLLMResponse = (id: string, response: string, finished: boolean, toolInvocations?: ToolInvocation[]) => void;
27
-
28
- export async function streamChatGPT(backendUrl: string, messages: Message[], tools: Tool[], onResponse: OnLLMResponse, token: string) {
26
+ export type OnLLMResponse = (
27
+ id: string,
28
+ response: string,
29
+ finished: boolean,
30
+ toolInvocations?: ToolInvocation[],
31
+ ) => void;
32
+
33
+ export async function streamChatGPT(
34
+ backendUrl: string,
35
+ messages: Message[],
36
+ tools: Tool[],
37
+ onResponse: OnLLMResponse,
38
+ token: string,
39
+ ) {
29
40
  const messageId = Math.random().toString(36).substring(3);
30
41
  let currentMessages: Message[] = [...messages];
31
42
 
@@ -33,7 +44,7 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
33
44
  messageId,
34
45
  messageCount: messages.length,
35
46
  toolCount: tools.length,
36
- backendUrl
47
+ backendUrl,
37
48
  });
38
49
 
39
50
  while (true) {
@@ -43,7 +54,7 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
43
54
  const response = await fetch(`${backendUrl}/ai/llm`, {
44
55
  method: 'POST',
45
56
  body: JSON.stringify({ messages: messagesForApi, tools, stream: true }),
46
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
57
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
47
58
  });
48
59
 
49
60
  if (!response.ok) {
@@ -58,12 +69,12 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
58
69
  const reader = response.body.getReader();
59
70
  const decoder = new TextDecoder('utf-8');
60
71
 
61
- let content = "";
72
+ let content = '';
62
73
  let done = false;
63
- let toolInvocations: { toolCallId: string, toolName: string, args: any }[] = [];
64
- let currentTextId = "";
74
+ let toolInvocations: { toolCallId: string; toolName: string; args: any }[] = [];
75
+ let currentTextId = '';
65
76
  let isToolCallMode = false;
66
- let buffer = ""; // Buffer for incomplete chunks
77
+ let buffer = ''; // Buffer for incomplete chunks
67
78
 
68
79
  while (!done) {
69
80
  const { value, done: readerDone } = await reader.read();
@@ -77,7 +88,7 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
77
88
 
78
89
  // Keep the last line in buffer if it's incomplete
79
90
  if (lines.length > 1) {
80
- buffer = lines.pop() || "";
91
+ buffer = lines.pop() || '';
81
92
  }
82
93
 
83
94
  for (const line of lines) {
@@ -162,7 +173,7 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
162
173
  toolInvocations.push({
163
174
  toolCallId: data.toolCallId,
164
175
  toolName: data.toolName,
165
- args: data.args || data.input
176
+ args: data.args || data.input,
166
177
  });
167
178
  }
168
179
  break;
@@ -225,7 +236,7 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
225
236
  if (content || toolInvocations.length > 0) {
226
237
  currentMessages.push({
227
238
  id: messageId,
228
- role: "assistant",
239
+ role: 'assistant',
229
240
  content: content,
230
241
  toolCalls: toolInvocations.length > 0 ? toolInvocations : undefined,
231
242
  });
@@ -237,20 +248,20 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
237
248
 
238
249
  const toolResults: Message[] = [];
239
250
  for (const toolInvocation of toolInvocations) {
240
- const tool = tools.find(t => t.name === toolInvocation.toolName);
251
+ const tool = tools.find((t) => t.name === toolInvocation.toolName);
241
252
  if (tool && tool.execute) {
242
253
  try {
243
254
  const result = await tool.execute(toolInvocation.args);
244
255
  toolResults.push({
245
256
  id: Math.random().toString(36).substring(3),
246
- role: "user",
257
+ role: 'user',
247
258
  content: `Tool '${toolInvocation.toolName}' returned: ${JSON.stringify(result)}`,
248
259
  });
249
260
  } catch (error) {
250
261
  console.error(`Error executing tool ${toolInvocation.toolName}:`, error);
251
262
  toolResults.push({
252
263
  id: Math.random().toString(36).substring(3),
253
- role: "user",
264
+ role: 'user',
254
265
  content: `Tool '${toolInvocation.toolName}' failed with error: ${error}`,
255
266
  });
256
267
  }
@@ -275,7 +286,6 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
275
286
 
276
287
  onResponse(messageId, content, true, toolInvocations);
277
288
  return;
278
-
279
289
  } catch (error) {
280
290
  console.error('Error in streamChatGPT:', error);
281
291
  onResponse(messageId, `Error: ${error instanceof Error ? error.message : String(error)}`, true, []);
@@ -1,5 +1,5 @@
1
- import { SupabaseClient } from "@supabase/supabase-js";
2
- import { PluginController } from "../../plugin/PluginController";
1
+ import { SupabaseClient } from '@supabase/supabase-js';
2
+ import { PluginController } from '../../plugin/PluginController';
3
3
 
4
4
  export type TriggerAction = { action_key: string } & Record<string, string | number | boolean>;
5
5
 
@@ -57,17 +57,14 @@ export class ExerciseController {
57
57
  */
58
58
  public async addExercise(params: CreateExerciseParams): Promise<Exercise> {
59
59
  const token = await this.pluginController.getToken();
60
- const response = await fetch(
61
- `${this.pluginController.getBackendUrl()}/exercises`,
62
- {
63
- method: 'POST',
64
- headers: {
65
- 'Content-Type': 'application/json',
66
- 'Authorization': `Bearer ${token}`,
67
- },
68
- body: JSON.stringify(params),
69
- }
70
- );
60
+ const response = await fetch(`${this.pluginController.getBackendUrl()}/exercises`, {
61
+ method: 'POST',
62
+ headers: {
63
+ 'Content-Type': 'application/json',
64
+ Authorization: `Bearer ${token}`,
65
+ },
66
+ body: JSON.stringify(params),
67
+ });
71
68
 
72
69
  if (!response.ok) {
73
70
  const errorText = await response.text();
@@ -84,15 +81,12 @@ export class ExerciseController {
84
81
  */
85
82
  public async deleteExercise(id: string): Promise<{ success: boolean; message: string }> {
86
83
  const token = await this.pluginController.getToken();
87
- const response = await fetch(
88
- `${this.pluginController.getBackendUrl()}/exercises/${id}`,
89
- {
90
- method: 'DELETE',
91
- headers: {
92
- 'Authorization': `Bearer ${token}`,
93
- },
94
- }
95
- );
84
+ const response = await fetch(`${this.pluginController.getBackendUrl()}/exercises/${id}`, {
85
+ method: 'DELETE',
86
+ headers: {
87
+ Authorization: `Bearer ${token}`,
88
+ },
89
+ });
96
90
 
97
91
  if (!response.ok) {
98
92
  const errorText = await response.text();
@@ -102,4 +96,3 @@ export class ExerciseController {
102
96
  return await response.json();
103
97
  }
104
98
  }
105
-
@@ -3,8 +3,8 @@ type PrimitiveType = 'string' | 'number' | 'boolean';
3
3
  // This is the type that can appear in the `type` property
4
4
  type ObjectToolParameterType =
5
5
  | PrimitiveType
6
- | { [key: string]: ObjectToolParameter } // for nested objects
7
- | [{ [key: string]: ObjectToolParameter }]; // for arrays of objects (notice the tuple type)
6
+ | { [key: string]: ObjectToolParameter } // for nested objects
7
+ | [{ [key: string]: ObjectToolParameter }]; // for arrays of objects (notice the tuple type)
8
8
 
9
9
  interface ObjectToolParameter {
10
10
  type: ObjectToolParameterType;
@@ -15,10 +15,10 @@ interface ObjectToolParameter {
15
15
 
16
16
  /**
17
17
  * The tools that the AI can use.
18
- *
18
+ *
19
19
  * The key is the name of the tool.
20
20
  * The value is the parameter of the tool.
21
- *
21
+ *
22
22
  */
23
23
  export type ObjectTool = {
24
24
  [key: string]: ObjectToolParameter;
@@ -50,14 +50,19 @@ export async function generateObject(backendUrl: string, request: ObjectRequest,
50
50
  behaviour: request.behaviour,
51
51
  instructions: request.instructions,
52
52
  }),
53
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
54
- }).then(response => response.json());
53
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
54
+ }).then((response) => response.json());
55
55
  }
56
56
 
57
57
  // TODO adjust stream to work with object
58
58
  export type OnLLMResponse = (id: string, response: string, finished: boolean, toolInvocations?: any[]) => void;
59
59
 
60
- export async function streamObject(backendUrl: string, request: ObjectRequest, onResponse: OnLLMResponse, token: string) {
60
+ export async function streamObject(
61
+ backendUrl: string,
62
+ request: ObjectRequest,
63
+ onResponse: OnLLMResponse,
64
+ token: string,
65
+ ) {
61
66
  const messageId = Math.random().toString(36).substring(3);
62
67
  const response = await fetch(`${backendUrl}/ai/llm-object`, {
63
68
  method: 'POST',
@@ -67,7 +72,7 @@ export async function streamObject(backendUrl: string, request: ObjectRequest, o
67
72
  systemInstructions: request.behaviour,
68
73
  secondaryInstructions: request.instructions,
69
74
  }),
70
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
75
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
71
76
  });
72
77
 
73
78
  if (!response.body) {
@@ -78,7 +83,7 @@ export async function streamObject(backendUrl: string, request: ObjectRequest, o
78
83
  const reader = response.body.getReader();
79
84
  const decoder = new TextDecoder('utf-8');
80
85
 
81
- let content = "";
86
+ let content = '';
82
87
  let done = false;
83
88
  let toolInvocations: any[] = [];
84
89
  while (!done) {
@@ -86,7 +91,7 @@ export async function streamObject(backendUrl: string, request: ObjectRequest, o
86
91
 
87
92
  if (value) {
88
93
  const chunk = decoder.decode(value, { stream: true });
89
- const lines = chunk.split('\n').filter(line => line.trim() !== '');
94
+ const lines = chunk.split('\n').filter((line) => line.trim() !== '');
90
95
 
91
96
  for (const line of lines) {
92
97
  const data = line.substring(3, line.length - 1);