@odda-ai/matching-core 1.0.3 → 1.0.4

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 (44) hide show
  1. package/dist/cjs/index.d.ts +3 -0
  2. package/dist/cjs/index.js +19 -0
  3. package/dist/cjs/package.json +1 -0
  4. package/dist/cjs/src/ai/AIProvider.d.ts +36 -0
  5. package/dist/cjs/src/ai/AIProvider.js +134 -0
  6. package/dist/cjs/src/ai/adapters/AnthropicAdapter.d.ts +12 -0
  7. package/dist/cjs/src/ai/adapters/AnthropicAdapter.js +42 -0
  8. package/dist/cjs/src/ai/adapters/OllamaAdapter.d.ts +17 -0
  9. package/dist/cjs/src/ai/adapters/OllamaAdapter.js +42 -0
  10. package/dist/cjs/src/ai/adapters/OpenAIAdapter.d.ts +12 -0
  11. package/dist/cjs/src/ai/adapters/OpenAIAdapter.js +51 -0
  12. package/dist/cjs/src/ai/adapters/index.d.ts +3 -0
  13. package/dist/cjs/src/ai/adapters/index.js +9 -0
  14. package/dist/cjs/src/ai/factory.d.ts +12 -0
  15. package/dist/cjs/src/ai/factory.js +40 -0
  16. package/dist/cjs/src/ai/index.d.ts +5 -0
  17. package/dist/cjs/src/ai/index.js +25 -0
  18. package/dist/cjs/src/ai/registry.d.ts +13 -0
  19. package/dist/cjs/src/ai/registry.js +17 -0
  20. package/dist/cjs/src/ai/types.d.ts +54 -0
  21. package/dist/cjs/src/ai/types.js +2 -0
  22. package/dist/cjs/src/cv-parser/PDFParserService.d.ts +41 -0
  23. package/dist/cjs/src/cv-parser/PDFParserService.js +176 -0
  24. package/dist/cjs/src/cv-parser/index.d.ts +2 -0
  25. package/dist/cjs/src/cv-parser/index.js +6 -0
  26. package/dist/cjs/src/cv-parser/types.d.ts +51 -0
  27. package/dist/cjs/src/cv-parser/types.js +2 -0
  28. package/dist/cjs/src/features/ai-cv-resume.service.d.ts +14 -0
  29. package/dist/cjs/src/features/ai-cv-resume.service.js +81 -0
  30. package/dist/cjs/src/features/ai-talent.service.d.ts +18 -0
  31. package/dist/cjs/src/features/ai-talent.service.js +32 -0
  32. package/dist/cjs/src/features/cv-chunking.service.d.ts +140 -0
  33. package/dist/cjs/src/features/cv-chunking.service.js +338 -0
  34. package/dist/cjs/src/features/index.d.ts +5 -0
  35. package/dist/cjs/src/features/index.js +23 -0
  36. package/dist/cjs/src/features/job-matcher.service.d.ts +14 -0
  37. package/dist/cjs/src/features/job-matcher.service.js +21 -0
  38. package/dist/cjs/src/features/prompts.d.ts +8 -0
  39. package/dist/cjs/src/features/prompts.js +613 -0
  40. package/dist/cjs/src/features/system-messages.d.ts +6 -0
  41. package/dist/cjs/src/features/system-messages.js +32 -0
  42. package/dist/cjs/src/features/types.d.ts +49 -0
  43. package/dist/cjs/src/features/types.js +18 -0
  44. package/package.json +3 -2
@@ -0,0 +1,613 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prompts = exports.JOB_MATCHING_PROMPT = exports.JOB_MATCHING_PROMPT_V1 = exports.CV_ANALYSIS_PROMPT = exports.CV_ANALYSIS_PROMPT_V1 = void 0;
4
+ const CV_ANALYSIS_PROMPT_V1 = (cvText) => `
5
+ Sei un esperto analista HR specializzato nell’analisi di curriculum vitae.
6
+ Il tuo compito è analizzare il seguente CV ed estrarre informazioni strutturate in formato JSON.
7
+
8
+ **CV da Analizzare:**
9
+ ${cvText}
10
+
11
+ ---
12
+
13
+ ## Istruzioni Ultra-Stabili:
14
+
15
+ ### 0. Dati Anagrafici (Massima Priorità)
16
+ - Estrai tutti i dati personali disponibili:
17
+ - \`firstName\` (OBBLIGATORIO, se non trovato usare \`"N/A"\`)
18
+ - \`lastName\` (OBBLIGATORIO, se non trovato usare \`"N/A"\`)
19
+ - \`email\`, \`phone\`, \`address\`, \`dateOfBirth\` (YYYY-MM-DD), \`nationality\`, \`linkedIn\`, \`github\`, \`website\` (opzionali, usare \`null\` se mancanti)
20
+ - Cerca nell’intestazione e nel corpo del CV.
21
+ - Mantieni sempre lo stesso ordine dei campi JSON.
22
+
23
+ ### 1. Profilo Professionale
24
+ - Breve descrizione (max 2-3 frasi) con:
25
+ - Ruolo principale
26
+ - Anni totali di esperienza
27
+ - Aree di specializzazione chiave
28
+ - Tono professionale e oggettivo.
29
+
30
+ ### 2. Skills Tecniche (Massima Stabilità)
31
+ - Estrai **solo skills esplicitamente menzionate**.
32
+ - Per ciascuna skill:
33
+ - \`proficiency\`: 0-100, calcolato rigidamente:
34
+ - Hobby/progetti personali: 20
35
+ - Progetti professionali base: 50
36
+ - Progetti professionali avanzati / responsabilità senior: 80
37
+ - Expertise avanzata / certificazioni: 90
38
+ - Bonus certificazioni avanzate: +10 (non oltre 100)
39
+ - \`seniority\`: basato sugli anni di esperienza specifica:
40
+ - JUNIOR: 0-2 anni
41
+ - MID: 2-5 anni
42
+ - SENIOR: 5-10 anni
43
+ - LEAD: 10-15 anni
44
+ - PRINCIPAL: 15+ anni
45
+ - \`experience\`: mesi di esperienza se menzionati, altrimenti \`null\`
46
+ - \`isInferred\`: false
47
+ - Inferisci **solo skills strettamente correlate** (max 5):
48
+ - React → JavaScript, HTML, CSS
49
+ - NestJS → Node.js, TypeScript
50
+ - PostgreSQL → SQL
51
+ - DevOps → Linux, Docker, Git
52
+ - Attingi anche da descrizioni di progetti e responsabilità o da una statistica generale, non solo dalla sezione skills.
53
+ - Per skill inferite:
54
+ - \`proficiency\`: 30-50
55
+ - \`seniority\`: uguale o inferiore alla skill correlata
56
+ - \`isInferred\`: true
57
+ - Usa \`referenceSkills\` per matching e inferenza coerente.
58
+ - Ordina sempre le skills in ordine alfabetico per consistenza.
59
+
60
+ ### 3. Esperienze Lavorative
61
+ - Seleziona 2-3 posizioni più rilevanti (cronologico inverso).
62
+ - Per ciascuna posizione:
63
+ - \`companyName\`
64
+ - \`role\`
65
+ - \`durationInYears\` (arrotondato a 0.5 anni)
66
+ - \`mainResponsibility\` (max 1 frase)
67
+ - Massimo 4-5 frasi totali.
68
+
69
+ ### 4. Certificazioni
70
+ - Estrai tutte le certificazioni con:
71
+ - \`name\`
72
+ - \`issuer\` (se disponibile)
73
+ - \`year\` (se disponibile)
74
+ - Se assenti, restituire array vuoto.
75
+
76
+ ### 5. Seniority Complessiva
77
+ - Basata su:
78
+ - Anni totali esperienza
79
+ - Livello dei ruoli ricoperti
80
+ - Numero di skills con \`proficiency ≥ 80\`
81
+ - Presenza di certificazioni avanzate
82
+ - Scala rigida:
83
+ - JUNIOR: 0-2 anni
84
+ - MID: 2-5 anni
85
+ - SENIOR: 5-10 anni
86
+ - LEAD: 10-15 anni
87
+ - PRINCIPAL: 15+ anni
88
+
89
+ ### 6. Anni di Esperienza Totale
90
+ - Somma esperienze lavorative professionali, **escludendo stage e hobby projects**.
91
+ - Se non esplicitati, inferire dai ruoli principali.
92
+
93
+ ---
94
+
95
+ ## Formato JSON Richiesto
96
+ Restituisci **solo un JSON valido**, senza markdown:
97
+
98
+ \`\`\`json
99
+ {
100
+ "personalInfo": {
101
+ "firstName": "Mario",
102
+ "lastName": "Rossi",
103
+ "email": "mario.rossi@example.com",
104
+ "phone": "+39 348 1234567",
105
+ "address": "Via Roma 123, Milano, Italia",
106
+ "dateOfBirth": "1990-05-15",
107
+ "nationality": "Italiana",
108
+ "linkedIn": "https://linkedin.com/in/mariorossi",
109
+ "github": "https://github.com/mariorossi",
110
+ "website": "https://mariorossi.dev"
111
+ },
112
+ "description": "Breve descrizione professionale",
113
+ "technicalSkills": [
114
+ {
115
+ "name": "NomeSkill",
116
+ "proficiency": 85,
117
+ "isInferred": false,
118
+ "seniority": "SENIOR",
119
+ "experience": 36
120
+ }
121
+ ],
122
+ "workExperienceSummary": "Riassunto esperienze rilevanti",
123
+ "certifications": [
124
+ {
125
+ "name": "Nome Certificazione",
126
+ "issuer": "Ente Certificatore",
127
+ "year": 2023
128
+ }
129
+ ],
130
+ "overallSeniority": "SENIOR",
131
+ "yearsOfExperience": 8
132
+ }
133
+
134
+ \`\`\`
135
+
136
+ Note Finali
137
+ - Rispondi SOLO con JSON valido.
138
+ - firstName e lastName obbligatori ("N/A" se mancanti).
139
+ - Tutti gli altri campi obbligatori (array vuoti se assenti).
140
+ - Mantieni coerenza e ripetibilità dei punteggi e inferenze tra CV simili.
141
+ `;
142
+ exports.CV_ANALYSIS_PROMPT_V1 = CV_ANALYSIS_PROMPT_V1;
143
+ const CV_ANALYSIS_PROMPT = (cvText) => `# Prompt Analisi CV in JSON – Versione Ultra-Stabile
144
+
145
+ Sei un esperto analista HR specializzato nell’analisi di curriculum vitae.
146
+ Il tuo compito è analizzare il CV fornito e restituire un JSON strutturato con tutte le informazioni principali.
147
+
148
+ **CV da Analizzare:**
149
+ ${cvText}
150
+
151
+ ---
152
+
153
+ ## Istruzioni Ultra-Stabili:
154
+
155
+ ### 0. Dati Anagrafici (Massima Priorità)
156
+ - Estrai tutti i dati personali disponibili:
157
+ - \`firstName\` (OBBLIGATORIO, se non trovato usare \`"N/A"\`)
158
+ - \`lastName\` (OBBLIGATORIO, se non trovato usare \`"N/A"\`)
159
+ - \`email\`, \`phone\`, \`address\`, \`dateOfBirth\` (YYYY-MM-DD), \`nationality\`, \`linkedIn\`, \`github\`, \`website\` (opzionali, usare \`null\` se mancanti)
160
+ - Cerca informazioni nell’intestazione e nel corpo del CV.
161
+ - Se la data di nascita contiene solo anno/mese, completare con giorno \`01\`.
162
+
163
+ ---
164
+
165
+ ### 1. Profilo Professionale
166
+ - Breve descrizione (max 2-3 frasi) con:
167
+ - Ruolo principale
168
+ - Anni totali di esperienza
169
+ - Settore/industria
170
+ - Aree di specializzazione chiave
171
+ - Tono professionale e oggettivo.
172
+
173
+ ---
174
+
175
+ ### 2. Skills Tecniche (Massima Stabilità)
176
+
177
+ #### 2.1 Estrazione esplicita
178
+ - Considera **solo le skills menzionate testualmente** nelle sezioni “Competenze”, “Skills”, “Progetti”, “Esperienze” o “Certificazioni tecniche”.
179
+ - Per ciascuna skill:
180
+ - \`name\` → come scritto nel CV (normalizzato per coerenza)
181
+ - \`proficiency\` → calcolato rigidamente:
182
+ - Hobby/progetti personali: 20
183
+ - Progetti professionali base: 50
184
+ - Progetti professionali avanzati / responsabilità senior: 80
185
+ - Expertise avanzata / certificazioni: 90
186
+ - Bonus certificazioni avanzate: +10 (max 100)
187
+ - \`seniority\` → basato sugli anni di esperienza specifica:
188
+ - JUNIOR: 0-2 anni
189
+ - MID: 2-5 anni
190
+ - SENIOR: 5-10 anni
191
+ - LEAD: 10-15 anni
192
+ - PRINCIPAL: 15+ anni
193
+ - \`experience\` → mesi esplicitamente menzionati o \`null\`
194
+ - \`isInferred\` → false
195
+
196
+ #### 2.2 Inferenza di skill correlate
197
+ - Solo per skill tecniche note, massimo 5 inferenze per CV.
198
+ - Mappe di inferenza (referenceSkills):
199
+ - React → JavaScript, TypeScript, HTML, CSS, JSX, Redux, Hooks, Context API, Router, SSR, Testing, Recoil, Zustand, Framer Motion, GSAP, Storybook, Playwright, Web Vitals
200
+ - Angular → TypeScript, HTML, CSS, RxJS, NgRx, CLI, DI, Testing, PWA, Lazy Loading
201
+ - Vue → JavaScript, TypeScript, HTML, CSS, Vuex, Router, Composition API, SSR, Testing, Pinia
202
+ - Node.js → JavaScript, TypeScript, Async/Await, Express.js, NestJS, REST, GraphQL, WebSockets, Microservices, Testing, gRPC, Thrift, Kafka, Celery, BullMQ
203
+ - NestJS → Node.js, TypeScript, REST, GraphQL, DI, Modules, Middleware, Pipes, Guards, Interceptors, TypeORM/Prisma
204
+ - Python → OOP, Async, Flask, Django, FastAPI, Testing, Pandas, NumPy, ML, gRPC, Kafka, Airflow, Prefect, MLflow, Kubeflow, Triton
205
+ - Java → OOP, Spring Boot, REST, Microservices, Concurrency, Testing, gRPC, Kafka
206
+ - C# → OOP, .NET Core, ASP.NET, REST, Microservices, Testing, gRPC
207
+ - SQL → PostgreSQL, MySQL, SQL Server, Oracle, Indexing, Joins, Transactions, Views, Procedures, TimescaleDB
208
+ - NoSQL → MongoDB, Redis, Cassandra, Aggregation, Replication, Sharding, Caching, Neo4j, ArangoDB, Elasticsearch, Meilisearch
209
+ - Redis → Caching, Pub/Sub, Session Management, Performance
210
+ - Messaging → RabbitMQ, Kafka, Event-driven, Queues, Retry, Streaming
211
+ - Docker → Containers, Images, Volumes, Networking, CI/CD, Security
212
+ - Kubernetes → Pods, Deployments, Services, Ingress, ConfigMaps, Secrets, Helm, Scaling, Observability
213
+ - DevOps → Linux, Git, CI/CD, Docker, Kubernetes, Monitoring, Logging, Cloud, Security, Terraform, Pulumi, CloudFormation, Vault, SOPS, Serverless Framework, SST
214
+ - Git → Version Control, Branching, Merging, PR
215
+ - Linux → Shell, Networking, Permissions, Cron, Systemd
216
+ - Cloud → AWS (EC2,S3,Lambda,RDS,IAM), GCP (Compute,Storage,Functions,BigQuery), Azure (VM,App,Functions,SQL), Edge/CDN (Cloudflare Workers, Fastly)
217
+ - REST API → HTTP, JSON, CRUD, Auth, Rate Limiting, Testing
218
+ - GraphQL → Schema, Resolvers, Subscriptions, Apollo, Caching
219
+ - Testing → Unit, Integration, E2E, TDD, BDD, Jest, Mocha, Cypress, Selenium, Postman/Newman
220
+ - CI/CD → Jenkins, GitHub Actions, GitLab CI, Pipelines, Rollbacks, Blue/Green
221
+ - Security → Auth, JWT, OAuth2, HTTPS, CORS, Encryption, Input Validation, Secrets, SAST, DAST, PenTesting, Keycloak, Auth0, Container Security
222
+ - Monitoring → Prometheus, Grafana, ELK, CloudWatch, Metrics, Tracing, OpenTelemetry, Datadog
223
+ - Microservices → Service Discovery, API Gateway, Event-driven, Circuit Breaker, CQRS, Saga, Serverless
224
+ - Architecture → MVC, MVVM, Layered, Event-driven, Serverless, Monolith vs Microservices, DDD, Hexagonal, Clean Architecture, Multi-tenant, SaaS Patterns
225
+ - Performance → Caching, Load Balancing, Scaling, DB Optimization, Code Splitting, Lazy Loading, CDN
226
+
227
+ - Per skill inferite:
228
+ - \`proficiency\` : 30-70 (inferiore o uguale alla skill madre, assegna un valore realistico in base alla relazione)
229
+ - \`seniority\`: uguale o inferiore alla skill madre
230
+ - \`experience\`: null
231
+ - \`isInferred\`: true
232
+ - \`source\`: opzionale, “inferred from {skill madre}”
233
+
234
+ #### 2.3 Ordinamento
235
+ - Ordinare alfabeticamente tutte le skill, prima esplicite, poi inferite.
236
+
237
+ ---
238
+
239
+ ### 3. Esperienze Lavorative
240
+ - Seleziona 2-3 posizioni più rilevanti, cronologico inverso.
241
+ - Per ciascuna posizione:
242
+ - \`companyName\`
243
+ - \`role\`
244
+ - \`durationInYears\` (arrotondato a 0.5)
245
+ - \`mainResponsibility\` (max 1 frase)
246
+ - Escludere stage o hobby projects dai calcoli di esperienza.
247
+
248
+ ---
249
+
250
+ ### 4. Certificazioni
251
+ - Estrarre tutte le certificazioni con:
252
+ - \`name\` (OBBLIGATORIO)
253
+ - \`issuer\` (null se non disponibile)
254
+ - \`year\` (null se non disponibile)
255
+ - Se assenti, restituire array vuoto.
256
+
257
+ ---
258
+
259
+ ### 5. Seniority Complessiva
260
+ - Basata su:
261
+ - Anni totali esperienza
262
+ - Livello dei ruoli ricoperti
263
+ - Numero di skill con \`proficiency ≥ 80\`
264
+ - Presenza di certificazioni avanzate
265
+ - Scala:
266
+ - JUNIOR: 0-2 anni
267
+ - MID: 2-5 anni
268
+ - SENIOR: 5-10 anni
269
+ - LEAD: 10-15 anni
270
+ - PRINCIPAL: 15+ anni
271
+
272
+ ---
273
+
274
+ ### 6. Anni di Esperienza Totale
275
+ - Somma esperienze lavorative professionali, **escludendo stage e hobby projects**.
276
+ - Se non esplicitati, inferire dai ruoli principali.
277
+
278
+ ---
279
+
280
+ ## Formato JSON Richiesto
281
+ Restituire **solo un JSON valido**, senza markdown.
282
+
283
+ \`\`\`json
284
+ {
285
+ "personalInfo": {
286
+ "firstName": "N/A",
287
+ "lastName": "N/A",
288
+ "email": null,
289
+ "phone": null,
290
+ "address": null,
291
+ "dateOfBirth": null,
292
+ "nationality": null,
293
+ "linkedIn": null,
294
+ "github": null,
295
+ "website": null
296
+ },
297
+ "description": "Breve descrizione professionale",
298
+ "technicalSkills": [
299
+ {
300
+ "name": "NomeSkill",
301
+ "proficiency": 85,
302
+ "isInferred": false,
303
+ "seniority": "SENIOR",
304
+ "experience": 36
305
+ }
306
+ ],
307
+ "workExperienceSummary": "Riassunto esperienze rilevanti",
308
+ "certifications": [
309
+ {
310
+ "name": "Nome Certificazione",
311
+ "issuer": "Ente Certificatore",
312
+ "year": 2023
313
+ }
314
+ ],
315
+ "overallSeniority": "SENIOR",
316
+ "yearsOfExperience": 8
317
+ }
318
+ `;
319
+ exports.CV_ANALYSIS_PROMPT = CV_ANALYSIS_PROMPT;
320
+ const JOB_MATCHING_PROMPT_V1 = (jobDescription, skillsList) => `Task: Perform end-to-end skill extraction, semantic matching, and scoring.
321
+
322
+ Input:
323
+ - Job Description: ${jobDescription}
324
+ - List of Reference Skills:
325
+ ${skillsList.map((skill) => ` - ${skill}`).join("\n")}
326
+
327
+ Instructions:
328
+
329
+ 1. Skill Extraction & Normalization
330
+ - Extract all relevant technical and soft skills from the Job Description
331
+ - Include explicit and clearly inferable implicit skills
332
+ - Normalize all skills to canonical names
333
+ - Map overly specific skills to their broader parent skills when appropriate
334
+
335
+ 2. Skill Importance Classification
336
+ For each extracted skill, determine its importance for the role:
337
+ - core: essential to perform the job
338
+ - enabling: improves effectiveness
339
+ - nice_to_have: optional or contextual
340
+
341
+ 3. Semantic Matching
342
+ For each Reference Skill:
343
+ - Evaluate semantic similarity with extracted skills
344
+ - Consider hierarchical and functional relationships (general ↔ specific)
345
+ - Recognize equivalent or alternative skills covering the same domain
346
+ - Do not penalize missing overly specific skills when a broader equivalent exists
347
+
348
+ 4. Scoring
349
+ Assign a multiplier between 0.00 and 1.00 based on:
350
+ - Semantic similarity
351
+ - Importance of the matched extracted skill
352
+ - Functional coverage by alternative skills
353
+ - Realistic expectations in a recruiting context
354
+
355
+ Scoring guidelines:
356
+ - 0.80–1.00 → crucial and strongly matched
357
+ - 0.50–0.79 → relevant or partially matched
358
+ - 0.20–0.49 → weak or indirect relevance
359
+ - < 0.20 → exclude from output
360
+
361
+ 5. Output
362
+ Return ONLY a valid JSON array.
363
+ Include only Reference Skills with multiplier > 0.
364
+
365
+ Output format:
366
+ [
367
+ { "skill": "Exact Reference Skill Name", "multiplier": 0.00 }
368
+ ]
369
+
370
+ Constraints:
371
+ - Do NOT include markdown
372
+ - Do NOT include explanations
373
+ - Do NOT include intermediate steps
374
+ - Return ONLY the final JSON array
375
+
376
+ Example:
377
+
378
+ Job Description:
379
+ "Looking for a Frontend Engineer with strong React experience.
380
+ You will collaborate with designers and backend engineers.
381
+ Experience with modern state management libraries is a plus."
382
+
383
+ Reference Skills:
384
+ - React
385
+ - Redux
386
+ - Zustand
387
+ - Communication
388
+ - AWS
389
+
390
+ Expected Output:
391
+ [
392
+ { "skill": "React", "multiplier": 0.95 },
393
+ { "skill": "Redux", "multiplier": 0.60 },
394
+ { "skill": "Zustand", "multiplier": 0.55 },
395
+ { "skill": "Communication", "multiplier": 0.40 }
396
+ ]
397
+ `;
398
+ exports.JOB_MATCHING_PROMPT_V1 = JOB_MATCHING_PROMPT_V1;
399
+ const JOB_MATCHING_PROMPT = (jobDescription, skillsList) => `# TASK
400
+ Perform two-pass deterministic skill extraction with validation, normalization, semantic alignment, classification, and scoring.
401
+
402
+ Precision target: ~90%.
403
+ Priority: avoid hallucinations and unjustified inferences.
404
+
405
+ Extraction must be text-grounded and validated before final output.
406
+
407
+ ---
408
+
409
+ # INPUT
410
+
411
+ ## Job Description
412
+ ${jobDescription}
413
+
414
+ ## Reference Skills
415
+ ${skillsList.map((skill) => `- ${skill}`).join("\n")}
416
+
417
+ ---
418
+
419
+ # GLOBAL RULES
420
+
421
+ 1. Do NOT invent skills.
422
+ 2. Do NOT use external knowledge.
423
+ 3. Do NOT assume standard tech stacks.
424
+ 4. Do NOT infer from job title alone.
425
+ 5. Every skill must be grounded in explicit text or strictly necessary logic.
426
+ 6. If uncertain → remove the skill.
427
+ 7. Precision > Recall.
428
+
429
+ ---
430
+
431
+ # PASS 1 — CONTROLLED EXTRACTION
432
+
433
+ Extract ALL candidate skills that satisfy one of the following:
434
+
435
+ ### A) Explicit Mention
436
+ Skill is directly written in the Job Description.
437
+
438
+ ### B) Deterministic Logical Necessity (STRICT)
439
+ Infer ONLY if:
440
+ - The responsibility cannot be performed without that skill.
441
+ - The inference is structurally required.
442
+ - The inference does not depend on market assumptions.
443
+
444
+ Allowed examples:
445
+ - “Build REST APIs” → REST
446
+ - “Write unit tests” → Unit Testing
447
+ - “Design relational database schema” → SQL
448
+
449
+ Forbidden examples:
450
+ - “Frontend Developer” → React
451
+ - “Cloud environment” → AWS
452
+ - “Agile team” → Scrum
453
+ - “Microservices” → Docker
454
+
455
+ For each candidate skill:
456
+ - Normalize to canonical name.
457
+ - Remove duplicates.
458
+ - Classify category:
459
+ - technical
460
+ - soft
461
+
462
+ ---
463
+
464
+ # PASS 2 — VALIDATION & PRUNING (CRITICAL FOR 90% PRECISION)
465
+
466
+ For EACH extracted skill, validate:
467
+
468
+ 1. Can I point to a direct phrase in the Job Description supporting this skill?
469
+ 2. Is the inference strictly necessary (not assumed)?
470
+ 3. Would a human reviewer agree this skill is clearly implied?
471
+
472
+ If ANY answer is uncertain → REMOVE the skill.
473
+
474
+ Do NOT keep borderline skills.
475
+ Do NOT keep ecosystem expansions.
476
+ Do NOT broaden vendor-specific tools unless explicitly stated.
477
+
478
+ After pruning:
479
+ The remaining list becomes the FINAL extracted skill set.
480
+
481
+ ---
482
+
483
+ # IMPORTANCE CLASSIFICATION (TEXT-DRIVEN ONLY)
484
+
485
+ Use only explicit textual signals.
486
+
487
+ CORE:
488
+ - must
489
+ - required
490
+ - essential
491
+ - primary responsibility
492
+ - strongly emphasized
493
+
494
+ ENABLING:
495
+ - preferred
496
+ - experience with
497
+ - plus
498
+ - good to have
499
+ - improves execution
500
+
501
+ NICE_TO_HAVE:
502
+ - optional
503
+ - secondary section
504
+ - clearly non-blocking
505
+
506
+ If ambiguous → classify as ENABLING.
507
+ Never upgrade importance without textual evidence.
508
+
509
+ ---
510
+
511
+ # REFERENCE SKILL MAPPING (AFTER VALIDATION ONLY)
512
+
513
+ For each validated extracted skill:
514
+
515
+ Step 1: Attempt exact match (case-insensitive).
516
+ Step 2: If no exact match → attempt strict semantic equivalence.
517
+ Step 3: If semantic confidence is not high → DO NOT MAP.
518
+
519
+ Mapping constraints:
520
+ - Only map when meaning is substantially identical.
521
+ - Do NOT map broader ↔ narrower unless coverage is complete.
522
+ - Do NOT force mapping.
523
+
524
+ If mapped:
525
+ - Use exact Reference Skill name.
526
+ - "isReferenceSkill": true
527
+
528
+ If not mapped:
529
+ - Keep normalized extracted name.
530
+ - "isReferenceSkill": false
531
+
532
+ Never remove unmatched skills.
533
+
534
+ ---
535
+
536
+ # MULTIPLIER SCORING (DETERMINISTIC RANGE SYSTEM)
537
+
538
+ Scoring depends ONLY on:
539
+ - Importance
540
+ - Mapping status
541
+
542
+ No subjective creativity.
543
+
544
+ If isReferenceSkill = true:
545
+
546
+ CORE → 0.90–1.00
547
+ ENABLING → 0.65–0.80
548
+ NICE_TO_HAVE → 0.40–0.55
549
+
550
+ If isReferenceSkill = false:
551
+
552
+ CORE → 0.80–0.90
553
+ ENABLING → 0.55–0.70
554
+ NICE_TO_HAVE → 0.30–0.50
555
+
556
+ Rules:
557
+ - Default to mid-range value.
558
+ - Use upper bound only if strongly emphasized.
559
+ - Never assign 1.00 unless clearly critical.
560
+ - Exclude skills with multiplier < 0.30.
561
+
562
+ ---
563
+
564
+ # JOB SKILL TYPE ASSIGNMENT
565
+
566
+ If category = technical:
567
+ - core OR enabling → technical_required
568
+ - nice_to_have → technical_nice_to_have
569
+
570
+ If category = soft:
571
+ - core OR enabling → soft_required
572
+ - nice_to_have → soft_nice_to_have
573
+
574
+ Allowed values only:
575
+ - technical_required
576
+ - technical_nice_to_have
577
+ - soft_required
578
+ - soft_nice_to_have
579
+
580
+ ---
581
+
582
+ # OUTPUT RULES (STRICT)
583
+
584
+ Return ONLY a valid JSON array.
585
+
586
+ - No markdown
587
+ - No explanations
588
+ - No reasoning
589
+ - No comments
590
+ - No intermediate steps
591
+ - No extra fields
592
+ - Include only skills with multiplier ≥ 0.30
593
+ - Include both mapped and unmapped skills
594
+ - If no skills validated → return []
595
+
596
+ ---
597
+
598
+ # OUTPUT FORMAT
599
+
600
+ [
601
+ {
602
+ "skill": "Final Skill Name",
603
+ "multiplier": 0.00,
604
+ "jobSkillType": "technical_required | technical_nice_to_have | soft_required | soft_nice_to_have",
605
+ "isReferenceSkill": true | false
606
+ }
607
+ ]
608
+ \`\`\``;
609
+ exports.JOB_MATCHING_PROMPT = JOB_MATCHING_PROMPT;
610
+ exports.prompts = {
611
+ cvAnalysis: exports.CV_ANALYSIS_PROMPT,
612
+ jobMatching: exports.JOB_MATCHING_PROMPT,
613
+ };
@@ -0,0 +1,6 @@
1
+ export declare const ANALYZE_RESUME: () => string | undefined;
2
+ export declare const JOB_MATCHING: () => string;
3
+ export declare const systemMessages: {
4
+ analyzeResume: () => string | undefined;
5
+ jobMatching: () => string;
6
+ };
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.systemMessages = exports.JOB_MATCHING = exports.ANALYZE_RESUME = void 0;
4
+ const ANALYZE_RESUME = () => undefined;
5
+ exports.ANALYZE_RESUME = ANALYZE_RESUME;
6
+ const JOB_MATCHING = () => `
7
+ You are a senior HR Analytics and Skill Intelligence expert specialized in realistic AI-based recruiting systems.
8
+
9
+ You work with noisy job descriptions, implicit requirements, rare skills, and non-standardized taxonomies.
10
+
11
+ You MUST follow these principles:
12
+ - Skills are semantic concepts, not keywords
13
+ - Overly specific skills must never be treated as hard requirements
14
+ - Implicit skills may be inferred only when clearly supported by responsibilities
15
+ - Soft skills are supporting signals, never exclusion criteria
16
+ - Matching must be realistic, recruiter-aligned, and explainable
17
+
18
+ Operational constraints:
19
+ - Normalize and canonicalize skill names
20
+ - Evaluate skill importance (core / enabling / nice-to-have)
21
+ - Prefer realistic recall over overly strict precision
22
+ - Do not invent unjustified skills
23
+
24
+ Output discipline:
25
+ - When structured output is requested, return ONLY valid JSON
26
+ - Do not include explanations, markdown, or extra text
27
+ `;
28
+ exports.JOB_MATCHING = JOB_MATCHING;
29
+ exports.systemMessages = {
30
+ analyzeResume: exports.ANALYZE_RESUME,
31
+ jobMatching: exports.JOB_MATCHING,
32
+ };
@@ -0,0 +1,49 @@
1
+ export declare enum Seniority {
2
+ JUNIOR = "JUNIOR",
3
+ MID = "MID",
4
+ SENIOR = "SENIOR",
5
+ LEAD = "LEAD",
6
+ PRINCIPAL = "PRINCIPAL"
7
+ }
8
+ export declare enum JobSkillType {
9
+ TECHNICAL_REQUIRED = "technical_required",
10
+ TECHNICAL_NICE_TO_HAVE = "technical_nice_to_have",
11
+ SOFT_REQUIRED = "soft_required",
12
+ SOFT_NICE_TO_HAVE = "soft_nice_to_have"
13
+ }
14
+ export type TechnicalSkill = {
15
+ name: string;
16
+ proficiency: number;
17
+ isInferred: boolean;
18
+ seniority: Seniority;
19
+ };
20
+ export type PersonalInfo = {
21
+ firstName?: string;
22
+ lastName?: string;
23
+ email?: string;
24
+ phone?: string;
25
+ address?: string;
26
+ dateOfBirth?: string;
27
+ nationality?: string;
28
+ linkedIn?: string;
29
+ github?: string;
30
+ website?: string;
31
+ };
32
+ export type Certification = {
33
+ name: string;
34
+ issuer?: string;
35
+ year?: number;
36
+ };
37
+ export type CvAnalysisRequest = {
38
+ cvText: string;
39
+ referenceSkills?: string[];
40
+ };
41
+ export type CvAnalysisResponse = {
42
+ personalInfo: PersonalInfo;
43
+ description: string;
44
+ technicalSkills: TechnicalSkill[];
45
+ workExperienceSummary: string;
46
+ certifications: Certification[];
47
+ overallSeniority: Seniority;
48
+ yearsOfExperience: number;
49
+ };