Use health portfolio in explained tender matching
This commit is contained in:
@@ -904,3 +904,10 @@ Taslak türü seçicisine erişilebilir ad eklendi. Üretim derlemesi geçti. Ö
|
||||
- Hazırlık kaleminde portföyden ürün seçilebilir; seçimin kimliği ve o andaki beyan kopyası bidDraft içinde saklanır. Ürün seçimi veya marka/model değişimi önceki teknik kaynak/uygunluk/ÜTS/numune/servis/teslim kontrollerini sıfırlar; uygunluk otomatik verilmez. Yeniden kontrol gerekliliği alanda açıklanır.
|
||||
- 203 otomatik test ve derleme geçti. Seçilen beyan kopyasının kaynak nesne değişince korunması ve bütün teknik onayların pending kalması test edildi. Yerel cihaz portföyü kaydı/yenileme, kaleme seçim, eski uygunluğu sıfırlama, çıktı engeli ve taslakta seçimin korunması dahil 6 tarayıcı kontrolü geçti (qa-health-portfolio.json).
|
||||
- Sentetik ÜTS beyanı resmi kayıt doğrulaması değildir. Portföy sonradan değişince mevcut teklifin seçilmiş kopyası otomatik güncellenmez; kullanıcı yeniden seçebilir. Bu tur tek cihaz/tek kalem sınandı; gerçek firma portföyü, beş resmi dosya ve dış çıktı kabulleri açık.
|
||||
|
||||
### D07/D08 — Portföyün açıklanabilir eşleşmeye katılması — 6 Eylül 2026
|
||||
- Yalnız yapılandırılmış sağlık portföyü giren hesabın ürünleri profilTerimleri tarafından okunmuyordu. Portföy ürün grubu ve marka/model metni sözlüksel eşleşmeye eklendi; nedenler kaynağı açıkça gösterir. Aynı ürün elle girilen listede de varsa iki kere sayılmaz.
|
||||
- Gömme için oluşturulan profil metni portföyü Firma portföyü (beyan) etiketiyle içerir. ÜTS beyanı/kayıt numarası ve servis personel kapasitesi puan terimine dönüştürülmez; ürün beyanı resmi uygunluk kanıtı değildir.
|
||||
- İlan metnindeki ilk 3000 karakter sınırı kaldırıldı. Daha sonraki ürün ifadeleri de ilan metni nedeniyle eşleşebilir.
|
||||
- 206 otomatik test ve derleme geçti. Portföy-only profil, açıklama kaynağı, ilgisiz akaryakıt örneğinin sıfır kalması, ÜTS/kapasitenin puan terimi olmaması, uzun metinde geç eşleşme, çift puan engeli ve portföy kaldırılınca eski puanın temizlenmesi doğrulandı.
|
||||
- Bu testler eşleşme bağlantısını kanıtlar; yüksek skor teknik yeterlilik veya gerçek teklif uygunluğu değildir. Büyük havuz performansı ve gerçek portföy/ilan örneklerinde eşleşme kalitesi ayrıca kabul edilmelidir.
|
||||
|
||||
@@ -23,6 +23,8 @@ export function profilTerimleri(userProfile) {
|
||||
const ekle = (liste, kaynak, agirlik) => (liste || []).map((t) => ({ terim: norm(t), ham: String(t).trim(), kaynak, agirlik }));
|
||||
const hepsi = [
|
||||
...ekle(c.extractedProducts, 'ürün', 1.0),
|
||||
...ekle((c.healthPortfolio || []).map(item=>item.group).filter(Boolean), 'portföy ürün grubu', 1.0),
|
||||
...ekle((c.healthPortfolio || []).map(item=>[item.brand,item.model].filter(Boolean).join(' ')).filter(Boolean), 'portföy marka/model', 1.0),
|
||||
...ekle(c.ihaleKonulari, 'ihale konusu', 1.0),
|
||||
...ekle(c.extractedSectors, 'sektör', 0.6),
|
||||
...ekle(c.extractedCertifications, 'sertifika', 0.3),
|
||||
@@ -52,7 +54,7 @@ export function uyumSkoru(tender, terimler) {
|
||||
{ ad: 'teklif cetveli', metin: norm([...(tender.kalemler || []), ...(tender.items || []).map((i) => i.ad)].join(' | ')), agirlik: 1.1 },
|
||||
{ ad: 'OKAS/CPV', metin: norm(tender.cpvLabel), agirlik: 0.7 },
|
||||
{ ad: 'sektör', metin: norm(tender.sektor), agirlik: 0.5 },
|
||||
{ ad: 'ilan metni', metin: norm(String(tender.aciklama || '').slice(0, 3000)), agirlik: 0.6 },
|
||||
{ ad: 'ilan metni', metin: norm(tender.aciklama), agirlik: 0.6 },
|
||||
];
|
||||
let puan = 0;
|
||||
const nedenler = [];
|
||||
@@ -79,6 +81,7 @@ export function uyumSkoru(tender, terimler) {
|
||||
export function profilMetni(userProfile) {
|
||||
const c = userProfile?.scrapedCapabilities || {};
|
||||
const parca = [
|
||||
c.healthPortfolio?.length ? 'Firma portföyü (beyan): ' + c.healthPortfolio.map(item=>[item.group,item.brand,item.model].filter(Boolean).join(' ')).filter(Boolean).join(', ') : '',
|
||||
c.ozet,
|
||||
c.extractedSectors?.length ? 'Sektör: ' + c.extractedSectors.join(', ') : '',
|
||||
c.extractedProducts?.length ? 'Ürünler: ' + c.extractedProducts.join(', ') : '',
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {profilTerimleri,profilMetni,havuzuPuanla} from '../src/services/uyum.js';
|
||||
const profile={scrapedCapabilities:{healthPortfolio:[{group:'Mikroskop',brand:'QA marka',model:'M200',utsStatus:'declared',utsReference:'KAYIT123',serviceCapacity:'5 teknisyen'}]}};
|
||||
test('portfolio-only profile produces explained product matches without treating UTS declaration as proof',()=>{
|
||||
const terms=profilTerimleri(profile);
|
||||
assert.ok(terms.some(t=>t.terim==='mikroskop'&&t.kaynak==='portföy ürün grubu'));
|
||||
assert.ok(!terms.some(t=>t.terim.includes('kayit123')||t.terim.includes('teknisyen')||t.terim.includes('declared')));
|
||||
const rows=havuzuPuanla([{id:'yes',baslik:'Mikroskop alımı'},{id:'no',baslik:'Akaryakıt alımı'}],profile);
|
||||
assert.ok(rows[0].aiMatchScore>0);assert.equal(rows[0].uyumNedenleri[0].kaynak,'portföy ürün grubu');assert.equal(rows[1].aiMatchScore,0);
|
||||
assert.match(profilMetni(profile),/Firma portföyü \(beyan\): Mikroskop QA marka M200/);
|
||||
});
|
||||
test('matching finds a portfolio product beyond the old 3000-character announcement cutoff',()=>{
|
||||
const [row]=havuzuPuanla([{id:'long',baslik:'Malzeme alımı',aciklama:'açıklama '.repeat(500)+'Mikroskop teslim edilecektir.'}],profile);
|
||||
assert.ok(row.aiMatchScore>0);assert.equal(row.uyumNedenleri[0].alan,'ilan metni');
|
||||
});
|
||||
test('same product in manual list and portfolio is not scored twice; removed portfolio leaves no invented score',()=>{
|
||||
const merged={scrapedCapabilities:{...profile.scrapedCapabilities,extractedProducts:['MİKROSKOP']}};
|
||||
assert.equal(profilTerimleri(merged).filter(t=>t.terim==='mikroskop').length,1);
|
||||
assert.equal(havuzuPuanla([{id:'old',baslik:'Mikroskop',aiMatchScore:90}],{scrapedCapabilities:{healthPortfolio:[]}})[0].aiMatchScore,null);
|
||||
});
|
||||
Reference in New Issue
Block a user