@naniteninja/profile-comparison-lib 0.0.1 → 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.
package/README.md CHANGED
@@ -1,314 +1,193 @@
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.
1
+ # Profile Comparison Library
2
+
3
+ Angular library that renders a side-by-side profile comparison (two profile images, a central draggable shape, and aligned interest lists). It is a **thin client**: you provide a backend URL; the library sends user config to your backend and displays the payload it returns. No API keys or key-entry modals in the library.
4
+
5
+ **You need a backend** that implements the profile comparison API (e.g. the **profile-comparison-server** repo). Provide its base URL via `PROFILE_COMPARISON_API_BASE_URL`. If not provided, the component shows **"Configure backend"**.
6
+
7
+ ---
8
+
9
+ ## Quickstart
10
+
11
+ 1. **Install the package**
12
+
13
+ ```bash
14
+ npm install profile-comparison-lib
15
+ ```
16
+
17
+ 2. **Provide the backend URL**
18
+
19
+ In `app.config.ts` (or `AppModule`):
20
+
21
+ ```typescript
22
+ import { PROFILE_COMPARISON_API_BASE_URL } from 'profile-comparison-lib';
23
+
24
+ providers: [
25
+ { provide: PROFILE_COMPARISON_API_BASE_URL, useValue: 'https://your-backend.com/api' },
26
+ ]
27
+ ```
28
+
29
+ Or with a factory (e.g. runtime toggle between backends):
30
+
31
+ ```typescript
32
+ providers: [{
33
+ provide: PROFILE_COMPARISON_API_BASE_URL,
34
+ useFactory: (backendUrl: BackendUrlService) => () => backendUrl.getBaseUrl(),
35
+ deps: [BackendUrlService],
36
+ }]
37
+ ```
38
+
39
+ 3. **Use the component**
40
+
41
+ Import the module and add the component to a template:
42
+
43
+ ```typescript
44
+ import { ProfileComparisonLibModule } from 'profile-comparison-lib';
45
+ ```
46
+
47
+ ```html
48
+ <lib-profile-comparison [config]="config"></lib-profile-comparison>
49
+ ```
50
+
51
+ ---
52
+
53
+ ## What the element looks like
54
+
55
+ When you use `<lib-profile-comparison>` in another Angular app you get:
56
+
57
+ - **Side-by-side profile comparison**: two profile images (left and right) with a central draggable “shape” and aligned interest lists between them.
58
+ - **Main regions**: left image, right image, center shape with text, loading indicator when a request is in progress.
59
+ - **Action**: “View Profile” on each side; the component emits `viewProfileClick` with `{ side: 'left' | 'right' }` so the host can route or act.
60
+
61
+ No key-entry modals or API key inputs appear in the library; all keys and third-party API calls live on your backend.
62
+
63
+ ---
64
+
65
+ ## Full setup (copy-paste)
66
+
67
+ 1. Create or open an Angular app (Angular ^20.0.0).
68
+
69
+ 2. Install the library and peer dependencies:
70
+
71
+ ```bash
72
+ npm install profile-comparison-lib @angular/core@^20 @angular/common@^20
73
+ ```
74
+
75
+ 3. Add the backend URL provider in `app.config.ts`:
76
+
77
+ ```typescript
78
+ import { ApplicationConfig } from '@angular/core';
79
+ import { provideHttpClient } from '@angular/common/http';
80
+ import { PROFILE_COMPARISON_API_BASE_URL } from 'profile-comparison-lib';
81
+
82
+ export const appConfig: ApplicationConfig = {
83
+ providers: [
84
+ provideHttpClient(),
85
+ { provide: PROFILE_COMPARISON_API_BASE_URL, useValue: 'https://your-backend.com/api' },
86
+ ],
87
+ };
88
+ ```
89
+
90
+ Or in `AppModule`:
91
+
92
+ ```typescript
93
+ import { PROFILE_COMPARISON_API_BASE_URL } from 'profile-comparison-lib';
94
+
95
+ @NgModule({
96
+ providers: [
97
+ { provide: PROFILE_COMPARISON_API_BASE_URL, useValue: 'https://your-backend.com/api' },
98
+ ],
99
+ })
100
+ export class AppModule {}
101
+ ```
102
+
103
+ 4. Import the module where you use the component:
104
+
105
+ ```typescript
106
+ import { ProfileComparisonLibModule } from 'profile-comparison-lib';
107
+
108
+ @NgModule({
109
+ imports: [ProfileComparisonLibModule, ...],
110
+ })
111
+ export class YourModule {}
112
+ ```
113
+
114
+ 5. Add the component to a template with required `[config]`:
115
+
116
+ ```html
117
+ <lib-profile-comparison
118
+ [config]="config"
119
+ [fadeAllEdges]="fadeAllEdges"
120
+ (matrixDataChange)="onMatrixData($event)"
121
+ (rawLLMOutputChange)="onRawLLMOutput($event)"
122
+ (viewProfileClick)="onViewProfile($event)"
123
+ ></lib-profile-comparison>
124
+ ```
125
+
126
+ 6. Run the app and ensure your backend is reachable at the URL you provided.
127
+
128
+ ---
129
+
130
+ ## Inputs and outputs
131
+
132
+ ### Inputs
133
+
134
+ - **`config`** (required) — `IProfileConfig`:
135
+
136
+ ```json
137
+ {
138
+ "person1Interests": ["Gaming", "Programming", "AI/ML"],
139
+ "person2Interests": ["AI machine learning", "Mobile Games", "Data Science"],
140
+ "person3Interests": ["Board Games", "Machine Learning"],
141
+ "user1Image": "data:image/jpeg;base64,...",
142
+ "user2Image": "data:image/jpeg;base64,..."
143
+ }
144
+ ```
145
+
146
+ `user1Image` and `user2Image` can be data URLs or URLs; the library sends them to the backend as needed.
147
+
148
+ - **`fadeAllEdges`** (optional) — `boolean`, default `false`. When true, fades the outer edges of the profile area.
149
+
150
+ ### Outputs
151
+
152
+ - **`matrixDataChange`** — `IMatrixData`: legend, headers, and rows for the similarity matrix.
153
+
154
+ Example payload:
155
+
156
+ ```json
157
+ {
158
+ "legend": [{ "abbr": "Gam", "full": "Gaming" }, { "abbr": "Pro", "full": "Programming" }],
159
+ "headers": ["Gam", "Pro", "AI/ML"],
160
+ "rows": [
161
+ { "label": "Gam", "values": ["1.00", "0.2", "0.5"] },
162
+ { "label": "Pro", "values": ["0.2", "1.00", "0.8"] }
163
+ ]
164
+ }
165
+ ```
166
+
167
+ - **`rawLLMOutputChange`** — `string`: raw LLM output from the backend (if any).
168
+
169
+ - **`viewProfileClick`** — `{ side: 'left' | 'right' }`: emitted when the user clicks “View Profile” on the left or right side. Use this to navigate or open a profile page.
170
+
171
+ Example:
172
+
173
+ ```typescript
174
+ onViewProfile(payload: { side: 'left' | 'right' }) {
175
+ this.router.navigate(['/profile', payload.side]);
176
+ }
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Backend API contract
182
+
183
+ The library calls your backend at `POST {baseUrl}/profile/compare-full` with body `{ config: IProfileConfig }`. The backend should return a display payload (face results, aligned lists, center item, matrix data, raw LLM output). See the **profile-comparison-server** repo and the lib interface `IComparisonPayload` for the response shape.
184
+
185
+ ---
186
+
187
+ ## Building the library
188
+
189
+ ```bash
190
+ ng build profile-comparison-lib
191
+ ```
192
+
193
+ Output is in `dist/profile-comparison-lib/` (FESM, typings, package.json). Peer dependencies: Angular `^20.0.0` only.