@fugood/llama.node 0.5.0 → 0.6.1
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/CMakeLists.txt +40 -5
- package/bin/darwin/arm64/llama-node.node +0 -0
- package/bin/darwin/x64/llama-node.node +0 -0
- package/bin/linux/arm64/llama-node.node +0 -0
- package/bin/linux/x64/llama-node.node +0 -0
- package/bin/linux-cuda/arm64/llama-node.node +0 -0
- package/bin/linux-cuda/x64/llama-node.node +0 -0
- package/bin/linux-vulkan/arm64/llama-node.node +0 -0
- package/bin/linux-vulkan/x64/llama-node.node +0 -0
- package/bin/win32/x64/llama-node.node +0 -0
- package/bin/win32/x64/node.lib +0 -0
- package/bin/win32-vulkan/arm64/llama-node.node +0 -0
- package/bin/win32-vulkan/arm64/node.lib +0 -0
- package/bin/win32-vulkan/x64/llama-node.node +0 -0
- package/bin/win32-vulkan/x64/node.lib +0 -0
- package/lib/binding.ts +46 -0
- package/lib/index.js +18 -0
- package/lib/index.ts +24 -0
- package/package.json +4 -1
- package/patches/node-api-headers+1.1.0.patch +26 -0
- package/src/DecodeAudioTokenWorker.cpp +40 -0
- package/src/DecodeAudioTokenWorker.h +22 -0
- package/src/EmbeddingWorker.cpp +7 -5
- package/src/LlamaCompletionWorker.cpp +64 -50
- package/src/LlamaCompletionWorker.h +6 -7
- package/src/LlamaContext.cpp +523 -224
- package/src/LlamaContext.h +25 -4
- package/src/LoadSessionWorker.cpp +4 -2
- package/src/SaveSessionWorker.cpp +10 -6
- package/src/TokenizeWorker.cpp +10 -5
- package/src/addons.cc +8 -11
- package/src/common.hpp +92 -93
- package/src/tts_utils.cpp +346 -0
- package/src/tts_utils.h +62 -0
- package/src/win_dynamic_load.c +2102 -0
- package/bin/win32/arm64/llama-node.node +0 -0
- package/bin/win32/arm64/node.lib +0 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#include "tts_utils.h"
|
|
2
|
+
|
|
3
|
+
using json = nlohmann::json;
|
|
4
|
+
|
|
5
|
+
std::string audio_text_from_speaker(json speaker,
|
|
6
|
+
const tts_type type = OUTETTS_V0_2) {
|
|
7
|
+
std::string audio_text = "<|text_start|>";
|
|
8
|
+
|
|
9
|
+
if (type == OUTETTS_V0_2 || type == OUTETTS_V0_3) {
|
|
10
|
+
std::string separator =
|
|
11
|
+
(type == OUTETTS_V0_3) ? "<|space|>" : "<|text_sep|>";
|
|
12
|
+
for (const auto &word : speaker["words"]) {
|
|
13
|
+
audio_text += word["word"].get<std::string>() + separator;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return audio_text;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
std::string audio_data_from_speaker(json speaker,
|
|
21
|
+
const tts_type type = OUTETTS_V0_2) {
|
|
22
|
+
std::string audio_data = "<|audio_start|>\n";
|
|
23
|
+
|
|
24
|
+
if (type == OUTETTS_V0_2 || type == OUTETTS_V0_3) {
|
|
25
|
+
std::string code_start = (type == OUTETTS_V0_3) ? "" : "<|code_start|>";
|
|
26
|
+
std::string code_end =
|
|
27
|
+
(type == OUTETTS_V0_3) ? "<|space|>" : "<|code_end|>";
|
|
28
|
+
for (const auto &word : speaker["words"]) {
|
|
29
|
+
std::string word_text = word["word"].get<std::string>();
|
|
30
|
+
double duration = word["duration"].get<double>();
|
|
31
|
+
std::vector<int> codes = word["codes"].get<std::vector<int>>();
|
|
32
|
+
|
|
33
|
+
// Create the audio output entry
|
|
34
|
+
std::ostringstream word_entry;
|
|
35
|
+
word_entry << word_text << "<|t_" << std::fixed << std::setprecision(2)
|
|
36
|
+
<< duration << "|>" + code_start;
|
|
37
|
+
for (const auto &Code : codes) {
|
|
38
|
+
word_entry << "<|" << Code << "|>";
|
|
39
|
+
}
|
|
40
|
+
word_entry << code_end << "\n";
|
|
41
|
+
audio_data += word_entry.str();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return audio_data;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static const std::map<int, std::string> ones = {
|
|
49
|
+
{0, "zero"}, {1, "one"}, {2, "two"}, {3, "three"},
|
|
50
|
+
{4, "four"}, {5, "five"}, {6, "six"}, {7, "seven"},
|
|
51
|
+
{8, "eight"}, {9, "nine"}, {10, "ten"}, {11, "eleven"},
|
|
52
|
+
{12, "twelve"}, {13, "thirteen"}, {14, "fourteen"}, {15, "fifteen"},
|
|
53
|
+
{16, "sixteen"}, {17, "seventeen"}, {18, "eighteen"}, {19, "nineteen"}};
|
|
54
|
+
|
|
55
|
+
static const std::map<int, std::string> tens = {
|
|
56
|
+
{2, "twenty"}, {3, "thirty"}, {4, "forty"}, {5, "fifty"},
|
|
57
|
+
{6, "sixty"}, {7, "seventy"}, {8, "eighty"}, {9, "ninety"}};
|
|
58
|
+
|
|
59
|
+
// Convert a number less than 1000 to words
|
|
60
|
+
std::string convert_less_than_thousand(int num) {
|
|
61
|
+
std::string result;
|
|
62
|
+
|
|
63
|
+
if (num >= 100) {
|
|
64
|
+
result += ones.at(num / 100) + " hundred ";
|
|
65
|
+
num %= 100;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (num >= 20) {
|
|
69
|
+
result += tens.at(num / 10);
|
|
70
|
+
if (num % 10 > 0) {
|
|
71
|
+
result += "-" + ones.at(num % 10);
|
|
72
|
+
}
|
|
73
|
+
} else if (num > 0) {
|
|
74
|
+
result += ones.at(num);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
std::string number_to_words(const std::string &number_str) {
|
|
81
|
+
try {
|
|
82
|
+
size_t decimal_pos = number_str.find('.');
|
|
83
|
+
std::string integer_part = number_str.substr(0, decimal_pos);
|
|
84
|
+
|
|
85
|
+
int int_number = std::stoi(integer_part);
|
|
86
|
+
std::string result;
|
|
87
|
+
|
|
88
|
+
if (int_number == 0) {
|
|
89
|
+
result = "zero";
|
|
90
|
+
} else {
|
|
91
|
+
if (int_number >= 1000000000) {
|
|
92
|
+
int billions = int_number / 1000000000;
|
|
93
|
+
result += convert_less_than_thousand(billions) + " billion ";
|
|
94
|
+
int_number %= 1000000000;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (int_number >= 1000000) {
|
|
98
|
+
int millions = int_number / 1000000;
|
|
99
|
+
result += convert_less_than_thousand(millions) + " million ";
|
|
100
|
+
int_number %= 1000000;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (int_number >= 1000) {
|
|
104
|
+
int thousands = int_number / 1000;
|
|
105
|
+
result += convert_less_than_thousand(thousands) + " thousand ";
|
|
106
|
+
int_number %= 1000;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (int_number > 0) {
|
|
110
|
+
result += convert_less_than_thousand(int_number);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Handle decimal part
|
|
115
|
+
if (decimal_pos != std::string::npos) {
|
|
116
|
+
result += " point";
|
|
117
|
+
std::string decimal_part = number_str.substr(decimal_pos + 1);
|
|
118
|
+
for (char digit : decimal_part) {
|
|
119
|
+
result += " " + ones.at(digit - '0');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
} catch (const std::exception &e) {
|
|
125
|
+
// Skip if fails
|
|
126
|
+
return " ";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
std::string replace_numbers_with_words(const std::string &input_text) {
|
|
131
|
+
std::regex number_pattern(R"(\d+(\.\d+)?)");
|
|
132
|
+
std::string result;
|
|
133
|
+
auto it = std::sregex_iterator(input_text.begin(), input_text.end(),
|
|
134
|
+
number_pattern);
|
|
135
|
+
auto end = std::sregex_iterator();
|
|
136
|
+
|
|
137
|
+
size_t last_pos = 0;
|
|
138
|
+
for (std::sregex_iterator i = it; i != end; ++i) {
|
|
139
|
+
const std::smatch &match = *i;
|
|
140
|
+
result.append(input_text, last_pos, match.position() - last_pos);
|
|
141
|
+
result.append(number_to_words(match.str()));
|
|
142
|
+
last_pos = match.position() + match.length();
|
|
143
|
+
}
|
|
144
|
+
result.append(input_text, last_pos);
|
|
145
|
+
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Based on:
|
|
150
|
+
// https://github.com/edwko/OuteTTS/blob/a613e79c489d8256dd657ea9168d78de75895d82/outetts/version/v1/prompt_processor.py#L39
|
|
151
|
+
std::string process_text(const std::string &text,
|
|
152
|
+
const tts_type tts_type = OUTETTS_V0_2) {
|
|
153
|
+
|
|
154
|
+
// For now I skipped text romanization as I am unsure how to handle
|
|
155
|
+
// uroman and MeCab implementations in C++
|
|
156
|
+
// maybe something like https://github.com/anyascii/anyascii/ could work.
|
|
157
|
+
// currently only English would be supported in this function
|
|
158
|
+
|
|
159
|
+
std::string processed_text = replace_numbers_with_words(text);
|
|
160
|
+
|
|
161
|
+
std::transform(processed_text.begin(), processed_text.end(),
|
|
162
|
+
processed_text.begin(), ::tolower);
|
|
163
|
+
|
|
164
|
+
std::regex special_chars(R"([-_/,\.\\])");
|
|
165
|
+
processed_text = std::regex_replace(processed_text, special_chars, " ");
|
|
166
|
+
|
|
167
|
+
std::regex non_alpha(R"([^a-z\s])");
|
|
168
|
+
processed_text = std::regex_replace(processed_text, non_alpha, "");
|
|
169
|
+
|
|
170
|
+
std::regex multiple_spaces(R"(\s+)");
|
|
171
|
+
processed_text = std::regex_replace(processed_text, multiple_spaces, " ");
|
|
172
|
+
|
|
173
|
+
processed_text =
|
|
174
|
+
std::regex_replace(processed_text, std::regex(R"(^\s+|\s+$)"), "");
|
|
175
|
+
|
|
176
|
+
/*
|
|
177
|
+
Replace spaces with the separator token same as in line 365
|
|
178
|
+
|
|
179
|
+
for (auto & c : prompt_user) {
|
|
180
|
+
if (c == ' ') {
|
|
181
|
+
prompt_clean += "<|text_sep|>";
|
|
182
|
+
*/
|
|
183
|
+
std::string separator =
|
|
184
|
+
(tts_type == OUTETTS_V0_3) ? "<|space|>" : "<|text_sep|>";
|
|
185
|
+
processed_text =
|
|
186
|
+
std::regex_replace(processed_text, std::regex(R"(\s)"), separator);
|
|
187
|
+
|
|
188
|
+
return processed_text;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
#ifdef _WIN32
|
|
192
|
+
#define M_PI 3.14159265358979323846
|
|
193
|
+
#endif
|
|
194
|
+
|
|
195
|
+
void fill_hann_window(int length, bool periodic, float *output) {
|
|
196
|
+
int offset = -1;
|
|
197
|
+
if (periodic) {
|
|
198
|
+
offset = 0;
|
|
199
|
+
}
|
|
200
|
+
for (int i = 0; i < length; i++) {
|
|
201
|
+
output[i] = 0.5 * (1.0 - cosf((2.0 * M_PI * i) / (length + offset)));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
void twiddle(float *real, float *imag, int k, int N) {
|
|
206
|
+
float angle = 2 * M_PI * k / N;
|
|
207
|
+
*real = cos(angle);
|
|
208
|
+
*imag = sin(angle);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void irfft(int n, const float *inp_cplx, float *out_real) {
|
|
212
|
+
int N = n / 2 + 1;
|
|
213
|
+
|
|
214
|
+
std::vector<float> real_input(N);
|
|
215
|
+
std::vector<float> imag_input(N);
|
|
216
|
+
for (int i = 0; i < N; ++i) {
|
|
217
|
+
real_input[i] = inp_cplx[2 * i];
|
|
218
|
+
imag_input[i] = inp_cplx[2 * i + 1];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
std::vector<float> real_output(n);
|
|
222
|
+
std::vector<float> imag_output(n);
|
|
223
|
+
|
|
224
|
+
for (int k = 0; k < n; ++k) {
|
|
225
|
+
real_output[k] = 0.0f;
|
|
226
|
+
imag_output[k] = 0.0f;
|
|
227
|
+
for (int m = 0; m < N; ++m) {
|
|
228
|
+
float twiddle_real;
|
|
229
|
+
float twiddle_imag;
|
|
230
|
+
|
|
231
|
+
twiddle(&twiddle_real, &twiddle_imag, k * m, n);
|
|
232
|
+
|
|
233
|
+
real_output[k] +=
|
|
234
|
+
real_input[m] * twiddle_real - imag_input[m] * twiddle_imag;
|
|
235
|
+
imag_output[k] +=
|
|
236
|
+
real_input[m] * twiddle_imag + imag_input[m] * twiddle_real;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
for (int i = 0; i < n; ++i) {
|
|
241
|
+
out_real[i] = real_output[i] / N;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
void fold(const std::vector<float> &data, int64_t n_out, int64_t n_win,
|
|
246
|
+
int64_t n_hop, int64_t n_pad, std::vector<float> &output) {
|
|
247
|
+
int64_t output_height = n_out;
|
|
248
|
+
int64_t kernel_w = n_win;
|
|
249
|
+
int64_t stride_w = n_hop;
|
|
250
|
+
int64_t width = n_out;
|
|
251
|
+
|
|
252
|
+
output.resize(width, 0.0f);
|
|
253
|
+
|
|
254
|
+
int64_t col_idx = 0;
|
|
255
|
+
for (int64_t w_col = 0; w_col < width; ++w_col) {
|
|
256
|
+
int64_t start = w_col * stride_w - n_pad;
|
|
257
|
+
int64_t end = start + kernel_w;
|
|
258
|
+
|
|
259
|
+
for (int64_t w_im = start; w_im < end; ++w_im) {
|
|
260
|
+
if (w_im >= 0 && w_im < output_height && col_idx < (int64_t)data.size()) {
|
|
261
|
+
output[w_im] += data[col_idx];
|
|
262
|
+
}
|
|
263
|
+
col_idx++;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
output.resize(n_out - 2 * n_pad);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
std::vector<float> embd_to_audio(const float *embd, const int n_codes,
|
|
271
|
+
const int n_embd, const int n_thread) {
|
|
272
|
+
const int n_fft = 1280;
|
|
273
|
+
const int n_hop = 320;
|
|
274
|
+
const int n_win = 1280;
|
|
275
|
+
const int n_pad = (n_win - n_hop) / 2;
|
|
276
|
+
const int n_out = (n_codes - 1) * n_hop + n_win;
|
|
277
|
+
|
|
278
|
+
std::vector<float> hann(n_fft);
|
|
279
|
+
|
|
280
|
+
fill_hann_window(hann.size(), true, hann.data());
|
|
281
|
+
|
|
282
|
+
int n_spec = n_embd * n_codes;
|
|
283
|
+
|
|
284
|
+
std::vector<float> E(n_spec);
|
|
285
|
+
std::vector<float> S(n_spec);
|
|
286
|
+
std::vector<float> ST(n_spec);
|
|
287
|
+
|
|
288
|
+
for (int l = 0; l < n_codes; ++l) {
|
|
289
|
+
for (int k = 0; k < n_embd; ++k) {
|
|
290
|
+
E[k * n_codes + l] = embd[l * n_embd + k];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
for (int k = 0; k < n_embd / 2; ++k) {
|
|
295
|
+
for (int l = 0; l < n_codes; ++l) {
|
|
296
|
+
float mag = E[(k)*n_codes + l];
|
|
297
|
+
float phi = E[(k + n_embd / 2) * n_codes + l];
|
|
298
|
+
|
|
299
|
+
mag = exp(mag);
|
|
300
|
+
|
|
301
|
+
if (mag > 1e2) {
|
|
302
|
+
mag = 1e2;
|
|
303
|
+
}
|
|
304
|
+
S[2 * (k * n_codes + l) + 0] = mag * cosf(phi);
|
|
305
|
+
S[2 * (k * n_codes + l) + 1] = mag * sinf(phi);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
for (int l = 0; l < n_codes; ++l) {
|
|
310
|
+
for (int k = 0; k < n_embd / 2; ++k) {
|
|
311
|
+
ST[l * n_embd + 2 * k + 0] = S[2 * (k * n_codes + l) + 0];
|
|
312
|
+
ST[l * n_embd + 2 * k + 1] = S[2 * (k * n_codes + l) + 1];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
std::vector<float> res(n_codes * n_fft);
|
|
317
|
+
std::vector<float> hann2(n_codes * n_fft);
|
|
318
|
+
|
|
319
|
+
std::vector<std::thread> workers(n_thread);
|
|
320
|
+
for (int i = 0; i < n_thread; ++i) {
|
|
321
|
+
workers[i] = std::thread([&, i]() {
|
|
322
|
+
for (int l = i; l < n_codes; l += n_thread) {
|
|
323
|
+
irfft(n_fft, ST.data() + l * n_embd, res.data() + l * n_fft);
|
|
324
|
+
for (int j = 0; j < n_fft; ++j) {
|
|
325
|
+
res[l * n_fft + j] *= hann[j];
|
|
326
|
+
hann2[l * n_fft + j] = hann[j] * hann[j];
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
for (int i = 0; i < n_thread; ++i) {
|
|
332
|
+
workers[i].join();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
std::vector<float> audio;
|
|
336
|
+
std::vector<float> env;
|
|
337
|
+
|
|
338
|
+
fold(res, n_out, n_win, n_hop, n_pad, audio);
|
|
339
|
+
fold(hann2, n_out, n_win, n_hop, n_pad, env); // TODO: can be done once
|
|
340
|
+
|
|
341
|
+
for (size_t i = 0; i < audio.size(); ++i) {
|
|
342
|
+
audio[i] /= env[i];
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return audio;
|
|
346
|
+
}
|
package/src/tts_utils.h
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <regex>
|
|
4
|
+
#include <sstream>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <thread>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
#include "json.hpp"
|
|
10
|
+
|
|
11
|
+
enum tts_type { UNKNOWN = -1, OUTETTS_V0_2 = 1, OUTETTS_V0_3 = 2 };
|
|
12
|
+
|
|
13
|
+
std::string audio_text_from_speaker(nlohmann::json speaker,
|
|
14
|
+
const tts_type type);
|
|
15
|
+
std::string audio_data_from_speaker(nlohmann::json speaker,
|
|
16
|
+
const tts_type type);
|
|
17
|
+
std::string process_text(const std::string &text, const tts_type tts_type);
|
|
18
|
+
std::vector<float> embd_to_audio(const float *embd, const int n_codes,
|
|
19
|
+
const int n_embd, const int n_thread);
|
|
20
|
+
|
|
21
|
+
// the default speaker profile is from:
|
|
22
|
+
// https://github.com/edwko/OuteTTS/blob/main/outetts/version/v1/default_speakers/en_male_1.json
|
|
23
|
+
static const char *DEFAULT_AUDIO_TEXT =
|
|
24
|
+
"<|text_start|>the<|text_sep|>overall<|text_sep|>package<|text_sep|>from<|"
|
|
25
|
+
"text_sep|>just<|text_sep|>two<|text_sep|>people<|text_sep|>is<|text_sep|>"
|
|
26
|
+
"pretty<|text_sep|>remarkable<|text_sep|>sure<|text_sep|>i<|text_sep|>have<"
|
|
27
|
+
"|text_sep|>some<|text_sep|>critiques<|text_sep|>about<|text_sep|>some<|"
|
|
28
|
+
"text_sep|>of<|text_sep|>the<|text_sep|>gameplay<|text_sep|>aspects<|text_"
|
|
29
|
+
"sep|>but<|text_sep|>its<|text_sep|>still<|text_sep|>really<|text_sep|>"
|
|
30
|
+
"enjoyable<|text_sep|>and<|text_sep|>it<|text_sep|>looks<|text_sep|>lovely<"
|
|
31
|
+
"|text_sep|>";
|
|
32
|
+
static const char *DEFAULT_AUDIO_DATA = R"(<|audio_start|>
|
|
33
|
+
the<|t_0.08|><|code_start|><|257|><|740|><|636|><|913|><|788|><|1703|><|code_end|>
|
|
34
|
+
overall<|t_0.36|><|code_start|><|127|><|201|><|191|><|774|><|700|><|532|><|1056|><|557|><|798|><|298|><|1741|><|747|><|1662|><|1617|><|1702|><|1527|><|368|><|1588|><|1049|><|1008|><|1625|><|747|><|1576|><|728|><|1019|><|1696|><|1765|><|code_end|>
|
|
35
|
+
package<|t_0.56|><|code_start|><|935|><|584|><|1319|><|627|><|1016|><|1491|><|1344|><|1117|><|1526|><|1040|><|239|><|1435|><|951|><|498|><|723|><|1180|><|535|><|789|><|1649|><|1637|><|78|><|465|><|1668|><|901|><|595|><|1675|><|117|><|1009|><|1667|><|320|><|840|><|79|><|507|><|1762|><|1508|><|1228|><|1768|><|802|><|1450|><|1457|><|232|><|639|><|code_end|>
|
|
36
|
+
from<|t_0.19|><|code_start|><|604|><|782|><|1682|><|872|><|1532|><|1600|><|1036|><|1761|><|647|><|1554|><|1371|><|653|><|1595|><|950|><|code_end|>
|
|
37
|
+
just<|t_0.25|><|code_start|><|1782|><|1670|><|317|><|786|><|1748|><|631|><|599|><|1155|><|1364|><|1524|><|36|><|1591|><|889|><|1535|><|541|><|440|><|1532|><|50|><|870|><|code_end|>
|
|
38
|
+
two<|t_0.24|><|code_start|><|1681|><|1510|><|673|><|799|><|805|><|1342|><|330|><|519|><|62|><|640|><|1138|><|565|><|1552|><|1497|><|1552|><|572|><|1715|><|1732|><|code_end|>
|
|
39
|
+
people<|t_0.39|><|code_start|><|593|><|274|><|136|><|740|><|691|><|633|><|1484|><|1061|><|1138|><|1485|><|344|><|428|><|397|><|1562|><|645|><|917|><|1035|><|1449|><|1669|><|487|><|442|><|1484|><|1329|><|1832|><|1704|><|600|><|761|><|653|><|269|><|code_end|>
|
|
40
|
+
is<|t_0.16|><|code_start|><|566|><|583|><|1755|><|646|><|1337|><|709|><|802|><|1008|><|485|><|1583|><|652|><|10|><|code_end|>
|
|
41
|
+
pretty<|t_0.32|><|code_start|><|1818|><|1747|><|692|><|733|><|1010|><|534|><|406|><|1697|><|1053|><|1521|><|1355|><|1274|><|816|><|1398|><|211|><|1218|><|817|><|1472|><|1703|><|686|><|13|><|822|><|445|><|1068|><|code_end|>
|
|
42
|
+
remarkable<|t_0.68|><|code_start|><|230|><|1048|><|1705|><|355|><|706|><|1149|><|1535|><|1787|><|1356|><|1396|><|835|><|1583|><|486|><|1249|><|286|><|937|><|1076|><|1150|><|614|><|42|><|1058|><|705|><|681|><|798|><|934|><|490|><|514|><|1399|><|572|><|1446|><|1703|><|1346|><|1040|><|1426|><|1304|><|664|><|171|><|1530|><|625|><|64|><|1708|><|1830|><|1030|><|443|><|1509|><|1063|><|1605|><|1785|><|721|><|1440|><|923|><|code_end|>
|
|
43
|
+
sure<|t_0.36|><|code_start|><|792|><|1780|><|923|><|1640|><|265|><|261|><|1525|><|567|><|1491|><|1250|><|1730|><|362|><|919|><|1766|><|543|><|1|><|333|><|113|><|970|><|252|><|1606|><|133|><|302|><|1810|><|1046|><|1190|><|1675|><|code_end|>
|
|
44
|
+
i<|t_0.08|><|code_start|><|123|><|439|><|1074|><|705|><|1799|><|637|><|code_end|>
|
|
45
|
+
have<|t_0.16|><|code_start|><|1509|><|599|><|518|><|1170|><|552|><|1029|><|1267|><|864|><|419|><|143|><|1061|><|0|><|code_end|>
|
|
46
|
+
some<|t_0.16|><|code_start|><|619|><|400|><|1270|><|62|><|1370|><|1832|><|917|><|1661|><|167|><|269|><|1366|><|1508|><|code_end|>
|
|
47
|
+
critiques<|t_0.60|><|code_start|><|559|><|584|><|1163|><|1129|><|1313|><|1728|><|721|><|1146|><|1093|><|577|><|928|><|27|><|630|><|1080|><|1346|><|1337|><|320|><|1382|><|1175|><|1682|><|1556|><|990|><|1683|><|860|><|1721|><|110|><|786|><|376|><|1085|><|756|><|1523|><|234|><|1334|><|1506|><|1578|><|659|><|612|><|1108|><|1466|><|1647|><|308|><|1470|><|746|><|556|><|1061|><|code_end|>
|
|
48
|
+
about<|t_0.29|><|code_start|><|26|><|1649|><|545|><|1367|><|1263|><|1728|><|450|><|859|><|1434|><|497|><|1220|><|1285|><|179|><|755|><|1154|><|779|><|179|><|1229|><|1213|><|922|><|1774|><|1408|><|code_end|>
|
|
49
|
+
some<|t_0.23|><|code_start|><|986|><|28|><|1649|><|778|><|858|><|1519|><|1|><|18|><|26|><|1042|><|1174|><|1309|><|1499|><|1712|><|1692|><|1516|><|1574|><|code_end|>
|
|
50
|
+
of<|t_0.07|><|code_start|><|197|><|716|><|1039|><|1662|><|64|><|code_end|>
|
|
51
|
+
the<|t_0.08|><|code_start|><|1811|><|1568|><|569|><|886|><|1025|><|1374|><|code_end|>
|
|
52
|
+
gameplay<|t_0.48|><|code_start|><|1269|><|1092|><|933|><|1362|><|1762|><|1700|><|1675|><|215|><|781|><|1086|><|461|><|838|><|1022|><|759|><|649|><|1416|><|1004|><|551|><|909|><|787|><|343|><|830|><|1391|><|1040|><|1622|><|1779|><|1360|><|1231|><|1187|><|1317|><|76|><|997|><|989|><|978|><|737|><|189|><|code_end|>
|
|
53
|
+
aspects<|t_0.56|><|code_start|><|1423|><|797|><|1316|><|1222|><|147|><|719|><|1347|><|386|><|1390|><|1558|><|154|><|440|><|634|><|592|><|1097|><|1718|><|712|><|763|><|1118|><|1721|><|1311|><|868|><|580|><|362|><|1435|><|868|><|247|><|221|><|886|><|1145|><|1274|><|1284|><|457|><|1043|><|1459|><|1818|><|62|><|599|><|1035|><|62|><|1649|><|778|><|code_end|>
|
|
54
|
+
but<|t_0.20|><|code_start|><|780|><|1825|><|1681|><|1007|><|861|><|710|><|702|><|939|><|1669|><|1491|><|613|><|1739|><|823|><|1469|><|648|><|code_end|>
|
|
55
|
+
its<|t_0.09|><|code_start|><|92|><|688|><|1623|><|962|><|1670|><|527|><|599|><|code_end|>
|
|
56
|
+
still<|t_0.27|><|code_start|><|636|><|10|><|1217|><|344|><|713|><|957|><|823|><|154|><|1649|><|1286|><|508|><|214|><|1760|><|1250|><|456|><|1352|><|1368|><|921|><|615|><|5|><|code_end|>
|
|
57
|
+
really<|t_0.36|><|code_start|><|55|><|420|><|1008|><|1659|><|27|><|644|><|1266|><|617|><|761|><|1712|><|109|><|1465|><|1587|><|503|><|1541|><|619|><|197|><|1019|><|817|><|269|><|377|><|362|><|1381|><|507|><|1488|><|4|><|1695|><|code_end|>
|
|
58
|
+
enjoyable<|t_0.49|><|code_start|><|678|><|501|><|864|><|319|><|288|><|1472|><|1341|><|686|><|562|><|1463|><|619|><|1563|><|471|><|911|><|730|><|1811|><|1006|><|520|><|861|><|1274|><|125|><|1431|><|638|><|621|><|153|><|876|><|1770|><|437|><|987|><|1653|><|1109|><|898|><|1285|><|80|><|593|><|1709|><|843|><|code_end|>
|
|
59
|
+
and<|t_0.15|><|code_start|><|1285|><|987|><|303|><|1037|><|730|><|1164|><|502|><|120|><|1737|><|1655|><|1318|><|code_end|>
|
|
60
|
+
it<|t_0.09|><|code_start|><|848|><|1366|><|395|><|1601|><|1513|><|593|><|1302|><|code_end|>
|
|
61
|
+
looks<|t_0.27|><|code_start|><|1281|><|1266|><|1755|><|572|><|248|><|1751|><|1257|><|695|><|1380|><|457|><|659|><|585|><|1315|><|1105|><|1776|><|736|><|24|><|736|><|654|><|1027|><|code_end|>
|
|
62
|
+
lovely<|t_0.56|><|code_start|><|634|><|596|><|1766|><|1556|><|1306|><|1285|><|1481|><|1721|><|1123|><|438|><|1246|><|1251|><|795|><|659|><|1381|><|1658|><|217|><|1772|><|562|><|952|><|107|><|1129|><|1112|><|467|><|550|><|1079|><|840|><|1615|><|1469|><|1380|><|168|><|917|><|836|><|1827|><|437|><|583|><|67|><|595|><|1087|><|1646|><|1493|><|1677|><|code_end|>)";
|