@hazeljs/ai 0.2.0-beta.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/README.md +496 -0
- package/dist/ai-enhanced.service.d.ts +108 -0
- package/dist/ai-enhanced.service.d.ts.map +1 -0
- package/dist/ai-enhanced.service.js +345 -0
- package/dist/ai-enhanced.types.d.ts +269 -0
- package/dist/ai-enhanced.types.d.ts.map +1 -0
- package/dist/ai-enhanced.types.js +2 -0
- package/dist/ai.decorator.d.ts +4 -0
- package/dist/ai.decorator.d.ts.map +1 -0
- package/dist/ai.decorator.js +57 -0
- package/dist/ai.module.d.ts +12 -0
- package/dist/ai.module.d.ts.map +1 -0
- package/dist/ai.module.js +44 -0
- package/dist/ai.service.d.ts +10 -0
- package/dist/ai.service.d.ts.map +1 -0
- package/dist/ai.service.js +261 -0
- package/dist/ai.types.d.ts +30 -0
- package/dist/ai.types.d.ts.map +1 -0
- package/dist/ai.types.js +2 -0
- package/dist/context/context.manager.d.ts +69 -0
- package/dist/context/context.manager.d.ts.map +1 -0
- package/dist/context/context.manager.js +168 -0
- package/dist/decorators/ai-function.decorator.d.ts +42 -0
- package/dist/decorators/ai-function.decorator.d.ts.map +1 -0
- package/dist/decorators/ai-function.decorator.js +80 -0
- package/dist/decorators/ai-validate.decorator.d.ts +46 -0
- package/dist/decorators/ai-validate.decorator.d.ts.map +1 -0
- package/dist/decorators/ai-validate.decorator.js +83 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/providers/anthropic.provider.d.ts +48 -0
- package/dist/providers/anthropic.provider.d.ts.map +1 -0
- package/dist/providers/anthropic.provider.js +194 -0
- package/dist/providers/cohere.provider.d.ts +57 -0
- package/dist/providers/cohere.provider.d.ts.map +1 -0
- package/dist/providers/cohere.provider.js +230 -0
- package/dist/providers/gemini.provider.d.ts +45 -0
- package/dist/providers/gemini.provider.d.ts.map +1 -0
- package/dist/providers/gemini.provider.js +180 -0
- package/dist/providers/ollama.provider.d.ts +45 -0
- package/dist/providers/ollama.provider.d.ts.map +1 -0
- package/dist/providers/ollama.provider.js +232 -0
- package/dist/providers/openai.provider.d.ts +47 -0
- package/dist/providers/openai.provider.d.ts.map +1 -0
- package/dist/providers/openai.provider.js +273 -0
- package/dist/tracking/token.tracker.d.ts +72 -0
- package/dist/tracking/token.tracker.d.ts.map +1 -0
- package/dist/tracking/token.tracker.js +222 -0
- package/dist/vector/vector.service.d.ts +50 -0
- package/dist/vector/vector.service.d.ts.map +1 -0
- package/dist/vector/vector.service.js +163 -0
- package/package.json +52 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.TokenTracker = void 0;
|
|
16
|
+
const core_1 = require("@hazeljs/core");
|
|
17
|
+
const core_2 = __importDefault(require("@hazeljs/core"));
|
|
18
|
+
/**
|
|
19
|
+
* Token Usage Tracker
|
|
20
|
+
* Tracks and limits token usage per user/request
|
|
21
|
+
*/
|
|
22
|
+
let TokenTracker = class TokenTracker {
|
|
23
|
+
constructor(config) {
|
|
24
|
+
this.usageHistory = [];
|
|
25
|
+
this.userUsage = new Map();
|
|
26
|
+
// Token costs per 1K tokens (as of 2024)
|
|
27
|
+
this.TOKEN_COSTS = {
|
|
28
|
+
'gpt-4-turbo-preview': { prompt: 0.01, completion: 0.03 },
|
|
29
|
+
'gpt-4': { prompt: 0.03, completion: 0.06 },
|
|
30
|
+
'gpt-3.5-turbo': { prompt: 0.0005, completion: 0.0015 },
|
|
31
|
+
'claude-3-opus': { prompt: 0.015, completion: 0.075 },
|
|
32
|
+
'claude-3-sonnet': { prompt: 0.003, completion: 0.015 },
|
|
33
|
+
'claude-3-haiku': { prompt: 0.00025, completion: 0.00125 },
|
|
34
|
+
};
|
|
35
|
+
this.config = {
|
|
36
|
+
maxTokensPerRequest: config?.maxTokensPerRequest || 4096,
|
|
37
|
+
maxTokensPerDay: config?.maxTokensPerDay || 100000,
|
|
38
|
+
maxTokensPerMonth: config?.maxTokensPerMonth || 1000000,
|
|
39
|
+
costPerToken: config?.costPerToken,
|
|
40
|
+
};
|
|
41
|
+
core_2.default.info('Token Tracker initialized', this.config);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Track token usage
|
|
45
|
+
*/
|
|
46
|
+
track(usage, model) {
|
|
47
|
+
// Calculate cost if not provided
|
|
48
|
+
if (!usage.cost && model) {
|
|
49
|
+
usage.cost = this.calculateCost(usage, model);
|
|
50
|
+
}
|
|
51
|
+
this.usageHistory.push(usage);
|
|
52
|
+
// Track per user if userId provided
|
|
53
|
+
if (usage.userId) {
|
|
54
|
+
const userHistory = this.userUsage.get(usage.userId) || [];
|
|
55
|
+
userHistory.push(usage);
|
|
56
|
+
this.userUsage.set(usage.userId, userHistory);
|
|
57
|
+
}
|
|
58
|
+
core_2.default.debug('Token usage tracked', {
|
|
59
|
+
userId: usage.userId,
|
|
60
|
+
totalTokens: usage.totalTokens,
|
|
61
|
+
cost: usage.cost,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if request is within limits
|
|
66
|
+
*/
|
|
67
|
+
async checkLimits(userId, requestTokens) {
|
|
68
|
+
// Check request token limit
|
|
69
|
+
if (requestTokens && requestTokens > this.config.maxTokensPerRequest) {
|
|
70
|
+
return {
|
|
71
|
+
allowed: false,
|
|
72
|
+
reason: `Request exceeds token limit (${requestTokens} > ${this.config.maxTokensPerRequest})`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (!userId) {
|
|
76
|
+
return { allowed: true };
|
|
77
|
+
}
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
const oneDayAgo = now - 24 * 60 * 60 * 1000;
|
|
80
|
+
const oneMonthAgo = now - 30 * 24 * 60 * 60 * 1000;
|
|
81
|
+
const userHistory = this.userUsage.get(userId) || [];
|
|
82
|
+
// Calculate daily usage
|
|
83
|
+
const dailyUsage = userHistory
|
|
84
|
+
.filter((u) => u.timestamp > oneDayAgo)
|
|
85
|
+
.reduce((sum, u) => sum + u.totalTokens, 0);
|
|
86
|
+
// Calculate monthly usage
|
|
87
|
+
const monthlyUsage = userHistory
|
|
88
|
+
.filter((u) => u.timestamp > oneMonthAgo)
|
|
89
|
+
.reduce((sum, u) => sum + u.totalTokens, 0);
|
|
90
|
+
const usage = {
|
|
91
|
+
today: dailyUsage,
|
|
92
|
+
month: monthlyUsage,
|
|
93
|
+
limit: {
|
|
94
|
+
daily: this.config.maxTokensPerDay,
|
|
95
|
+
monthly: this.config.maxTokensPerMonth,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
// Check daily limit
|
|
99
|
+
if (dailyUsage >= this.config.maxTokensPerDay) {
|
|
100
|
+
return {
|
|
101
|
+
allowed: false,
|
|
102
|
+
reason: 'Daily token limit exceeded',
|
|
103
|
+
usage,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// Check monthly limit
|
|
107
|
+
if (monthlyUsage >= this.config.maxTokensPerMonth) {
|
|
108
|
+
return {
|
|
109
|
+
allowed: false,
|
|
110
|
+
reason: 'Monthly token limit exceeded',
|
|
111
|
+
usage,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return { allowed: true, usage };
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Calculate cost for token usage
|
|
118
|
+
*/
|
|
119
|
+
calculateCost(usage, model) {
|
|
120
|
+
const costs = this.TOKEN_COSTS[model];
|
|
121
|
+
if (!costs) {
|
|
122
|
+
core_2.default.warn(`Unknown model for cost calculation: ${model}`);
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
const promptCost = (usage.promptTokens / 1000) * costs.prompt;
|
|
126
|
+
const completionCost = (usage.completionTokens / 1000) * costs.completion;
|
|
127
|
+
return promptCost + completionCost;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get usage statistics for a user
|
|
131
|
+
*/
|
|
132
|
+
getUserStats(userId, days = 30) {
|
|
133
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
|
|
134
|
+
const userHistory = (this.userUsage.get(userId) || []).filter((u) => u.timestamp > cutoff);
|
|
135
|
+
const totalTokens = userHistory.reduce((sum, u) => sum + u.totalTokens, 0);
|
|
136
|
+
const totalCost = userHistory.reduce((sum, u) => sum + (u.cost || 0), 0);
|
|
137
|
+
const requestCount = userHistory.length;
|
|
138
|
+
return {
|
|
139
|
+
totalTokens,
|
|
140
|
+
totalCost,
|
|
141
|
+
requestCount,
|
|
142
|
+
averageTokensPerRequest: requestCount > 0 ? Math.round(totalTokens / requestCount) : 0,
|
|
143
|
+
dailyAverage: Math.round(totalTokens / days),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get global statistics
|
|
148
|
+
*/
|
|
149
|
+
getGlobalStats(days = 30) {
|
|
150
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
|
|
151
|
+
const recentUsage = this.usageHistory.filter((u) => u.timestamp > cutoff);
|
|
152
|
+
const totalTokens = recentUsage.reduce((sum, u) => sum + u.totalTokens, 0);
|
|
153
|
+
const totalCost = recentUsage.reduce((sum, u) => sum + (u.cost || 0), 0);
|
|
154
|
+
const requestCount = recentUsage.length;
|
|
155
|
+
// Calculate per-user stats
|
|
156
|
+
const userStats = new Map();
|
|
157
|
+
recentUsage.forEach((u) => {
|
|
158
|
+
if (u.userId) {
|
|
159
|
+
const stats = userStats.get(u.userId) || { tokens: 0, cost: 0 };
|
|
160
|
+
stats.tokens += u.totalTokens;
|
|
161
|
+
stats.cost += u.cost || 0;
|
|
162
|
+
userStats.set(u.userId, stats);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
// Get top users
|
|
166
|
+
const topUsers = Array.from(userStats.entries())
|
|
167
|
+
.map(([userId, stats]) => ({
|
|
168
|
+
userId,
|
|
169
|
+
tokens: stats.tokens,
|
|
170
|
+
cost: stats.cost,
|
|
171
|
+
}))
|
|
172
|
+
.sort((a, b) => b.tokens - a.tokens)
|
|
173
|
+
.slice(0, 10);
|
|
174
|
+
return {
|
|
175
|
+
totalTokens,
|
|
176
|
+
totalCost,
|
|
177
|
+
requestCount,
|
|
178
|
+
uniqueUsers: userStats.size,
|
|
179
|
+
topUsers,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Clear old usage data
|
|
184
|
+
*/
|
|
185
|
+
cleanup(daysToKeep = 90) {
|
|
186
|
+
const cutoff = Date.now() - daysToKeep * 24 * 60 * 60 * 1000;
|
|
187
|
+
// Clean global history
|
|
188
|
+
this.usageHistory = this.usageHistory.filter((u) => u.timestamp > cutoff);
|
|
189
|
+
// Clean per-user history
|
|
190
|
+
for (const [userId, history] of this.userUsage.entries()) {
|
|
191
|
+
const filtered = history.filter((u) => u.timestamp > cutoff);
|
|
192
|
+
if (filtered.length === 0) {
|
|
193
|
+
this.userUsage.delete(userId);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
this.userUsage.set(userId, filtered);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
core_2.default.info(`Cleaned up usage data older than ${daysToKeep} days`);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Export usage data
|
|
203
|
+
*/
|
|
204
|
+
exportData(userId) {
|
|
205
|
+
if (userId) {
|
|
206
|
+
return this.userUsage.get(userId) || [];
|
|
207
|
+
}
|
|
208
|
+
return [...this.usageHistory];
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Update configuration
|
|
212
|
+
*/
|
|
213
|
+
updateConfig(config) {
|
|
214
|
+
this.config = { ...this.config, ...config };
|
|
215
|
+
core_2.default.info('Token tracker configuration updated', this.config);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
exports.TokenTracker = TokenTracker;
|
|
219
|
+
exports.TokenTracker = TokenTracker = __decorate([
|
|
220
|
+
(0, core_1.Injectable)(),
|
|
221
|
+
__metadata("design:paramtypes", [Object])
|
|
222
|
+
], TokenTracker);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { VectorStoreConfig, VectorDocument, VectorSearchRequest, VectorSearchResult, VectorDatabase } from '../ai-enhanced.types';
|
|
2
|
+
/**
|
|
3
|
+
* Vector database service
|
|
4
|
+
*
|
|
5
|
+
* Note: This is a mock implementation. In production, you would use actual vector database clients:
|
|
6
|
+
* - Pinecone: npm install @pinecone-database/pinecone
|
|
7
|
+
* - Weaviate: npm install weaviate-ts-client
|
|
8
|
+
* - Qdrant: npm install @qdrant/js-client-rest
|
|
9
|
+
* - Chroma: npm install chromadb
|
|
10
|
+
*/
|
|
11
|
+
export declare class VectorService {
|
|
12
|
+
private config?;
|
|
13
|
+
private documents;
|
|
14
|
+
/**
|
|
15
|
+
* Initialize vector store
|
|
16
|
+
*/
|
|
17
|
+
initialize(config: VectorStoreConfig): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Upsert documents
|
|
20
|
+
*/
|
|
21
|
+
upsert(documents: VectorDocument[]): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Search for similar documents
|
|
24
|
+
*/
|
|
25
|
+
search(request: VectorSearchRequest): Promise<VectorSearchResult[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Delete documents
|
|
28
|
+
*/
|
|
29
|
+
delete(ids: string[]): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Get document by ID
|
|
32
|
+
*/
|
|
33
|
+
get(id: string): Promise<VectorDocument | null>;
|
|
34
|
+
/**
|
|
35
|
+
* Clear all documents
|
|
36
|
+
*/
|
|
37
|
+
clear(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Get statistics
|
|
40
|
+
*/
|
|
41
|
+
getStats(): Promise<{
|
|
42
|
+
count: number;
|
|
43
|
+
database: VectorDatabase;
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Calculate cosine similarity between two vectors
|
|
47
|
+
*/
|
|
48
|
+
private cosineSimilarity;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=vector.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector.service.d.ts","sourceRoot":"","sources":["../../src/vector/vector.service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACf,MAAM,sBAAsB,CAAC;AAI9B;;;;;;;;GAQG;AACH,qBACa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,CAAoB;IACnC,OAAO,CAAC,SAAS,CAA0C;IAE3D;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB1D;;OAEG;IACG,MAAM,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBxD;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAoCzE;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAa1C;;OAEG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAQrD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,cAAc,CAAA;KAAE,CAAC;IAWtE;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAiBzB"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.VectorService = void 0;
|
|
13
|
+
const core_1 = require("@hazeljs/core");
|
|
14
|
+
const core_2 = __importDefault(require("@hazeljs/core"));
|
|
15
|
+
/**
|
|
16
|
+
* Vector database service
|
|
17
|
+
*
|
|
18
|
+
* Note: This is a mock implementation. In production, you would use actual vector database clients:
|
|
19
|
+
* - Pinecone: npm install @pinecone-database/pinecone
|
|
20
|
+
* - Weaviate: npm install weaviate-ts-client
|
|
21
|
+
* - Qdrant: npm install @qdrant/js-client-rest
|
|
22
|
+
* - Chroma: npm install chromadb
|
|
23
|
+
*/
|
|
24
|
+
let VectorService = class VectorService {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.documents = new Map();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Initialize vector store
|
|
30
|
+
*/
|
|
31
|
+
async initialize(config) {
|
|
32
|
+
this.config = config;
|
|
33
|
+
core_2.default.info(`Vector store initialized: ${config.database}`);
|
|
34
|
+
// In production, initialize the actual vector database client
|
|
35
|
+
// switch (config.database) {
|
|
36
|
+
// case 'pinecone':
|
|
37
|
+
// this.client = new PineconeClient();
|
|
38
|
+
// await this.client.init({ apiKey: config.apiKey });
|
|
39
|
+
// break;
|
|
40
|
+
// case 'weaviate':
|
|
41
|
+
// this.client = weaviate.client({ scheme: 'https', host: config.endpoint });
|
|
42
|
+
// break;
|
|
43
|
+
// // ... other databases
|
|
44
|
+
// }
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Upsert documents
|
|
48
|
+
*/
|
|
49
|
+
async upsert(documents) {
|
|
50
|
+
core_2.default.debug(`Upserting ${documents.length} documents`);
|
|
51
|
+
for (const doc of documents) {
|
|
52
|
+
// Generate mock embedding if not provided
|
|
53
|
+
if (!doc.embedding) {
|
|
54
|
+
doc.embedding = Array.from({ length: 1536 }, () => Math.random() * 2 - 1);
|
|
55
|
+
}
|
|
56
|
+
this.documents.set(doc.id, doc);
|
|
57
|
+
}
|
|
58
|
+
// In production:
|
|
59
|
+
// await this.client.upsert({
|
|
60
|
+
// vectors: documents.map(doc => ({
|
|
61
|
+
// id: doc.id,
|
|
62
|
+
// values: doc.embedding,
|
|
63
|
+
// metadata: { content: doc.content, ...doc.metadata },
|
|
64
|
+
// })),
|
|
65
|
+
// });
|
|
66
|
+
core_2.default.info(`Upserted ${documents.length} documents`);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Search for similar documents
|
|
70
|
+
*/
|
|
71
|
+
async search(request) {
|
|
72
|
+
core_2.default.debug(`Searching for: ${request.query}`);
|
|
73
|
+
// Mock implementation - generate random query embedding
|
|
74
|
+
const queryEmbedding = Array.from({ length: 1536 }, () => Math.random() * 2 - 1);
|
|
75
|
+
// Calculate cosine similarity for all documents
|
|
76
|
+
const results = [];
|
|
77
|
+
for (const [id, doc] of this.documents) {
|
|
78
|
+
if (doc.embedding) {
|
|
79
|
+
const score = this.cosineSimilarity(queryEmbedding, doc.embedding);
|
|
80
|
+
results.push({
|
|
81
|
+
id,
|
|
82
|
+
content: doc.content,
|
|
83
|
+
score,
|
|
84
|
+
metadata: doc.metadata,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Sort by score and return top K
|
|
89
|
+
results.sort((a, b) => b.score - a.score);
|
|
90
|
+
const topK = request.topK || 10;
|
|
91
|
+
// In production:
|
|
92
|
+
// const response = await this.client.query({
|
|
93
|
+
// vector: queryEmbedding,
|
|
94
|
+
// topK: request.topK || 10,
|
|
95
|
+
// filter: request.filter,
|
|
96
|
+
// });
|
|
97
|
+
core_2.default.info(`Found ${results.length} results`);
|
|
98
|
+
return results.slice(0, topK);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Delete documents
|
|
102
|
+
*/
|
|
103
|
+
async delete(ids) {
|
|
104
|
+
core_2.default.debug(`Deleting ${ids.length} documents`);
|
|
105
|
+
for (const id of ids) {
|
|
106
|
+
this.documents.delete(id);
|
|
107
|
+
}
|
|
108
|
+
// In production:
|
|
109
|
+
// await this.client.delete({ ids });
|
|
110
|
+
core_2.default.info(`Deleted ${ids.length} documents`);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get document by ID
|
|
114
|
+
*/
|
|
115
|
+
async get(id) {
|
|
116
|
+
return this.documents.get(id) || null;
|
|
117
|
+
// In production:
|
|
118
|
+
// const response = await this.client.fetch({ ids: [id] });
|
|
119
|
+
// return response.vectors[id];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Clear all documents
|
|
123
|
+
*/
|
|
124
|
+
async clear() {
|
|
125
|
+
this.documents.clear();
|
|
126
|
+
core_2.default.info('All documents cleared');
|
|
127
|
+
// In production:
|
|
128
|
+
// await this.client.deleteAll();
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get statistics
|
|
132
|
+
*/
|
|
133
|
+
async getStats() {
|
|
134
|
+
return {
|
|
135
|
+
count: this.documents.size,
|
|
136
|
+
database: this.config?.database || 'pinecone',
|
|
137
|
+
};
|
|
138
|
+
// In production:
|
|
139
|
+
// const stats = await this.client.describeIndexStats();
|
|
140
|
+
// return { count: stats.totalVectorCount, database: this.config.database };
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Calculate cosine similarity between two vectors
|
|
144
|
+
*/
|
|
145
|
+
cosineSimilarity(a, b) {
|
|
146
|
+
if (a.length !== b.length) {
|
|
147
|
+
throw new Error('Vectors must have the same length');
|
|
148
|
+
}
|
|
149
|
+
let dotProduct = 0;
|
|
150
|
+
let normA = 0;
|
|
151
|
+
let normB = 0;
|
|
152
|
+
for (let i = 0; i < a.length; i++) {
|
|
153
|
+
dotProduct += a[i] * b[i];
|
|
154
|
+
normA += a[i] * a[i];
|
|
155
|
+
normB += b[i] * b[i];
|
|
156
|
+
}
|
|
157
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
exports.VectorService = VectorService;
|
|
161
|
+
exports.VectorService = VectorService = __decorate([
|
|
162
|
+
(0, core_1.Injectable)()
|
|
163
|
+
], VectorService);
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hazeljs/ai",
|
|
3
|
+
"version": "0.2.0-beta.1",
|
|
4
|
+
"description": "AI integration module for HazelJS framework",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc --skipLibCheck",
|
|
12
|
+
"test": "jest --coverage --maxWorkers=1",
|
|
13
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
14
|
+
"lint:fix": "eslint \"src/**/*.ts\" --fix",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@anthropic-ai/sdk": "^0.71.2",
|
|
19
|
+
"@google/generative-ai": "^0.24.1",
|
|
20
|
+
"@hazeljs/cache": "file:../cache",
|
|
21
|
+
"@hazeljs/core": "file:../core",
|
|
22
|
+
"cohere-ai": "^7.14.0",
|
|
23
|
+
"openai": "^6.15.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^20.17.50",
|
|
27
|
+
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
|
28
|
+
"@typescript-eslint/parser": "^8.18.2",
|
|
29
|
+
"eslint": "^8.56.0",
|
|
30
|
+
"jest": "^29.7.0",
|
|
31
|
+
"ts-jest": "^29.1.2",
|
|
32
|
+
"typescript": "^5.3.3"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/hazel-js/hazeljs.git",
|
|
40
|
+
"directory": "packages/ai"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"hazeljs",
|
|
44
|
+
"ai",
|
|
45
|
+
"openai",
|
|
46
|
+
"anthropic",
|
|
47
|
+
"gemini",
|
|
48
|
+
"llm"
|
|
49
|
+
],
|
|
50
|
+
"author": "Muhammad Arslan <marslan@hazeljs.com>",
|
|
51
|
+
"license": "MIT"
|
|
52
|
+
}
|