modelfusion 0.115.0 → 0.116.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/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.116.0 - 2024-01-05
4
+
5
+ ### Added
6
+
7
+ - Semantic classifier. An easy way to determine a class of a text using embeddings. Example:
8
+
9
+ ```ts
10
+ import { SemanticClassifier, openai } from "modelfusion";
11
+
12
+ const classifier = new SemanticClassifier({
13
+ embeddingModel: openai.TextEmbedder({
14
+ model: "text-embedding-ada-002",
15
+ }),
16
+ similarityThreshold: 0.82,
17
+ clusters: [
18
+ {
19
+ name: "politics" as const,
20
+ values: [
21
+ "isn't politics the best thing ever",
22
+ "why don't you tell me about your political opinions",
23
+ "don't you just love the president",
24
+ "don't you just hate the president",
25
+ "they're going to destroy this country!",
26
+ "they will save the country!",
27
+ ],
28
+ },
29
+ {
30
+ name: "chitchat" as const,
31
+ values: [
32
+ "how's the weather today?",
33
+ "how are things going?",
34
+ "lovely weather today",
35
+ "the weather is horrendous",
36
+ "let's go to the chippy",
37
+ ],
38
+ },
39
+ ],
40
+ });
41
+
42
+ console.log(await classifier.classify("don't you love politics?")); // politics
43
+ console.log(await classifier.classify("how's the weather today?")); // chitchat
44
+ console.log(
45
+ await classifier.classify("I'm interested in learning about llama 2")
46
+ ); // null
47
+ ```
48
+
3
49
  ## v0.115.0 - 2024-01-05
4
50
 
5
51
  ### Removed
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SemanticClassifier = void 0;
4
+ const embed_js_1 = require("../model-function/embed/embed.cjs");
5
+ const cosineSimilarity_js_1 = require("../util/cosineSimilarity.cjs");
6
+ class SemanticClassifier {
7
+ constructor({ clusters, embeddingModel, similarityThreshold, }) {
8
+ Object.defineProperty(this, "clusters", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: void 0
13
+ });
14
+ Object.defineProperty(this, "embeddingModel", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: void 0
19
+ });
20
+ Object.defineProperty(this, "similarityThreshold", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: void 0
25
+ });
26
+ Object.defineProperty(this, "embeddings", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: void 0
31
+ });
32
+ this.clusters = clusters;
33
+ this.embeddingModel = embeddingModel;
34
+ this.similarityThreshold = similarityThreshold;
35
+ }
36
+ async getEmbeddings() {
37
+ if (this.embeddings != null) {
38
+ return this.embeddings;
39
+ }
40
+ const embeddings = [];
41
+ for (const cluster of this.clusters) {
42
+ const clusterEmbeddings = await (0, embed_js_1.embedMany)(this.embeddingModel, cluster.values);
43
+ for (let i = 0; i < clusterEmbeddings.length; i++) {
44
+ embeddings.push({
45
+ embedding: clusterEmbeddings[i],
46
+ clusterValue: cluster.values[i],
47
+ clusterName: cluster.name,
48
+ });
49
+ }
50
+ }
51
+ this.embeddings = embeddings; // lazy caching
52
+ return embeddings;
53
+ }
54
+ async classify(value) {
55
+ const valueEmbedding = await (0, embed_js_1.embed)(this.embeddingModel, value);
56
+ const clusterEmbeddings = await this.getEmbeddings();
57
+ const allMatches = [];
58
+ for (const embedding of clusterEmbeddings) {
59
+ const similarity = (0, cosineSimilarity_js_1.cosineSimilarity)(valueEmbedding, embedding.embedding);
60
+ if (similarity >= this.similarityThreshold) {
61
+ allMatches.push({
62
+ similarity,
63
+ clusterValue: embedding.clusterValue,
64
+ clusterName: embedding.clusterName,
65
+ });
66
+ }
67
+ }
68
+ // sort (highest similarity first)
69
+ allMatches.sort((a, b) => b.similarity - a.similarity);
70
+ return allMatches.length > 0
71
+ ? allMatches[0].clusterName
72
+ : null;
73
+ }
74
+ }
75
+ exports.SemanticClassifier = SemanticClassifier;
@@ -0,0 +1,25 @@
1
+ import { Vector } from "../core/Vector.js";
2
+ import { EmbeddingModel } from "../model-function/embed/EmbeddingModel.js";
3
+ export interface SemanticCluster<VALUE, NAME extends string> {
4
+ name: NAME;
5
+ values: VALUE[];
6
+ }
7
+ export declare class SemanticClassifier<VALUE, CLUSTERS extends Array<SemanticCluster<VALUE, string>>> {
8
+ readonly clusters: CLUSTERS;
9
+ readonly embeddingModel: EmbeddingModel<VALUE>;
10
+ readonly similarityThreshold: number;
11
+ private embeddings;
12
+ constructor({ clusters, embeddingModel, similarityThreshold, }: {
13
+ clusters: CLUSTERS;
14
+ embeddingModel: EmbeddingModel<VALUE>;
15
+ similarityThreshold: number;
16
+ });
17
+ getEmbeddings(): Promise<{
18
+ embedding: Vector;
19
+ clusterValue: VALUE;
20
+ clusterName: string;
21
+ }[]>;
22
+ classify(value: VALUE): Promise<ClusterNames<CLUSTERS> | null>;
23
+ }
24
+ type ClusterNames<CLUSTERS> = CLUSTERS extends Array<SemanticCluster<unknown, infer NAME>> ? NAME : never;
25
+ export {};
@@ -0,0 +1,71 @@
1
+ import { embed, embedMany } from "../model-function/embed/embed.js";
2
+ import { cosineSimilarity } from "../util/cosineSimilarity.js";
3
+ export class SemanticClassifier {
4
+ constructor({ clusters, embeddingModel, similarityThreshold, }) {
5
+ Object.defineProperty(this, "clusters", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ Object.defineProperty(this, "embeddingModel", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ Object.defineProperty(this, "similarityThreshold", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ Object.defineProperty(this, "embeddings", {
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true,
27
+ value: void 0
28
+ });
29
+ this.clusters = clusters;
30
+ this.embeddingModel = embeddingModel;
31
+ this.similarityThreshold = similarityThreshold;
32
+ }
33
+ async getEmbeddings() {
34
+ if (this.embeddings != null) {
35
+ return this.embeddings;
36
+ }
37
+ const embeddings = [];
38
+ for (const cluster of this.clusters) {
39
+ const clusterEmbeddings = await embedMany(this.embeddingModel, cluster.values);
40
+ for (let i = 0; i < clusterEmbeddings.length; i++) {
41
+ embeddings.push({
42
+ embedding: clusterEmbeddings[i],
43
+ clusterValue: cluster.values[i],
44
+ clusterName: cluster.name,
45
+ });
46
+ }
47
+ }
48
+ this.embeddings = embeddings; // lazy caching
49
+ return embeddings;
50
+ }
51
+ async classify(value) {
52
+ const valueEmbedding = await embed(this.embeddingModel, value);
53
+ const clusterEmbeddings = await this.getEmbeddings();
54
+ const allMatches = [];
55
+ for (const embedding of clusterEmbeddings) {
56
+ const similarity = cosineSimilarity(valueEmbedding, embedding.embedding);
57
+ if (similarity >= this.similarityThreshold) {
58
+ allMatches.push({
59
+ similarity,
60
+ clusterValue: embedding.clusterValue,
61
+ clusterName: embedding.clusterName,
62
+ });
63
+ }
64
+ }
65
+ // sort (highest similarity first)
66
+ allMatches.sort((a, b) => b.similarity - a.similarity);
67
+ return allMatches.length > 0
68
+ ? allMatches[0].clusterName
69
+ : null;
70
+ }
71
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./SemanticClassifier.cjs"), exports);
@@ -0,0 +1 @@
1
+ export * from "./SemanticClassifier.js";
@@ -0,0 +1 @@
1
+ export * from "./SemanticClassifier.js";
package/index.cjs CHANGED
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./classifier/index.cjs"), exports);
17
18
  __exportStar(require("./core/index.cjs"), exports);
18
19
  __exportStar(require("./model-function/index.cjs"), exports);
19
20
  __exportStar(require("./model-provider/index.cjs"), exports);
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./classifier/index.js";
1
2
  export * from "./core/index.js";
2
3
  export * from "./model-function/index.js";
3
4
  export * from "./model-provider/index.js";
package/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./classifier/index.js";
1
2
  export * from "./core/index.js";
2
3
  export * from "./model-function/index.js";
3
4
  export * from "./model-provider/index.js";
@@ -32,16 +32,16 @@ export declare class MistralTextEmbeddingModel extends AbstractModel<MistralText
32
32
  doEmbedValues(texts: string[], options: FunctionCallOptions): Promise<{
33
33
  response: {
34
34
  object: string;
35
- data: {
36
- object: string;
37
- embedding: number[];
38
- index: number;
39
- }[];
40
35
  model: string;
41
36
  usage: {
42
37
  prompt_tokens: number;
43
38
  total_tokens: number;
44
39
  };
40
+ data: {
41
+ object: string;
42
+ embedding: number[];
43
+ index: number;
44
+ }[];
45
45
  id: string;
46
46
  };
47
47
  embeddings: number[][];
@@ -77,29 +77,29 @@ declare const MistralTextEmbeddingResponseSchema: z.ZodObject<{
77
77
  }>;
78
78
  }, "strip", z.ZodTypeAny, {
79
79
  object: string;
80
- data: {
81
- object: string;
82
- embedding: number[];
83
- index: number;
84
- }[];
85
80
  model: string;
86
81
  usage: {
87
82
  prompt_tokens: number;
88
83
  total_tokens: number;
89
84
  };
90
- id: string;
91
- }, {
92
- object: string;
93
85
  data: {
94
86
  object: string;
95
87
  embedding: number[];
96
88
  index: number;
97
89
  }[];
90
+ id: string;
91
+ }, {
92
+ object: string;
98
93
  model: string;
99
94
  usage: {
100
95
  prompt_tokens: number;
101
96
  total_tokens: number;
102
97
  };
98
+ data: {
99
+ object: string;
100
+ embedding: number[];
101
+ index: number;
102
+ }[];
103
103
  id: string;
104
104
  }>;
105
105
  export type MistralTextEmbeddingResponse = z.infer<typeof MistralTextEmbeddingResponseSchema>;
@@ -40,11 +40,11 @@ export declare class OllamaChatModel extends AbstractModel<OllamaChatModelSettin
40
40
  get settingsForEvent(): Partial<OllamaChatModelSettings>;
41
41
  doGenerateTexts(prompt: OllamaChatPrompt, options: FunctionCallOptions): Promise<{
42
42
  response: {
43
+ model: string;
43
44
  message: {
44
45
  role: string;
45
46
  content: string;
46
47
  };
47
- model: string;
48
48
  done: true;
49
49
  created_at: string;
50
50
  total_duration: number;
@@ -61,11 +61,11 @@ export declare class OllamaChatModel extends AbstractModel<OllamaChatModelSettin
61
61
  }>;
62
62
  restoreGeneratedTexts(rawResponse: unknown): {
63
63
  response: {
64
+ model: string;
64
65
  message: {
65
66
  role: string;
66
67
  content: string;
67
68
  };
68
- model: string;
69
69
  done: true;
70
70
  created_at: string;
71
71
  total_duration: number;
@@ -82,11 +82,11 @@ export declare class OllamaChatModel extends AbstractModel<OllamaChatModelSettin
82
82
  };
83
83
  private processTextGenerationResponse;
84
84
  doStreamText(prompt: OllamaChatPrompt, options: FunctionCallOptions): Promise<AsyncIterable<import("../../index.js").Delta<{
85
+ model: string;
85
86
  message: {
86
87
  role: string;
87
88
  content: string;
88
89
  };
89
- model: string;
90
90
  done: false;
91
91
  created_at: string;
92
92
  } | {
@@ -141,11 +141,11 @@ declare const ollamaChatResponseSchema: z.ZodObject<{
141
141
  eval_count: z.ZodNumber;
142
142
  eval_duration: z.ZodNumber;
143
143
  }, "strip", z.ZodTypeAny, {
144
+ model: string;
144
145
  message: {
145
146
  role: string;
146
147
  content: string;
147
148
  };
148
- model: string;
149
149
  done: true;
150
150
  created_at: string;
151
151
  total_duration: number;
@@ -155,11 +155,11 @@ declare const ollamaChatResponseSchema: z.ZodObject<{
155
155
  load_duration?: number | undefined;
156
156
  prompt_eval_duration?: number | undefined;
157
157
  }, {
158
+ model: string;
158
159
  message: {
159
160
  role: string;
160
161
  content: string;
161
162
  };
162
- model: string;
163
163
  done: true;
164
164
  created_at: string;
165
165
  total_duration: number;
@@ -185,19 +185,19 @@ declare const ollamaChatStreamChunkSchema: z.ZodDiscriminatedUnion<"done", [z.Zo
185
185
  content: string;
186
186
  }>;
187
187
  }, "strip", z.ZodTypeAny, {
188
+ model: string;
188
189
  message: {
189
190
  role: string;
190
191
  content: string;
191
192
  };
192
- model: string;
193
193
  done: false;
194
194
  created_at: string;
195
195
  }, {
196
+ model: string;
196
197
  message: {
197
198
  role: string;
198
199
  content: string;
199
200
  };
200
- model: string;
201
201
  done: false;
202
202
  created_at: string;
203
203
  }>, z.ZodObject<{
@@ -247,11 +247,11 @@ export declare const OllamaChatResponseFormat: {
247
247
  requestBodyValues: unknown;
248
248
  response: Response;
249
249
  }) => Promise<{
250
+ model: string;
250
251
  message: {
251
252
  role: string;
252
253
  content: string;
253
254
  };
254
- model: string;
255
255
  done: true;
256
256
  created_at: string;
257
257
  total_duration: number;
@@ -271,11 +271,11 @@ export declare const OllamaChatResponseFormat: {
271
271
  handler: ({ response }: {
272
272
  response: Response;
273
273
  }) => Promise<AsyncIterable<import("../../index.js").Delta<{
274
+ model: string;
274
275
  message: {
275
276
  role: string;
276
277
  content: string;
277
278
  };
278
- model: string;
279
279
  done: false;
280
280
  created_at: string;
281
281
  } | {
@@ -52,16 +52,16 @@ export declare class OpenAITextEmbeddingModel extends AbstractModel<OpenAITextEm
52
52
  doEmbedValues(texts: string[], callOptions: FunctionCallOptions): Promise<{
53
53
  response: {
54
54
  object: "list";
55
- data: {
56
- object: "embedding";
57
- embedding: number[];
58
- index: number;
59
- }[];
60
55
  model: string;
61
56
  usage: {
62
57
  prompt_tokens: number;
63
58
  total_tokens: number;
64
59
  };
60
+ data: {
61
+ object: "embedding";
62
+ embedding: number[];
63
+ index: number;
64
+ }[];
65
65
  };
66
66
  embeddings: number[][];
67
67
  }>;
@@ -95,28 +95,28 @@ declare const openAITextEmbeddingResponseSchema: z.ZodObject<{
95
95
  }>;
96
96
  }, "strip", z.ZodTypeAny, {
97
97
  object: "list";
98
- data: {
99
- object: "embedding";
100
- embedding: number[];
101
- index: number;
102
- }[];
103
98
  model: string;
104
99
  usage: {
105
100
  prompt_tokens: number;
106
101
  total_tokens: number;
107
102
  };
108
- }, {
109
- object: "list";
110
103
  data: {
111
104
  object: "embedding";
112
105
  embedding: number[];
113
106
  index: number;
114
107
  }[];
108
+ }, {
109
+ object: "list";
115
110
  model: string;
116
111
  usage: {
117
112
  prompt_tokens: number;
118
113
  total_tokens: number;
119
114
  };
115
+ data: {
116
+ object: "embedding";
117
+ embedding: number[];
118
+ index: number;
119
+ }[];
120
120
  }>;
121
121
  export type OpenAITextEmbeddingResponse = z.infer<typeof openAITextEmbeddingResponseSchema>;
122
122
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modelfusion",
3
3
  "description": "The TypeScript library for building AI applications.",
4
- "version": "0.115.0",
4
+ "version": "0.116.1",
5
5
  "author": "Lars Grammel",
6
6
  "license": "MIT",
7
7
  "keywords": [