@tc-libs/seo-generator 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -0
- package/package.json +19 -0
- package/src/controllers/seo-generator.admin.controller.d.ts +8 -0
- package/src/controllers/seo-generator.admin.controller.js +41 -0
- package/src/controllers/seo-generator.admin.controller.js.map +1 -0
- package/src/dtos/admin/seo-generator.generate.admin.dto.d.ts +5 -0
- package/src/dtos/admin/seo-generator.generate.admin.dto.js +24 -0
- package/src/dtos/admin/seo-generator.generate.admin.dto.js.map +1 -0
- package/src/index.d.ts +6 -0
- package/src/index.js +10 -0
- package/src/index.js.map +1 -0
- package/src/seo-generator.module.d.ts +6 -0
- package/src/seo-generator.module.js +47 -0
- package/src/seo-generator.module.js.map +1 -0
- package/src/seo-generator.module.options.d.ts +22 -0
- package/src/seo-generator.module.options.js +5 -0
- package/src/seo-generator.module.options.js.map +1 -0
- package/src/serializations/seo-generator.serialization.d.ts +3 -0
- package/src/serializations/seo-generator.serialization.js +8 -0
- package/src/serializations/seo-generator.serialization.js.map +1 -0
- package/src/services/seo-generator.service.d.ts +37 -0
- package/src/services/seo-generator.service.js +119 -0
- package/src/services/seo-generator.service.js.map +1 -0
package/README.md
ADDED
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tc-libs/seo-generator",
|
|
3
|
+
"version": "3.8.0",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"@nestjs/common": "^11.0.12",
|
|
6
|
+
"@nestjs/swagger": "^11.1.0",
|
|
7
|
+
"@tc-libs/authentication": "3.8.0",
|
|
8
|
+
"@tc-libs/response": "3.8.0",
|
|
9
|
+
"class-validator": "^0.14.1",
|
|
10
|
+
"@tc-libs/database": "3.8.0",
|
|
11
|
+
"openai": "^6.33.0",
|
|
12
|
+
"@tc-libs/storage": "3.8.0",
|
|
13
|
+
"tslib": "^2.8.1"
|
|
14
|
+
},
|
|
15
|
+
"type": "commonjs",
|
|
16
|
+
"main": "./src/index.js",
|
|
17
|
+
"typings": "./src/index.d.ts",
|
|
18
|
+
"types": "./src/index.d.ts"
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IResponse } from '@tc-libs/response';
|
|
2
|
+
import { SeoGeneratorService } from '../services/seo-generator.service';
|
|
3
|
+
import { SeoGeneratorGenerateAdminDto } from '../dtos/admin/seo-generator.generate.admin.dto';
|
|
4
|
+
export declare class SeoGeneratorAdminController {
|
|
5
|
+
private readonly _seoGenerator;
|
|
6
|
+
constructor(_seoGenerator: SeoGeneratorService);
|
|
7
|
+
create({ context, entity, languages }: SeoGeneratorGenerateAdminDto): Promise<IResponse>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SeoGeneratorAdminController = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
7
|
+
const authentication_1 = require("@tc-libs/authentication");
|
|
8
|
+
const response_1 = require("@tc-libs/response");
|
|
9
|
+
const seo_generator_service_1 = require("../services/seo-generator.service");
|
|
10
|
+
const seo_generator_serialization_1 = require("../serializations/seo-generator.serialization");
|
|
11
|
+
const seo_generator_generate_admin_dto_1 = require("../dtos/admin/seo-generator.generate.admin.dto");
|
|
12
|
+
let SeoGeneratorAdminController = class SeoGeneratorAdminController {
|
|
13
|
+
constructor(_seoGenerator) {
|
|
14
|
+
this._seoGenerator = _seoGenerator;
|
|
15
|
+
}
|
|
16
|
+
async create({ context, entity, languages }) {
|
|
17
|
+
const response = await this._seoGenerator.generateSeoMetadata(entity, context, languages);
|
|
18
|
+
return { data: response };
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.SeoGeneratorAdminController = SeoGeneratorAdminController;
|
|
22
|
+
tslib_1.__decorate([
|
|
23
|
+
(0, response_1.Response)('seo-generator.create', {
|
|
24
|
+
serialization: seo_generator_serialization_1.SeoGeneratorSerialization,
|
|
25
|
+
}),
|
|
26
|
+
(0, common_1.Post)('generate'),
|
|
27
|
+
tslib_1.__param(0, (0, common_1.Body)()),
|
|
28
|
+
tslib_1.__metadata("design:type", Function),
|
|
29
|
+
tslib_1.__metadata("design:paramtypes", [seo_generator_generate_admin_dto_1.SeoGeneratorGenerateAdminDto]),
|
|
30
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
31
|
+
], SeoGeneratorAdminController.prototype, "create", null);
|
|
32
|
+
exports.SeoGeneratorAdminController = SeoGeneratorAdminController = tslib_1.__decorate([
|
|
33
|
+
(0, swagger_1.ApiTags)('seo-generator.admin'),
|
|
34
|
+
(0, authentication_1.AuthCombinedAdminAccessClassProtected)(),
|
|
35
|
+
(0, common_1.Controller)({
|
|
36
|
+
version: '1',
|
|
37
|
+
path: '/seo-generator',
|
|
38
|
+
}),
|
|
39
|
+
tslib_1.__metadata("design:paramtypes", [seo_generator_service_1.SeoGeneratorService])
|
|
40
|
+
], SeoGeneratorAdminController);
|
|
41
|
+
//# sourceMappingURL=seo-generator.admin.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-generator.admin.controller.js","sourceRoot":"","sources":["../../../../../packages/seo-generator/src/controllers/seo-generator.admin.controller.ts"],"names":[],"mappings":";;;;AAAA,2CAAwD;AACxD,6CAA0C;AAC1C,4DAAgF;AAChF,gDAAwD;AACxD,6EAAwE;AACxE,+FAA0F;AAC1F,qGAA8F;AAQvF,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IACtC,YAA6B,aAAkC;QAAlC,kBAAa,GAAb,aAAa,CAAqB;IAAG,CAAC;IAK7D,AAAN,KAAK,CAAC,MAAM,CACF,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAgC;QAEpE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAC3D,MAAM,EACN,OAAO,EACP,SAAS,CACV,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC5B,CAAC;CACF,CAAA;AAhBY,kEAA2B;AAMhC;IAJL,IAAA,mBAAQ,EAAC,sBAAsB,EAAE;QAChC,aAAa,EAAE,uDAAyB;KACzC,CAAC;IACD,IAAA,aAAI,EAAC,UAAU,CAAC;IAEd,mBAAA,IAAA,aAAI,GAAE,CAAA;;6CAAiC,+DAA4B;;yDAQrE;sCAfU,2BAA2B;IANvC,IAAA,iBAAO,EAAC,qBAAqB,CAAC;IAC9B,IAAA,sDAAqC,GAAE;IACvC,IAAA,mBAAU,EAAC;QACV,OAAO,EAAE,GAAG;QACZ,IAAI,EAAE,gBAAgB;KACvB,CAAC;6CAE4C,2CAAmB;GADpD,2BAA2B,CAgBvC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SeoGeneratorGenerateAdminDto = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const class_validator_1 = require("class-validator");
|
|
6
|
+
class SeoGeneratorGenerateAdminDto {
|
|
7
|
+
}
|
|
8
|
+
exports.SeoGeneratorGenerateAdminDto = SeoGeneratorGenerateAdminDto;
|
|
9
|
+
tslib_1.__decorate([
|
|
10
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
11
|
+
(0, class_validator_1.IsString)(),
|
|
12
|
+
tslib_1.__metadata("design:type", String)
|
|
13
|
+
], SeoGeneratorGenerateAdminDto.prototype, "entity", void 0);
|
|
14
|
+
tslib_1.__decorate([
|
|
15
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
16
|
+
(0, class_validator_1.IsString)(),
|
|
17
|
+
tslib_1.__metadata("design:type", String)
|
|
18
|
+
], SeoGeneratorGenerateAdminDto.prototype, "context", void 0);
|
|
19
|
+
tslib_1.__decorate([
|
|
20
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
21
|
+
(0, class_validator_1.IsString)({ each: true }),
|
|
22
|
+
tslib_1.__metadata("design:type", Array)
|
|
23
|
+
], SeoGeneratorGenerateAdminDto.prototype, "languages", void 0);
|
|
24
|
+
//# sourceMappingURL=seo-generator.generate.admin.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-generator.generate.admin.dto.js","sourceRoot":"","sources":["../../../../../../packages/seo-generator/src/dtos/admin/seo-generator.generate.admin.dto.ts"],"names":[],"mappings":";;;;AAAA,qDAAuD;AAEvD,MAAa,4BAA4B;CAUxC;AAVD,oEAUC;AAPC;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;4DACI;AAGf;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;6DACK;AAGhB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,EAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;;+DACL"}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './seo-generator.module.options';
|
|
2
|
+
export * from './seo-generator.module';
|
|
3
|
+
export * from './services/seo-generator.service';
|
|
4
|
+
export * from './controllers/seo-generator.admin.controller';
|
|
5
|
+
export * from './dtos/admin/seo-generator.generate.admin.dto';
|
|
6
|
+
export * from './serializations/seo-generator.serialization';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./seo-generator.module.options"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./seo-generator.module"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./services/seo-generator.service"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./controllers/seo-generator.admin.controller"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./dtos/admin/seo-generator.generate.admin.dto"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./serializations/seo-generator.serialization"), exports);
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/seo-generator/src/index.ts"],"names":[],"mappings":";;;AAAA,yEAA+C;AAC/C,iEAAuC;AACvC,2EAAiD;AACjD,uFAA6D;AAC7D,wFAA8D;AAC9D,uFAA6D"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import SeoGeneratorModuleAsyncOptions, { SeoGeneratorModuleOptions } from './seo-generator.module.options';
|
|
3
|
+
export declare class SeoGeneratorModule {
|
|
4
|
+
static register(options: SeoGeneratorModuleOptions, isGlobal?: boolean): DynamicModule;
|
|
5
|
+
static registerAsync(options: SeoGeneratorModuleAsyncOptions, isGlobal?: boolean): DynamicModule;
|
|
6
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var SeoGeneratorModule_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.SeoGeneratorModule = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const seo_generator_service_1 = require("./services/seo-generator.service");
|
|
8
|
+
const seo_generator_module_options_1 = require("./seo-generator.module.options");
|
|
9
|
+
const providers = [seo_generator_service_1.SeoGeneratorService];
|
|
10
|
+
let SeoGeneratorModule = SeoGeneratorModule_1 = class SeoGeneratorModule {
|
|
11
|
+
static register(options, isGlobal) {
|
|
12
|
+
return {
|
|
13
|
+
module: SeoGeneratorModule_1,
|
|
14
|
+
providers: [
|
|
15
|
+
{ provide: seo_generator_module_options_1.SEO_GENERATOR_CONFIG_OPTIONS, useValue: options },
|
|
16
|
+
...providers,
|
|
17
|
+
],
|
|
18
|
+
exports: providers,
|
|
19
|
+
global: isGlobal,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
static registerAsync(options, isGlobal) {
|
|
23
|
+
return {
|
|
24
|
+
module: SeoGeneratorModule_1,
|
|
25
|
+
imports: [...(options.imports || [])],
|
|
26
|
+
providers: [
|
|
27
|
+
{
|
|
28
|
+
provide: seo_generator_module_options_1.SEO_GENERATOR_CONFIG_OPTIONS,
|
|
29
|
+
useFactory: options.useFactory,
|
|
30
|
+
inject: options.inject,
|
|
31
|
+
},
|
|
32
|
+
...providers,
|
|
33
|
+
],
|
|
34
|
+
exports: providers,
|
|
35
|
+
global: isGlobal,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
exports.SeoGeneratorModule = SeoGeneratorModule;
|
|
40
|
+
exports.SeoGeneratorModule = SeoGeneratorModule = SeoGeneratorModule_1 = tslib_1.__decorate([
|
|
41
|
+
(0, common_1.Module)({
|
|
42
|
+
imports: [],
|
|
43
|
+
providers,
|
|
44
|
+
exports: providers,
|
|
45
|
+
})
|
|
46
|
+
], SeoGeneratorModule);
|
|
47
|
+
//# sourceMappingURL=seo-generator.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-generator.module.js","sourceRoot":"","sources":["../../../../packages/seo-generator/src/seo-generator.module.ts"],"names":[],"mappings":";;;;;AAAA,2CAAuD;AACvD,4EAAuE;AACvE,iFAGwC;AAExC,MAAM,SAAS,GAAG,CAAC,2CAAmB,CAAC,CAAC;AAOjC,IAAM,kBAAkB,0BAAxB,MAAM,kBAAkB;IAC7B,MAAM,CAAC,QAAQ,CACb,OAAkC,EAClC,QAAkB;QAElB,OAAO;YACL,MAAM,EAAE,oBAAkB;YAC1B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,2DAA4B,EAAE,QAAQ,EAAE,OAAO,EAAE;gBAC5D,GAAG,SAAS;aACb;YACD,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,QAAQ;SACjB,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,aAAa,CAClB,OAAuC,EACvC,QAAkB;QAElB,OAAO;YACL,MAAM,EAAE,oBAAkB;YAC1B,OAAO,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YACrC,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,2DAA4B;oBACrC,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;iBACvB;gBACD,GAAG,SAAS;aACb;YACD,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,QAAQ;SACjB,CAAC;IACJ,CAAC;CACF,CAAA;AAlCY,gDAAkB;6BAAlB,kBAAkB;IAL9B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,EAAE;QACX,SAAS;QACT,OAAO,EAAE,SAAS;KACnB,CAAC;GACW,kBAAkB,CAkC9B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ModuleMetadata } from '@nestjs/common';
|
|
2
|
+
import { FactoryProvider } from '@nestjs/common/interfaces/modules/provider.interface';
|
|
3
|
+
export declare const SEO_GENERATOR_CONFIG_OPTIONS = "SEO_GENERATOR_CONFIG_OPTIONS";
|
|
4
|
+
export interface SeoGeneratorModuleOptions {
|
|
5
|
+
models: {
|
|
6
|
+
mini: {
|
|
7
|
+
code: string;
|
|
8
|
+
price: {
|
|
9
|
+
input: number;
|
|
10
|
+
cachedInput: number;
|
|
11
|
+
output: number;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
apiKey: string;
|
|
16
|
+
prompt: {
|
|
17
|
+
fileName: string;
|
|
18
|
+
folder: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
type SeoGeneratorModuleAsyncOptions = Pick<ModuleMetadata, 'imports'> & Pick<FactoryProvider<SeoGeneratorModuleOptions>, 'useFactory' | 'inject'>;
|
|
22
|
+
export default SeoGeneratorModuleAsyncOptions;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-generator.module.options.js","sourceRoot":"","sources":["../../../../packages/seo-generator/src/seo-generator.module.options.ts"],"names":[],"mappings":";;;AAGa,QAAA,4BAA4B,GAAG,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SeoGeneratorSerialization = void 0;
|
|
4
|
+
const database_1 = require("@tc-libs/database");
|
|
5
|
+
class SeoGeneratorSerialization extends database_1.SeoEntity {
|
|
6
|
+
}
|
|
7
|
+
exports.SeoGeneratorSerialization = SeoGeneratorSerialization;
|
|
8
|
+
//# sourceMappingURL=seo-generator.serialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-generator.serialization.js","sourceRoot":"","sources":["../../../../../packages/seo-generator/src/serializations/seo-generator.serialization.ts"],"names":[],"mappings":";;;AAAA,gDAA8C;AAE9C,MAAa,yBAA0B,SAAQ,oBAAS;CAAG;AAA3D,8DAA2D"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { StorageAwsS3Service } from '@tc-libs/storage';
|
|
2
|
+
import { SeoEntity } from '@tc-libs/database';
|
|
3
|
+
import { SeoGeneratorModuleOptions } from '../seo-generator.module.options';
|
|
4
|
+
export type OpenAIModel = {
|
|
5
|
+
code: string;
|
|
6
|
+
price: {
|
|
7
|
+
input: number;
|
|
8
|
+
cachedInput: number;
|
|
9
|
+
output: number;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export interface SeoGeneratorCostBreakdown {
|
|
13
|
+
language: string;
|
|
14
|
+
inputTokens: number;
|
|
15
|
+
cachedInputTokens: number;
|
|
16
|
+
outputTokens: number;
|
|
17
|
+
cost: number;
|
|
18
|
+
}
|
|
19
|
+
export interface SeoGeneratorResult {
|
|
20
|
+
seo: SeoEntity;
|
|
21
|
+
cost: number;
|
|
22
|
+
breakdown: SeoGeneratorCostBreakdown[];
|
|
23
|
+
}
|
|
24
|
+
export declare class SeoGeneratorService {
|
|
25
|
+
private readonly _options;
|
|
26
|
+
private readonly _storage;
|
|
27
|
+
private readonly logger;
|
|
28
|
+
private readonly openai;
|
|
29
|
+
private cachedPrompt;
|
|
30
|
+
private cachedPromptAt;
|
|
31
|
+
private openaiModel;
|
|
32
|
+
private readonly PROMPT_TTL;
|
|
33
|
+
constructor(_options: SeoGeneratorModuleOptions, _storage: StorageAwsS3Service);
|
|
34
|
+
private getPromptTemplate;
|
|
35
|
+
private computeCost;
|
|
36
|
+
generateSeoMetadata(entity: string, context: string, languages: string[]): Promise<SeoGeneratorResult>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var SeoGeneratorService_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.SeoGeneratorService = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const openai_1 = tslib_1.__importDefault(require("openai"));
|
|
8
|
+
const storage_1 = require("@tc-libs/storage");
|
|
9
|
+
const seo_generator_module_options_1 = require("../seo-generator.module.options");
|
|
10
|
+
let SeoGeneratorService = SeoGeneratorService_1 = class SeoGeneratorService {
|
|
11
|
+
constructor(_options, _storage) {
|
|
12
|
+
this._options = _options;
|
|
13
|
+
this._storage = _storage;
|
|
14
|
+
this.logger = new common_1.Logger(SeoGeneratorService_1.name);
|
|
15
|
+
this.PROMPT_TTL = 30 * 60 * 1000;
|
|
16
|
+
this.openai = new openai_1.default({
|
|
17
|
+
apiKey: this._options.apiKey,
|
|
18
|
+
});
|
|
19
|
+
this.openaiModel = this._options.models.mini;
|
|
20
|
+
}
|
|
21
|
+
async getPromptTemplate() {
|
|
22
|
+
if (this.cachedPrompt &&
|
|
23
|
+
Date.now() - this.cachedPromptAt < this.PROMPT_TTL) {
|
|
24
|
+
return this.cachedPrompt;
|
|
25
|
+
}
|
|
26
|
+
const stream = (await this._storage.downloadFile(this._options.prompt.fileName, this._options.prompt.folder));
|
|
27
|
+
const chunks = [];
|
|
28
|
+
for await (const chunk of stream) {
|
|
29
|
+
chunks.push(chunk);
|
|
30
|
+
}
|
|
31
|
+
this.cachedPrompt = Buffer.concat(chunks).toString('utf-8');
|
|
32
|
+
this.cachedPromptAt = Date.now();
|
|
33
|
+
return this.cachedPrompt;
|
|
34
|
+
}
|
|
35
|
+
computeCost(usage) {
|
|
36
|
+
const { price } = this.openaiModel;
|
|
37
|
+
const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
38
|
+
const uncachedInput = usage.prompt_tokens - cachedTokens;
|
|
39
|
+
return ((uncachedInput * price.input +
|
|
40
|
+
cachedTokens * price.cachedInput +
|
|
41
|
+
usage.completion_tokens * price.output) /
|
|
42
|
+
1_000_000);
|
|
43
|
+
}
|
|
44
|
+
async generateSeoMetadata(entity, context, languages) {
|
|
45
|
+
const prompt = await this.getPromptTemplate();
|
|
46
|
+
const title = {};
|
|
47
|
+
const description = {};
|
|
48
|
+
let totalCost = 0;
|
|
49
|
+
const breakdown = [];
|
|
50
|
+
for (const lang of languages) {
|
|
51
|
+
const completion = await this.openai.chat.completions.create({
|
|
52
|
+
model: this.openaiModel.code,
|
|
53
|
+
messages: [
|
|
54
|
+
{ role: 'system', content: prompt },
|
|
55
|
+
{
|
|
56
|
+
role: 'system',
|
|
57
|
+
content: `IMPORTANT: Generate the output in "${lang}" language.`,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
role: 'user',
|
|
61
|
+
content: `Entità di riferimento: ${entity}\nContesto: ${context}`,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
response_format: {
|
|
65
|
+
type: 'json_schema',
|
|
66
|
+
json_schema: {
|
|
67
|
+
name: 'seo_metadata',
|
|
68
|
+
strict: true,
|
|
69
|
+
schema: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
title: { type: 'string' },
|
|
73
|
+
description: { type: 'string' },
|
|
74
|
+
},
|
|
75
|
+
required: ['title', 'description'],
|
|
76
|
+
additionalProperties: false,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
if (completion.usage) {
|
|
82
|
+
const cost = this.computeCost(completion.usage);
|
|
83
|
+
totalCost += cost;
|
|
84
|
+
breakdown.push({
|
|
85
|
+
language: lang,
|
|
86
|
+
inputTokens: completion.usage.prompt_tokens -
|
|
87
|
+
(completion.usage.prompt_tokens_details?.cached_tokens ?? 0),
|
|
88
|
+
cachedInputTokens: completion.usage.prompt_tokens_details?.cached_tokens ?? 0,
|
|
89
|
+
outputTokens: completion.usage.completion_tokens,
|
|
90
|
+
cost,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const content = completion.choices[0].message.content;
|
|
94
|
+
if (!content) {
|
|
95
|
+
this.logger.warn(`Empty response from OpenAI for language: ${lang}`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const parsed = JSON.parse(content);
|
|
99
|
+
title[lang] = parsed.title;
|
|
100
|
+
description[lang] = parsed.description;
|
|
101
|
+
}
|
|
102
|
+
this.logger.log(`SEO generated for [${languages.join(', ')}] — cost: $${totalCost.toFixed(6)}`);
|
|
103
|
+
return {
|
|
104
|
+
seo: {
|
|
105
|
+
title: title,
|
|
106
|
+
description: description,
|
|
107
|
+
},
|
|
108
|
+
cost: totalCost,
|
|
109
|
+
breakdown,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
exports.SeoGeneratorService = SeoGeneratorService;
|
|
114
|
+
exports.SeoGeneratorService = SeoGeneratorService = SeoGeneratorService_1 = tslib_1.__decorate([
|
|
115
|
+
(0, common_1.Injectable)(),
|
|
116
|
+
tslib_1.__param(0, (0, common_1.Inject)(seo_generator_module_options_1.SEO_GENERATOR_CONFIG_OPTIONS)),
|
|
117
|
+
tslib_1.__metadata("design:paramtypes", [Object, storage_1.StorageAwsS3Service])
|
|
118
|
+
], SeoGeneratorService);
|
|
119
|
+
//# sourceMappingURL=seo-generator.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-generator.service.js","sourceRoot":"","sources":["../../../../../packages/seo-generator/src/services/seo-generator.service.ts"],"names":[],"mappings":"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"}
|