prebid.js 9.52.0 → 9.53.2
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/.circleci/config.yml +27 -4
- package/creative/crossDomain.js +4 -2
- package/dist/33acrossAnalyticsAdapter.js +1 -1
- package/dist/33acrossBidAdapter.js +1 -1
- package/dist/33acrossIdSystem.js +1 -1
- package/dist/BTBidAdapter.js +1 -1
- package/dist/adagioAnalyticsAdapter.js +1 -1
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adagioUtils.js +1 -1
- package/dist/addefendBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/adlooxRtdProvider.js +1 -1
- package/dist/adqueryBidAdapter.js +1 -1
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adstirBidAdapter.js +1 -1
- package/dist/adtrgtmeBidAdapter.js +1 -1
- package/dist/adxcgAnalyticsAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/adyoulikeBidAdapter.js +1 -1
- package/dist/agmaAnalyticsAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/aniviewBidAdapter.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/beopBidAdapter.js +1 -1
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bitmediaBidAdapter.js +1 -1
- package/dist/bridBidAdapter.js +1 -1
- package/dist/bridgeuppBidAdapter.js +1 -1
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/carodaBidAdapter.js +1 -1
- package/dist/chromeAiRtdProvider.js +1 -0
- package/dist/chtnwBidAdapter.js +1 -1
- package/dist/chunk-core.js +1 -1
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/contxtfulBidAdapter.js +1 -1
- package/dist/conversantAnalyticsAdapter.js +1 -1
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/cwireBidAdapter.js +1 -1
- package/dist/dailymotionBidAdapter.js +1 -1
- package/dist/debugging-standalone.js +1 -1
- package/dist/dependencies.json +10 -2
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/dxkultureBidAdapter.js +1 -1
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/equativBidAdapter.js +1 -1
- package/dist/eskimiBidAdapter.js +1 -1
- package/dist/euidIdSystem.js +1 -1
- package/dist/exadsBidAdapter.js +1 -1
- package/dist/excoBidAdapter.js +1 -1
- package/dist/fanAdapter.js +1 -1
- package/dist/feedadBidAdapter.js +1 -1
- package/dist/finativeBidAdapter.js +1 -1
- package/dist/freewheel-sspBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/greenbidsAnalyticsAdapter.js +1 -1
- package/dist/greenbidsBidAdapter.js +1 -1
- package/dist/greenbidsRtdProvider.js +1 -1
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/hypelabBidAdapter.js +1 -1
- package/dist/id5AnalyticsAdapter.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/imdsBidAdapter.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/inmobiBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/intentIqAnalyticsAdapter.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/jixieBidAdapter.js +1 -1
- package/dist/jixieIdSystem.js +1 -0
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/kargoBidAdapter.js +1 -1
- package/dist/kimberliteBidAdapter.js +1 -1
- package/dist/konduitAnalyticsAdapter.js +1 -1
- package/dist/kueezBidAdapter.js +1 -1
- package/dist/lassoBidAdapter.js +1 -1
- package/dist/lifestreetBidAdapter.js +1 -1
- package/dist/liveIntentId.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/luceadBidAdapter.js +1 -1
- package/dist/mabidderBidAdapter.js +1 -1
- package/dist/madsenseBidAdapter.js +1 -1
- package/dist/magniteAnalyticsAdapter.js +1 -1
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/medianetBidAdapter.js +1 -1
- package/dist/medianetUtils.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/missenaBidAdapter.js +1 -1
- package/dist/mobilefuseBidAdapter.js +1 -1
- package/dist/nextMillenniumBidAdapter.js +1 -1
- package/dist/nexx360Utils.js +1 -1
- package/dist/nobidAnalyticsAdapter.js +1 -1
- package/dist/nobidBidAdapter.js +1 -1
- package/dist/nodalsAiRtdProvider.js +1 -1
- package/dist/not-for-prod/prebid.js +175 -173
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/openxBidAdapter.js +1 -1
- package/dist/optidigitalBidAdapter.js +1 -1
- package/dist/orbidderBidAdapter.js +1 -1
- package/dist/ortb2.5Translator.js +1 -1
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/ozoneBidAdapter.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/prebidServerBidAdapter.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticAnalyticsAdapter.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubmaticRtdProvider.js +1 -1
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pubxaiAnalyticsAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/relevatehealthBidAdapter.js +1 -1
- package/dist/retailspotBidAdapter.js +1 -1
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseUtils.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/showheroes-bsBidAdapter.js +1 -1
- package/dist/smaatoBidAdapter.js +1 -1
- package/dist/smartadserverBidAdapter.js +1 -1
- package/dist/smartxBidAdapter.js +1 -1
- package/dist/smilewantedBidAdapter.js +1 -1
- package/dist/snigelBidAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/sparteoBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/stvBidAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/taboolaBidAdapter.js +1 -1
- package/dist/tappxBidAdapter.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/terceptAnalyticsAdapter.js +1 -1
- package/dist/themoneytizerBidAdapter.js +1 -1
- package/dist/trionBidAdapter.js +1 -1
- package/dist/tripleliftBidAdapter.js +1 -1
- package/dist/ttdBidAdapter.js +1 -1
- package/dist/ucfunnelAnalyticsAdapter.js +1 -1
- package/dist/uid2IdSystem.js +1 -1
- package/dist/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/unrulyBidAdapter.js +1 -1
- package/dist/userId.js +1 -1
- package/dist/vidazooUtils.js +1 -1
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/yahooAdsBidAdapter.js +1 -1
- package/dist/yandexBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/gulpfile.js +12 -6
- package/integrationExamples/chromeai/japanese.html +224 -0
- package/integrationExamples/gpt/x-domain/creative.html +1 -1
- package/karma.conf.maker.js +7 -7
- package/karmaRunner.js +3 -3
- package/libraries/liveIntentId/shared.js +16 -0
- package/modules/.submodules.json +1 -0
- package/modules/aniviewBidAdapter.js +32 -23
- package/modules/chromeAiRtdProvider.js +421 -0
- package/modules/chromeAiRtdProvider.md +230 -0
- package/modules/fanAdapter.js +318 -124
- package/modules/ixBidAdapter.js +5 -0
- package/modules/jixieIdSystem.js +186 -0
- package/modules/ozoneBidAdapter.js +214 -336
- package/modules/prebidServerBidAdapter/index.js +59 -35
- package/modules/pubmaticRtdProvider.js +418 -4
- package/modules/pubmaticRtdProvider.md +12 -2
- package/modules/relevatehealthBidAdapter.js +20 -130
- package/modules/relevatehealthBidAdapter.md +1 -2
- package/modules/sovrnBidAdapter.js +4 -4
- package/modules/teadsBidAdapter.js +5 -0
- package/modules/ttdBidAdapter.js +5 -4
- package/modules/userId/index.js +30 -31
- package/package.json +5 -4
- package/src/adapterManager.js +3 -0
- package/test/spec/libraries/cmUtils_spec.js +17 -12
- package/test/spec/modules/aniviewBidAdapter_spec.js +15 -2
- package/test/spec/modules/chromeAiRtdProvider_spec.js +393 -0
- package/test/spec/modules/dgkeywordRtdProvider_spec.js +5 -2
- package/test/spec/modules/euidIdSystem_spec.js +9 -3
- package/test/spec/modules/fanAdapter_spec.js +264 -268
- package/test/spec/modules/id5IdSystem_spec.js +57 -101
- package/test/spec/modules/identityLinkIdSystem_spec.js +1 -0
- package/test/spec/modules/idxIdSystem_spec.js +2 -75
- package/test/spec/modules/instreamTracking_spec.js +15 -18
- package/test/spec/modules/ixBidAdapter_spec.js +26 -0
- package/test/spec/modules/jixieIdSystem_spec.js +303 -0
- package/test/spec/modules/liveIntentExternalIdSystem_spec.js +5 -0
- package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +5 -0
- package/test/spec/modules/liveIntentIdSystem_spec.js +38 -0
- package/test/spec/modules/lmpIdSystem_spec.js +2 -81
- package/test/spec/modules/ozoneBidAdapter_spec.js +511 -658
- package/test/spec/modules/prebidServerBidAdapter_spec.js +72 -2
- package/test/spec/modules/pubmaticBidAdapter_spec.js +411 -126
- package/test/spec/modules/pubmaticRtdProvider_spec.js +946 -2
- package/test/spec/modules/raynRtdProvider_spec.js +18 -22
- package/test/spec/modules/relevatehealthBidAdapter_spec.js +9 -39
- package/test/spec/modules/sharedIdSystem_spec.js +3 -3
- package/test/spec/modules/sovrnBidAdapter_spec.js +71 -3
- package/test/spec/modules/teadsBidAdapter_spec.js +9 -4
- package/test/spec/modules/ttdBidAdapter_spec.js +24 -2
- package/test/spec/modules/uid2IdSystem_helpers.js +5 -2
- package/test/spec/modules/userId_spec.js +142 -387
- package/test/spec/modules/yieldoneAnalyticsAdapter_spec.js +13 -12
- package/test/spec/modules/zeotapIdPlusIdSystem_spec.js +3 -69
- package/wdio.shared.conf.js +2 -2
- package/CLAUDE.md +0 -1
|
@@ -157,31 +157,40 @@ export const spec = {
|
|
|
157
157
|
return [];
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
return converter.fromORTB({ response: body, request: bidderRequest.data }).bids
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
160
|
+
return converter.fromORTB({ response: body, request: bidderRequest.data }).bids
|
|
161
|
+
.filter((prebidBid, index) => !!bids[index].adm || !!bids[index].nurl)
|
|
162
|
+
.map((prebidBid, index) => {
|
|
163
|
+
const bid = bids[index];
|
|
164
|
+
const replacements = {
|
|
165
|
+
auctionPrice: prebidBid.cpm,
|
|
166
|
+
auctionId: prebidBid.requestId,
|
|
167
|
+
auctionBidId: bid.bidid,
|
|
168
|
+
auctionImpId: bid.impid,
|
|
169
|
+
auctionSeatId: prebidBid.seatBidId,
|
|
170
|
+
auctionAdId: bid.adid,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const bidAdmWithReplacedMacros = replaceMacros(bid.adm, replacements);
|
|
174
|
+
|
|
175
|
+
if (isVideoType(prebidBid.mediaType)) {
|
|
176
|
+
if (bidAdmWithReplacedMacros) {
|
|
177
|
+
prebidBid.vastXml = bidAdmWithReplacedMacros;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (bid.nurl) {
|
|
181
|
+
if (!prebidBid.vastXml) {
|
|
182
|
+
prebidBid.vastUrl = replaceMacros(bid.nurl, replacements);
|
|
183
|
+
} else {
|
|
184
|
+
// We do not want to use the vastUrl if we have the vastXml
|
|
185
|
+
delete prebidBid.vastUrl
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
prebidBid.ad = bidAdmWithReplacedMacros;
|
|
178
190
|
}
|
|
179
|
-
} else {
|
|
180
|
-
prebidBid.ad = bidAdmWithReplacedMacros;
|
|
181
|
-
}
|
|
182
191
|
|
|
183
|
-
|
|
184
|
-
|
|
192
|
+
return prebidBid;
|
|
193
|
+
});
|
|
185
194
|
},
|
|
186
195
|
|
|
187
196
|
getUserSyncs(syncOptions, serverResponses) {
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { submodule } from '../src/hook.js';
|
|
2
|
+
import { logError, mergeDeep, logMessage, deepSetValue, deepAccess } from '../src/utils.js';
|
|
3
|
+
import { getCoreStorageManager } from '../src/storageManager.js';
|
|
4
|
+
|
|
5
|
+
/* global LanguageDetector, Summarizer */
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const CONSTANTS = Object.freeze({
|
|
11
|
+
SUBMODULE_NAME: 'chromeAi',
|
|
12
|
+
REAL_TIME_MODULE: 'realTimeData',
|
|
13
|
+
LOG_PRE_FIX: 'ChromeAI-Rtd-Provider:',
|
|
14
|
+
STORAGE_KEY: 'chromeAi_detected_data', // Single key for both language and keywords
|
|
15
|
+
MIN_TEXT_LENGTH: 20,
|
|
16
|
+
DEFAULT_CONFIG: {
|
|
17
|
+
languageDetector: {
|
|
18
|
+
enabled: true,
|
|
19
|
+
confidence: 0.8,
|
|
20
|
+
ortb2Path: 'site.content.language' // Default path for language
|
|
21
|
+
},
|
|
22
|
+
summarizer: {
|
|
23
|
+
enabled: false,
|
|
24
|
+
type: 'headline', // 'headline' or 'paragraph'
|
|
25
|
+
format: 'markdown', // 'markdown' or 'plaintext'
|
|
26
|
+
length: 'short', // 'short', 'medium', or 'long'
|
|
27
|
+
ortb2Path: 'site.content.keywords', // Default path for keywords
|
|
28
|
+
cacheInLocalStorage: true // Whether to cache detected keywords in localStorage
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const storage = getCoreStorageManager(CONSTANTS.SUBMODULE_NAME);
|
|
34
|
+
let moduleConfig = JSON.parse(JSON.stringify(CONSTANTS.DEFAULT_CONFIG));
|
|
35
|
+
let detectedKeywords = null; // To store generated summary/keywords
|
|
36
|
+
|
|
37
|
+
// Helper to initialize Chrome AI API instances (LanguageDetector, Summarizer)
|
|
38
|
+
const _createAiApiInstance = async (ApiConstructor, options) => {
|
|
39
|
+
const apiName = ApiConstructor.name; // e.g., "LanguageDetector" or "Summarizer"
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
if (!(apiName in self) || typeof self[apiName] !== 'function') { // Also check if it's a function (constructor)
|
|
43
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} ${apiName} API not available or not a constructor in self.`);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const availability = await ApiConstructor.availability();
|
|
48
|
+
if (availability === 'unavailable') {
|
|
49
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} ${apiName} is unavailable.`);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let instance;
|
|
54
|
+
if (availability === 'available') {
|
|
55
|
+
instance = await ApiConstructor.create(options);
|
|
56
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} ${apiName} instance created (was available).`);
|
|
57
|
+
} else { // Assuming 'after-download' or similar state if not 'available'
|
|
58
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} ${apiName} model needs download.`);
|
|
59
|
+
|
|
60
|
+
instance = await ApiConstructor.create(options);
|
|
61
|
+
instance.addEventListener('downloadprogress', (e) => {
|
|
62
|
+
const progress = e.total > 0 ? Math.round(e.loaded / e.total * 100) : (e.loaded > 0 ? 'In progress' : 'Starting');
|
|
63
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} ${apiName} model DL: ${progress}${e.total > 0 ? '%' : ''}`);
|
|
64
|
+
});
|
|
65
|
+
await instance.ready;
|
|
66
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} ${apiName} model ready after download.`);
|
|
67
|
+
}
|
|
68
|
+
return instance;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error creating ${apiName} instance:`, error);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const mergeModuleConfig = (config) => {
|
|
76
|
+
// Start with a deep copy of default_config to ensure all keys are present
|
|
77
|
+
let newConfig = JSON.parse(JSON.stringify(CONSTANTS.DEFAULT_CONFIG));
|
|
78
|
+
if (config?.params) {
|
|
79
|
+
mergeDeep(newConfig, config.params);
|
|
80
|
+
}
|
|
81
|
+
moduleConfig = newConfig; // Assign to module-level variable
|
|
82
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Module config set:`, moduleConfig);
|
|
83
|
+
return moduleConfig;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const getCurrentUrl = () => window.location.href;
|
|
87
|
+
|
|
88
|
+
export const getPageText = () => {
|
|
89
|
+
const text = document.body.textContent;
|
|
90
|
+
if (!text || text.length < CONSTANTS.MIN_TEXT_LENGTH) {
|
|
91
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Not enough text content (length: ${text?.length || 0}) for processing.`);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return text;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// --- Chrome AI LocalStorage Helper Functions ---
|
|
98
|
+
export const _getChromeAiDataFromLocalStorage = (url) => {
|
|
99
|
+
if (!storage.hasLocalStorage() || !storage.localStorageIsEnabled()) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const currentUrl = url || getCurrentUrl();
|
|
103
|
+
const storedJson = storage.getDataFromLocalStorage(CONSTANTS.STORAGE_KEY);
|
|
104
|
+
if (storedJson) {
|
|
105
|
+
try {
|
|
106
|
+
const storedObject = JSON.parse(storedJson);
|
|
107
|
+
return storedObject?.[currentUrl] || null;
|
|
108
|
+
} catch (e) {
|
|
109
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error parsing Chrome AI data from localStorage:`, e);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const _storeChromeAiDataInLocalStorage = (url, data) => {
|
|
116
|
+
try {
|
|
117
|
+
if (!storage.hasLocalStorage() || !storage.localStorageIsEnabled()) {
|
|
118
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} localStorage is not available, cannot store Chrome AI data.`);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
let overallStorageObject = {};
|
|
122
|
+
const existingStoredJson = storage.getDataFromLocalStorage(CONSTANTS.STORAGE_KEY);
|
|
123
|
+
if (existingStoredJson) {
|
|
124
|
+
try {
|
|
125
|
+
overallStorageObject = JSON.parse(existingStoredJson);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error parsing existing Chrome AI data from localStorage:`, e);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const currentUrl = url || getCurrentUrl();
|
|
131
|
+
overallStorageObject[currentUrl] = {
|
|
132
|
+
...overallStorageObject[currentUrl], // Preserve any existing data
|
|
133
|
+
...data // Overwrite or add new data
|
|
134
|
+
};
|
|
135
|
+
storage.setDataInLocalStorage(CONSTANTS.STORAGE_KEY, JSON.stringify(overallStorageObject));
|
|
136
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Chrome AI data stored in localStorage for ${currentUrl}:`, data);
|
|
137
|
+
return true;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error storing Chrome AI data to localStorage:`, error);
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const isLanguageInLocalStorage = (url) => {
|
|
145
|
+
const chromeAiData = _getChromeAiDataFromLocalStorage(url);
|
|
146
|
+
return chromeAiData?.language || null;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const getPrioritizedLanguageData = (reqBidsConfigObj) => {
|
|
150
|
+
// 1. Check auction-specific ORTB2 (passed in reqBidsConfigObj for getBidRequestData)
|
|
151
|
+
// Uses configurable path for language
|
|
152
|
+
if (reqBidsConfigObj && moduleConfig.languageDetector) {
|
|
153
|
+
const langPath = moduleConfig.languageDetector.ortb2Path;
|
|
154
|
+
const lang = deepAccess(reqBidsConfigObj.ortb2Fragments?.global, langPath);
|
|
155
|
+
if (lang) {
|
|
156
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Language '${lang}' found in auction-specific ortb2Fragments at path '${langPath}'.`);
|
|
157
|
+
return { language: lang, source: 'auction_ortb2' };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 2. Check localStorage (relevant for both init and getBidRequestData)
|
|
162
|
+
const storedLangData = isLanguageInLocalStorage(getCurrentUrl());
|
|
163
|
+
if (storedLangData) {
|
|
164
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Language '${storedLangData.language}' found in localStorage.`);
|
|
165
|
+
return { ...storedLangData, source: 'localStorage' };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return null;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const getPrioritizedKeywordsData = (reqBidsConfigObj) => {
|
|
172
|
+
// 1. Check auction-specific ORTB2 (passed in reqBidsConfigObj for getBidRequestData)
|
|
173
|
+
if (reqBidsConfigObj && moduleConfig.summarizer) {
|
|
174
|
+
const keywordsPath = moduleConfig.summarizer.ortb2Path;
|
|
175
|
+
const keywords = deepAccess(reqBidsConfigObj.ortb2Fragments?.global, keywordsPath);
|
|
176
|
+
if (keywords && Array.isArray(keywords) && keywords.length > 0) {
|
|
177
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Keywords found in auction-specific ortb2Fragments at path '${keywordsPath}'.`, keywords);
|
|
178
|
+
return { keywords: keywords, source: 'auction_ortb2' };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 2. Check localStorage (if enabled)
|
|
183
|
+
if (moduleConfig.summarizer?.cacheInLocalStorage === true) {
|
|
184
|
+
const chromeAiData = _getChromeAiDataFromLocalStorage();
|
|
185
|
+
const storedKeywords = chromeAiData?.keywords;
|
|
186
|
+
if (storedKeywords && Array.isArray(storedKeywords) && storedKeywords.length > 0) {
|
|
187
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Keywords found in localStorage.`, storedKeywords);
|
|
188
|
+
return { keywords: storedKeywords, source: 'localStorage' };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export const storeDetectedLanguage = (language, confidence, url) => {
|
|
195
|
+
if (!language) {
|
|
196
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} No valid language to store`);
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
const dataPayload = { language: language, confidence: confidence };
|
|
200
|
+
return _storeChromeAiDataInLocalStorage(url, { language: dataPayload });
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export const detectLanguage = async (text) => {
|
|
204
|
+
const detector = await _createAiApiInstance(LanguageDetector);
|
|
205
|
+
if (!detector) {
|
|
206
|
+
return null; // Error already logged by _createAiApiInstance
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
const results = await detector.detect(text);
|
|
211
|
+
if (!results || results.length === 0) {
|
|
212
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} No language results from API.`);
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const topResult = results[0];
|
|
216
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Detected lang: ${topResult.detectedLanguage} (conf: ${topResult.confidence.toFixed(2)})`);
|
|
217
|
+
if (topResult.confidence < moduleConfig.languageDetector.confidence) {
|
|
218
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Lang confidence (${topResult.confidence.toFixed(2)}) < threshold (${moduleConfig.languageDetector.confidence}).`);
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
return { language: topResult.detectedLanguage, confidence: topResult.confidence };
|
|
222
|
+
} catch (error) {
|
|
223
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error during LanguageDetector.detect():`, error);
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export const detectSummary = async (text, config) => {
|
|
229
|
+
const summaryOptions = {
|
|
230
|
+
type: config.type,
|
|
231
|
+
format: config.format,
|
|
232
|
+
length: config.length,
|
|
233
|
+
};
|
|
234
|
+
const summarizer = await _createAiApiInstance(Summarizer, summaryOptions);
|
|
235
|
+
if (!summarizer) {
|
|
236
|
+
return null; // Error already logged by _createAiApiInstance
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
const summaryResult = await summarizer.summarize(text, summaryOptions);
|
|
241
|
+
if (!summaryResult) {
|
|
242
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} No summary result from API.`);
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Summary generated (type: ${summaryOptions.type}, len: ${summaryOptions.length}):`, summaryResult.substring(0, 100) + '...');
|
|
246
|
+
return summaryResult; // This is a string
|
|
247
|
+
} catch (error) {
|
|
248
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error during Summarizer.summarize():`, error);
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const initLanguageDetector = async () => {
|
|
254
|
+
const existingLanguage = getPrioritizedLanguageData(null); // Pass null or undefined for reqBidsConfigObj
|
|
255
|
+
if (existingLanguage && existingLanguage.source === 'localStorage') {
|
|
256
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Language detection skipped, language '${existingLanguage.language}' found in localStorage.`);
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const pageText = getPageText();
|
|
261
|
+
if (!pageText) return false;
|
|
262
|
+
|
|
263
|
+
const detectionResult = await detectLanguage(pageText);
|
|
264
|
+
if (!detectionResult) {
|
|
265
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Failed to detect language from page content.`);
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
return storeDetectedLanguage(detectionResult.language, detectionResult.confidence, getCurrentUrl());
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
export const storeDetectedKeywords = (keywords, url) => {
|
|
272
|
+
if (!keywords || !Array.isArray(keywords) || keywords.length === 0) {
|
|
273
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} No valid keywords array to store`);
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
return _storeChromeAiDataInLocalStorage(url, { keywords: keywords });
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const initSummarizer = async () => {
|
|
280
|
+
// Check for prioritized/cached keywords first (reqBidsConfigObj is null during init)
|
|
281
|
+
const prioritizedData = getPrioritizedKeywordsData(null);
|
|
282
|
+
if (prioritizedData && prioritizedData.source === 'localStorage') {
|
|
283
|
+
detectedKeywords = prioritizedData.keywords;
|
|
284
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Summarizer skipped, keywords from localStorage.`, detectedKeywords);
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
// If auction_ortb2 had data, it would be handled by getBidRequestData directly, init focuses on detection/localStorage
|
|
288
|
+
|
|
289
|
+
const pageText = getPageText();
|
|
290
|
+
if (!pageText) {
|
|
291
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Summarizer: No/short text, cannot generate keywords.`);
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!moduleConfig.summarizer) {
|
|
296
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Summarizer config missing during init.`);
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const summaryText = await detectSummary(pageText, moduleConfig.summarizer);
|
|
301
|
+
if (summaryText) {
|
|
302
|
+
// The API returns a single summary string. We treat this string as a single keyword.
|
|
303
|
+
// If multiple keywords were desired from the summary, further processing would be needed here.
|
|
304
|
+
detectedKeywords = [summaryText];
|
|
305
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Summary processed and new keywords generated:`, detectedKeywords);
|
|
306
|
+
|
|
307
|
+
if (moduleConfig.summarizer.cacheInLocalStorage === true) {
|
|
308
|
+
storeDetectedKeywords(detectedKeywords, getCurrentUrl());
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Failed to generate summary, no new keywords.`);
|
|
313
|
+
return false;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const init = async (config) => {
|
|
317
|
+
moduleConfig = mergeModuleConfig(config);
|
|
318
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Initializing with config:`, moduleConfig);
|
|
319
|
+
|
|
320
|
+
const activeInitializations = [];
|
|
321
|
+
|
|
322
|
+
if (moduleConfig.languageDetector?.enabled !== false) {
|
|
323
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Language detection enabled. Initializing...`);
|
|
324
|
+
activeInitializations.push(initLanguageDetector());
|
|
325
|
+
} else {
|
|
326
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Language detection disabled by config.`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Summarizer Initialization
|
|
330
|
+
if (moduleConfig.summarizer?.enabled === true) {
|
|
331
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Summarizer enabled. Initializing...`);
|
|
332
|
+
activeInitializations.push(initSummarizer());
|
|
333
|
+
} else {
|
|
334
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Summarizer disabled by config.`);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (activeInitializations.length === 0) {
|
|
338
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} No features enabled for initialization.`);
|
|
339
|
+
return true; // Module is considered initialized if no features are active/enabled.
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Wait for all enabled features to attempt initialization
|
|
343
|
+
try {
|
|
344
|
+
const results = await Promise.all(activeInitializations);
|
|
345
|
+
// Consider init successful if at least one feature init succeeded, or if no features were meant to run.
|
|
346
|
+
const overallSuccess = results.length > 0 ? results.some(result => result === true) : true;
|
|
347
|
+
if (overallSuccess) {
|
|
348
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Relevant features initialized.`);
|
|
349
|
+
} else {
|
|
350
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} All enabled features failed to initialize.`);
|
|
351
|
+
}
|
|
352
|
+
return overallSuccess;
|
|
353
|
+
} catch (error) {
|
|
354
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error during feature initializations:`, error);
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Add language data to bid request
|
|
361
|
+
* @param {Object} reqBidsConfigObj - Request bids configuration object
|
|
362
|
+
* @param {function} callback - Callback function
|
|
363
|
+
*/
|
|
364
|
+
const getBidRequestData = (reqBidsConfigObj, callback) => {
|
|
365
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} reqBidsConfigObj:`, reqBidsConfigObj);
|
|
366
|
+
|
|
367
|
+
// Ensure ortb2Fragments and global path exist for potential deepSetValue operations
|
|
368
|
+
reqBidsConfigObj.ortb2Fragments = reqBidsConfigObj.ortb2Fragments || {};
|
|
369
|
+
reqBidsConfigObj.ortb2Fragments.global = reqBidsConfigObj.ortb2Fragments.global || {};
|
|
370
|
+
|
|
371
|
+
// Language Data Enrichment
|
|
372
|
+
if (moduleConfig.languageDetector?.enabled !== false) {
|
|
373
|
+
const languageData = getPrioritizedLanguageData(reqBidsConfigObj);
|
|
374
|
+
if (languageData && languageData.source !== 'auction_ortb2') {
|
|
375
|
+
const langPath = moduleConfig.languageDetector.ortb2Path;
|
|
376
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Enriching ORTB2 path '${langPath}' with lang '${languageData.language}' from ${languageData.source}.`);
|
|
377
|
+
deepSetValue(reqBidsConfigObj.ortb2Fragments.global, langPath, languageData.language);
|
|
378
|
+
} else if (languageData?.source === 'auction_ortb2') {
|
|
379
|
+
const langPath = moduleConfig.languageDetector.ortb2Path;
|
|
380
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Lang already in auction ORTB2 at path '${langPath}', no enrichment needed.`);
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Language detection disabled, no lang enrichment.`);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Summarizer Data (Keywords) Enrichment
|
|
387
|
+
if (moduleConfig.summarizer?.enabled === true) {
|
|
388
|
+
const keywordsPath = moduleConfig.summarizer.ortb2Path;
|
|
389
|
+
const auctionKeywords = deepAccess(reqBidsConfigObj.ortb2Fragments.global, keywordsPath);
|
|
390
|
+
|
|
391
|
+
if (auctionKeywords && Array.isArray(auctionKeywords) && auctionKeywords.length > 0) {
|
|
392
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Keywords already present in auction_ortb2 at path '${keywordsPath}', no enrichment from module.`, auctionKeywords);
|
|
393
|
+
} else {
|
|
394
|
+
// auction_ortb2 path is empty, try to use keywords from initSummarizer (localStorage or fresh detection)
|
|
395
|
+
if (detectedKeywords && detectedKeywords.length > 0) {
|
|
396
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Enriching ORTB2 path '${keywordsPath}' with keywords from module (localStorage/detection):`, detectedKeywords);
|
|
397
|
+
deepSetValue(reqBidsConfigObj.ortb2Fragments.global, keywordsPath, detectedKeywords);
|
|
398
|
+
} else {
|
|
399
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Summarizer enabled, but no keywords from auction_ortb2, localStorage, or fresh detection for path '${keywordsPath}'.`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
} else {
|
|
403
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Summarizer disabled, no keyword enrichment.`);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} Final reqBidsConfigObj for auction:`, reqBidsConfigObj);
|
|
407
|
+
callback();
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
/** @type {RtdSubmodule} */
|
|
411
|
+
export const chromeAiSubmodule = {
|
|
412
|
+
name: CONSTANTS.SUBMODULE_NAME,
|
|
413
|
+
init,
|
|
414
|
+
getBidRequestData
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
export const registerSubModule = () => {
|
|
418
|
+
submodule(CONSTANTS.REAL_TIME_MODULE, chromeAiSubmodule);
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
registerSubModule();
|