@adminforth/upload 1.0.18 → 1.0.20

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.
@@ -103,7 +103,7 @@
103
103
 
104
104
  <script setup lang="ts">
105
105
 
106
- import { ref, onMounted } from 'vue'
106
+ import { ref, onMounted, nextTick } from 'vue'
107
107
  import { Carousel } from 'flowbite';
108
108
  import { callAdminForthApi } from '@/utils';
109
109
 
@@ -184,6 +184,7 @@ async function generateImages() {
184
184
  variant: 'danger',
185
185
  timeout: 15,
186
186
  });
187
+ loading.value = false;
187
188
  return;
188
189
  }
189
190
 
@@ -196,7 +197,7 @@ async function generateImages() {
196
197
  // 'https://via.placeholder.com/600x400?text=Image+1',
197
198
  // 'https://via.placeholder.com/600x400?text=Image+2',
198
199
  // ];
199
- await new Promise(resolve => setTimeout(resolve, 0));
200
+ await nextTick();
200
201
 
201
202
  caurosel.value = new Carousel(
202
203
  document.getElementById('gallery'),
@@ -212,7 +213,7 @@ async function generateImages() {
212
213
  override: true,
213
214
  }
214
215
  );
215
- await new Promise(resolve => setTimeout(resolve, 0));
216
+ await nextTick();
216
217
  loading.value = false;
217
218
  }
218
219
 
@@ -103,7 +103,7 @@
103
103
 
104
104
  <script setup lang="ts">
105
105
 
106
- import { ref, onMounted } from 'vue'
106
+ import { ref, onMounted, nextTick } from 'vue'
107
107
  import { Carousel } from 'flowbite';
108
108
  import { callAdminForthApi } from '@/utils';
109
109
 
@@ -184,6 +184,7 @@ async function generateImages() {
184
184
  variant: 'danger',
185
185
  timeout: 15,
186
186
  });
187
+ loading.value = false;
187
188
  return;
188
189
  }
189
190
 
@@ -196,7 +197,7 @@ async function generateImages() {
196
197
  // 'https://via.placeholder.com/600x400?text=Image+1',
197
198
  // 'https://via.placeholder.com/600x400?text=Image+2',
198
199
  // ];
199
- await new Promise(resolve => setTimeout(resolve, 0));
200
+ await nextTick();
200
201
 
201
202
  caurosel.value = new Carousel(
202
203
  document.getElementById('gallery'),
@@ -212,7 +213,7 @@ async function generateImages() {
212
213
  override: true,
213
214
  }
214
215
  );
215
- await new Promise(resolve => setTimeout(resolve, 0));
216
+ await nextTick();
216
217
  loading.value = false;
217
218
  }
218
219
 
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
11
11
  import { ExpirationStatus, GetObjectCommand, PutObjectCommand, S3 } from '@aws-sdk/client-s3';
12
12
  import { AdminForthPlugin, suggestIfTypo } from "adminforth";
13
13
  import { Readable } from "stream";
14
+ import { RateLimiter, getClientIp } from "adminforth";
14
15
  const ADMINFORTH_NOT_YET_USED_TAG = 'adminforth-candidate-for-cleanup';
15
16
  export default class UploadPlugin extends AdminForthPlugin {
16
17
  constructor(options) {
@@ -409,11 +410,19 @@ export default class UploadPlugin extends AdminForthPlugin {
409
410
  server.endpoint({
410
411
  method: 'POST',
411
412
  path: `/plugin/${this.pluginInstanceId}/generate_images`,
412
- handler: (_c) => __awaiter(this, [_c], void 0, function* ({ body }) {
413
+ handler: (_c) => __awaiter(this, [_c], void 0, function* ({ body, headers }) {
414
+ var _d, _e;
413
415
  const { prompt } = body;
414
416
  if (this.options.generation.provider !== 'openai-dall-e') {
415
417
  throw new Error(`Provider ${this.options.generation.provider} is not supported`);
416
418
  }
419
+ if ((_d = this.options.generation.rateLimit) === null || _d === void 0 ? void 0 : _d.limit) {
420
+ // rate limit
421
+ const { error } = RateLimiter.checkRateLimit(this.pluginInstanceId, (_e = this.options.generation.rateLimit) === null || _e === void 0 ? void 0 : _e.limit, getClientIp(headers));
422
+ if (error) {
423
+ return { error: this.options.generation.rateLimit.errorMessage };
424
+ }
425
+ }
417
426
  const { model, size, apiKey } = this.options.generation.openAiOptions;
418
427
  const url = 'https://api.openai.com/v1/images/generations';
419
428
  let error = null;
@@ -445,7 +454,7 @@ export default class UploadPlugin extends AdminForthPlugin {
445
454
  server.endpoint({
446
455
  method: 'GET',
447
456
  path: `/plugin/${this.pluginInstanceId}/cors-proxy`,
448
- handler: (_d) => __awaiter(this, [_d], void 0, function* ({ query, response }) {
457
+ handler: (_f) => __awaiter(this, [_f], void 0, function* ({ query, response }) {
449
458
  const { url } = query;
450
459
  const resp = yield fetch(url);
451
460
  response.setHeader('Content-Type', resp.headers.get('Content-Type'));
package/index.ts CHANGED
@@ -4,6 +4,7 @@ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
4
4
  import { ExpirationStatus, GetObjectCommand, ObjectCannedACL, PutObjectCommand, S3 } from '@aws-sdk/client-s3';
5
5
  import { AdminForthPlugin, AdminForthResourceColumn, AdminForthResourcePages, IAdminForth, IHttpServer, suggestIfTypo } from "adminforth";
6
6
  import { Readable } from "stream";
7
+ import { RateLimiter, getClientIp } from "adminforth";
7
8
 
8
9
  const ADMINFORTH_NOT_YET_USED_TAG = 'adminforth-candidate-for-cleanup';
9
10
 
@@ -451,13 +452,25 @@ export default class UploadPlugin extends AdminForthPlugin {
451
452
  server.endpoint({
452
453
  method: 'POST',
453
454
  path: `/plugin/${this.pluginInstanceId}/generate_images`,
454
- handler: async ({ body }) => {
455
+ handler: async ({ body, headers }) => {
455
456
  const { prompt } = body;
456
457
 
457
458
  if (this.options.generation.provider !== 'openai-dall-e') {
458
459
  throw new Error(`Provider ${this.options.generation.provider} is not supported`);
459
460
  }
460
461
 
462
+ if (this.options.generation.rateLimit?.limit) {
463
+ // rate limit
464
+ const { error } = RateLimiter.checkRateLimit(
465
+ this.pluginInstanceId,
466
+ this.options.generation.rateLimit?.limit,
467
+ getClientIp(headers),
468
+ );
469
+ if (error) {
470
+ return { error: this.options.generation.rateLimit.errorMessage };
471
+ }
472
+ }
473
+
461
474
  const { model, size, apiKey } = this.options.generation.openAiOptions;
462
475
  const url = 'https://api.openai.com/v1/images/generations';
463
476
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/upload",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/types.ts CHANGED
@@ -128,6 +128,25 @@ export type PluginOptions = {
128
128
  * where plugin is used.
129
129
  */
130
130
  fieldsForContext? : string[],
131
+
132
+
133
+ /**
134
+ * Since AI generation can be expensive, we can limit the number of requests per IP.
135
+ */
136
+ rateLimit?: {
137
+
138
+ /**
139
+ * E.g. 5/1d - 5 requests per day
140
+ * 3/1h - 3 requests per hour
141
+ */
142
+ limit: string,
143
+
144
+ /**
145
+ * !Not used now
146
+ * Message shown to user when rate limit is reached
147
+ */
148
+ errorMessage: string,
149
+ },
131
150
  }
132
151
 
133
152
  }