@naniteninja/profile-comparison-lib 0.0.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
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# Profile Comparison Library
|
|
2
|
+
|
|
3
|
+
A powerful Angular 20 library for comparing user profiles using advanced AI-powered semantic similarity analysis and face detection capabilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Semantic Text Similarity**: Uses TensorFlow.js Universal Sentence Encoder for intelligent text comparison
|
|
8
|
+
- **Face Detection & Alignment**: Integrates with API Ninjas Face Detection API for facial analysis
|
|
9
|
+
- **Interest Matching**: Smart alignment of interests between profiles with similarity scoring
|
|
10
|
+
- **TypeScript Support**: Fully typed interfaces and services
|
|
11
|
+
- **Observable-based**: Reactive programming with RxJS observables
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install profile-comparison-lib-test
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Dependencies
|
|
20
|
+
|
|
21
|
+
The library requires the following peer dependencies:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @tensorflow/tfjs @tensorflow-models/universal-sentence-encoder
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
### 1. Import the Module
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { ProfileComparisonLibModule } from "profile-comparison-lib-test";
|
|
33
|
+
|
|
34
|
+
@NgModule({
|
|
35
|
+
imports: [
|
|
36
|
+
ProfileComparisonLibModule,
|
|
37
|
+
// ... other imports
|
|
38
|
+
],
|
|
39
|
+
})
|
|
40
|
+
export class AppModule {}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 2. Environment Configuration
|
|
44
|
+
|
|
45
|
+
Add your API Ninjas API key to your environment configuration:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// environment.ts
|
|
49
|
+
export const environment = {
|
|
50
|
+
production: false,
|
|
51
|
+
apiNinjasKey: "your-api-ninjas-key-here",
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**⚠️ Security Note**: Never hardcode API keys in your source code. Always use environment variables or secure configuration management.
|
|
56
|
+
|
|
57
|
+
## API Reference
|
|
58
|
+
|
|
59
|
+
### Services
|
|
60
|
+
|
|
61
|
+
#### EmbeddingService
|
|
62
|
+
|
|
63
|
+
Provides semantic similarity analysis using TensorFlow.js Universal Sentence Encoder.
|
|
64
|
+
|
|
65
|
+
**Methods:**
|
|
66
|
+
|
|
67
|
+
- `getEmbedding(text: string): Observable<Float32Array>`
|
|
68
|
+
- Generates embedding vector for a single text
|
|
69
|
+
- `calculateSimilarity(primaryText: string, comparisonText: string): Observable<number>`
|
|
70
|
+
- Calculates cosine similarity between two texts (returns value between -1 and 1)
|
|
71
|
+
- `alignLists(listA: string[], listB: string[]): Observable<IWordAlignment[]>`
|
|
72
|
+
- Aligns words from listA with most similar words in listB
|
|
73
|
+
- `findBestMatchingPairs(listA: string[], listB: string[], threshold?: number): Observable<IWordPair[]>`
|
|
74
|
+
- Finds best matching pairs between two lists above similarity threshold (default: 0.15)
|
|
75
|
+
|
|
76
|
+
#### ProfileService
|
|
77
|
+
|
|
78
|
+
Handles API integration for text similarity and face detection.
|
|
79
|
+
|
|
80
|
+
**Methods:**
|
|
81
|
+
|
|
82
|
+
- `compareInterests(text_1: string, text_2: string, apiKey: string): Observable<any>`
|
|
83
|
+
- Compares two text strings using API Ninjas Text Similarity API
|
|
84
|
+
- `detectFace(file: File, apiKey: string): Observable<FaceDetectionResult>`
|
|
85
|
+
- Detects faces in uploaded image files
|
|
86
|
+
|
|
87
|
+
### Interfaces
|
|
88
|
+
|
|
89
|
+
#### IProfileConfig
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
interface IProfileConfig {
|
|
93
|
+
person1Interests: string[];
|
|
94
|
+
person2Interests: string[];
|
|
95
|
+
person3Interests: string[];
|
|
96
|
+
user1Image: string;
|
|
97
|
+
user2Image: string;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### FaceDetectionResult
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
interface FaceDetectionResult {
|
|
105
|
+
imageUrl: string;
|
|
106
|
+
faces: { x: number; y: number; width: number; height: number }[];
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### BoundingBox
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
interface BoundingBox {
|
|
114
|
+
x: number;
|
|
115
|
+
y: number;
|
|
116
|
+
width: number;
|
|
117
|
+
height: number;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### Point
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
interface Point {
|
|
125
|
+
x: number;
|
|
126
|
+
y: number;
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### IWordAlignment
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
interface IWordAlignment {
|
|
134
|
+
word: string;
|
|
135
|
+
alignedWith: string | null;
|
|
136
|
+
score: number;
|
|
137
|
+
index: number;
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### IWordPair
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
interface IWordPair {
|
|
145
|
+
wordA: string;
|
|
146
|
+
wordB: string;
|
|
147
|
+
score: number;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Usage Examples
|
|
152
|
+
|
|
153
|
+
### Basic Text Similarity
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { EmbeddingService } from 'profile-comparison-lib-test';
|
|
157
|
+
|
|
158
|
+
constructor(private embeddingService: EmbeddingService) {}
|
|
159
|
+
|
|
160
|
+
compareTexts() {
|
|
161
|
+
this.embeddingService.calculateSimilarity('I love traveling', 'I enjoy journeys')
|
|
162
|
+
.subscribe(similarity => {
|
|
163
|
+
console.log(`Similarity: ${(similarity * 100).toFixed(1)}%`);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Interest Matching
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { EmbeddingService } from 'profile-comparison-lib-test';
|
|
172
|
+
|
|
173
|
+
constructor(private embeddingService: EmbeddingService) {}
|
|
174
|
+
|
|
175
|
+
matchInterests() {
|
|
176
|
+
const interests1 = ['traveling', 'photography', 'cooking'];
|
|
177
|
+
const interests2 = ['journeys', 'cameras', 'baking'];
|
|
178
|
+
|
|
179
|
+
this.embeddingService.findBestMatchingPairs$(interests1, interests2, 0.2)
|
|
180
|
+
.subscribe(pairs => {
|
|
181
|
+
pairs.forEach(pair => {
|
|
182
|
+
console.log(`${pair.wordA} ↔ ${pair.wordB} (${(pair.score * 100).toFixed(1)}%)`);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Face Detection
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { ProfileService } from 'profile-comparison-lib-test';
|
|
192
|
+
import { environment } from '../environments/environment';
|
|
193
|
+
|
|
194
|
+
constructor(private profileService: ProfileService) {}
|
|
195
|
+
|
|
196
|
+
detectFaces(imageFile: File) {
|
|
197
|
+
this.profileService.detectFace(imageFile, environment.apiNinjasKey)
|
|
198
|
+
.subscribe(result => {
|
|
199
|
+
console.log(`Found ${result.faces.length} faces`);
|
|
200
|
+
result.faces.forEach((face, index) => {
|
|
201
|
+
console.log(`Face ${index + 1}: x=${face.x}, y=${face.y}, width=${face.width}, height=${face.height}`);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Complete Profile Comparison
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import { EmbeddingService, ProfileService, IProfileConfig } from "profile-comparison-lib-test";
|
|
211
|
+
import { environment } from "../environments/environment";
|
|
212
|
+
|
|
213
|
+
export class ProfileComparisonComponent {
|
|
214
|
+
constructor(private embeddingService: EmbeddingService, private profileService: ProfileService) {}
|
|
215
|
+
|
|
216
|
+
compareProfiles(config: IProfileConfig) {
|
|
217
|
+
// Compare interests between person1 and person2
|
|
218
|
+
this.embeddingService.findBestMatchingPairs(
|
|
219
|
+
config.person1Interests,
|
|
220
|
+
config.person2Interests,
|
|
221
|
+
0.15
|
|
222
|
+
).subscribe(matches => {
|
|
223
|
+
console.log("Interest matches:", matches);
|
|
224
|
+
|
|
225
|
+
// Sort by similarity score
|
|
226
|
+
const sortedMatches = matches.sort((a, b) => b.score - a.score);
|
|
227
|
+
|
|
228
|
+
// Display top matches
|
|
229
|
+
sortedMatches.slice(0, 5).forEach((match) => {
|
|
230
|
+
console.log(`${match.wordA} matches ${match.wordB} (${(match.score * 100).toFixed(1)}%)`);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Component Usage
|
|
238
|
+
|
|
239
|
+
The library includes a basic component that can be used as a starting point:
|
|
240
|
+
|
|
241
|
+
```html
|
|
242
|
+
<lib-profile-comparison-lib></lib-profile-comparison-lib>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Building the Library
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
ng build profile-comparison-lib-test
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Running Tests
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
ng test profile-comparison-lib-test
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## API Keys Required
|
|
258
|
+
|
|
259
|
+
This library requires an API key from [API Ninjas](https://api.api-ninjas.com/) for:
|
|
260
|
+
|
|
261
|
+
- Text similarity comparison
|
|
262
|
+
- Face detection functionality
|
|
263
|
+
|
|
264
|
+
Sign up at API Ninjas to get your free API key.
|
|
265
|
+
|
|
266
|
+
## Browser Compatibility
|
|
267
|
+
|
|
268
|
+
- Chrome 119+
|
|
269
|
+
- Firefox 115+
|
|
270
|
+
- Safari 16.4+
|
|
271
|
+
- Edge 119+
|
|
272
|
+
|
|
273
|
+
Angular 20 requires modern browsers with ES2022+ support. TensorFlow.js requires WebGL support for optimal performance.
|
|
274
|
+
|
|
275
|
+
## Performance Considerations
|
|
276
|
+
|
|
277
|
+
- The Universal Sentence Encoder model (~25MB) is loaded lazily on first use
|
|
278
|
+
- Model loading is cached for subsequent operations
|
|
279
|
+
- Face detection API calls count against your API Ninjas quota
|
|
280
|
+
- Consider implementing caching for repeated similarity calculations
|
|
281
|
+
|
|
282
|
+
## Error Handling
|
|
283
|
+
|
|
284
|
+
All service methods return observables with proper error handling. Wrap calls in try-catch blocks or use RxJS error operators:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
this.embeddingService
|
|
288
|
+
.calculateSimilarity('text1', 'text2')
|
|
289
|
+
.pipe(
|
|
290
|
+
catchError((error) => {
|
|
291
|
+
console.error("Similarity calculation failed:", error);
|
|
292
|
+
return of(0); // Return default similarity
|
|
293
|
+
})
|
|
294
|
+
)
|
|
295
|
+
.subscribe((similarity) => {
|
|
296
|
+
// Handle successful result
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Contributing
|
|
301
|
+
|
|
302
|
+
1. Fork the repository
|
|
303
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
304
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
305
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
306
|
+
5. Open a Pull Request
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
This project is licensed under the MIT License.
|
|
311
|
+
|
|
312
|
+
## Support
|
|
313
|
+
|
|
314
|
+
For issues and questions, please create an issue in the GitHub repository.
|