You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.ts 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import { z } from 'zod'
  2. import { ArrayType, Type } from './types'
  3. import type { ArrayItems, Field, LLMNodeType } from './types'
  4. import { draft07Validator, forbidBooleanProperties } from '@/utils/validators'
  5. import type { ValidationError } from 'jsonschema'
  6. export const checkNodeValid = (_payload: LLMNodeType) => {
  7. return true
  8. }
  9. export const getFieldType = (field: Field) => {
  10. const { type, items } = field
  11. if(field.schemaType === 'file') return 'file'
  12. if (type !== Type.array || !items)
  13. return type
  14. return ArrayType[items.type as keyof typeof ArrayType]
  15. }
  16. export const getHasChildren = (schema: Field) => {
  17. const complexTypes = [Type.object, Type.array]
  18. if (!complexTypes.includes(schema.type))
  19. return false
  20. if (schema.type === Type.object)
  21. return schema.properties && Object.keys(schema.properties).length > 0
  22. if (schema.type === Type.array)
  23. return schema.items && schema.items.type === Type.object && schema.items.properties && Object.keys(schema.items.properties).length > 0
  24. }
  25. export const getTypeOf = (target: any) => {
  26. if (target === null) return 'null'
  27. if (typeof target !== 'object') {
  28. return typeof target
  29. }
  30. else {
  31. return Object.prototype.toString
  32. .call(target)
  33. .slice(8, -1)
  34. .toLocaleLowerCase()
  35. }
  36. }
  37. export const inferType = (value: any): Type => {
  38. const type = getTypeOf(value)
  39. if (type === 'array') return Type.array
  40. // type boolean will be treated as string
  41. if (type === 'boolean') return Type.string
  42. if (type === 'number') return Type.number
  43. if (type === 'string') return Type.string
  44. if (type === 'object') return Type.object
  45. return Type.string
  46. }
  47. export const jsonToSchema = (json: any): Field => {
  48. const schema: Field = {
  49. type: inferType(json),
  50. }
  51. if (schema.type === Type.object) {
  52. schema.properties = {}
  53. schema.required = []
  54. schema.additionalProperties = false
  55. Object.entries(json).forEach(([key, value]) => {
  56. schema.properties![key] = jsonToSchema(value)
  57. schema.required!.push(key)
  58. })
  59. }
  60. else if (schema.type === Type.array) {
  61. schema.items = jsonToSchema(json[0]) as ArrayItems
  62. }
  63. return schema
  64. }
  65. export const checkJsonDepth = (json: any) => {
  66. if (!json || getTypeOf(json) !== 'object')
  67. return 0
  68. let maxDepth = 0
  69. if (getTypeOf(json) === 'array') {
  70. if (json[0] && getTypeOf(json[0]) === 'object')
  71. maxDepth = checkJsonDepth(json[0])
  72. }
  73. else if (getTypeOf(json) === 'object') {
  74. const propertyDepths = Object.values(json).map(value => checkJsonDepth(value))
  75. maxDepth = propertyDepths.length ? Math.max(...propertyDepths) + 1 : 1
  76. }
  77. return maxDepth
  78. }
  79. export const checkJsonSchemaDepth = (schema: Field) => {
  80. if (!schema || getTypeOf(schema) !== 'object')
  81. return 0
  82. let maxDepth = 0
  83. if (schema.type === Type.object && schema.properties) {
  84. const propertyDepths = Object.values(schema.properties).map(value => checkJsonSchemaDepth(value))
  85. maxDepth = propertyDepths.length ? Math.max(...propertyDepths) + 1 : 1
  86. }
  87. else if (schema.type === Type.array && schema.items && schema.items.type === Type.object) {
  88. maxDepth = checkJsonSchemaDepth(schema.items) + 1
  89. }
  90. return maxDepth
  91. }
  92. export const findPropertyWithPath = (target: any, path: string[]) => {
  93. let current = target
  94. for (const key of path)
  95. current = current[key]
  96. return current
  97. }
  98. export const validateSchemaAgainstDraft7 = (schemaToValidate: any) => {
  99. // First check against Draft-07
  100. const result = draft07Validator(schemaToValidate)
  101. // Then apply custom rule
  102. const customErrors = forbidBooleanProperties(schemaToValidate)
  103. return [...result.errors, ...customErrors]
  104. }
  105. export const getValidationErrorMessage = (errors: Array<ValidationError | string>) => {
  106. const message = errors.map((error) => {
  107. if (typeof error === 'string')
  108. return error
  109. else
  110. return `Error: ${error.stack}\n`
  111. }).join('')
  112. return message
  113. }
  114. // Previous Not support boolean type, so transform boolean to string when paste it into schema editor
  115. export const convertBooleanToString = (schema: any) => {
  116. if (schema.type === Type.boolean)
  117. schema.type = Type.string
  118. if (schema.type === Type.array && schema.items && schema.items.type === Type.boolean)
  119. schema.items.type = Type.string
  120. if (schema.type === Type.object) {
  121. schema.properties = Object.entries(schema.properties).reduce((acc, [key, value]) => {
  122. acc[key] = convertBooleanToString(value)
  123. return acc
  124. }, {} as any)
  125. }
  126. if (schema.type === Type.array && schema.items && schema.items.type === Type.object) {
  127. schema.items.properties = Object.entries(schema.items.properties).reduce((acc, [key, value]) => {
  128. acc[key] = convertBooleanToString(value)
  129. return acc
  130. }, {} as any)
  131. }
  132. return schema
  133. }
  134. const schemaRootObject = z.object({
  135. type: z.literal('object'),
  136. properties: z.record(z.string(), z.any()),
  137. required: z.array(z.string()),
  138. additionalProperties: z.boolean().optional(),
  139. })
  140. export const preValidateSchema = (schema: any) => {
  141. const result = schemaRootObject.safeParse(schema)
  142. return result
  143. }