@drodil/backstage-plugin-qeta-backend-module-openai 3.6.1
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 +32 -0
- package/configSchema.d.ts +83 -0
- package/dist/OpenAIHandler.cjs.js +165 -0
- package/dist/OpenAIHandler.cjs.js.map +1 -0
- package/dist/index.cjs.js +10 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/module.cjs.js +27 -0
- package/dist/module.cjs.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# backstage-plugin-qeta-backend-module-openai
|
|
2
|
+
|
|
3
|
+
The openai backend module for the qeta plugin.
|
|
4
|
+
|
|
5
|
+
This plugin provides means to use OpenAI API to create answers to questions. It works
|
|
6
|
+
also as a reference for creating new AI backend modules for the qeta plugin.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Installation starts by installing the backend module to the backend package.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
yarn workspace backend add @drodil/backstage-plugin-qeta-backend-module-openai
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Next, add it to your `packages/backend/src/index.ts`:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { createBackend } from '@backstage/backend-defaults';
|
|
20
|
+
const backend = createBackend();
|
|
21
|
+
// ... other plugins
|
|
22
|
+
backend.add(import('@drodil/backstage-plugin-qeta-backend-module-openai'));
|
|
23
|
+
backend.start();
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Additionally you need to add the necessary config to your `app-config.yaml`:
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
qeta:
|
|
30
|
+
openai:
|
|
31
|
+
apiKey: 'your-openai-key'
|
|
32
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: Copyright 2023 - 2024 OP Financial Group (https://op.fi). All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: LicenseRef-OpAllRightsReserved
|
|
4
|
+
*/
|
|
5
|
+
import { HumanDuration } from '@backstage/types';
|
|
6
|
+
|
|
7
|
+
export interface Config {
|
|
8
|
+
qeta?: {
|
|
9
|
+
openai?: {
|
|
10
|
+
answer?: {
|
|
11
|
+
/**
|
|
12
|
+
* Whether to enable OpenAI for existing questions. Defaults to true.
|
|
13
|
+
* Setting this false will disable AI answers in the question page.
|
|
14
|
+
*/
|
|
15
|
+
existingQuestions?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether to enable OpenAI for new questions. Defaults to true.
|
|
18
|
+
* Setting this false will disable AI answers in the Ask a question form.
|
|
19
|
+
*/
|
|
20
|
+
newQuestions?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to enable OpenAI for article summaries. Defaults to true.
|
|
23
|
+
* Setting this false will disable AI summary in the article page.
|
|
24
|
+
*/
|
|
25
|
+
articleSummary?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Cache time-to-live for OpenAI responses. Defaults to 1 hour.
|
|
29
|
+
*/
|
|
30
|
+
cacheTtl?: number | HumanDuration;
|
|
31
|
+
/**
|
|
32
|
+
* The endpoint for accessing OpenAI services. Defaults to process.env.OPENAI_BASE_URL or
|
|
33
|
+
* https://api.openai.com/v1.
|
|
34
|
+
*/
|
|
35
|
+
endpoint?: string;
|
|
36
|
+
/**
|
|
37
|
+
* The API key for accessing OpenAI services. Defaults to process.env.OPENAI_API_KEY.
|
|
38
|
+
*
|
|
39
|
+
* @visibility secret
|
|
40
|
+
*/
|
|
41
|
+
apiKey?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Organization ID for accessing OpenAI services. Defaults to process.env.OPENAI_ORG_ID.
|
|
44
|
+
*
|
|
45
|
+
* @visibility secret
|
|
46
|
+
*/
|
|
47
|
+
organization?: string;
|
|
48
|
+
/**
|
|
49
|
+
* The model to use for generating responses. Defaults to gpt-3.5-turbo.
|
|
50
|
+
*/
|
|
51
|
+
model?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Project ID for accessing OpenAI services. Defaults to process.env.OPENAI_PROJECT_ID.
|
|
54
|
+
*/
|
|
55
|
+
project?: string;
|
|
56
|
+
/**
|
|
57
|
+
* The temperature to use for generating responses.
|
|
58
|
+
*/
|
|
59
|
+
temperature?: number;
|
|
60
|
+
/**
|
|
61
|
+
* The maximum number of tokens to generate in the response.
|
|
62
|
+
*/
|
|
63
|
+
maxTokens?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Additional prompts to send to OpenAI.
|
|
66
|
+
*/
|
|
67
|
+
prompts?: {
|
|
68
|
+
/**
|
|
69
|
+
* System prompt to send to OpenAI.
|
|
70
|
+
*/
|
|
71
|
+
system?: string;
|
|
72
|
+
/**
|
|
73
|
+
* User prompt prefix.
|
|
74
|
+
*/
|
|
75
|
+
userPrefix?: string;
|
|
76
|
+
/**
|
|
77
|
+
* User prompt suffix.
|
|
78
|
+
*/
|
|
79
|
+
userSuffix?: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var openai = require('openai');
|
|
4
|
+
var types = require('@backstage/types');
|
|
5
|
+
|
|
6
|
+
class OpenAIHandler {
|
|
7
|
+
constructor(logger, config, cache) {
|
|
8
|
+
this.logger = logger;
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.cache = cache;
|
|
11
|
+
this.model = this.config.getOptionalString("qeta.openai.model") ?? "gpt-3.5-turbo";
|
|
12
|
+
this.maxTokens = this.config.getOptionalNumber("qeta.openai.maxTokens");
|
|
13
|
+
this.temperature = this.config.getOptionalNumber("qeta.openai.temperature");
|
|
14
|
+
this.systemPrompt = this.config.getOptionalString(
|
|
15
|
+
"qeta.openai.prompts.system"
|
|
16
|
+
);
|
|
17
|
+
this.userPromptPrefix = this.config.getOptionalString(
|
|
18
|
+
"qeta.openai.prompts.userPrefix"
|
|
19
|
+
);
|
|
20
|
+
this.userPromptSuffix = this.config.getOptionalString(
|
|
21
|
+
"qeta.openai.prompts.userSuffix"
|
|
22
|
+
);
|
|
23
|
+
const cacheTtlConfig = config.getOptional("qeta.openai.cacheTtl");
|
|
24
|
+
let ttl;
|
|
25
|
+
if (cacheTtlConfig !== void 0 && cacheTtlConfig !== null) {
|
|
26
|
+
if (typeof cacheTtlConfig === "number") {
|
|
27
|
+
ttl = cacheTtlConfig;
|
|
28
|
+
} else if (typeof cacheTtlConfig === "object" && !Array.isArray(cacheTtlConfig)) {
|
|
29
|
+
ttl = types.durationToMilliseconds(cacheTtlConfig);
|
|
30
|
+
} else {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Invalid configuration qeta.openai.cacheTtl: ${cacheTtlConfig}, expected milliseconds number or HumanDuration object`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
this.cacheTtl = ttl ?? types.durationToMilliseconds({ hours: 1 });
|
|
37
|
+
}
|
|
38
|
+
model;
|
|
39
|
+
maxTokens;
|
|
40
|
+
temperature;
|
|
41
|
+
systemPrompt;
|
|
42
|
+
userPromptPrefix;
|
|
43
|
+
userPromptSuffix;
|
|
44
|
+
cacheTtl;
|
|
45
|
+
async answerExistingQuestion(question, options) {
|
|
46
|
+
const enabled = this.config.getOptionalBoolean(
|
|
47
|
+
"qeta.openai.answer.existingQuestions"
|
|
48
|
+
);
|
|
49
|
+
if (enabled === false) {
|
|
50
|
+
throw new Error("OpenAI is disabled for existing questions");
|
|
51
|
+
}
|
|
52
|
+
const cached = await this.cache?.get(
|
|
53
|
+
`openai:question_${question.id}`
|
|
54
|
+
);
|
|
55
|
+
if (cached) {
|
|
56
|
+
return JSON.parse(cached);
|
|
57
|
+
}
|
|
58
|
+
this.logger.info(`Answering question ${question.id} using OpenAI`);
|
|
59
|
+
const prompt = `${question.title}
|
|
60
|
+
${question.content}`;
|
|
61
|
+
const completion = await this.getCompletion(
|
|
62
|
+
prompt,
|
|
63
|
+
options?.credentials?.principal.userEntityRef
|
|
64
|
+
);
|
|
65
|
+
const ret = { answer: completion };
|
|
66
|
+
await this.cache?.set(
|
|
67
|
+
`openai:question_${question.id}`,
|
|
68
|
+
JSON.stringify(ret),
|
|
69
|
+
{
|
|
70
|
+
ttl: this.cacheTtl
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
return ret;
|
|
74
|
+
}
|
|
75
|
+
async answerNewQuestion(title, content, options) {
|
|
76
|
+
const enabled = this.config.getOptionalBoolean(
|
|
77
|
+
"qeta.openai.answer.newQuestions"
|
|
78
|
+
);
|
|
79
|
+
if (enabled === false) {
|
|
80
|
+
throw new Error("OpenAI is disabled for new questions");
|
|
81
|
+
}
|
|
82
|
+
this.logger.info(`Answering question ${title} using OpenAI`);
|
|
83
|
+
const prompt = `${title}
|
|
84
|
+
${content}`;
|
|
85
|
+
const completion = await this.getCompletion(
|
|
86
|
+
prompt,
|
|
87
|
+
options?.credentials?.principal.userEntityRef
|
|
88
|
+
);
|
|
89
|
+
return { answer: completion };
|
|
90
|
+
}
|
|
91
|
+
async summarizeArticle(article, options) {
|
|
92
|
+
const enabled = this.config.getOptionalBoolean(
|
|
93
|
+
"qeta.openai.answer.articleSummary"
|
|
94
|
+
);
|
|
95
|
+
if (enabled === false) {
|
|
96
|
+
throw new Error("OpenAI is disabled for article summaries");
|
|
97
|
+
}
|
|
98
|
+
const cached = await this.cache?.get(
|
|
99
|
+
`openai:article_summary_${article.id}`
|
|
100
|
+
);
|
|
101
|
+
if (cached) {
|
|
102
|
+
return JSON.parse(cached);
|
|
103
|
+
}
|
|
104
|
+
this.logger.info(`Summarizing article ${article.id} using OpenAI`);
|
|
105
|
+
const prompt = `Can you summarize this article?
|
|
106
|
+
Title: ${article.title}
|
|
107
|
+
Content: ${article.content}`;
|
|
108
|
+
const completion = await this.getCompletion(
|
|
109
|
+
prompt,
|
|
110
|
+
options?.credentials?.principal.userEntityRef
|
|
111
|
+
);
|
|
112
|
+
const ret = { answer: completion };
|
|
113
|
+
await this.cache?.set(
|
|
114
|
+
`openai:article_summary_${article.id}`,
|
|
115
|
+
JSON.stringify(ret),
|
|
116
|
+
{
|
|
117
|
+
ttl: this.cacheTtl
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
return ret;
|
|
121
|
+
}
|
|
122
|
+
async getCompletion(prompt, user) {
|
|
123
|
+
const client = this.getClient();
|
|
124
|
+
let completion;
|
|
125
|
+
try {
|
|
126
|
+
const messages = new Array();
|
|
127
|
+
if (this.systemPrompt) {
|
|
128
|
+
messages.push({ role: "system", content: this.systemPrompt });
|
|
129
|
+
}
|
|
130
|
+
const userPrompt = {
|
|
131
|
+
role: "user",
|
|
132
|
+
content: `${this.userPromptPrefix ?? ""}${prompt}${this.userPromptSuffix ?? ""}`
|
|
133
|
+
};
|
|
134
|
+
messages.push(userPrompt);
|
|
135
|
+
completion = await client.chat.completions.create({
|
|
136
|
+
model: this.model,
|
|
137
|
+
messages,
|
|
138
|
+
stream: false,
|
|
139
|
+
max_tokens: this.maxTokens,
|
|
140
|
+
temperature: this.temperature,
|
|
141
|
+
user,
|
|
142
|
+
n: 1
|
|
143
|
+
});
|
|
144
|
+
} catch (e) {
|
|
145
|
+
this.logger.error(`Error from OpenAI: ${e}`);
|
|
146
|
+
throw new Error("Failed to get response from OpenAI");
|
|
147
|
+
}
|
|
148
|
+
if (completion.choices.length === 0 || !completion.choices[0].message.content) {
|
|
149
|
+
throw new Error("No response from OpenAI");
|
|
150
|
+
}
|
|
151
|
+
return completion.choices[0].message.content;
|
|
152
|
+
}
|
|
153
|
+
getClient() {
|
|
154
|
+
const apiKey = this.config.getOptionalString("qeta.openai.apiKey");
|
|
155
|
+
const organization = this.config.getOptionalString(
|
|
156
|
+
"qeta.openai.organization"
|
|
157
|
+
);
|
|
158
|
+
const endpoint = this.config.getOptionalString("qeta.openai.endpoint");
|
|
159
|
+
const project = this.config.getOptionalString("qeta.openai.project");
|
|
160
|
+
return new openai.OpenAI({ baseURL: endpoint, apiKey, organization, project });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
exports.OpenAIHandler = OpenAIHandler;
|
|
165
|
+
//# sourceMappingURL=OpenAIHandler.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAIHandler.cjs.js","sources":["../src/OpenAIHandler.ts"],"sourcesContent":["/*\n * SPDX-FileCopyrightText: Copyright 2024 OP Financial Group (https://op.fi). All Rights Reserved.\n * SPDX-License-Identifier: LicenseRef-OpAllRightsReserved\n */\nimport { AIHandler } from '@drodil/backstage-plugin-qeta-node';\nimport {\n BackstageCredentials,\n BackstageUserPrincipal,\n CacheService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport {\n AIResponse,\n Article,\n Question,\n} from '@drodil/backstage-plugin-qeta-common';\nimport { Config } from '@backstage/config';\nimport { OpenAI } from 'openai';\nimport { durationToMilliseconds } from '@backstage/types';\n\nexport class OpenAIHandler implements AIHandler {\n private readonly model: string;\n private readonly maxTokens?: number;\n private readonly temperature?: number;\n private readonly systemPrompt?: string;\n private readonly userPromptPrefix?: string;\n private readonly userPromptSuffix?: string;\n private readonly cacheTtl?: number;\n\n constructor(\n private readonly logger: LoggerService,\n private readonly config: Config,\n private readonly cache?: CacheService,\n ) {\n this.model =\n this.config.getOptionalString('qeta.openai.model') ?? 'gpt-3.5-turbo';\n this.maxTokens = this.config.getOptionalNumber('qeta.openai.maxTokens');\n this.temperature = this.config.getOptionalNumber('qeta.openai.temperature');\n this.systemPrompt = this.config.getOptionalString(\n 'qeta.openai.prompts.system',\n );\n this.userPromptPrefix = this.config.getOptionalString(\n 'qeta.openai.prompts.userPrefix',\n );\n this.userPromptSuffix = this.config.getOptionalString(\n 'qeta.openai.prompts.userSuffix',\n );\n\n const cacheTtlConfig = config.getOptional('qeta.openai.cacheTtl');\n let ttl: number | undefined;\n if (cacheTtlConfig !== undefined && cacheTtlConfig !== null) {\n if (typeof cacheTtlConfig === 'number') {\n ttl = cacheTtlConfig;\n } else if (\n typeof cacheTtlConfig === 'object' &&\n !Array.isArray(cacheTtlConfig)\n ) {\n ttl = durationToMilliseconds(cacheTtlConfig);\n } else {\n throw new Error(\n `Invalid configuration qeta.openai.cacheTtl: ${cacheTtlConfig}, expected milliseconds number or HumanDuration object`,\n );\n }\n }\n this.cacheTtl = ttl ?? durationToMilliseconds({ hours: 1 });\n }\n\n async answerExistingQuestion(\n question: Question,\n options?: {\n credentials?: BackstageCredentials<BackstageUserPrincipal>;\n },\n ): Promise<AIResponse> {\n const enabled = this.config.getOptionalBoolean(\n 'qeta.openai.answer.existingQuestions',\n );\n if (enabled === false) {\n throw new Error('OpenAI is disabled for existing questions');\n }\n\n const cached = await this.cache?.get<string>(\n `openai:question_${question.id}`,\n );\n if (cached) {\n return JSON.parse(cached);\n }\n\n this.logger.info(`Answering question ${question.id} using OpenAI`);\n\n const prompt = `${question.title}\\n${question.content}`;\n const completion = await this.getCompletion(\n prompt,\n options?.credentials?.principal.userEntityRef,\n );\n\n const ret = { answer: completion };\n await this.cache?.set(\n `openai:question_${question.id}`,\n JSON.stringify(ret),\n {\n ttl: this.cacheTtl,\n },\n );\n return ret;\n }\n\n async answerNewQuestion(\n title: string,\n content: string,\n options?: { credentials?: BackstageCredentials<BackstageUserPrincipal> },\n ): Promise<AIResponse> {\n const enabled = this.config.getOptionalBoolean(\n 'qeta.openai.answer.newQuestions',\n );\n if (enabled === false) {\n throw new Error('OpenAI is disabled for new questions');\n }\n\n this.logger.info(`Answering question ${title} using OpenAI`);\n\n const prompt = `${title}\\n${content}`;\n const completion = await this.getCompletion(\n prompt,\n options?.credentials?.principal.userEntityRef,\n );\n return { answer: completion };\n }\n\n async summarizeArticle(\n article: Article,\n options?: { credentials?: BackstageCredentials<BackstageUserPrincipal> },\n ): Promise<AIResponse> {\n const enabled = this.config.getOptionalBoolean(\n 'qeta.openai.answer.articleSummary',\n );\n if (enabled === false) {\n throw new Error('OpenAI is disabled for article summaries');\n }\n\n const cached = await this.cache?.get<string>(\n `openai:article_summary_${article.id}`,\n );\n if (cached) {\n return JSON.parse(cached);\n }\n\n this.logger.info(`Summarizing article ${article.id} using OpenAI`);\n const prompt = `Can you summarize this article?\\nTitle: ${article.title}\\nContent: ${article.content}`;\n const completion = await this.getCompletion(\n prompt,\n options?.credentials?.principal.userEntityRef,\n );\n\n const ret = { answer: completion };\n await this.cache?.set(\n `openai:article_summary_${article.id}`,\n JSON.stringify(ret),\n {\n ttl: this.cacheTtl,\n },\n );\n return ret;\n }\n\n private async getCompletion(prompt: string, user?: string) {\n const client = this.getClient();\n\n let completion;\n try {\n const messages: Array<OpenAI.ChatCompletionMessageParam> =\n new Array<OpenAI.ChatCompletionMessageParam>();\n if (this.systemPrompt) {\n messages.push({ role: 'system', content: this.systemPrompt });\n }\n const userPrompt: OpenAI.ChatCompletionMessageParam = {\n role: 'user',\n content: `${this.userPromptPrefix ?? ''}${prompt}${\n this.userPromptSuffix ?? ''\n }`,\n };\n messages.push(userPrompt);\n\n completion = await client.chat.completions.create({\n model: this.model,\n messages: messages,\n stream: false,\n max_tokens: this.maxTokens,\n temperature: this.temperature,\n user,\n n: 1,\n });\n } catch (e) {\n // Hide the real error from users\n this.logger.error(`Error from OpenAI: ${e}`);\n throw new Error('Failed to get response from OpenAI');\n }\n\n if (\n completion.choices.length === 0 ||\n !completion.choices[0].message.content\n ) {\n throw new Error('No response from OpenAI');\n }\n return completion.choices[0].message.content;\n }\n\n private getClient() {\n const apiKey = this.config.getOptionalString('qeta.openai.apiKey');\n const organization = this.config.getOptionalString(\n 'qeta.openai.organization',\n );\n const endpoint = this.config.getOptionalString('qeta.openai.endpoint');\n const project = this.config.getOptionalString('qeta.openai.project');\n\n return new OpenAI({ baseURL: endpoint, apiKey, organization, project });\n }\n}\n"],"names":["durationToMilliseconds","OpenAI"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var backstagePluginQetaNode = require('@drodil/backstage-plugin-qeta-node');
|
|
5
|
+
var OpenAIHandler = require('./OpenAIHandler.cjs.js');
|
|
6
|
+
|
|
7
|
+
const qetaModuleOpenai = backendPluginApi.createBackendModule({
|
|
8
|
+
pluginId: "qeta",
|
|
9
|
+
moduleId: "openai",
|
|
10
|
+
register(reg) {
|
|
11
|
+
reg.registerInit({
|
|
12
|
+
deps: {
|
|
13
|
+
logger: backendPluginApi.coreServices.logger,
|
|
14
|
+
config: backendPluginApi.coreServices.rootConfig,
|
|
15
|
+
ai: backstagePluginQetaNode.qetaAIExtensionPoint,
|
|
16
|
+
cache: backendPluginApi.coreServices.cache
|
|
17
|
+
},
|
|
18
|
+
async init({ logger, config, ai, cache }) {
|
|
19
|
+
const handler = new OpenAIHandler.OpenAIHandler(logger, config, cache);
|
|
20
|
+
ai.setAIHandler(handler);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
exports.qetaModuleOpenai = qetaModuleOpenai;
|
|
27
|
+
//# sourceMappingURL=module.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.cjs.js","sources":["../src/module.ts"],"sourcesContent":["/*\n * SPDX-FileCopyrightText: Copyright 2024 OP Financial Group (https://op.fi). All Rights Reserved.\n * SPDX-License-Identifier: LicenseRef-OpAllRightsReserved\n */\nimport {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { qetaAIExtensionPoint } from '@drodil/backstage-plugin-qeta-node';\nimport { OpenAIHandler } from './OpenAIHandler';\n\nexport const qetaModuleOpenai = createBackendModule({\n pluginId: 'qeta',\n moduleId: 'openai',\n register(reg) {\n reg.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n ai: qetaAIExtensionPoint,\n cache: coreServices.cache,\n },\n async init({ logger, config, ai, cache }) {\n const handler = new OpenAIHandler(logger, config, cache);\n ai.setAIHandler(handler);\n },\n });\n },\n});\n"],"names":["createBackendModule","coreServices","qetaAIExtensionPoint","OpenAIHandler"],"mappings":";;;;;;AAWO,MAAM,mBAAmBA,oCAAoB,CAAA;AAAA,EAClD,QAAU,EAAA,MAAA;AAAA,EACV,QAAU,EAAA,QAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,MAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,UAAA;AAAA,QACrB,EAAI,EAAAC,4CAAA;AAAA,QACJ,OAAOD,6BAAa,CAAA,KAAA;AAAA,OACtB;AAAA,MACA,MAAM,IAAK,CAAA,EAAE,QAAQ,MAAQ,EAAA,EAAA,EAAI,OAAS,EAAA;AACxC,QAAA,MAAM,OAAU,GAAA,IAAIE,2BAAc,CAAA,MAAA,EAAQ,QAAQ,KAAK,CAAA,CAAA;AACvD,QAAA,EAAA,CAAG,aAAa,OAAO,CAAA,CAAA;AAAA,OACzB;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@drodil/backstage-plugin-qeta-backend-module-openai",
|
|
3
|
+
"description": "The OpenAI backend module for the qeta plugin.",
|
|
4
|
+
"version": "3.6.1",
|
|
5
|
+
"main": "dist/index.cjs.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/drodil/backstage-plugin-qeta",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/drodil/backstage-plugin-qeta/issues"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/drodil/backstage-plugin-qeta.git"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public",
|
|
18
|
+
"main": "dist/index.cjs.js",
|
|
19
|
+
"types": "dist/index.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"backstage": {
|
|
22
|
+
"role": "backend-plugin-module",
|
|
23
|
+
"pluginId": "qeta",
|
|
24
|
+
"pluginPackage": "@drodil/backstage-plugin-qeta-backend"
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"scripts": {
|
|
28
|
+
"start": "backstage-cli package start",
|
|
29
|
+
"build": "backstage-cli package build",
|
|
30
|
+
"lint": "backstage-cli package lint",
|
|
31
|
+
"test": "backstage-cli package test",
|
|
32
|
+
"clean": "backstage-cli package clean",
|
|
33
|
+
"prepack": "backstage-cli package prepack",
|
|
34
|
+
"postpack": "backstage-cli package postpack",
|
|
35
|
+
"tsc": "tsc"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@backstage/backend-plugin-api": "^1.0.1",
|
|
39
|
+
"@backstage/config": "^1.2.0",
|
|
40
|
+
"@backstage/types": "^1.1.1",
|
|
41
|
+
"@drodil/backstage-plugin-qeta-common": "^3.6.1",
|
|
42
|
+
"@drodil/backstage-plugin-qeta-node": "^3.6.1",
|
|
43
|
+
"openai": "^4.68.4"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@backstage/backend-test-utils": "^1.0.2",
|
|
47
|
+
"@backstage/cli": "^0.28.1"
|
|
48
|
+
},
|
|
49
|
+
"files": [
|
|
50
|
+
"dist",
|
|
51
|
+
"configSchema.d.ts"
|
|
52
|
+
],
|
|
53
|
+
"configSchema": "configSchema.d.ts"
|
|
54
|
+
}
|