@rimori/client 2.5.32 → 2.5.33-next.0
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.
- package/dist/cli/scripts/init/dev-registration.js +118 -136
- package/dist/cli/scripts/init/main.js +116 -127
- package/dist/cli/scripts/init/package-setup.js +15 -2
- package/dist/cli/scripts/release/detect-translation-languages.js +24 -35
- package/dist/cli/scripts/release/release-config-upload.js +87 -100
- package/dist/cli/scripts/release/release-db-update.js +70 -81
- package/dist/cli/scripts/release/release-file-upload.js +75 -91
- package/dist/cli/scripts/release/release-prompts-upload.js +60 -72
- package/dist/cli/scripts/release/release.js +20 -31
- package/dist/controller/AccomplishmentController.js +12 -12
- package/dist/controller/AudioController.js +15 -33
- package/dist/controller/TranslationController.js +108 -118
- package/dist/fromRimori/EventBus.js +20 -31
- package/dist/plugin/CommunicationHandler.js +73 -81
- package/dist/plugin/Logger.js +71 -83
- package/dist/plugin/RimoriClient.js +31 -31
- package/dist/plugin/StandaloneClient.js +81 -98
- package/dist/plugin/TTS/ChunkedAudioPlayer.js +31 -41
- package/dist/plugin/TTS/MessageSender.js +28 -37
- package/dist/plugin/module/AIModule.js +215 -237
- package/dist/plugin/module/DbModule.js +22 -31
- package/dist/plugin/module/EventModule.js +23 -32
- package/dist/plugin/module/ExerciseModule.js +42 -56
- package/dist/plugin/module/PluginModule.js +97 -106
- package/dist/plugin/module/SharedContentController.js +170 -207
- package/dist/plugin/module/StorageModule.js +18 -29
- package/dist/worker/WorkerSetup.js +23 -34
- package/package.json +1 -1
|
@@ -1,116 +1,99 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { EventBus } from '../fromRimori/EventBus';
|
|
11
2
|
import { DEFAULT_ANON_KEY, DEFAULT_ENDPOINT } from '../utils/endpoint';
|
|
12
3
|
export class StandaloneClient {
|
|
4
|
+
static instance;
|
|
5
|
+
config;
|
|
6
|
+
supabase; // TODO: remove any
|
|
13
7
|
constructor(config) {
|
|
14
8
|
throw new Error('Authentication is disabled until new developer platform is released.');
|
|
15
9
|
// this.supabase = createClient(config.url, config.key);
|
|
16
10
|
this.supabase = {};
|
|
17
11
|
this.config = config;
|
|
18
12
|
}
|
|
19
|
-
static getInstance() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return StandaloneClient.instance;
|
|
34
|
-
});
|
|
13
|
+
static async getInstance() {
|
|
14
|
+
if (!StandaloneClient.instance) {
|
|
15
|
+
const config = await fetch('https://app.rimori.se/config.json')
|
|
16
|
+
.then((res) => res.json())
|
|
17
|
+
.catch((err) => {
|
|
18
|
+
console.warn('Error fetching config.json, using default values', err);
|
|
19
|
+
});
|
|
20
|
+
StandaloneClient.instance = new StandaloneClient({
|
|
21
|
+
url: config?.SUPABASE_URL || DEFAULT_ENDPOINT,
|
|
22
|
+
key: config?.SUPABASE_ANON_KEY || DEFAULT_ANON_KEY,
|
|
23
|
+
backendUrl: config?.BACKEND_URL || 'https://api.rimori.se',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return StandaloneClient.instance;
|
|
35
27
|
}
|
|
36
|
-
getClient() {
|
|
37
|
-
return
|
|
38
|
-
return this.supabase;
|
|
39
|
-
});
|
|
28
|
+
async getClient() {
|
|
29
|
+
return this.supabase;
|
|
40
30
|
}
|
|
41
|
-
needsLogin() {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return error !== null;
|
|
45
|
-
});
|
|
31
|
+
async needsLogin() {
|
|
32
|
+
const { error } = await this.supabase.auth.getUser();
|
|
33
|
+
return error !== null;
|
|
46
34
|
}
|
|
47
|
-
login(email, password) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return true;
|
|
56
|
-
});
|
|
35
|
+
async login(email, password) {
|
|
36
|
+
const { error } = await this.supabase.auth.signInWithPassword({ email, password });
|
|
37
|
+
if (error) {
|
|
38
|
+
console.error('Login failed:', error);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
console.log('Successfully logged in');
|
|
42
|
+
return true;
|
|
57
43
|
}
|
|
58
|
-
static initListeners(pluginId) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const { data:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.maybeSingle();
|
|
79
|
-
guildId = (profile === null || profile === void 0 ? void 0 : profile.current_guild_id) || null;
|
|
80
|
-
}
|
|
44
|
+
static async initListeners(pluginId) {
|
|
45
|
+
console.warn('The plugin seams to not be running inside the Rimori platform. Switching to development standalone mode.');
|
|
46
|
+
// console.log("event that needs to be handled", event);
|
|
47
|
+
const { supabase, config } = await StandaloneClient.getInstance();
|
|
48
|
+
// EventBus.on("*", async (event) => {
|
|
49
|
+
EventBus.respond('standalone', 'global.supabase.requestAccess', async () => {
|
|
50
|
+
const session = await supabase.auth.getSession();
|
|
51
|
+
console.log('session', session);
|
|
52
|
+
// Call the NestJS backend endpoint instead of the Supabase edge function
|
|
53
|
+
// get current guild id if any
|
|
54
|
+
let guildId = null;
|
|
55
|
+
try {
|
|
56
|
+
const { data: { user }, } = await supabase.auth.getUser();
|
|
57
|
+
if (user) {
|
|
58
|
+
const { data: profile } = await supabase
|
|
59
|
+
.from('profiles')
|
|
60
|
+
.select('current_guild_id')
|
|
61
|
+
.eq('user_id', user.id)
|
|
62
|
+
.maybeSingle();
|
|
63
|
+
guildId = profile?.current_guild_id || null;
|
|
81
64
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
guildId: guildId,
|
|
94
|
-
}),
|
|
95
|
-
});
|
|
96
|
-
if (!response.ok) {
|
|
97
|
-
const errorText = yield response.text();
|
|
98
|
-
throw new Error(`Failed to get plugin token. ${response.status}: ${errorText}`);
|
|
99
|
-
}
|
|
100
|
-
const data = yield response.json();
|
|
101
|
-
return {
|
|
102
|
-
token: data.token,
|
|
65
|
+
}
|
|
66
|
+
catch (_) {
|
|
67
|
+
guildId = null;
|
|
68
|
+
}
|
|
69
|
+
const response = await fetch(`${config.backendUrl}/plugin/token`, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': 'application/json',
|
|
73
|
+
Authorization: `Bearer ${session.data.session?.access_token}`,
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify({
|
|
103
76
|
pluginId: pluginId,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
77
|
+
guildId: guildId,
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
const errorText = await response.text();
|
|
82
|
+
throw new Error(`Failed to get plugin token. ${response.status}: ${errorText}`);
|
|
83
|
+
}
|
|
84
|
+
const data = await response.json();
|
|
85
|
+
return {
|
|
86
|
+
token: data.token,
|
|
87
|
+
pluginId: pluginId,
|
|
88
|
+
url: config.url,
|
|
89
|
+
key: config.key,
|
|
90
|
+
backendUrl: config.backendUrl,
|
|
91
|
+
tablePrefix: pluginId,
|
|
92
|
+
expiration: new Date(Date.now() + 1000 * 60 * 60 * 1.5), // 1.5 hours
|
|
93
|
+
};
|
|
114
94
|
});
|
|
95
|
+
EventBus.on('*', async (event) => {
|
|
96
|
+
console.log('[standalone] would send event to parent', event);
|
|
97
|
+
}, ['standalone']);
|
|
115
98
|
}
|
|
116
99
|
}
|
|
@@ -1,27 +1,21 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
export class ChunkedAudioPlayer {
|
|
2
|
+
audioContext;
|
|
3
|
+
chunkQueue = [];
|
|
4
|
+
isPlaying = false;
|
|
5
|
+
analyser;
|
|
6
|
+
dataArray;
|
|
7
|
+
shouldMonitorLoudness = true;
|
|
8
|
+
isMonitoring = false;
|
|
9
|
+
handle = 0;
|
|
10
|
+
volume = 1.0;
|
|
11
|
+
loudnessCallback = () => { };
|
|
12
|
+
currentIndex = 0;
|
|
13
|
+
startedPlaying = false;
|
|
14
|
+
onEndOfSpeech = () => { };
|
|
15
|
+
backgroundNoiseLevel = 30; // Background noise level that should be treated as baseline (0)
|
|
16
|
+
currentSource = null;
|
|
17
|
+
stopped = false;
|
|
11
18
|
constructor() {
|
|
12
|
-
this.chunkQueue = [];
|
|
13
|
-
this.isPlaying = false;
|
|
14
|
-
this.shouldMonitorLoudness = true;
|
|
15
|
-
this.isMonitoring = false;
|
|
16
|
-
this.handle = 0;
|
|
17
|
-
this.volume = 1.0;
|
|
18
|
-
this.loudnessCallback = () => { };
|
|
19
|
-
this.currentIndex = 0;
|
|
20
|
-
this.startedPlaying = false;
|
|
21
|
-
this.onEndOfSpeech = () => { };
|
|
22
|
-
this.backgroundNoiseLevel = 30; // Background noise level that should be treated as baseline (0)
|
|
23
|
-
this.currentSource = null;
|
|
24
|
-
this.stopped = false;
|
|
25
19
|
this.init();
|
|
26
20
|
}
|
|
27
21
|
init() {
|
|
@@ -37,17 +31,15 @@ export class ChunkedAudioPlayer {
|
|
|
37
31
|
setVolume(volume) {
|
|
38
32
|
this.volume = volume;
|
|
39
33
|
}
|
|
40
|
-
addChunk(chunk, position) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
});
|
|
34
|
+
async addChunk(chunk, position) {
|
|
35
|
+
if (this.stopped)
|
|
36
|
+
return;
|
|
37
|
+
console.log('Adding chunk', position, chunk);
|
|
38
|
+
this.chunkQueue[position] = chunk;
|
|
39
|
+
if (position === 0 && !this.startedPlaying) {
|
|
40
|
+
this.startedPlaying = true;
|
|
41
|
+
this.playChunks();
|
|
42
|
+
}
|
|
51
43
|
}
|
|
52
44
|
playChunks() {
|
|
53
45
|
if (this.isPlaying || this.stopped)
|
|
@@ -89,7 +81,7 @@ export class ChunkedAudioPlayer {
|
|
|
89
81
|
try {
|
|
90
82
|
this.currentSource.stop();
|
|
91
83
|
}
|
|
92
|
-
catch
|
|
84
|
+
catch {
|
|
93
85
|
// already stopped
|
|
94
86
|
}
|
|
95
87
|
this.currentSource = null;
|
|
@@ -148,13 +140,11 @@ export class ChunkedAudioPlayer {
|
|
|
148
140
|
});
|
|
149
141
|
});
|
|
150
142
|
}
|
|
151
|
-
playAgain() {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
});
|
|
143
|
+
async playAgain() {
|
|
144
|
+
console.log('Playing again');
|
|
145
|
+
if (this.chunkQueue.length > 0 && !this.isPlaying) {
|
|
146
|
+
this.playChunks();
|
|
147
|
+
}
|
|
158
148
|
}
|
|
159
149
|
monitorLoudness() {
|
|
160
150
|
// Stop monitoring when the flag is false
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { ChunkedAudioPlayer } from './ChunkedAudioPlayer';
|
|
11
2
|
export class MessageSender {
|
|
3
|
+
player = new ChunkedAudioPlayer();
|
|
4
|
+
fetchedSentences = new Set();
|
|
5
|
+
lastLoading = false;
|
|
6
|
+
voice;
|
|
7
|
+
voiceBackend;
|
|
8
|
+
cache;
|
|
9
|
+
voiceSpeed = 1;
|
|
10
|
+
instructions;
|
|
12
11
|
constructor(voiceBackend, voice, cache = false) {
|
|
13
|
-
|
|
14
|
-
this.fetchedSentences = new Set();
|
|
15
|
-
this.lastLoading = false;
|
|
16
|
-
this.voiceSpeed = 1;
|
|
17
|
-
if ((voice === null || voice === void 0 ? void 0 : voice.split('_').length) !== 2) {
|
|
12
|
+
if (voice?.split('_').length !== 2) {
|
|
18
13
|
throw new Error("Invalid voice id format '" + voice + "'. Voice id needs to look like <provider>_<voice_id>");
|
|
19
14
|
}
|
|
20
15
|
this.voiceBackend = voiceBackend;
|
|
@@ -42,34 +37,30 @@ export class MessageSender {
|
|
|
42
37
|
}
|
|
43
38
|
return result;
|
|
44
39
|
}
|
|
45
|
-
handleNewText(currentText, isLoading) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
yield this.player.addChunk(audioData, i);
|
|
61
|
-
}
|
|
40
|
+
async handleNewText(currentText, isLoading) {
|
|
41
|
+
if (!this.lastLoading && isLoading) {
|
|
42
|
+
this.reset();
|
|
43
|
+
}
|
|
44
|
+
this.lastLoading = isLoading;
|
|
45
|
+
if (!currentText) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const sentences = this.getCompletedSentences(currentText, isLoading);
|
|
49
|
+
for (let i = 0; i < sentences.length; i++) {
|
|
50
|
+
const sentence = sentences[i];
|
|
51
|
+
if (!this.fetchedSentences.has(sentence)) {
|
|
52
|
+
this.fetchedSentences.add(sentence);
|
|
53
|
+
const audioData = await this.generateSpeech(sentence);
|
|
54
|
+
await this.player.addChunk(audioData, i);
|
|
62
55
|
}
|
|
63
|
-
}
|
|
56
|
+
}
|
|
64
57
|
}
|
|
65
58
|
setInstructions(instructions) {
|
|
66
59
|
this.instructions = instructions;
|
|
67
60
|
}
|
|
68
|
-
generateSpeech(sentence) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return yield blob.arrayBuffer();
|
|
72
|
-
});
|
|
61
|
+
async generateSpeech(sentence) {
|
|
62
|
+
const blob = await this.voiceBackend(sentence, this.voice, this.voiceSpeed, undefined, this.cache, this.instructions);
|
|
63
|
+
return await blob.arrayBuffer();
|
|
73
64
|
}
|
|
74
65
|
play() {
|
|
75
66
|
this.player.playAgain();
|