Skip to content

Commit

Permalink
Merge branch 'feat/better-json-schemas-developer-experience' into dev…
Browse files Browse the repository at this point in the history
…elop
  • Loading branch information
louistiti committed Apr 11, 2023
2 parents 5061cac + 8c89cbf commit 5b4cd9d
Show file tree
Hide file tree
Showing 96 changed files with 398 additions and 139 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ skills/**/memory/*.json
core/data/models/*.nlp
package.json.backup
.python-version
schemas/**/*.json
1 change: 1 addition & 0 deletions core/config/voice/amazon.sample.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../schemas/voice-config-schemas/amazon.json",
"credentials": {
"accessKeyId": "",
"secretAccessKey": ""
Expand Down
1 change: 1 addition & 0 deletions core/config/voice/google-cloud.sample.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../schemas/voice-config-schemas/google-cloud.json",
"type": "service_account",
"project_id": "",
"private_key_id": "",
Expand Down
1 change: 1 addition & 0 deletions core/config/voice/watson-stt.sample.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../schemas/voice-config-schemas/watson-stt.json",
"apikey": "",
"url": "https://stream.watsonplatform.net/speech-to-text/api"
}
1 change: 1 addition & 0 deletions core/config/voice/watson-tts.sample.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../schemas/voice-config-schemas/watson-tts.json",
"apikey": "",
"url": "https://stream.watsonplatform.net/text-to-speech/api"
}
1 change: 1 addition & 0 deletions core/data/en/answers.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../schemas/global-data/global-answers.json",
"answers": {
"success": {},
"errors": {
Expand Down
1 change: 1 addition & 0 deletions core/data/en/global-entities/color.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../../schemas/global-data/global-entity.json",
"options": {
"red": {
"synonyms": ["red"],
Expand Down
1 change: 1 addition & 0 deletions core/data/en/global-entities/level.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../../schemas/global-data/global-entity.json",
"options": {
"LOW": {
"synonyms": ["low"]
Expand Down
1 change: 1 addition & 0 deletions core/data/en/global-entities/partner_assistant.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../../schemas/global-data/global-entity.json",
"options": {
"Alexa": {
"synonyms": ["Alexa"],
Expand Down
1 change: 1 addition & 0 deletions core/data/en/global-resolvers/affirmation_denial.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../../schemas/global-data/global-resolver.json",
"name": "affirmation_denial",
"intents": {
"affirmation": {
Expand Down
1 change: 1 addition & 0 deletions core/data/fr/answers.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../schemas/global-data/global-answers.json",
"answers": {
"success": {},
"errors": {
Expand Down
1 change: 1 addition & 0 deletions core/data/fr/global-entities/color.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../../schemas/global-data/global-entity.json",
"options": {
"rouge": {
"synonyms": ["rouge"],
Expand Down
1 change: 1 addition & 0 deletions core/data/fr/global-entities/level.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../../schemas/global-data/global-entity.json",
"options": {
"bas": {
"synonyms": ["bas", "basse"],
Expand Down
1 change: 1 addition & 0 deletions core/data/fr/global-entities/partner_assistant.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../../schemas/global-data/global-entity.json",
"options": {
"Alexa": {
"synonyms": ["Alexa"],
Expand Down
1 change: 1 addition & 0 deletions core/data/fr/global-resolvers/affirmation_denial.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../../../schemas/global-data/global-resolver.json",
"name": "affirmation_denial",
"intents": {
"affirmation": {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"prepare": "husky install",
"generate:skills-endpoints": "ts-node scripts/generate/run-generate-skills-endpoints.js",
"generate:http-api-key": "ts-node scripts/generate/run-generate-http-api-key.js",
"generate:json-schemas": "ts-node scripts/generate/run-generate-json-schemas.js",
"build": "npm run build:app && npm run build:server",
"build:app": "cross-env LEON_NODE_ENV=production ts-node scripts/app/run-build-app.js",
"build:server": "npm run delete-dist:server && npm run train && npm run generate:skills-endpoints && tsc && resolve-tspaths && shx rm -rf server/dist/core server/dist/package.json && shx mv -f server/dist/server/src/* server/dist && shx rm -rf server/dist/server && shx mkdir -p server/dist/tmp",
Expand Down
78 changes: 78 additions & 0 deletions scripts/generate/generate-json-schemas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import fs from 'node:fs'
import path from 'node:path'

import { LogHelper } from '@/helpers/log-helper'
import {
domainSchemaObject,
skillSchemaObject,
skillConfigSchemaObject
} from '@/schemas/skill-schemas'
import {
globalEntitySchemaObject,
globalResolverSchemaObject,
globalAnswersSchemaObject
} from '@/schemas/global-data-schemas'
import {
amazonVoiceConfiguration,
googleCloudVoiceConfiguration,
watsonVoiceConfiguration
} from '@/schemas/voice-config-schemas'

/**
* Generate JSON schemas
* @param {string} categoryName
* @param {Map<string, Object>} schemas
*/
export const generateSchemas = async (categoryName, schemas) => {
const categorySchemasPath = path.join(process.cwd(), 'schemas', categoryName)
await fs.promises.mkdir(categorySchemasPath, { recursive: true })
for (const [schemaName, schemaObject] of schemas.entries()) {
const schemaPath = path.join(categorySchemasPath, `${schemaName}.json`)
await fs.promises.writeFile(
schemaPath,
JSON.stringify(
{
$schema: 'https://json-schema.org/draft-07/schema',
...schemaObject
},
null,
2
)
)
}
}

export default async () => {
LogHelper.info('Generating the JSON schemas...')
await Promise.all([
generateSchemas(
'global-data',
new Map([
['global-entity', globalEntitySchemaObject],
['global-resolver', globalResolverSchemaObject],
['global-answers', globalAnswersSchemaObject]
])
),
generateSchemas(
'skill-schemas',
new Map([
['domain', domainSchemaObject],
['skill', skillSchemaObject],
['skill-config', skillConfigSchemaObject]
])
),
generateSchemas(
'voice-config-schemas',
new Map([
['amazon', amazonVoiceConfiguration],
[
'google-cloud',
googleCloudVoiceConfiguration
],
['watson-stt', watsonVoiceConfiguration],
['watson-tts', watsonVoiceConfiguration]
])
)
])
LogHelper.success('JSON schemas generated')
}
14 changes: 14 additions & 0 deletions scripts/generate/run-generate-json-schemas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { LogHelper } from '@/helpers/log-helper'

import generateJsonSchemas from './generate-json-schemas'

/**
* Execute the generating JSON schemas script
*/
;(async () => {
try {
await generateJsonSchemas()
} catch (error) {
LogHelper.error(`Failed to generate the json schemas: ${error}`)
}
})()
2 changes: 2 additions & 0 deletions scripts/setup/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { LogHelper } from '@/helpers/log-helper'

import train from '../train/train'
import generateHttpApiKey from '../generate/generate-http-api-key'
import generateJsonSchemas from '../generate/generate-json-schemas'

import setupDotenv from './setup-dotenv'
import setupCore from './setup-core'
Expand All @@ -22,6 +23,7 @@ import setupPythonBinaries from './setup-python-binaries'
LoaderHelper.stop()
await setupPythonBinaries()
await generateHttpApiKey()
await generateJsonSchemas()
LoaderHelper.start()
await train()

Expand Down
20 changes: 19 additions & 1 deletion server/src/pre-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,24 @@ interface ObjectUnknown {
}

const validateSchema = (
schemaName: string,
schema: ObjectUnknown,
contentToValidate: ObjectUnknown,
customErrorMessage: string
): void => {
const schemaFile = `${schemaName}.json`
const validate = ajv.compile(schema)
const isValid = validate(contentToValidate)
const isValidSchemaKey =
typeof contentToValidate['$schema'] === 'string' &&
contentToValidate['$schema'].endsWith(schemaFile)
const isValid = validate(contentToValidate) && isValidSchemaKey
if (!isValid) {
LogHelper.error(customErrorMessage)
if (!isValidSchemaKey) {
LogHelper.error(
`The schema key "$schema" is not valid. Expected "${schemaName}", but got "${contentToValidate['$schema']}".`
)
}
LogHelper.error(customErrorMessage)
const errors = new AggregateAjvError(validate.errors ?? [])
for (const error of errors) {
Expand Down Expand Up @@ -88,6 +99,7 @@ const GLOBAL_DATA_SCHEMAS = {
)
const [configName] = file.split('.') as [keyof typeof VOICE_CONFIG_SCHEMAS]
validateSchema(
`voice-config-schemas/${configName}`,
VOICE_CONFIG_SCHEMAS[configName],
config,
`The voice configuration schema "${voiceConfigPath}" is not valid:`
Expand Down Expand Up @@ -116,6 +128,7 @@ const GLOBAL_DATA_SCHEMAS = {
await fs.promises.readFile(globalEntityPath, 'utf8')
)
validateSchema(
'global-data/global-entity',
globalEntitySchemaObject,
globalEntity,
`The global entity schema "${globalEntityPath}" is not valid:`
Expand All @@ -136,6 +149,7 @@ const GLOBAL_DATA_SCHEMAS = {
await fs.promises.readFile(globalResolverPath, 'utf8')
)
validateSchema(
'global-data/global-resolver',
globalResolverSchemaObject,
globalResolver,
`The global resolver schema "${globalResolverPath}" is not valid:`
Expand All @@ -150,6 +164,7 @@ const GLOBAL_DATA_SCHEMAS = {
await fs.promises.readFile(globalAnswersPath, 'utf8')
)
validateSchema(
'global-data/global-answers',
GLOBAL_DATA_SCHEMAS.answers,
answers,
`The global answers schema "${globalAnswersPath}" is not valid:`
Expand All @@ -173,6 +188,7 @@ const GLOBAL_DATA_SCHEMAS = {
await fs.promises.readFile(pathToDomain, 'utf8')
)
validateSchema(
'skill-schemas/domain',
domainSchemaObject,
domainObject,
`The domain schema "${pathToDomain}" is not valid:`
Expand All @@ -192,6 +208,7 @@ const GLOBAL_DATA_SCHEMAS = {
await fs.promises.readFile(pathToSkill, 'utf8')
)
validateSchema(
'skill-schemas/skill',
skillSchemaObject,
skillObject,
`The skill schema "${pathToSkill}" is not valid:`
Expand All @@ -211,6 +228,7 @@ const GLOBAL_DATA_SCHEMAS = {
await fs.promises.readFile(skillConfigPath, 'utf8')
)
validateSchema(
'skill-schemas/skill-config',
skillConfigSchemaObject,
skillConfig,
`The skill config schema "${skillConfigPath}" is not valid:`
Expand Down
53 changes: 25 additions & 28 deletions server/src/schemas/global-data-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,37 @@ export const globalEntitySchemaObject = Type.Strict(
)
)
},
{ additionalProperties: false }
{
description:
'Global entities can hold data that can directly be reused in skills.'
}
)
)
export const globalResolverSchemaObject = Type.Strict(
Type.Object(
{
name: Type.String(),
intents: Type.Record(
Type.String(),
Type.Object(
{
utterance_samples: Type.Array(Type.String()),
value: Type.Unknown()
},
{ additionalProperties: false }
)
Type.Object({
name: Type.String(),
intents: Type.Record(
Type.String(),
Type.Object(
{
utterance_samples: Type.Array(Type.String()),
value: Type.Unknown()
},
{ additionalProperties: false }
)
},
{ additionalProperties: false }
)
)
})
)
export const globalAnswersSchemaObject = Type.Strict(
Type.Object(
{
answers: Type.Record(
Type.String(),
Type.Union([
Type.Record(Type.String(), Type.String()),
Type.Array(Type.String())
])
)
},
{ additionalProperties: false }
)
Type.Object({
answers: Type.Record(
Type.String(),
Type.Union([
Type.Record(Type.String(), Type.String()),
Type.Array(Type.String())
])
)
})
)

export type GlobalEntitySchema = Static<typeof globalEntitySchemaObject>
Expand Down
Loading

0 comments on commit 5b4cd9d

Please sign in to comment.