ai-assistant.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { type IGrantedGroup, GroupType } from '@growi/core';
  2. import createError from 'http-errors';
  3. import { type Model, type Document, Schema } from 'mongoose';
  4. import { getOrCreateModel } from '~/server/util/mongoose-utils';
  5. import { type AiAssistant, AiAssistantShareScope, AiAssistantAccessScope } from '../../interfaces/ai-assistant';
  6. import { generateGlobPatterns } from '../utils/generate-glob-patterns';
  7. export interface AiAssistantDocument extends AiAssistant, Document {}
  8. interface AiAssistantModel extends Model<AiAssistantDocument> {
  9. findByPagePaths(pagePaths: string[]): Promise<AiAssistantDocument[]>;
  10. setDefault(id: string, isDefault: boolean): Promise<AiAssistantDocument>;
  11. }
  12. /*
  13. * Schema Definition
  14. */
  15. const schema = new Schema<AiAssistantDocument>(
  16. {
  17. name: {
  18. type: String,
  19. required: true,
  20. },
  21. description: {
  22. type: String,
  23. required: true,
  24. default: '',
  25. },
  26. additionalInstruction: {
  27. type: String,
  28. required: true,
  29. default: '',
  30. },
  31. pagePathPatterns: [{
  32. type: String,
  33. required: true,
  34. }],
  35. vectorStore: {
  36. type: Schema.Types.ObjectId,
  37. ref: 'VectorStore',
  38. required: true,
  39. },
  40. owner: {
  41. type: Schema.Types.ObjectId,
  42. ref: 'User',
  43. required: true,
  44. },
  45. grantedGroupsForShareScope: {
  46. type: [{
  47. type: {
  48. type: String,
  49. enum: Object.values(GroupType),
  50. required: true,
  51. default: 'UserGroup',
  52. },
  53. item: {
  54. type: Schema.Types.ObjectId,
  55. refPath: 'grantedGroupsForShareScope.type',
  56. required: true,
  57. index: true,
  58. },
  59. }],
  60. validate: [function(arr: IGrantedGroup[]): boolean {
  61. if (arr == null) return true;
  62. const uniqueItemValues = new Set(arr.map(e => e.item));
  63. return arr.length === uniqueItemValues.size;
  64. }, 'grantedGroups contains non unique item'],
  65. default: [],
  66. },
  67. grantedGroupsForAccessScope: {
  68. type: [{
  69. type: {
  70. type: String,
  71. enum: Object.values(GroupType),
  72. required: true,
  73. default: 'UserGroup',
  74. },
  75. item: {
  76. type: Schema.Types.ObjectId,
  77. refPath: 'grantedGroupsForAccessScope.type',
  78. required: true,
  79. index: true,
  80. },
  81. }],
  82. validate: [function(arr: IGrantedGroup[]): boolean {
  83. if (arr == null) return true;
  84. const uniqueItemValues = new Set(arr.map(e => e.item));
  85. return arr.length === uniqueItemValues.size;
  86. }, 'grantedGroups contains non unique item'],
  87. default: [],
  88. },
  89. shareScope: {
  90. type: String,
  91. enum: Object.values(AiAssistantShareScope),
  92. required: true,
  93. },
  94. accessScope: {
  95. type: String,
  96. enum: Object.values(AiAssistantAccessScope),
  97. required: true,
  98. },
  99. isDefault: {
  100. type: Boolean,
  101. required: true,
  102. default: false,
  103. },
  104. },
  105. {
  106. timestamps: true,
  107. },
  108. );
  109. schema.statics.findByPagePaths = async function(pagePaths: string[]): Promise<AiAssistantDocument[]> {
  110. const pagePathsWithGlobPattern = pagePaths.map(pagePath => generateGlobPatterns(pagePath)).flat();
  111. const assistants = await this.find({
  112. $or: [
  113. // Case 1: Exact match
  114. { pagePathPatterns: { $in: pagePaths } },
  115. // Case 2: Glob pattern match
  116. { pagePathPatterns: { $in: pagePathsWithGlobPattern } },
  117. ],
  118. }).populate('vectorStore');
  119. return assistants;
  120. };
  121. schema.statics.setDefault = async function(id: string, isDefault: boolean): Promise<AiAssistantDocument> {
  122. const aiAssistant = await this.findOne({ _id: id, shareScope: AiAssistantAccessScope.PUBLIC_ONLY });
  123. if (aiAssistant == null) {
  124. throw createError(404, 'AiAssistant document does not exist');
  125. }
  126. await this.updateMany({ isDefault: true }, { isDefault: false });
  127. aiAssistant.isDefault = isDefault;
  128. const updatedAiAssistant = await aiAssistant.save();
  129. return updatedAiAssistant;
  130. };
  131. export default getOrCreateModel<AiAssistantDocument, AiAssistantModel>('AiAssistant', schema);