@bytebrand/export-cars 1.26.28 → 1.26.30
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 +100 -0
- package/dist/configs/index.d.ts +1 -0
- package/dist/configs/index.js +1 -0
- package/dist/configs/index.js.map +1 -1
- package/dist/configs/openai-ads.config.d.ts +22 -0
- package/dist/configs/openai-ads.config.js +56 -0
- package/dist/configs/openai-ads.config.js.map +1 -0
- package/dist/enums/export-type.enum.d.ts +2 -1
- package/dist/enums/export-type.enum.js +1 -0
- package/dist/enums/export-type.enum.js.map +1 -1
- package/dist/enums/image-type.enum.d.ts +2 -1
- package/dist/enums/image-type.enum.js +1 -0
- package/dist/enums/image-type.enum.js.map +1 -1
- package/dist/export.schema.d.ts +6 -2
- package/dist/export.schema.js +4 -0
- package/dist/export.schema.js.map +1 -1
- package/dist/exporters/index.d.ts +1 -0
- package/dist/exporters/index.js +1 -0
- package/dist/exporters/index.js.map +1 -1
- package/dist/exporters/openai-ads.exporter.d.ts +13 -0
- package/dist/exporters/openai-ads.exporter.js +91 -0
- package/dist/exporters/openai-ads.exporter.js.map +1 -0
- package/dist/formats/openai-ads-csv.builder.d.ts +15 -0
- package/dist/formats/openai-ads-csv.builder.js +48 -0
- package/dist/formats/openai-ads-csv.builder.js.map +1 -0
- package/dist/interfaces/openai-ads.interface.d.ts +35 -0
- package/dist/interfaces/openai-ads.interface.js +37 -0
- package/dist/interfaces/openai-ads.interface.js.map +1 -0
- package/dist/interfaces/params.interface.d.ts +10 -0
- package/dist/services/feed-guard.d.ts +44 -0
- package/dist/services/feed-guard.js +156 -0
- package/dist/services/feed-guard.js.map +1 -0
- package/dist/services/image-url-validator.service.d.ts +45 -0
- package/dist/services/image-url-validator.service.js +141 -0
- package/dist/services/image-url-validator.service.js.map +1 -0
- package/dist/services/images.service.d.ts +12 -0
- package/dist/services/images.service.js +46 -1
- package/dist/services/images.service.js.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/openai-ads-feed-run.d.ts +74 -0
- package/dist/services/openai-ads-feed-run.js +151 -0
- package/dist/services/openai-ads-feed-run.js.map +1 -0
- package/dist/services/openai-ads-ledger.d.ts +19 -0
- package/dist/services/openai-ads-ledger.js +72 -0
- package/dist/services/openai-ads-ledger.js.map +1 -0
- package/dist/services/publication-gate.js +8 -8
- package/dist/transformers/openai-ads.transformer.d.ts +29 -0
- package/dist/transformers/openai-ads.transformer.js +166 -0
- package/dist/transformers/openai-ads.transformer.js.map +1 -0
- package/dist/transformers/openai-image-fields.d.ts +16 -0
- package/dist/transformers/openai-image-fields.js +34 -0
- package/dist/transformers/openai-image-fields.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/openai-ads/AUDIT.md +235 -0
- package/docs/openai-ads/RUNBOOK.md +94 -0
- package/package.json +64 -64
- package/schema/feed-items.json +134 -134
- package/src/configs/config.ts +99 -99
- package/src/configs/index.ts +1 -0
- package/src/configs/openai-ads.config.ts +70 -0
- package/src/enums/export-type.enum.ts +2 -0
- package/src/enums/image-type.enum.ts +5 -0
- package/src/export.schema.ts +6 -0
- package/src/exporters/index.ts +1 -0
- package/src/exporters/openai-ads.exporter.ts +93 -0
- package/src/formats/openai-ads-csv.builder.ts +55 -0
- package/src/interfaces/openai-ads.interface.ts +64 -0
- package/src/interfaces/params.interface.ts +13 -0
- package/src/services/feed-guard.ts +219 -0
- package/src/services/image-url-validator.service.ts +181 -0
- package/src/services/images.service.ts +72 -0
- package/src/services/index.ts +1 -0
- package/src/services/openai-ads-feed-run.ts +226 -0
- package/src/services/openai-ads-ledger.ts +116 -0
- package/src/services/publication-gate.ts +119 -119
- package/src/transformers/openai-ads.transformer.ts +243 -0
- package/src/transformers/openai-image-fields.ts +60 -0
- package/test/clean-images.test.ts +86 -0
- package/test/fixtures/images-service.harness.ts +32 -0
- package/test/fixtures/images.golden.json +218 -0
- package/test/fixtures/imbo-images.fixture.ts +77 -0
- package/test/fixtures/openai-ads.fixture.ts +89 -0
- package/test/image-url-validator.test.ts +110 -0
- package/test/images-regression.test.ts +23 -0
- package/test/openai-ads-feed-run.test.ts +278 -0
- package/test/openai-ads-mapping.test.ts +157 -0
- package/test/openai-image-fields.test.ts +99 -0
- package/test/publication-gate.test.ts +86 -86
package/README.md
CHANGED
|
@@ -47,6 +47,106 @@ bq mk --table \
|
|
|
47
47
|
|
|
48
48
|
Tables created before 1.26.28 need the two gate columns: `bq update <table> schema/feed-items.json`.
|
|
49
49
|
|
|
50
|
+
## Clean images for ChatGPT Ads / OpenAI product feed (ADV-336)
|
|
51
|
+
|
|
52
|
+
Library only. The OpenAI ExportType, transformer and version bump come with ADV-335.
|
|
53
|
+
|
|
54
|
+
**Clean profile** (`ImageType.clean`, `ImagesService.getCleanImages`):
|
|
55
|
+
- Uses only the car's own Imbo photos (the loader's cleaned list), ordered deterministically:
|
|
56
|
+
- the hero first: a 3/4 exterior, `ext_f_right`, else `ext_f_left`;
|
|
57
|
+
- then the other exterior views, then the interior views (`IMAGES_SORT_ORDER`).
|
|
58
|
+
- Drops `_feat_` close-ups, `conext_*`, codes unknown to `IMAGES_SORT_ORDER` (e.g. `simple_*`, `middle_console`,
|
|
59
|
+
`ext_lr_main`) and repeated imageIdentifiers.
|
|
60
|
+
- Returns `[]` when there is no 3/4 exterior shot: the car is skipped. A placeholder is never added.
|
|
61
|
+
- Every URL is the explicit JPEG `https://images.auto.de/carimage/{carId}/{imageId}/large-cached.jpeg`. The
|
|
62
|
+
extension-less `.../large` returns WebP or JPEG depending on the `Accept` header (no `Vary`), so the format
|
|
63
|
+
a crawler gets could differ from the one we checked.
|
|
64
|
+
- What the images host does to these photos (imbo `background` transform):
|
|
65
|
+
- plates are blurred;
|
|
66
|
+
- EXIF orientation is applied;
|
|
67
|
+
- images are not upscaled; the output is about 1000–1600 px wide, 4:3 for background-removed photos;
|
|
68
|
+
- no overlay or logo.
|
|
69
|
+
|
|
70
|
+
No sRGB conversion is done; source photos carry no ICC profile.
|
|
71
|
+
- The Meta AIA financing images (`generated_images/.../meta-aia-financing-*`) are never used here. A rate or
|
|
72
|
+
financing overlay stays off.
|
|
73
|
+
|
|
74
|
+
**URL check** (`ImageUrlValidator`, one instance per export run):
|
|
75
|
+
- Sends HEAD, falling back to GET on 405/501, with a bounded number of parallel requests. Each URL is checked once per run.
|
|
76
|
+
- A URL is valid only if:
|
|
77
|
+
- the final status is 200;
|
|
78
|
+
- the MIME type is `image/jpeg` or `image/png` (WebP only if a partner explicitly allows it);
|
|
79
|
+
- it is HTTPS;
|
|
80
|
+
- it has no credentials and is not a `noimage` placeholder;
|
|
81
|
+
- redirects stay within `maxRedirects`.
|
|
82
|
+
- images.auto.de answers unknown, deleted or foreign-car images with **404 plus an image/jpeg body**, so the
|
|
83
|
+
Content-Type alone proves nothing.
|
|
84
|
+
- `stats` returns per-reason counts for the run log: `http_status`, `wrong_mime`, `timeout`,
|
|
85
|
+
`too_many_redirects`, `placeholder`, `not_https`, `credentials_in_url`, `invalid_url`, `network_error`,
|
|
86
|
+
`budget_exhausted`.
|
|
87
|
+
|
|
88
|
+
**OpenAI fields** (`transformers/openai-image-fields.ts`):
|
|
89
|
+
- `image_url` = the first valid hero candidate.
|
|
90
|
+
- `additional_image_urls` = all other valid images, exterior before interior, with no count limit (OpenAI states none).
|
|
91
|
+
- No valid hero means `fields: null`: skip the car and count it.
|
|
92
|
+
- Serialization:
|
|
93
|
+
- CSV: `serializeAdditionalImageUrlsForCsv` gives one quoted cell, URLs comma-separated, commas inside URLs as `%2C`.
|
|
94
|
+
- JSONL: `serializeAdditionalImageUrlsForJsonl` gives an array.
|
|
95
|
+
- Do not mix these with the Google-compatible `image_link` / `additional_image_link`.
|
|
96
|
+
- OpenAI states no pixel, ratio, byte or count limits for product images. None are enforced here, and none
|
|
97
|
+
may be added without the account's written requirements (GATE subtask).
|
|
98
|
+
|
|
99
|
+
**Crawler access**
|
|
100
|
+
- Images host `images.auto.de`:
|
|
101
|
+
- direct nginx, not behind Cloudflare, so no WAF;
|
|
102
|
+
- `robots.txt` returns 404, which means everything is allowed;
|
|
103
|
+
- OAI-SearchBot gets 200.
|
|
104
|
+
- CDP `www.auto.de/search/vehicle/<id>`:
|
|
105
|
+
- `services/content-wordpress/wp/robots.txt` disallows `/search/` for `*`. OpenAI crawlers obey robots.txt,
|
|
106
|
+
so a dedicated `OAI-AdsBot` group allows `/search/vehicle/` and repeats the `*` Disallow rules (a bot with
|
|
107
|
+
its own group ignores `*`). Keep both groups in sync.
|
|
108
|
+
- OAI-SearchBot stays under `*`.
|
|
109
|
+
- Cloudflare: the custom rule "Allow Search Bots" (`cf.client.bot`, skip) runs before "captcha for search"
|
|
110
|
+
(js_challenge on `www.auto.de/search`). A CF-verified OAI-AdsBot should pass. Unverified clients outside
|
|
111
|
+
DACH get a 403 challenge. No CF rule change was made.
|
|
112
|
+
|
|
113
|
+
**QA / runbook**
|
|
114
|
+
- Unit and regression tests: `npm test`.
|
|
115
|
+
- `test/images-regression.test.ts` compares every existing image output (default, marketing, Google ext/int)
|
|
116
|
+
with `test/fixtures/images.golden.json`. That file was recorded before this change. Never regenerate it to
|
|
117
|
+
make the test pass.
|
|
118
|
+
- Real-photo check: build the clean list from the public Imbo list
|
|
119
|
+
`https://www.auto.de/service/image-imbo/users/<carId>/images.json?fields[]=imageIdentifier&fields[]=metadata&metadata=1&limit=0`,
|
|
120
|
+
then run `ImageUrlValidator` with an OAI-SearchBot `userAgent`.
|
|
121
|
+
- Crawler check: with an OAI-AdsBot UA, `curl https://www.auto.de/robots.txt` and the CDP. Run from a non-DACH
|
|
122
|
+
vantage and expect a challenge unless the IP is a verified OpenAI one.
|
|
123
|
+
- Rollback:
|
|
124
|
+
- library: nothing uses `ImageType.clean` until ADV-335 wires it, so revert the commit;
|
|
125
|
+
- robots.txt: remove the `OAI-AdsBot` group and redeploy content-wordpress.
|
|
126
|
+
|
|
127
|
+
**Known risks / open questions**
|
|
128
|
+
- No revision marker in v1. An in-place Imbo `PUT` keeps the imageIdentifier, so the same URL can serve new
|
|
129
|
+
bytes from a stale cache. After a car is deleted, cached image URLs can keep answering 200 until the cache
|
|
130
|
+
expires. Mitigations:
|
|
131
|
+
- send a full catalog upload on every image or description change (ADV-335);
|
|
132
|
+
- re-validate on every run.
|
|
133
|
+
- `ext_lr_main` (a real side or rear-3/4 exterior shot, present on most cars) is unknown to `IMAGES_SORT_ORDER`,
|
|
134
|
+
so the clean profile drops it.
|
|
135
|
+
- The CDP is a client-side SPA with no SSR (fe-main nginx serves `index.html` for `/search*`). A crawler that
|
|
136
|
+
doesn't run JS sees an empty page, which is a risk for the OAI-AdsBot landing-page review.
|
|
137
|
+
- Pre-existing: the `DEFAULT_IMAGES` placeholders (`carimage/noimage/...`) answer 404, yet default-type partner
|
|
138
|
+
feeds append them when a car has fewer than 17 photos. Separate ticket.
|
|
139
|
+
- Marketing: open www to OAI-SearchBot (ChatGPT search indexing)? Not done, business decision.
|
|
140
|
+
- No rights or licence flag exists in the Imbo metadata, so "missing rights" cannot be enforced from data.
|
|
141
|
+
- Before go-live, the account's image requirements must be confirmed with OpenAI (GATE).
|
|
142
|
+
|
|
143
|
+
## OpenAI Ads vehicle feed (`exportType=openai_ads`, ADV-335)
|
|
144
|
+
|
|
145
|
+
OpenAI-format product CSV for ChatGPT Ads, built from the base export snapshot with the clean images above.
|
|
146
|
+
Dry-run by default (`resources/openai_ads-dryrun/`), fail-closed (`services/feed-guard.ts`), sold/removed cars kept as
|
|
147
|
+
`out_of_stock` via a ledger of sent ids. No transport yet. Mapping and open questions: `docs/openai-ads/AUDIT.md`;
|
|
148
|
+
params, guard codes, monitoring and rollback: `docs/openai-ads/RUNBOOK.md`.
|
|
149
|
+
|
|
50
150
|
## Publication gate for estimated EnVKV values (EnVKV C8)
|
|
51
151
|
|
|
52
152
|
car-basic-data fills missing or implausible consumption / CO2 values from the CO2 estimator, the
|
package/dist/configs/index.d.ts
CHANGED
package/dist/configs/index.js
CHANGED
|
@@ -36,4 +36,5 @@ __exportStar(require("./mitula.config"), exports);
|
|
|
36
36
|
__exportStar(require("./awin.config"), exports);
|
|
37
37
|
__exportStar(require("./evium.config"), exports);
|
|
38
38
|
__exportStar(require("./santander.config"), exports);
|
|
39
|
+
__exportStar(require("./openai-ads.config"), exports);
|
|
39
40
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/configs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,gDAA8B;AAC9B,kDAAgC;AAChC,qDAAmC;AACnC,oDAAkC;AAClC,kDAAgC;AAChC,sDAAoC;AACpC,iDAA+B;AAC/B,8CAA4B;AAC5B,kDAAgC;AAChC,6DAA2C;AAC3C,mDAAiC;AACjC,qDAAmC;AACnC,iDAA+B;AAC/B,kDAAgC;AAChC,sDAAoC;AACpC,yDAAuC;AACvC,kDAAgC;AAChC,kDAAgC;AAChC,gDAA8B;AAC9B,iDAA+B;AAC/B,qDAAmC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/configs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,gDAA8B;AAC9B,kDAAgC;AAChC,qDAAmC;AACnC,oDAAkC;AAClC,kDAAgC;AAChC,sDAAoC;AACpC,iDAA+B;AAC/B,8CAA4B;AAC5B,kDAAgC;AAChC,6DAA2C;AAC3C,mDAAiC;AACjC,qDAAmC;AACnC,iDAA+B;AAC/B,kDAAgC;AAChC,sDAAoC;AACpC,yDAAuC;AACvC,kDAAgC;AAChC,kDAAgC;AAChC,gDAA8B;AAC9B,iDAA+B;AAC/B,qDAAmC;AACnC,sDAAoC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Params } from '../interfaces/params.interface';
|
|
2
|
+
import { FeedGuardOptions } from '../services/feed-guard';
|
|
3
|
+
import { Config } from './config';
|
|
4
|
+
export declare const OPENAI_ADS_DEFAULTS: {
|
|
5
|
+
sellerName: string;
|
|
6
|
+
retentionDays: number;
|
|
7
|
+
imageConcurrency: number;
|
|
8
|
+
minSourceItems: number;
|
|
9
|
+
minPublishedItems: number;
|
|
10
|
+
maxDropPercent: number;
|
|
11
|
+
maxSourceAgeHours: number;
|
|
12
|
+
maxStaleHours: number;
|
|
13
|
+
};
|
|
14
|
+
export declare class OpenAiAdsConfig extends Config {
|
|
15
|
+
dryRun: boolean;
|
|
16
|
+
sellerName: string;
|
|
17
|
+
retentionDays: number;
|
|
18
|
+
imageConcurrency: number;
|
|
19
|
+
stateDir: string;
|
|
20
|
+
feedGuard: FeedGuardOptions;
|
|
21
|
+
constructor(params: Params);
|
|
22
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenAiAdsConfig = exports.OPENAI_ADS_DEFAULTS = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
const enums_1 = require("../enums");
|
|
6
|
+
const config_1 = require("./config");
|
|
7
|
+
const text = (value) => (typeof value === 'string' ? value.trim() : '');
|
|
8
|
+
const positiveNumber = (value, fallback) => {
|
|
9
|
+
const parsed = (0, lodash_1.toNumber)(text(value));
|
|
10
|
+
return text(value) && Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
11
|
+
};
|
|
12
|
+
exports.OPENAI_ADS_DEFAULTS = {
|
|
13
|
+
sellerName: 'auto.de',
|
|
14
|
+
retentionDays: 15,
|
|
15
|
+
imageConcurrency: 16,
|
|
16
|
+
minSourceItems: 1000,
|
|
17
|
+
minPublishedItems: 500,
|
|
18
|
+
maxDropPercent: 20,
|
|
19
|
+
maxSourceAgeHours: 26,
|
|
20
|
+
maxStaleHours: 48,
|
|
21
|
+
};
|
|
22
|
+
class OpenAiAdsConfig extends config_1.Config {
|
|
23
|
+
dryRun;
|
|
24
|
+
sellerName;
|
|
25
|
+
retentionDays;
|
|
26
|
+
imageConcurrency;
|
|
27
|
+
stateDir;
|
|
28
|
+
feedGuard;
|
|
29
|
+
constructor(params) {
|
|
30
|
+
super(params);
|
|
31
|
+
this.dryRun = text(params.openAiAdsDryRun).toLowerCase() !== 'false';
|
|
32
|
+
const mode = this.dryRun ? 'dryrun' : 'export';
|
|
33
|
+
this.pathesConfig.localConvertedDirectory = `resources/${enums_1.ExportType.OPENAI_ADS}-${mode}`;
|
|
34
|
+
this.stateDir = `resources/${enums_1.ExportType.OPENAI_ADS}-state/${mode}`;
|
|
35
|
+
this.imageType = enums_1.ImageType.clean;
|
|
36
|
+
this.sellerName = text(params.openAiAdsSellerName) || exports.OPENAI_ADS_DEFAULTS.sellerName;
|
|
37
|
+
this.retentionDays = positiveNumber(params.openAiAdsRetentionDays, exports.OPENAI_ADS_DEFAULTS.retentionDays);
|
|
38
|
+
this.imageConcurrency = positiveNumber(params.openAiAdsImageConcurrency, exports.OPENAI_ADS_DEFAULTS.imageConcurrency);
|
|
39
|
+
const cap = positiveNumber(params.maxCurrentSalesPrice, 0);
|
|
40
|
+
this.maxCurrentSalesPrice = cap || undefined;
|
|
41
|
+
this.feedGuard = {
|
|
42
|
+
stateDir: this.stateDir,
|
|
43
|
+
minSourceItems: positiveNumber(params.feedGuardMinSourceItems, exports.OPENAI_ADS_DEFAULTS.minSourceItems),
|
|
44
|
+
minPublishedItems: positiveNumber(params.feedGuardMinPublishedItems, exports.OPENAI_ADS_DEFAULTS.minPublishedItems),
|
|
45
|
+
maxDropPercent: positiveNumber(params.feedGuardMaxDropPercent, exports.OPENAI_ADS_DEFAULTS.maxDropPercent),
|
|
46
|
+
maxSourceAgeHours: positiveNumber(params.feedGuardMaxSourceAgeHours, exports.OPENAI_ADS_DEFAULTS.maxSourceAgeHours),
|
|
47
|
+
maxStaleHours: positiveNumber(params.feedGuardMaxStaleHours, exports.OPENAI_ADS_DEFAULTS.maxStaleHours),
|
|
48
|
+
acceptDrop: text(params.feedGuardAcceptDrop).toLowerCase() === 'true',
|
|
49
|
+
};
|
|
50
|
+
this.outputFiles = [
|
|
51
|
+
`${this.pathesConfig.localConvertedDirectory}/api_export_cars_${enums_1.ExportType.OPENAI_ADS}.${enums_1.FileType.CSV}`,
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.OpenAiAdsConfig = OpenAiAdsConfig;
|
|
56
|
+
//# sourceMappingURL=openai-ads.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-ads.config.js","sourceRoot":"","sources":["../../src/configs/openai-ads.config.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,5 +25,6 @@ var ExportType;
|
|
|
25
25
|
ExportType["AWIN"] = "awin";
|
|
26
26
|
ExportType["SANTANDER"] = "santander";
|
|
27
27
|
ExportType["EVIUM"] = "evium";
|
|
28
|
+
ExportType["OPENAI_ADS"] = "openai_ads";
|
|
28
29
|
})(ExportType || (exports.ExportType = ExportType = {}));
|
|
29
30
|
//# sourceMappingURL=export-type.enum.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export-type.enum.js","sourceRoot":"","sources":["../../src/enums/export-type.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,
|
|
1
|
+
{"version":3,"file":"export-type.enum.js","sourceRoot":"","sources":["../../src/enums/export-type.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,UAkCX;AAlCD,WAAY,UAAU;IAIpB,+BAAiB,CAAA;IACjB,iCAAmB,CAAA;IACnB,6BAAe,CAAA;IACf,uCAAyB,CAAA;IACzB,+BAAiB,CAAA;IACjB,uBAAS,CAAA;IACT,+BAAiB,CAAA;IACjB,6BAAe,CAAA;IACf,qCAAuB,CAAA;IAIvB,mCAAqB,CAAA;IACrB,qCAAuB,CAAA;IAIvB,2BAAa,CAAA;IACb,yCAA2B,CAAA;IAC3B,uCAAyB,CAAA;IACzB,sDAAwC,CAAA;IACxC,+BAAiB,CAAA;IACjB,4CAA8B,CAAA;IAC9B,+BAAiB,CAAA;IACjB,+BAAiB,CAAA;IACjB,2BAAa,CAAA;IACb,qCAAuB,CAAA;IACvB,6BAAe,CAAA;IAEf,uCAAyB,CAAA;AAC3B,CAAC,EAlCW,UAAU,0BAAV,UAAU,QAkCrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-type.enum.js","sourceRoot":"","sources":["../../src/enums/image-type.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,
|
|
1
|
+
{"version":3,"file":"image-type.enum.js","sourceRoot":"","sources":["../../src/enums/image-type.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,SAQX;AARD,WAAY,SAAS;IACnB,gCAAmB,CAAA;IACnB,oCAAuB,CAAA;IAKvB,4BAAe,CAAA;AACjB,CAAC,EARW,SAAS,yBAAT,SAAS,QAQpB"}
|
package/dist/export.schema.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AlleskralleConfig, As24Config, Auto24Config, AutouncleConfig, DasparkingConfig, EautoConfig, FbConfig, GoogleConfig, MarktdeConfig, MeinstadtConfig, OoyyoConfig, YescarConfig, KleinanzeigeFocusConfig, AutoboerseConfig, ByOwnerConfig, FacebookShopConfig, CriteoConfig, TrovitConfig, MitulaConfig, AwinConfig, EviumConfig, SantanderConfig } from './configs';
|
|
2
|
-
import { As24Exporter, Auto24Exporter, AutouncleExporter, ByOwnerExporter, FbExporter, GoogleExporter, MeinstadtExporter, MobileExporter, OoyyoExporter, ModixExporter, RubrikkExporter, FacebookShopExporter, TrovitExporter, AwinExporter, SantanderExporter, CriteoExporter } from './exporters';
|
|
1
|
+
import { AlleskralleConfig, As24Config, Auto24Config, AutouncleConfig, DasparkingConfig, EautoConfig, FbConfig, GoogleConfig, MarktdeConfig, MeinstadtConfig, OoyyoConfig, YescarConfig, KleinanzeigeFocusConfig, AutoboerseConfig, ByOwnerConfig, FacebookShopConfig, CriteoConfig, TrovitConfig, MitulaConfig, AwinConfig, EviumConfig, SantanderConfig, OpenAiAdsConfig } from './configs';
|
|
2
|
+
import { As24Exporter, Auto24Exporter, AutouncleExporter, ByOwnerExporter, FbExporter, GoogleExporter, MeinstadtExporter, MobileExporter, OoyyoExporter, ModixExporter, RubrikkExporter, FacebookShopExporter, TrovitExporter, AwinExporter, SantanderExporter, CriteoExporter, OpenAiAdsExporter } from './exporters';
|
|
3
3
|
export declare const exportSchema: {
|
|
4
4
|
eauto: {
|
|
5
5
|
config: typeof EautoConfig;
|
|
@@ -89,4 +89,8 @@ export declare const exportSchema: {
|
|
|
89
89
|
config: typeof SantanderConfig;
|
|
90
90
|
exporter: typeof SantanderExporter;
|
|
91
91
|
};
|
|
92
|
+
openai_ads: {
|
|
93
|
+
config: typeof OpenAiAdsConfig;
|
|
94
|
+
exporter: typeof OpenAiAdsExporter;
|
|
95
|
+
};
|
|
92
96
|
};
|
package/dist/export.schema.js
CHANGED
|
@@ -93,5 +93,9 @@ exports.exportSchema = {
|
|
|
93
93
|
config: configs_1.SantanderConfig,
|
|
94
94
|
exporter: exporters_1.SantanderExporter,
|
|
95
95
|
},
|
|
96
|
+
[enums_1.ExportType.OPENAI_ADS]: {
|
|
97
|
+
config: configs_1.OpenAiAdsConfig,
|
|
98
|
+
exporter: exporters_1.OpenAiAdsExporter,
|
|
99
|
+
},
|
|
96
100
|
};
|
|
97
101
|
//# sourceMappingURL=export.schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.schema.js","sourceRoot":"","sources":["../src/export.schema.ts"],"names":[],"mappings":";;;AAAA,mCAAqC;AAErC,
|
|
1
|
+
{"version":3,"file":"export.schema.js","sourceRoot":"","sources":["../src/export.schema.ts"],"names":[],"mappings":"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"}
|
package/dist/exporters/index.js
CHANGED
|
@@ -30,4 +30,5 @@ __exportStar(require("./facebook-shop.exporter"), exports);
|
|
|
30
30
|
__exportStar(require("./trovit.exporter"), exports);
|
|
31
31
|
__exportStar(require("./awin.exporter"), exports);
|
|
32
32
|
__exportStar(require("./santander.exporter"), exports);
|
|
33
|
+
__exportStar(require("./openai-ads.exporter"), exports);
|
|
33
34
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exporters/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,oDAAkC;AAClC,uDAAqC;AACrC,sDAAoC;AACpC,oDAAkC;AAClC,gDAA8B;AAC9B,oDAAkC;AAClC,uDAAqC;AACrC,oDAAkC;AAClC,mDAAiC;AACjC,mDAAiC;AACjC,qDAAmC;AACnC,2DAAyC;AACzC,oDAAkC;AAClC,kDAAgC;AAChC,uDAAqC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exporters/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,oDAAkC;AAClC,uDAAqC;AACrC,sDAAoC;AACpC,oDAAkC;AAClC,gDAA8B;AAC9B,oDAAkC;AAClC,uDAAqC;AACrC,oDAAkC;AAClC,mDAAiC;AACjC,mDAAiC;AACjC,qDAAmC;AACnC,2DAAyC;AACzC,oDAAkC;AAClC,kDAAgC;AAChC,uDAAqC;AACrC,wDAAsC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CarService, ConfigService, ImagesService, LoaderService, RulesService } from '../services';
|
|
2
|
+
import { Exporter } from '../interfaces/exporter.interface';
|
|
3
|
+
export declare class OpenAiAdsExporter implements Exporter {
|
|
4
|
+
private carService;
|
|
5
|
+
private configService;
|
|
6
|
+
private rulesService;
|
|
7
|
+
private loaderService;
|
|
8
|
+
private imagesService;
|
|
9
|
+
constructor(carService: CarService, configService: ConfigService, rulesService: RulesService, loaderService: LoaderService, imagesService: ImagesService);
|
|
10
|
+
export(): Promise<void>;
|
|
11
|
+
private readonly dealerStatuses;
|
|
12
|
+
private dealerStatus;
|
|
13
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.OpenAiAdsExporter = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const cronicle_helper_1 = require("@bytebrand/cronicle-helper");
|
|
15
|
+
const schema_tools_1 = require("@bytebrand/schema-tools");
|
|
16
|
+
const i18n_dictionaries_1 = require("@bytebrand/i18n-dictionaries");
|
|
17
|
+
const services_1 = require("../services");
|
|
18
|
+
const image_url_validator_service_1 = require("../services/image-url-validator.service");
|
|
19
|
+
const feed_guard_1 = require("../services/feed-guard");
|
|
20
|
+
const openai_ads_feed_run_1 = require("../services/openai-ads-feed-run");
|
|
21
|
+
const openai_image_fields_1 = require("../transformers/openai-image-fields");
|
|
22
|
+
let OpenAiAdsExporter = class OpenAiAdsExporter {
|
|
23
|
+
carService;
|
|
24
|
+
configService;
|
|
25
|
+
rulesService;
|
|
26
|
+
loaderService;
|
|
27
|
+
imagesService;
|
|
28
|
+
constructor(carService, configService, rulesService, loaderService, imagesService) {
|
|
29
|
+
this.carService = carService;
|
|
30
|
+
this.configService = configService;
|
|
31
|
+
this.rulesService = rulesService;
|
|
32
|
+
this.loaderService = loaderService;
|
|
33
|
+
this.imagesService = imagesService;
|
|
34
|
+
}
|
|
35
|
+
async export() {
|
|
36
|
+
const config = this.configService.config;
|
|
37
|
+
const translator = new schema_tools_1.TranslatorExtended({ ...i18n_dictionaries_1.de, ...i18n_dictionaries_1.deVehicleProps, ...i18n_dictionaries_1.deVehicleDetailsPage });
|
|
38
|
+
const validator = new image_url_validator_service_1.ImageUrlValidator({ concurrency: config.imageConcurrency });
|
|
39
|
+
const run = new openai_ads_feed_run_1.OpenAiAdsFeedRun({
|
|
40
|
+
forEachChunk: fn => this.loaderService.process((chunk) => fn(chunk.data)),
|
|
41
|
+
filterCar: source => this.carService.filterCar(source, this.rulesService.rules),
|
|
42
|
+
dealerStatus: ownerId => this.dealerStatus(ownerId),
|
|
43
|
+
resolveImages: ({ car, images }) => (0, openai_image_fields_1.resolveOpenAiImageFields)(this.imagesService.getCleanImages(car._id, images), validator),
|
|
44
|
+
imageStats: () => validator.stats,
|
|
45
|
+
guard: new feed_guard_1.FeedGuard(config.feedGuard),
|
|
46
|
+
}, {
|
|
47
|
+
runId: config.runId,
|
|
48
|
+
dryRun: config.dryRun,
|
|
49
|
+
sourceDirectory: config.pathesConfig.localDirectory,
|
|
50
|
+
sourceBaseFileName: config.pathesConfig.baseFileName,
|
|
51
|
+
outputFile: config.outputFiles[0],
|
|
52
|
+
stateDir: config.stateDir,
|
|
53
|
+
retentionDays: config.retentionDays,
|
|
54
|
+
mapping: {
|
|
55
|
+
domain: config.domain,
|
|
56
|
+
sellerName: config.sellerName,
|
|
57
|
+
translate: key => translator.translateVal(key),
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
try {
|
|
61
|
+
const report = await run.run();
|
|
62
|
+
if (report.stale) {
|
|
63
|
+
console.log(`OpenAI ads feed STALE: last good file ${report.lastGoodAgeHours?.toFixed(1)} h old`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
cronicle_helper_1.LoggerService.exitError(`OpenAI ads feed not published: ${error?.message ?? error}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
dealerStatuses = new Map();
|
|
72
|
+
dealerStatus(ownerId) {
|
|
73
|
+
if (!ownerId) {
|
|
74
|
+
return Promise.resolve('unknown');
|
|
75
|
+
}
|
|
76
|
+
if (!this.dealerStatuses.has(ownerId)) {
|
|
77
|
+
this.dealerStatuses.set(ownerId, this.carService.getOwner(ownerId).then(owner => (!owner ? 'unknown' : owner.active === false || owner.blacklist === true ? 'inactive' : 'active'), () => 'unknown'));
|
|
78
|
+
}
|
|
79
|
+
return this.dealerStatuses.get(ownerId);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
exports.OpenAiAdsExporter = OpenAiAdsExporter;
|
|
83
|
+
exports.OpenAiAdsExporter = OpenAiAdsExporter = __decorate([
|
|
84
|
+
(0, common_1.Injectable)(),
|
|
85
|
+
__metadata("design:paramtypes", [services_1.CarService,
|
|
86
|
+
services_1.ConfigService,
|
|
87
|
+
services_1.RulesService,
|
|
88
|
+
services_1.LoaderService,
|
|
89
|
+
services_1.ImagesService])
|
|
90
|
+
], OpenAiAdsExporter);
|
|
91
|
+
//# sourceMappingURL=openai-ads.exporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-ads.exporter.js","sourceRoot":"","sources":["../../src/exporters/openai-ads.exporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { OpenAiAdsRow } from '../interfaces/openai-ads.interface';
|
|
2
|
+
export declare const toCsvCell: (value: string | boolean | undefined | null) => string;
|
|
3
|
+
export declare const toCsvLine: (cells: Array<string | boolean | undefined | null>) => string;
|
|
4
|
+
export declare const openAiAdsCsvHeader: () => string;
|
|
5
|
+
export declare const openAiAdsCsvRow: (row: OpenAiAdsRow) => string;
|
|
6
|
+
export declare class OpenAiAdsCsvBuilder {
|
|
7
|
+
private readonly fileName;
|
|
8
|
+
private stream;
|
|
9
|
+
private rows;
|
|
10
|
+
constructor(fileName: string);
|
|
11
|
+
buildStart(): Promise<void>;
|
|
12
|
+
addItem(row: OpenAiAdsRow): Promise<void>;
|
|
13
|
+
buildEnd(): Promise<number>;
|
|
14
|
+
private write;
|
|
15
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenAiAdsCsvBuilder = exports.openAiAdsCsvRow = exports.openAiAdsCsvHeader = exports.toCsvLine = exports.toCsvCell = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const events_1 = require("events");
|
|
6
|
+
const openai_ads_interface_1 = require("../interfaces/openai-ads.interface");
|
|
7
|
+
const toCsvCell = (value) => {
|
|
8
|
+
if (value === undefined || value === null) {
|
|
9
|
+
return '';
|
|
10
|
+
}
|
|
11
|
+
const text = typeof value === 'boolean' ? (value ? 'true' : 'false') : value;
|
|
12
|
+
return /[",\r\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
|
|
13
|
+
};
|
|
14
|
+
exports.toCsvCell = toCsvCell;
|
|
15
|
+
const toCsvLine = (cells) => `${cells.map(exports.toCsvCell).join(',')}\n`;
|
|
16
|
+
exports.toCsvLine = toCsvLine;
|
|
17
|
+
const openAiAdsCsvHeader = () => (0, exports.toCsvLine)([...openai_ads_interface_1.OPENAI_ADS_COLUMNS]);
|
|
18
|
+
exports.openAiAdsCsvHeader = openAiAdsCsvHeader;
|
|
19
|
+
const openAiAdsCsvRow = (row) => (0, exports.toCsvLine)(openai_ads_interface_1.OPENAI_ADS_COLUMNS.map(column => row[column]));
|
|
20
|
+
exports.openAiAdsCsvRow = openAiAdsCsvRow;
|
|
21
|
+
class OpenAiAdsCsvBuilder {
|
|
22
|
+
fileName;
|
|
23
|
+
stream;
|
|
24
|
+
rows = 0;
|
|
25
|
+
constructor(fileName) {
|
|
26
|
+
this.fileName = fileName;
|
|
27
|
+
}
|
|
28
|
+
async buildStart() {
|
|
29
|
+
this.stream = (0, fs_1.createWriteStream)(this.fileName, { encoding: 'utf8' });
|
|
30
|
+
await this.write((0, exports.openAiAdsCsvHeader)());
|
|
31
|
+
}
|
|
32
|
+
async addItem(row) {
|
|
33
|
+
await this.write((0, exports.openAiAdsCsvRow)(row));
|
|
34
|
+
this.rows += 1;
|
|
35
|
+
}
|
|
36
|
+
async buildEnd() {
|
|
37
|
+
this.stream.end();
|
|
38
|
+
await (0, events_1.once)(this.stream, 'finish');
|
|
39
|
+
return this.rows;
|
|
40
|
+
}
|
|
41
|
+
async write(chunk) {
|
|
42
|
+
if (!this.stream.write(chunk)) {
|
|
43
|
+
await (0, events_1.once)(this.stream, 'drain');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.OpenAiAdsCsvBuilder = OpenAiAdsCsvBuilder;
|
|
48
|
+
//# sourceMappingURL=openai-ads-csv.builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-ads-csv.builder.js","sourceRoot":"","sources":["../../src/formats/openai-ads-csv.builder.ts"],"names":[],"mappings":";;;AAAA,2BAAoD;AACpD,mCAA8B;AAE9B,6EAAsF;AAK/E,MAAM,SAAS,GAAG,CAAC,KAA0C,EAAU,EAAE;IAC9E,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;QACzC,OAAO,EAAE,CAAC;KACX;IACD,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7E,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACxE,CAAC,CAAC;AANW,QAAA,SAAS,aAMpB;AAEK,MAAM,SAAS,GAAG,CAAC,KAAiD,EAAU,EAAE,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,iBAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AAAjH,QAAA,SAAS,aAAwG;AAEvH,MAAM,kBAAkB,GAAG,GAAW,EAAE,CAAC,IAAA,iBAAS,EAAC,CAAC,GAAG,yCAAkB,CAAC,CAAC,CAAC;AAAtE,QAAA,kBAAkB,sBAAoD;AAE5E,MAAM,eAAe,GAAG,CAAC,GAAiB,EAAU,EAAE,CAAC,IAAA,iBAAS,EAAC,yCAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAA1G,QAAA,eAAe,mBAA2F;AAOvH,MAAa,mBAAmB;IAID;IAHrB,MAAM,CAAc;IACpB,IAAI,GAAG,CAAC,CAAC;IAEjB,YAA6B,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAI,CAAC;IAElD,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,MAAM,GAAG,IAAA,sBAAiB,EAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QACrE,MAAM,IAAI,CAAC,KAAK,CAAC,IAAA,0BAAkB,GAAE,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAiB;QAC7B,MAAM,IAAI,CAAC,KAAK,CAAC,IAAA,uBAAe,EAAC,GAAG,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAClB,MAAM,IAAA,aAAI,EAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,KAAa;QAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;YAC7B,MAAM,IAAA,aAAI,EAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAClC;IACH,CAAC;CACF;AA3BD,kDA2BC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare const OPENAI_ADS_COLUMNS: readonly ["item_id", "title", "description", "url", "brand", "seller_name", "image_url", "additional_image_urls", "availability", "price", "condition", "is_ads_eligible"];
|
|
2
|
+
export type OpenAiAdsColumn = typeof OPENAI_ADS_COLUMNS[number];
|
|
3
|
+
export type OpenAiAdsAvailability = 'in_stock' | 'out_of_stock';
|
|
4
|
+
export type OpenAiAdsCondition = 'new' | 'used';
|
|
5
|
+
export interface OpenAiAdsRow {
|
|
6
|
+
item_id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
url: string;
|
|
10
|
+
brand: string;
|
|
11
|
+
seller_name: string;
|
|
12
|
+
image_url: string;
|
|
13
|
+
additional_image_urls: string;
|
|
14
|
+
availability: OpenAiAdsAvailability;
|
|
15
|
+
price: string;
|
|
16
|
+
condition: OpenAiAdsCondition;
|
|
17
|
+
is_ads_eligible: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare enum OpenAiAdsExclusion {
|
|
20
|
+
noId = "no_id",
|
|
21
|
+
duplicateId = "duplicate_id",
|
|
22
|
+
filtered = "filtered",
|
|
23
|
+
invalidPrice = "invalid_price",
|
|
24
|
+
noTitle = "no_title",
|
|
25
|
+
noBrand = "no_brand",
|
|
26
|
+
conditionUnknown = "condition_unknown",
|
|
27
|
+
dealerInactive = "dealer_inactive",
|
|
28
|
+
dealerUnknown = "dealer_unknown",
|
|
29
|
+
noImage = "no_image"
|
|
30
|
+
}
|
|
31
|
+
export declare enum OpenAiAdsOutOfStockReason {
|
|
32
|
+
reserved = "reserved",
|
|
33
|
+
soldFlag = "sold_flag",
|
|
34
|
+
notInSnapshot = "not_in_snapshot"
|
|
35
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenAiAdsOutOfStockReason = exports.OpenAiAdsExclusion = exports.OPENAI_ADS_COLUMNS = void 0;
|
|
4
|
+
exports.OPENAI_ADS_COLUMNS = [
|
|
5
|
+
'item_id',
|
|
6
|
+
'title',
|
|
7
|
+
'description',
|
|
8
|
+
'url',
|
|
9
|
+
'brand',
|
|
10
|
+
'seller_name',
|
|
11
|
+
'image_url',
|
|
12
|
+
'additional_image_urls',
|
|
13
|
+
'availability',
|
|
14
|
+
'price',
|
|
15
|
+
'condition',
|
|
16
|
+
'is_ads_eligible',
|
|
17
|
+
];
|
|
18
|
+
var OpenAiAdsExclusion;
|
|
19
|
+
(function (OpenAiAdsExclusion) {
|
|
20
|
+
OpenAiAdsExclusion["noId"] = "no_id";
|
|
21
|
+
OpenAiAdsExclusion["duplicateId"] = "duplicate_id";
|
|
22
|
+
OpenAiAdsExclusion["filtered"] = "filtered";
|
|
23
|
+
OpenAiAdsExclusion["invalidPrice"] = "invalid_price";
|
|
24
|
+
OpenAiAdsExclusion["noTitle"] = "no_title";
|
|
25
|
+
OpenAiAdsExclusion["noBrand"] = "no_brand";
|
|
26
|
+
OpenAiAdsExclusion["conditionUnknown"] = "condition_unknown";
|
|
27
|
+
OpenAiAdsExclusion["dealerInactive"] = "dealer_inactive";
|
|
28
|
+
OpenAiAdsExclusion["dealerUnknown"] = "dealer_unknown";
|
|
29
|
+
OpenAiAdsExclusion["noImage"] = "no_image";
|
|
30
|
+
})(OpenAiAdsExclusion || (exports.OpenAiAdsExclusion = OpenAiAdsExclusion = {}));
|
|
31
|
+
var OpenAiAdsOutOfStockReason;
|
|
32
|
+
(function (OpenAiAdsOutOfStockReason) {
|
|
33
|
+
OpenAiAdsOutOfStockReason["reserved"] = "reserved";
|
|
34
|
+
OpenAiAdsOutOfStockReason["soldFlag"] = "sold_flag";
|
|
35
|
+
OpenAiAdsOutOfStockReason["notInSnapshot"] = "not_in_snapshot";
|
|
36
|
+
})(OpenAiAdsOutOfStockReason || (exports.OpenAiAdsOutOfStockReason = OpenAiAdsOutOfStockReason = {}));
|
|
37
|
+
//# sourceMappingURL=openai-ads.interface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-ads.interface.js","sourceRoot":"","sources":["../../src/interfaces/openai-ads.interface.ts"],"names":[],"mappings":";;;AAGa,QAAA,kBAAkB,GAAG;IAChC,SAAS;IACT,OAAO;IACP,aAAa;IACb,KAAK;IACL,OAAO;IACP,aAAa;IACb,WAAW;IACX,uBAAuB;IACvB,cAAc;IACd,OAAO;IACP,WAAW;IACX,iBAAiB;CACT,CAAC;AA4BX,IAAY,kBAWX;AAXD,WAAY,kBAAkB;IAC5B,oCAAc,CAAA;IACd,kDAA4B,CAAA;IAC5B,2CAAqB,CAAA;IACrB,oDAA8B,CAAA;IAC9B,0CAAoB,CAAA;IACpB,0CAAoB,CAAA;IACpB,4DAAsC,CAAA;IACtC,wDAAkC,CAAA;IAClC,sDAAgC,CAAA;IAChC,0CAAoB,CAAA;AACtB,CAAC,EAXW,kBAAkB,kCAAlB,kBAAkB,QAW7B;AAGD,IAAY,yBAKX;AALD,WAAY,yBAAyB;IACnC,kDAAqB,CAAA;IACrB,mDAAsB,CAAA;IAEtB,8DAAiC,CAAA;AACnC,CAAC,EALW,yBAAyB,yCAAzB,yBAAyB,QAKpC"}
|
|
@@ -18,6 +18,16 @@ export interface Params {
|
|
|
18
18
|
publicationGateBqProject?: string;
|
|
19
19
|
publicationGateBqDataset?: string;
|
|
20
20
|
publicationGateBqTable?: string;
|
|
21
|
+
openAiAdsDryRun?: string;
|
|
22
|
+
openAiAdsSellerName?: string;
|
|
23
|
+
openAiAdsRetentionDays?: string;
|
|
24
|
+
openAiAdsImageConcurrency?: string;
|
|
25
|
+
feedGuardMinSourceItems?: string;
|
|
26
|
+
feedGuardMinPublishedItems?: string;
|
|
27
|
+
feedGuardMaxDropPercent?: string;
|
|
28
|
+
feedGuardMaxSourceAgeHours?: string;
|
|
29
|
+
feedGuardMaxStaleHours?: string;
|
|
30
|
+
feedGuardAcceptDrop?: string;
|
|
21
31
|
}
|
|
22
32
|
export interface FeedItemsBigQueryTarget {
|
|
23
33
|
project: string;
|