@genai-fi/nanogpt 0.23.0 → 1.0.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.
Files changed (109) hide show
  1. package/README.md +78 -281
  2. package/dist/{DatasetBuilder-C0iJT29K.js → DatasetBuilder-DU1G1OKX.js} +20 -23
  3. package/dist/{RealDiv-CNsvC4AU.js → RealDiv-CSnvtN2E.js} +20 -20
  4. package/dist/{Reshape-dnm9bO3B.js → Reshape-BlylqwWy.js} +12 -12
  5. package/dist/TeachableLLM.d.ts +10 -15
  6. package/dist/TeachableLLM.js +201 -2
  7. package/dist/api/responses.d.ts +81 -0
  8. package/dist/api/responses.js +169 -0
  9. package/dist/api/training.d.ts +70 -0
  10. package/dist/api/training.js +205 -0
  11. package/dist/data/docx.js +9 -3036
  12. package/dist/data/stream.d.ts +8 -8
  13. package/dist/data/stream.js +1 -1
  14. package/dist/data/textLoader.d.ts +1 -1
  15. package/dist/data/textLoader.js +2 -2
  16. package/dist/data.d.ts +3 -0
  17. package/dist/data.js +12 -0
  18. package/dist/{dist-BqAU9-yi.js → dist-CwK5S7Ls.js} +2168 -2168
  19. package/dist/{gpgpu_math-DBYEAAdI.js → gpgpu_math-20tPK8LM.js} +458 -458
  20. package/dist/{Generator.d.ts → inference/Generator.d.ts} +16 -44
  21. package/dist/inference/Generator.js +271 -0
  22. package/dist/inference/tokenisePrompt.d.ts +4 -0
  23. package/dist/inference/tokenisePrompt.js +13 -0
  24. package/dist/inference/types.d.ts +44 -8
  25. package/dist/inference/utilities.d.ts +9 -0
  26. package/dist/inference/utilities.js +20 -0
  27. package/dist/jszip.min-DKa1Rjyn.js +3033 -0
  28. package/dist/{kernel_funcs_utils-D-mATnGR.js → kernel_funcs_utils-ql8Y8qPn.js} +96 -93
  29. package/dist/layers/MLP.d.ts +1 -1
  30. package/dist/layers/PositionEmbedding.d.ts +2 -1
  31. package/dist/layers/PositionEmbedding.js +1 -1
  32. package/dist/layers/RMSNorm.d.ts +1 -1
  33. package/dist/layers/TiedEmbedding.js +1 -1
  34. package/dist/layers.d.ts +4 -0
  35. package/dist/layers.js +14 -0
  36. package/dist/loader/load.js +58 -2
  37. package/dist/loader/loadHF.d.ts +1 -1
  38. package/dist/loader/loadHF.js +17 -2
  39. package/dist/loader/loadTransformers.js +46 -2
  40. package/dist/loader/newZipLoad.js +25 -2
  41. package/dist/loader/oldZipLoad.d.ts +1 -1
  42. package/dist/loader/oldZipLoad.js +37 -2
  43. package/dist/loader/save.js +75 -2
  44. package/dist/loader/types.d.ts +3 -3
  45. package/dist/main.d.ts +34 -43
  46. package/dist/main.js +12327 -20
  47. package/dist/{matMulGelu-BAIgQaRx.js → matMulGelu-CBoqTZM7.js} +2 -2
  48. package/dist/models/NanoGPTV1.js +95 -2
  49. package/dist/models/NanoGPTV2.js +86 -2
  50. package/dist/models/factory.js +13 -2
  51. package/dist/models/model.js +76 -2
  52. package/dist/models.d.ts +4 -0
  53. package/dist/models.js +14 -0
  54. package/dist/ops/dot16.js +1 -1
  55. package/dist/ops/matMulGelu.js +1 -1
  56. package/dist/ops/webgl/adamAdjust.js +1 -1
  57. package/dist/ops/webgl/fusedSoftmax.js +2 -2
  58. package/dist/ops/webgl/gelu.js +2 -2
  59. package/dist/ops/webgl/log.js +5 -5
  60. package/dist/ops/webgl/matMulGelu.js +1 -1
  61. package/dist/ops/webgl/matMulMul.js +1 -1
  62. package/dist/{stream-BjdpSNqB.js → stream-BpAwcvHz.js} +565 -561
  63. package/dist/{tfjs_backend-CydPRQTc.js → tfjs_backend-h5weiy1O.js} +36 -36
  64. package/dist/tokenise.d.ts +4 -0
  65. package/dist/tokenise.js +15 -0
  66. package/dist/tokeniser/CharTokeniser.js +18 -20
  67. package/dist/tokeniser/bpe.js +18 -22
  68. package/dist/training/BasicTrainer.d.ts +5 -10
  69. package/dist/training/BasicTrainer.js +80 -88
  70. package/dist/training/DatasetBuilder.d.ts +4 -4
  71. package/dist/training/DatasetBuilder.js +1 -1
  72. package/dist/training/PreTrainer.js +1 -1
  73. package/dist/training/SFTTrainer.js +1 -1
  74. package/dist/training/configure.d.ts +3 -0
  75. package/dist/training/configure.js +32 -0
  76. package/dist/training/factory.d.ts +6 -0
  77. package/dist/training/factory.js +8 -0
  78. package/dist/training/prepareData.d.ts +22 -0
  79. package/dist/training/prepareData.js +49 -0
  80. package/dist/training/tasks/TokenStore.d.ts +2 -1
  81. package/dist/training/tasks/TokenStore.js +8 -5
  82. package/dist/training/tasks/tokenStream.d.ts +17 -0
  83. package/dist/training/tasks/tokenStream.js +46 -0
  84. package/dist/training/types.d.ts +14 -1
  85. package/dist/training/validateOptions.d.ts +2 -0
  86. package/dist/training/validateOptions.js +19 -0
  87. package/dist/training/validation.js +4 -2
  88. package/dist/utilities/arrayShape.d.ts +1 -0
  89. package/dist/utilities/arrayShape.js +8 -0
  90. package/dist/utilities/random.d.ts +1 -0
  91. package/dist/utilities/random.js +19 -0
  92. package/dist/utilities/waitForModel.d.ts +1 -1
  93. package/dist/v4-BK7K-jy_.js +30 -0
  94. package/package.json +8 -2
  95. package/dist/Generator.js +0 -2
  96. package/dist/Trainer-DBsyWJ4s.js +0 -228
  97. package/dist/Trainer.d.ts +0 -45
  98. package/dist/Trainer.js +0 -2
  99. package/dist/main-BSaDGH7I.js +0 -13274
  100. package/dist/training/tasks/ConversationTask.d.ts +0 -17
  101. package/dist/training/tasks/ConversationTask.js +0 -29
  102. package/dist/training/tasks/PretrainingTask.d.ts +0 -17
  103. package/dist/training/tasks/PretrainingTask.js +0 -42
  104. package/dist/training/tasks/StartSentenceTask.d.ts +0 -18
  105. package/dist/training/tasks/StartSentenceTask.js +0 -45
  106. package/dist/training/tasks/Task.d.ts +0 -29
  107. package/dist/training/tasks/Task.js +0 -50
  108. package/dist/training/tasks/splitter.d.ts +0 -5
  109. package/dist/training/tasks/splitter.js +0 -18
@@ -1,12 +1,12 @@
1
1
  import { Bo as e, Gs as t, Ps as n, oc as r } from "./dist-Da20xy8E.js";
2
- import { E as i, a, c as o, d as s, j as c, l, u, z as d } from "./gpgpu_math-DBYEAAdI.js";
2
+ import { $ as i, C as a, a as o, et as s, j as c, nt as l, tt as u, v as d } from "./gpgpu_math-20tPK8LM.js";
3
3
  //#region node_modules/@tensorflow/tfjs-backend-webgl/dist/reshape_packed_gpu.js
4
4
  var f = class {
5
5
  constructor(e, t) {
6
6
  this.variableNames = ["A"], this.packedInputs = !0, this.packedOutput = !0, this.customUniforms = [{
7
7
  name: "inputShape",
8
8
  type: "ivec3"
9
- }], this.outputShape = e, this.enableShapeUniforms = a(this.outputShape.length);
9
+ }], this.outputShape = e, this.enableShapeUniforms = o(this.outputShape.length);
10
10
  let n = "";
11
11
  for (let e = 0; e < 4; e++) {
12
12
  let t = "thisRC = rc;";
@@ -25,7 +25,7 @@ var f = class {
25
25
  }
26
26
  this.userCode = `
27
27
  ${p(t, this.enableShapeUniforms)}
28
- ${this.enableShapeUniforms ? l() : o(e)}
28
+ ${this.enableShapeUniforms ? s() : i(e)}
29
29
 
30
30
  void main() {
31
31
  ivec3 rc = getOutputCoords();
@@ -46,7 +46,7 @@ var f = class {
46
46
  function p(e, t) {
47
47
  return `
48
48
  ivec3 inputCoordsFromReshapedOutCoords(int index) {
49
- ${t ? s([
49
+ ${t ? l([
50
50
  "r",
51
51
  "c",
52
52
  "d"
@@ -62,24 +62,24 @@ function p(e, t) {
62
62
  //#endregion
63
63
  //#region node_modules/@tensorflow/tfjs-backend-webgl/dist/kernel_utils/reshape.js
64
64
  function m(e, t, n) {
65
- let r = [i(e.shape), ...c(e.shape)], a = {
65
+ let r = [d(e.shape), ...a(e.shape)], i = {
66
66
  dtype: e.dtype,
67
67
  shape: r,
68
68
  dataId: e.dataId
69
- }, o = new f([i(t), ...c(t)], r), s = [r], l = n.runWebGLProgram(o, [a], e.dtype, s, !0);
69
+ }, o = new f([d(t), ...a(t)], r), s = [r], c = n.runWebGLProgram(o, [i], e.dtype, s, !0);
70
70
  return {
71
- dataId: l.dataId,
71
+ dataId: c.dataId,
72
72
  shape: t,
73
- dtype: l.dtype
73
+ dtype: c.dtype
74
74
  };
75
75
  }
76
76
  //#endregion
77
77
  //#region node_modules/@tensorflow/tfjs-backend-webgl/dist/kernels/Reshape.js
78
78
  function h(e) {
79
- let { inputs: i, backend: a, attrs: o } = e, { x: s } = i, { shape: c } = o, l = a, u = r(s.shape), f = t(c, u), p = r(f);
80
- n(u === p, () => `The new shape (${f}) has ${p} elements and the old shape (${s.shape}) has ${u} elements. The new shape and old shape must have the same number of elements.`);
81
- let h = l.texData.get(s.dataId);
82
- return h.isPacked && !d(s.shape, f) && !(h.texture !== null && d(h.shape, f)) ? m(s, f, l) : (l.incRef(s.dataId), {
79
+ let { inputs: i, backend: a, attrs: o } = e, { x: s } = i, { shape: l } = o, u = a, d = r(s.shape), f = t(l, d), p = r(f);
80
+ n(d === p, () => `The new shape (${f}) has ${p} elements and the old shape (${s.shape}) has ${d} elements. The new shape and old shape must have the same number of elements.`);
81
+ let h = u.texData.get(s.dataId);
82
+ return h.isPacked && !c(s.shape, f) && !(h.texture !== null && c(h.shape, f)) ? m(s, f, u) : (u.incRef(s.dataId), {
83
83
  dataId: s.dataId,
84
84
  shape: f,
85
85
  dtype: s.dtype
@@ -1,15 +1,14 @@
1
1
  import { GPTConfig, LoRAConfig } from './models/config';
2
- import { Conversation, ITokeniser } from './tokeniser/type';
2
+ import { ITokeniser } from './tokeniser/type';
3
3
  import { SaveOptions } from './loader/save';
4
4
  import { LoadModelOptions } from './loader/load';
5
- import { IGenerateOptions, IGenerator } from './Generator';
6
- import { default as Trainer, TrainingType } from './Trainer';
7
- import { ConversationStream } from './main';
5
+ import { ConversationStream } from './data/stream';
8
6
  import { default as MemoryProfiler } from './utilities/profile';
9
7
  import { default as Model, ModelForwardAttributes } from './models/model';
10
- import { Task } from './training/tasks/Task';
11
- import { TrainingLogEntry, TrainingOptions } from './training/types';
12
8
  import { ModelMode, TransformersMetadata } from './loader/types';
9
+ import { default as Responses } from './api/responses';
10
+ import { default as Training } from './api/training';
11
+ import { GPUOptions } from './patches/webgpu_base';
13
12
  type TeachableLLMStatus = 'warmup' | 'awaitingTokens' | 'ready' | 'training' | 'loading' | 'busy' | 'error';
14
13
  export default class TeachableLLM {
15
14
  private ee;
@@ -18,10 +17,11 @@ export default class TeachableLLM {
18
17
  private _tokeniser?;
19
18
  private _status;
20
19
  private _memoryRequirements?;
20
+ private _responses;
21
+ private _training;
21
22
  meta: TransformersMetadata;
22
- private _trainer;
23
+ static selectBackend(backend: 'cpu' | 'webgl' | 'webgpu', options?: GPUOptions): Promise<void>;
23
24
  constructor(tokeniser?: ITokeniser, model?: Model<ModelForwardAttributes, GPTConfig>);
24
- get currentTrainer(): Trainer | null;
25
25
  get vocab(): string[];
26
26
  get mode(): ModelMode;
27
27
  set mode(mode: ModelMode);
@@ -50,22 +50,17 @@ export default class TeachableLLM {
50
50
  get enableProfiler(): boolean;
51
51
  set enableProfiler(value: boolean);
52
52
  getNumParams(): number;
53
- trainer(trainingType?: TrainingType, options?: TrainingOptions): Trainer;
54
- train(text: Task[], options?: TrainingOptions, trainingType?: TrainingType): Promise<void>;
55
53
  trainTokeniser(text: ConversationStream[]): Promise<number>;
56
- generator(): IGenerator;
57
- generateText(prompt: Conversation[], options?: IGenerateOptions): Promise<Conversation[]>;
58
- generateText(options?: IGenerateOptions): Promise<Conversation[]>;
54
+ get responses(): Responses;
55
+ get training(): Training;
59
56
  dispose(): void;
60
57
  on(event: 'status', listener: (status: TeachableLLMStatus) => void): void;
61
58
  on(event: 'mode', listener: (mode: ModelMode) => void): void;
62
59
  on(event: 'error', listener: (error: Error) => void): void;
63
- on(event: 'trainStep', listener: (step: TrainingLogEntry) => void): void;
64
60
  on(event: 'loaded' | 'changeLoRA', listener: () => void): void;
65
61
  off(event: 'status', listener: (status: TeachableLLMStatus) => void): void;
66
62
  off(event: 'mode', listener: (mode: ModelMode) => void): void;
67
63
  off(event: 'error', listener: (error: Error) => void): void;
68
- off(event: 'trainStep', listener: (step: TrainingLogEntry) => void): void;
69
64
  off(event: 'loaded' | 'changeLoRA', listener: () => void): void;
70
65
  }
71
66
  export {};
@@ -1,2 +1,201 @@
1
- import { i as e } from "./main-BSaDGH7I.js";
2
- export { e as default };
1
+ import { t as e } from "./eventemitter3-D_qV3Lof.js";
2
+ import t from "./tokeniser/CharTokeniser.js";
3
+ import n from "./tokeniser/bpe.js";
4
+ import { validateConfig as r } from "./models/config.js";
5
+ import { dummyPassTrainAsync as i } from "./utilities/dummy.js";
6
+ import a from "./models/factory.js";
7
+ import { loadModel as o } from "./loader/load.js";
8
+ import { saveModel as s } from "./loader/save.js";
9
+ import c from "./utilities/profile.js";
10
+ import l from "./api/responses.js";
11
+ import u from "./api/training.js";
12
+ import { selectBackend as d } from "./backend.js";
13
+ //#region lib/TeachableLLM.ts
14
+ var f = class f {
15
+ ee = new e();
16
+ _config;
17
+ _model;
18
+ _tokeniser;
19
+ _status = "loading";
20
+ _memoryRequirements;
21
+ _responses = null;
22
+ _training = null;
23
+ meta = {
24
+ version: 2,
25
+ application: "@genai-fi/nanogpt"
26
+ };
27
+ static selectBackend(e, t) {
28
+ return d(e, t);
29
+ }
30
+ constructor(e, t) {
31
+ this._config = t?.config, this._tokeniser = e, this._model = t, t?.metaData && (this.meta = t.metaData);
32
+ }
33
+ get vocab() {
34
+ return this._tokeniser?.getVocab() || [];
35
+ }
36
+ get mode() {
37
+ return this._model?.metaData?.mode ?? "untrained";
38
+ }
39
+ set mode(e) {
40
+ if (!this._model) throw Error("model_not_initialized.");
41
+ this._model.metaData.mode === "conversational" && e === "completion" || e !== "untrained" && (this._model.metaData.mode = e, this.ee.emit("mode", e));
42
+ }
43
+ get loaded() {
44
+ return !!this._model && !!this._tokeniser && !!this._config;
45
+ }
46
+ get config() {
47
+ if (!this._config) throw Error("configuration_not_initialized.");
48
+ return this._config;
49
+ }
50
+ get model() {
51
+ if (!this._model) throw Error("model_not_initialized.");
52
+ return this._model;
53
+ }
54
+ get tokeniser() {
55
+ if (!this._tokeniser) throw Error("tokeniser_not_initialized.");
56
+ return this._tokeniser;
57
+ }
58
+ get status() {
59
+ return this._status;
60
+ }
61
+ get ready() {
62
+ return this._status === "ready" && !!this._model && !!this._tokeniser;
63
+ }
64
+ get busy() {
65
+ return this._status === "busy" || this._status === "training";
66
+ }
67
+ createLoRA(e, t) {
68
+ if (!this._model) throw Error("model_not_initialized.");
69
+ this._model.createLoRA(e, t), this.ee.emit("changeLoRA");
70
+ }
71
+ deleteLoRA(e) {
72
+ if (!this._model) throw Error("model_not_initialized.");
73
+ this._model.deleteLoRA(e), this.ee.emit("changeLoRA");
74
+ }
75
+ renameLoRA(e, t) {
76
+ if (!this._model) throw Error("model_not_initialized.");
77
+ this._model.renameLoRA(e, t), this.ee.emit("changeLoRA");
78
+ }
79
+ attachLoRA(e) {
80
+ if (!this._model) throw Error("model_not_initialized.");
81
+ this.model.lora?.name !== e && (this._model.attachLoRA(e), this.ee.emit("changeLoRA"));
82
+ }
83
+ detachLoRA() {
84
+ if (!this._model) throw Error("model_not_initialized.");
85
+ this._model.detachLoRA(), this.ee.emit("changeLoRA");
86
+ }
87
+ hasLoRA(e) {
88
+ if (!this._model) throw Error("model_not_initialized.");
89
+ return this._model.hasLoRA(e);
90
+ }
91
+ listLoRAs() {
92
+ if (!this._model) throw Error("model_not_initialized.");
93
+ return this._model.listLoRAs();
94
+ }
95
+ estimateTrainingMemoryUsage(e) {
96
+ let t = this._memoryRequirements ?? {
97
+ perBatch: 0,
98
+ tapeSize: 0,
99
+ gradients: 0
100
+ }, n = t.perBatch * e, r = t.gradients;
101
+ return n * .66 + r * 4;
102
+ }
103
+ setStatus(e) {
104
+ this._status !== e && (this._status = e, this.ee.emit("status", e));
105
+ }
106
+ saveModel(e) {
107
+ if (!this._model || !this._tokeniser) throw Error("model_or_tokeniser_not_initialized.");
108
+ let t = (e?.includeOptimizer && this._training?.getPretrainingJob()) ?? null;
109
+ return s(this._model, this._tokeniser, {
110
+ ...e,
111
+ name: e?.name || this.meta.name
112
+ }, t ? {
113
+ optimizer: t.trainer.optimizer,
114
+ trainingLog: t.trainer.log
115
+ } : void 0);
116
+ }
117
+ static loadModel(e, t) {
118
+ let n = new f();
119
+ return o(e, t).then(({ model: e, tokeniser: t, metaData: a, optimizer: o, log: s }) => {
120
+ r(e.config), n._model = e, n._tokeniser = t, n._config = e.config, a && (n.meta = a), n.setStatus("warmup"), i(e).then((t) => {
121
+ n._memoryRequirements = t, o && e.metaData.pretrainingSettings && e.metaData.pretrainingData && n.training.restore(e.metaData.pretrainingSettings, s || [], o, e.metaData.pretrainingData), n.setStatus("ready"), n.ee.emit("loaded"), n.ee.emit("mode", n.mode);
122
+ }).catch((e) => {
123
+ n.setStatus("error"), n.ee.emit("error", e), console.error("Error during warmup:", e);
124
+ });
125
+ }).catch((e) => {
126
+ n.setStatus("error"), n.ee.emit("error", e), console.error("Error loading model:", e);
127
+ }), n;
128
+ }
129
+ static create(e, o) {
130
+ r(o);
131
+ let s = o, c = e === "char" ? new t(s.vocabSize) : e === "bpe" ? new n(s.vocabSize) : e, l = a(s), u = new f(c, l);
132
+ return u.setStatus("warmup"), i(l).then((e) => {
133
+ u._memoryRequirements = e, u.tokeniser.trained ? (u.setStatus("ready"), u.ee.emit("loaded"), u.ee.emit("mode", u.mode)) : (u.setStatus("awaitingTokens"), u.ee.emit("loaded"), u.ee.emit("mode", u.mode), u.tokeniser.once("trainStatus", (e) => {
134
+ e === "trained" && u.setStatus("ready");
135
+ }));
136
+ }).catch((e) => {
137
+ u.setStatus("error"), u.ee.emit("error", e), console.error("Error during warmup:", e);
138
+ }), u;
139
+ }
140
+ getProfiler() {
141
+ return this._model?.getProfiler();
142
+ }
143
+ get enableProfiler() {
144
+ return !!this._model?.getProfiler();
145
+ }
146
+ set enableProfiler(e) {
147
+ if (e) {
148
+ if (!this._config) return;
149
+ this.model.getProfiler() || this.model.setProfiler(new c());
150
+ } else this.model.getProfiler() && this.model.setProfiler(null);
151
+ }
152
+ getNumParams() {
153
+ return this._model ? this._model.getNumParams() : 0;
154
+ }
155
+ async trainTokeniser(e) {
156
+ if (!this._tokeniser) throw Error("tokeniser_not_initialized.");
157
+ let t = await this._tokeniser.train(e);
158
+ return this._status === "awaitingTokens" && this.setStatus("ready"), t;
159
+ }
160
+ get responses() {
161
+ if (!this._responses) {
162
+ if (!this._model || !this._tokeniser) throw Error("model_or_tokeniser_not_initialized.");
163
+ this._responses = new l(this._model, this._tokeniser), this._responses.on("error", (e) => {
164
+ this.setStatus("error"), this.ee.emit("error", e);
165
+ }), this._responses.on("status", (e) => {
166
+ e === "busy" ? this.setStatus("busy") : e === "ready" && this.setStatus("ready");
167
+ });
168
+ }
169
+ return this._responses;
170
+ }
171
+ get training() {
172
+ if (!this._training) {
173
+ if (!this._model || !this._tokeniser) throw Error("model_or_tokeniser_not_initialized.");
174
+ this._training = new u(this._model, this._tokeniser), this._training.on("running", () => {
175
+ this.setStatus("busy");
176
+ }), this._training.on("completed", () => {
177
+ this._training?.training || this.setStatus("ready");
178
+ }), this._training.on("cancelled", () => {
179
+ this._training?.training || this.setStatus("ready");
180
+ }), this._training.on("error", (e) => {
181
+ this.setStatus("error"), this.ee.emit("error", e);
182
+ });
183
+ }
184
+ return this._training;
185
+ }
186
+ dispose() {
187
+ this._responses &&= (this._responses.dispose(), null), this._training &&= (this._training.dispose(), null), this._model?.dispose(), this.ee.removeAllListeners();
188
+ }
189
+ on(e, t) {
190
+ if (e === "loaded" && this.loaded) {
191
+ setTimeout(() => t(), 0);
192
+ return;
193
+ }
194
+ this.ee.on(e, t);
195
+ }
196
+ off(e, t) {
197
+ this.ee.off(e, t);
198
+ }
199
+ };
200
+ //#endregion
201
+ export { f as default };
@@ -0,0 +1,81 @@
1
+ import { IGenerateOptions, IGeneratorResponse } from '../../inference/types';
2
+ import { ITokeniser } from '../../tokeniser/type';
3
+ import { default as Model, ModelForwardAttributes } from '../../models/model';
4
+ import { GPTConfig } from '../../models/config';
5
+ interface ResponseEvents {
6
+ status: (status: 'ready' | 'busy') => void;
7
+ error: (error: Error) => void;
8
+ done: (id: string) => void;
9
+ hook: (id: string) => void;
10
+ generating: (id: string) => void;
11
+ }
12
+ export default class Responses {
13
+ private ee;
14
+ private _model;
15
+ private _tokeniser;
16
+ private _busyCount;
17
+ private _responses;
18
+ private _jobQueue;
19
+ private _hookedResponses;
20
+ private _resumeWaiters;
21
+ constructor(model: Model<ModelForwardAttributes, GPTConfig>, tokeniser: ITokeniser);
22
+ /** Number of generation jobs currently queued. */
23
+ get queued(): number;
24
+ private _processNextJob;
25
+ private _runForRecord;
26
+ /**
27
+ * Subscribe to response lifecycle events.
28
+ * @param event One of `status`, `error`, `done`, `hook`, or `generating`
29
+ * @param listener Callback invoked when the event fires
30
+ */
31
+ on<E extends keyof ResponseEvents>(event: E, listener: ResponseEvents[E]): void;
32
+ /**
33
+ * Unsubscribe a previously registered event listener.
34
+ * @param event Event name the listener was registered for
35
+ * @param listener The listener to remove
36
+ */
37
+ off<E extends keyof ResponseEvents>(event: E, listener: ResponseEvents[E]): void;
38
+ private generator;
39
+ private _cleanup;
40
+ /** Start a new text generation or resume a previous one.
41
+ * @param options Response options object
42
+ * @param callback Intermediate responses per token or chunk.
43
+ */
44
+ create(options: IGenerateOptions, callback?: (response: IGeneratorResponse) => void): Promise<IGeneratorResponse>;
45
+ /**
46
+ * Retry a previous response generation, optionally truncating the conversation at `index`.
47
+ * @param id ID of the existing response to retry
48
+ * @param index Optional conversation index to truncate before regenerating
49
+ */
50
+ retry(id: string, index?: number): Promise<IGeneratorResponse>;
51
+ /**
52
+ * Get the current generator response for a given ID.
53
+ * Returns `null` if no response with that ID exists.
54
+ * @param id Response ID
55
+ */
56
+ getResponse(id: string): IGeneratorResponse | null;
57
+ /**
58
+ * Cancel an in-progress generation and resolve any waiting hooks.
59
+ * @param id Response ID to cancel
60
+ * @returns `true` if the response was found and cancelled, otherwise `false`
61
+ */
62
+ cancel(id: string): boolean;
63
+ /**
64
+ * Put a response into "hooked" mode so generation pauses at the next chunk.
65
+ * @param id Response ID to hook
66
+ * @returns `true` if the response exists and was hooked, otherwise `false`
67
+ */
68
+ hook(id: string): boolean;
69
+ /**
70
+ * Resume a previously hooked response, releasing a single paused chunk.
71
+ * @param id Response ID to resume
72
+ * @returns `true` if the resume action was performed or the response is still hooked
73
+ */
74
+ resume(id: string): boolean;
75
+ /**
76
+ * Dispose all generators, clear queues and internal bookkeeping.
77
+ * This releases resources held by this Responses manager.
78
+ */
79
+ dispose(): void;
80
+ }
81
+ export {};
@@ -0,0 +1,169 @@
1
+ import { t as e } from "../eventemitter3-D_qV3Lof.js";
2
+ import t from "../inference/Generator.js";
3
+ import { t as n } from "../v4-BK7K-jy_.js";
4
+ //#region lib/api/responses.ts
5
+ var r = class {
6
+ ee;
7
+ _model;
8
+ _tokeniser;
9
+ _busyCount = 0;
10
+ _responses = /* @__PURE__ */ new Map();
11
+ _jobQueue = [];
12
+ _hookedResponses = /* @__PURE__ */ new Set();
13
+ _resumeWaiters = /* @__PURE__ */ new Map();
14
+ constructor(t, n) {
15
+ this._model = t, this._tokeniser = n, this.ee = new e();
16
+ }
17
+ get queued() {
18
+ return this._jobQueue.length;
19
+ }
20
+ async _processNextJob() {
21
+ if (this._jobQueue.length === 0) return;
22
+ let e = this._jobQueue.shift();
23
+ try {
24
+ let t = await this._runForRecord(e.id, e.options, e.callback);
25
+ e.resolve && e.resolve(t);
26
+ } catch (t) {
27
+ e.reject && e.reject(t), this.ee.emit("error", t);
28
+ }
29
+ }
30
+ async _runForRecord(e, t, n) {
31
+ let r = t.previous_response_id ? this._responses.get(t.previous_response_id) : void 0;
32
+ if (r) {
33
+ let e = r.generator.getConversation();
34
+ t.input && Array.isArray(t.input) ? t.input = [...e, ...t.input] : t.input && typeof t.input == "string" ? t.input = [...e, {
35
+ role: t.nonConversational ? "text" : "user",
36
+ content: t.input
37
+ }] : t.input = e;
38
+ }
39
+ let i = r ? r.generator : this._responses.get(e).generator, a = n ? () => n({
40
+ output: i.getConversation(),
41
+ id: e,
42
+ done: !1
43
+ }) : null;
44
+ a && i.on("tokens", a);
45
+ let o = this._responses.get(e), s = {
46
+ ...t,
47
+ _onChunk: async () => {
48
+ this._hookedResponses.has(e) && await new Promise((t) => {
49
+ let n = this._resumeWaiters.get(e) || [];
50
+ n.push(t), this._resumeWaiters.set(e, n), this.ee.emit("hook", e);
51
+ });
52
+ }
53
+ };
54
+ this.ee.emit("generating", t.previous_response_id || e);
55
+ let c = t.input ? i.generate(Array.isArray(t.input) ? t.input : [{
56
+ role: t.nonConversational ? "text" : "user",
57
+ content: t.input
58
+ }], s) : i.generate(s);
59
+ if (t.background) return c.then(() => {
60
+ o.done = !0, this._hookedResponses.delete(e), this._resumeWaiters.delete(e), a && i.off("tokens", a), this.ee.emit("done", e), this._processNextJob();
61
+ }), {
62
+ output: null,
63
+ id: e,
64
+ done: !1
65
+ };
66
+ let l = await c;
67
+ return a && i.off("tokens", a), o.done = !0, this._hookedResponses.delete(e), this._resumeWaiters.delete(e), this.ee.emit("done", e), this._processNextJob(), {
68
+ output: l,
69
+ id: e,
70
+ done: !0
71
+ };
72
+ }
73
+ on(e, t) {
74
+ this.ee.on(e, t);
75
+ }
76
+ off(e, t) {
77
+ this.ee.off(e, t);
78
+ }
79
+ generator() {
80
+ if (!this._model || !this._tokeniser) throw Error("model_or_tokeniser_not_initialized.");
81
+ let e = new t(this._model, this._tokeniser);
82
+ return e.on("start", () => {
83
+ this._busyCount === 0 && this.ee.emit("status", "busy"), this._busyCount++;
84
+ }), e.on("stop", () => {
85
+ this._busyCount--, this._busyCount === 0 && this.ee.emit("status", "ready");
86
+ }), e;
87
+ }
88
+ _cleanup() {
89
+ let e = Date.now();
90
+ this._responses.forEach((t, n) => {
91
+ t.done && e - t.timestamp > 300 * 1e3 && (t.generator.dispose(), this._responses.delete(n));
92
+ });
93
+ }
94
+ async create(e, t) {
95
+ let r = n(), i = e.previous_response_id ? this._responses.get(e.previous_response_id) : void 0;
96
+ i ? i.timestamp = Date.now() : this._cleanup();
97
+ let a = {
98
+ id: r,
99
+ generator: i ? i.generator : this.generator(),
100
+ done: !1,
101
+ timestamp: Date.now(),
102
+ options: e,
103
+ callback: t
104
+ };
105
+ if (this._responses.set(r, a), this._busyCount > 0 && !e.background) {
106
+ if (this._jobQueue.length > 10) throw Error("Job queue is too long, rejecting new job");
107
+ return new Promise((n, i) => {
108
+ this._jobQueue.push({
109
+ id: r,
110
+ options: e,
111
+ callback: t,
112
+ resolve: n,
113
+ reject: i
114
+ });
115
+ });
116
+ }
117
+ return this._runForRecord(r, e, t);
118
+ }
119
+ async retry(e, t) {
120
+ let n = this._responses.get(e);
121
+ if (n) {
122
+ let r = n.generator.getConversation();
123
+ if (t !== void 0 && t >= 0 && t < r.length && r.splice(t), n.done = !1, n.timestamp = Date.now(), this._busyCount > 0 && !n.options.background) {
124
+ if (this._jobQueue.length > 10) throw Error("Job queue is too long, rejecting new job");
125
+ return new Promise((t, r) => {
126
+ this._jobQueue.push({
127
+ id: e,
128
+ options: n.options,
129
+ callback: n.callback,
130
+ resolve: t,
131
+ reject: r
132
+ });
133
+ });
134
+ }
135
+ return this._runForRecord(e, n.options, n.callback);
136
+ }
137
+ throw Error(`No response found for id: ${e}`);
138
+ }
139
+ getResponse(e) {
140
+ let t = this._responses.get(e);
141
+ return t ? {
142
+ output: t.generator.getConversation(),
143
+ id: t.id,
144
+ done: t.done
145
+ } : null;
146
+ }
147
+ cancel(e) {
148
+ let t = this._responses.get(e);
149
+ return t ? (this._hookedResponses.delete(e), (this._resumeWaiters.get(e) || []).forEach((e) => e()), this._resumeWaiters.delete(e), t.generator.stop(), !0) : !1;
150
+ }
151
+ hook(e) {
152
+ return this._responses.has(e) ? (this._hookedResponses.add(e), !0) : !1;
153
+ }
154
+ resume(e) {
155
+ let t = this._resumeWaiters.get(e);
156
+ if (!t || t.length === 0) return this._hookedResponses.has(e);
157
+ let n = t.shift();
158
+ return t.length === 0 && this._resumeWaiters.delete(e), n(), !0;
159
+ }
160
+ dispose() {
161
+ this._resumeWaiters.forEach((e) => {
162
+ e.forEach((e) => e());
163
+ }), this._resumeWaiters.clear(), this._hookedResponses.clear(), this._responses.forEach((e) => {
164
+ e.generator.dispose();
165
+ }), this._responses.clear(), this.ee.removeAllListeners();
166
+ }
167
+ };
168
+ //#endregion
169
+ export { r as default };
@@ -0,0 +1,70 @@
1
+ import { ITokeniser } from '../../tokeniser/type';
2
+ import { default as Model, ModelForwardAttributes } from '../../models/model';
3
+ import { GPTConfig } from '../../models/config';
4
+ import { ConversationStream } from '../../data/stream';
5
+ import { TokenStore } from '../../training/tasks/TokenStore';
6
+ import { DatasetMetadata } from '../../loader/types';
7
+ import { TrainingLogEntry, TrainingOptions } from '../../training/types';
8
+ import { default as BasicTrainer } from '../../training/BasicTrainer';
9
+ import { Dataset } from '@tensorflow/tfjs-data';
10
+ import { Tensor } from '@tensorflow/tfjs-core';
11
+ import { AdamWOptimizer } from '../../training/AdamW';
12
+ export type TrainingState = 'pending' | 'running' | 'paused' | 'pausing' | 'completed' | 'cancelled' | 'cancelling' | 'error';
13
+ export interface ITrainingJob {
14
+ id: string;
15
+ state: TrainingState;
16
+ history: TrainingLogEntry[] | null;
17
+ progress: number;
18
+ remaining: number;
19
+ trainer: BasicTrainer;
20
+ options: TrainingOptions;
21
+ trainDataset?: Dataset<{
22
+ xs: Tensor;
23
+ ys: Tensor;
24
+ }>;
25
+ validationDataset?: Dataset<{
26
+ xs: Tensor;
27
+ ys: Tensor;
28
+ }>;
29
+ totalTokens: number;
30
+ datasets: DatasetMetadata[];
31
+ datasetId?: string;
32
+ breakOnLog: boolean;
33
+ }
34
+ interface TrainingEvents {
35
+ error: (id: string, error: Error) => void;
36
+ completed: (id: string) => void;
37
+ running: (id: string) => void;
38
+ paused: (id: string) => void;
39
+ cancelled: (id: string) => void;
40
+ pausing: (id: string) => void;
41
+ cancelling: (id: string) => void;
42
+ progress: (job: ITrainingJob) => void;
43
+ }
44
+ export default class Training {
45
+ private ee;
46
+ private _model;
47
+ private _tokeniser;
48
+ private _jobs;
49
+ constructor(model: Model<ModelForwardAttributes, GPTConfig>, tokeniser: ITokeniser);
50
+ private setState;
51
+ get activeJobs(): number;
52
+ get training(): boolean;
53
+ private assertValidJobId;
54
+ private assertValidOptions;
55
+ private assertValidDatasets;
56
+ private assertValidDataInput;
57
+ on<E extends keyof TrainingEvents>(event: E, listener: TrainingEvents[E]): void;
58
+ off<E extends keyof TrainingEvents>(event: E, listener: TrainingEvents[E]): void;
59
+ restore(options: TrainingOptions, log: TrainingLogEntry[], optimizer: AdamWOptimizer, datasets: DatasetMetadata[]): ITrainingJob;
60
+ private launchJob;
61
+ job(options: TrainingOptions, data: (ConversationStream[] | Uint16Array[] | TokenStore) | undefined, datasets: DatasetMetadata[], validation?: Uint16Array[] | TokenStore): Promise<ITrainingJob>;
62
+ getJob(id: string): ITrainingJob | null;
63
+ /** Resume a paused job and optionally change some options. */
64
+ resume(id: string): Promise<void>;
65
+ cancel(id: string): void;
66
+ breakpoints(id: string, enabled: boolean): void;
67
+ getPretrainingJob(): ITrainingJob | null;
68
+ dispose(): void;
69
+ }
70
+ export {};