@yrpri/api 9.0.89 → 9.0.90

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.
@@ -21,7 +21,7 @@ export class YpBaseAssistant extends YpBaseChatBot {
21
21
  this.availableTools = new Map();
22
22
  this.toolCallTimeout = 30000; // 30 seconds
23
23
  this.maxModeTransitions = 10;
24
- this.modelName = "gpt-4o";
24
+ this.modelName = process.env.OPENAI_STREAMING_MODEL_NAME || "gpt-4o-2024-11-20";
25
25
  this.defaultSystemPrompt = `<coreImportantSystemInstructions>
26
26
  You are a helpful, witty, and friendly AI. Act like a human, but remember that you aren't a human and that you can't do human things in the real world.
27
27
  Your voice and personality should be warm and engaging, with a lively and playful tone. Talk quickly.
@@ -3,6 +3,7 @@ import { YpSubscriptionPlan } from "../../../../models/subscriptionPlan.js";
3
3
  import { YpAgentProduct } from "../../../../models/agentProduct.js";
4
4
  import { YpAgentProductBundle } from "../../../../models/agentProductBundle.js";
5
5
  import { YpAgentProductRun } from "../../../../models/agentProductRun.js";
6
+ import { Op } from "sequelize";
6
7
  export class SubscriptionModels {
7
8
  constructor(assistant) {
8
9
  this.assistant = assistant;
@@ -18,7 +19,10 @@ export class SubscriptionModels {
18
19
  // Get all available subscription plans with their associated agent products
19
20
  const availablePlans = await YpSubscriptionPlan.findAll({
20
21
  where: {
21
- // status: 'active', // Only get active plans
22
+ id: {
23
+ [Op.in]: [1, 6],
24
+ },
25
+ // status: 'active', // Only get active plans
22
26
  },
23
27
  attributes: ['id', 'configuration', 'name', 'description'],
24
28
  include: [
@@ -1,7 +1,7 @@
1
1
  // commonTools.ts
2
- import { AgentModels } from './models/agents.js';
3
- import { SubscriptionModels } from './models/subscriptions.js';
4
- import { BaseAssistantTools } from './baseTools.js';
2
+ import { AgentModels } from "./models/agents.js";
3
+ import { SubscriptionModels } from "./models/subscriptions.js";
4
+ import { BaseAssistantTools } from "./baseTools.js";
5
5
  export class NavigationTools extends BaseAssistantTools {
6
6
  constructor(assistant) {
7
7
  super(assistant);
@@ -9,10 +9,10 @@ export class NavigationTools extends BaseAssistantTools {
9
9
  this.subscriptionModels = new SubscriptionModels(assistant);
10
10
  }
11
11
  async goBackToMainAssistant() {
12
- await this.assistant.handleModeSwitch('agent_selection_mode', 'User requested to return to the main assistant', {});
12
+ await this.assistant.handleModeSwitch("agent_selection_mode", "User requested to return to the main assistant", {});
13
13
  return {
14
14
  success: true,
15
- data: { message: 'Returned to main assistant' },
15
+ data: { message: "Returned to main assistant" },
16
16
  };
17
17
  }
18
18
  get connectDirectlyToAgent() {
@@ -36,12 +36,31 @@ export class NavigationTools extends BaseAssistantTools {
36
36
  params = this.assistant.getCleanedParams(params);
37
37
  console.log(`handler: connect_to_one_of_the_agents: ${JSON.stringify(params, null, 2)}`);
38
38
  try {
39
- const { plan, subscription } = await this.subscriptionModels.loadAgentProductPlanAndSubscription(params.subscriptionPlanId);
39
+ let { plan, subscription } = await this.subscriptionModels.loadAgentProductPlanAndSubscription(params.subscriptionPlanId);
40
40
  if (!plan?.AgentProduct) {
41
41
  throw new Error(`Agent product with id ${params.subscriptionPlanId} not found`);
42
42
  }
43
+ //TODO: Does not work as the user is not logged in. Lets figure it out.
44
+ /*if (plan.configuration.amount == 0) {
45
+ const result = await this.subscriptionModels.subscribeToAgentPlan(
46
+ plan.AgentProduct!.id,
47
+ plan.id
48
+ );
49
+
50
+ if (!result.success || !result.subscription || !result.plan) {
51
+ return {
52
+ success: false,
53
+ error: result.error || "Failed to subscribe to agent plan",
54
+ };
55
+ } else {
56
+ plan = result.plan;
57
+ subscription = result.subscription;
58
+ }
59
+ }*/
43
60
  console.log(`Loading: ${plan?.AgentProduct?.name} ${subscription?.id}`);
44
- await this.updateCurrentAgentProductPlan(plan, subscription, { sendEvent: false });
61
+ await this.updateCurrentAgentProductPlan(plan, subscription, {
62
+ sendEvent: false,
63
+ });
45
64
  await this.assistant.handleModeSwitch("agent_direct_connection_mode", `Directly connected to agent: ${plan?.AgentProduct?.name}`, params);
46
65
  const html = `<div class="agent-chips"><yp-agent-chip
47
66
  isSelected
@@ -61,9 +80,7 @@ export class NavigationTools extends BaseAssistantTools {
61
80
  };
62
81
  }
63
82
  catch (error) {
64
- const errorMessage = error instanceof Error
65
- ? error.message
66
- : "Failed to select agent";
83
+ const errorMessage = error instanceof Error ? error.message : "Failed to select agent";
67
84
  console.error(`Failed to select agent: ${errorMessage}`);
68
85
  return {
69
86
  success: false,
@@ -19,7 +19,7 @@ export class YpBaseChatBotWithVoice extends YpBaseChatBot {
19
19
  };
20
20
  // Default voice configuration
21
21
  this.voiceConfig = {
22
- model: "gpt-4o-realtime-preview-2024-12-17",
22
+ model: process.env.OPENAI_VOICE_MODEL_NAME || "gpt-4o-realtime-preview-2024-12-17",
23
23
  voice: "echo",
24
24
  modalities: ["text", "audio"],
25
25
  };
@@ -50,7 +50,7 @@ async function setupAgentProductsConfiguration() {
50
50
  },
51
51
  {
52
52
  name: "Competitor analysis report",
53
- shortName: "Competitor Analysis Report",
53
+ shortName: "Competitor Report",
54
54
  shortDescription: "Report on the state of your key competitors and recommendations.",
55
55
  description: "Report on the state of your key competitors where all the information gathered in earlier steps has been consolidated into chapters for each competitor and concludes with a chapter on action-oriented recommendations.",
56
56
  agentClassUuid: "1cf3af64-a5f6-a7c1-91c1-51fb13c72f1a",
@@ -554,7 +554,7 @@ router.get('/*', function botController(req, res, next) {
554
554
  ], error => {
555
555
  if (error) {
556
556
  log.error("Id for nonSpa is not a number", { error });
557
- res.sendStatus(404);
557
+ res.sendStatus(200);
558
558
  }
559
559
  else {
560
560
  if (req.ypCommunity && req.ypCommunity.id != null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yrpri/api",
3
- "version": "9.0.89",
3
+ "version": "9.0.90",
4
4
  "license": "MIT",
5
5
  "author": "Robert Bjarnason & Citizens Foundation",
6
6
  "repository": {
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ const models = require('../../models/index.cjs');
3
+ const moment = require('moment');
4
+ const maxNumberFromPath = process.argv[2];
5
+ const maxNumberOfNotificationsToDelete = maxNumberFromPath ? maxNumberFromPath : 1000;
6
+ let numberOfDeletedNotifications = 0;
7
+ let startTime = moment();
8
+ function sleep(ms) {
9
+ return new Promise(resolve => setTimeout(resolve, ms));
10
+ }
11
+ const chunk = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
12
+ (async () => {
13
+ let haveNotificationsToDelete = true;
14
+ let userOffset = 0;
15
+ while (haveNotificationsToDelete && numberOfDeletedNotifications < maxNumberOfNotificationsToDelete) {
16
+ try {
17
+ const users = await models.User.unscoped().findAll({
18
+ where: {
19
+ created_at: {
20
+ [models.Sequelize.Op.lte]: moment().add(-3, 'days').toISOString()
21
+ },
22
+ profile_data: {
23
+ isAnonymousUser: {
24
+ [models.Sequelize.Op.is]: true
25
+ }
26
+ }
27
+ },
28
+ attributes: ['id'],
29
+ order: ['id'],
30
+ offset: userOffset,
31
+ limit: 500
32
+ });
33
+ if (users.length > 0) {
34
+ console.log(`${users.length} users offset ${userOffset}`);
35
+ userOffset += 500;
36
+ const userIds = users.map(n => { return n.id; });
37
+ let haveNotificationsLeftToProcess = true;
38
+ let notificationsOffset = 0;
39
+ while (haveNotificationsLeftToProcess && numberOfDeletedNotifications < maxNumberOfNotificationsToDelete) {
40
+ const notifications = await models.AcNotification.unscoped().findAll({
41
+ where: {
42
+ user_id: {
43
+ [models.Sequelize.Op.in]: userIds
44
+ }
45
+ },
46
+ limit: 1000,
47
+ offset: notificationsOffset,
48
+ order: ['user_id'],
49
+ attributes: ['id'],
50
+ });
51
+ console.log(`${notifications.length} notifications offset ${notificationsOffset}`);
52
+ if (notifications.length > 0) {
53
+ notificationsOffset += 1000;
54
+ const notificationIds = notifications.map(n => { return n.id; });
55
+ const chunkedIds = chunk(notificationIds, 100);
56
+ for (let i = 0; i < chunkedIds.length; i++) {
57
+ const destroyInfo = await models.AcNotification.unscoped().destroy({
58
+ where: {
59
+ id: {
60
+ [models.Sequelize.Op.in]: chunkedIds[i]
61
+ }
62
+ }
63
+ });
64
+ numberOfDeletedNotifications += destroyInfo;
65
+ console.log(`${numberOfDeletedNotifications}`);
66
+ await sleep(50);
67
+ if (numberOfDeletedNotifications >= maxNumberOfNotificationsToDelete) {
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ else {
73
+ haveNotificationsLeftToProcess = false;
74
+ console.log("No more notifications left to process from user");
75
+ }
76
+ await sleep(100);
77
+ }
78
+ }
79
+ else {
80
+ haveNotificationsToDelete = false;
81
+ }
82
+ }
83
+ catch (error) {
84
+ console.error(error);
85
+ haveNotificationsToDelete = false;
86
+ }
87
+ }
88
+ console.log(`${numberOfDeletedNotifications} old anon notifications deleted`);
89
+ console.log(`Duration ${moment(moment() - startTime).format("HH:mm:ss.SSS")}`);
90
+ process.exit();
91
+ })();
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ const models = require('../../models/index.cjs');
3
+ const moment = require('moment');
4
+ const maxNumberFromPath = process.argv[2];
5
+ // Default to 1,000,000 if no command line arg given, adjust as you see fit
6
+ const maxNumberOfNotificationsToDelete = maxNumberFromPath ? parseInt(maxNumberFromPath) : 1000000;
7
+ let numberOfDeletedNotifications = 0;
8
+ const startTime = moment();
9
+ function sleep(ms) {
10
+ return new Promise(resolve => setTimeout(resolve, ms));
11
+ }
12
+ function chunk(arr, size) {
13
+ return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => arr.slice(i * size, i * size + size));
14
+ }
15
+ (async () => {
16
+ let haveNotificationsToDelete = true;
17
+ let offset = 0;
18
+ // Calculate the cutoff date for "older than 1 year"
19
+ const cutoffDate = moment().subtract(1, 'year').toISOString();
20
+ while (haveNotificationsToDelete && numberOfDeletedNotifications < maxNumberOfNotificationsToDelete) {
21
+ try {
22
+ // Fetch a batch of notifications older than 1 year
23
+ const notifications = await models.AcNotification.unscoped().findAll({
24
+ where: {
25
+ created_at: {
26
+ [models.Sequelize.Op.lte]: cutoffDate,
27
+ },
28
+ },
29
+ limit: 1000,
30
+ offset: offset,
31
+ order: ['id'],
32
+ attributes: ['id'],
33
+ });
34
+ if (notifications.length > 0) {
35
+ console.log(`${notifications.length} notifications found at offset ${offset}`);
36
+ offset += 1000;
37
+ // Extract IDs and chunk them to avoid huge deletions in one query
38
+ const notificationIds = notifications.map(n => n.id);
39
+ const chunkedIds = chunk(notificationIds, 100);
40
+ // Delete chunk by chunk
41
+ for (const chunkIds of chunkedIds) {
42
+ const destroyInfo = await models.AcNotification.unscoped().destroy({
43
+ where: {
44
+ id: {
45
+ [models.Sequelize.Op.in]: chunkIds,
46
+ },
47
+ },
48
+ });
49
+ numberOfDeletedNotifications += destroyInfo;
50
+ console.log(`Total deleted so far: ${numberOfDeletedNotifications}`);
51
+ await sleep(10); // short pause
52
+ // Stop if we’ve hit our daily (or run) limit
53
+ if (numberOfDeletedNotifications >= maxNumberOfNotificationsToDelete) {
54
+ break;
55
+ }
56
+ }
57
+ }
58
+ else {
59
+ // No more notifications to delete
60
+ haveNotificationsToDelete = false;
61
+ }
62
+ await sleep(25); // short pause between big fetches
63
+ }
64
+ catch (error) {
65
+ console.error(error);
66
+ haveNotificationsToDelete = false;
67
+ }
68
+ }
69
+ console.log(`${numberOfDeletedNotifications} old notifications deleted`);
70
+ console.log(`Duration: ${moment(moment() - startTime).format('HH:mm:ss.SSS')}`);
71
+ process.exit();
72
+ })();
@@ -68,6 +68,10 @@ var generateSitemap = async function (req, res) {
68
68
  })
69
69
  .then(function (communities) {
70
70
  _.forEach(communities, function (community) {
71
+ if (!community) {
72
+ console.error("No community found in sitemap generation");
73
+ return;
74
+ }
71
75
  const path = "/community/" + community.id;
72
76
  if (community.hostname &&
73
77
  wildCardDomainNames.indexOf(domainName) > -1) {
@@ -134,6 +138,10 @@ var generateSitemap = async function (req, res) {
134
138
  })
135
139
  .then(function (groups) {
136
140
  _.forEach(groups, function (group) {
141
+ if (!group) {
142
+ console.error("No group found in sitemap generation");
143
+ return;
144
+ }
137
145
  const path = "/group/" + group.id;
138
146
  if (group.Community.hostname &&
139
147
  wildCardDomainNames.indexOf(domainName) > -1) {
@@ -217,6 +225,10 @@ var generateSitemap = async function (req, res) {
217
225
  })
218
226
  .then(function (posts) {
219
227
  _.forEach(posts, function (post) {
228
+ if (!post) {
229
+ console.error("No post found in sitemap generation");
230
+ return;
231
+ }
220
232
  links.push({ url: "/post/" + post.id });
221
233
  });
222
234
  seriesCallback();