Skip to content

Commit

Permalink
feat(cli): various cli improvements (#144)
Browse files Browse the repository at this point in the history
* chore(nlu-cli): download is a subcommand of lang

* chore(nlu-cli): move default values outside of cli

* chore(nlu-cli): extract yargs parameters in separate files

* feat(nlu-cli): all cli arguments can be passed as env variables

* feat(nlu-cli): config file with schema for both nlu and lang server (#143)

* progress

* feat(nlu-cli): config file with schema for both nlu and lang server

* chore(nlu-server): remove support for NLU_SERVER_CONFIG env var

* chore: write config schemas in appdata cache

* minor fix

* fix github workflows

* fix default nlu server config

* chore: default config now has doc = false
  • Loading branch information
franklevasseur committed Nov 26, 2021
1 parent e5be6fe commit 4f53fae
Show file tree
Hide file tree
Showing 32 changed files with 536 additions and 414 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/binary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
mv ./dist/$bin_original_name ./nlu
- name: Download language models
run: |
./nlu download --lang en --dim 25
./nlu lang download --lang en --dim 25
- name: Run Regression Test
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/bitfan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ jobs:
yarn build
- name: Download language models
run: |
yarn start download --lang fr --dim 100
yarn start download --lang en --dim 100
yarn start lang download --lang fr --dim 100
yarn start lang download --lang en --dim 100
- name: Run Regression Test
run: |
yarn start lang --dim 100 &
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ jspm_packages/
dist/


config.json
*.config.json
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"console": "integratedTerminal",
"sourceMaps": true,
"autoAttachChildProcesses": true,
"args": ["--config=./config.json"],
"args": ["--config=./nlu.config.json"],
"outFiles": ["${workspaceRoot}/packages/**/*.js", "${workspaceRoot}/node_modules/**/*.js"]
},
{
Expand Down
3 changes: 0 additions & 3 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
const gulp = require('gulp')
const package = require('./scripts/gulp.package')
const config = require('./scripts/gulp.config')
const release = require('./scripts/gulp.release')

gulp.task('default', (cb) => {
console.log(`
Development Cheat Sheet
==================================
yarn cmd package Packages Application in binaries
yarn cmd config Upsert new NLU server config file
yarn cmd bump Bump version and update change log
yarn cmd changelog Print change log
`)
cb()
})

gulp.task('package', package.package)
gulp.task('config', config.upsertConfigFile)
gulp.task('bump', release.bumpVersion)
gulp.task('changelog', release.printChangeLog)
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@
]
},
"scripts": {
"postinstall": "yarn cmd config",
"cmd": "yarn run gulp",
"dev": "cross-env tsnd --transpile-only --watch ./packages/**/*.ts ./packages/nlu-cli/src/index.ts",
"dev": "cross-env tsnd --transpile-only --exit-child --watch ./packages/**/*.ts ./packages/nlu-cli/src/index.ts",
"start": "cross-env node ./packages/nlu-cli/dist/index.js",
"build": "tsc --build ./tsconfig.json",
"clean": "yarn workspaces run clean",
Expand Down
2 changes: 1 addition & 1 deletion packages/bitfan/src/services/bp-provider/stan-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class StanProvider {
public async predict(utterances: string[]): Promise<PredictOutput[]> {
const predOutput = await this._client.predict(APP_ID, this._modelId ?? '', { utterances })
if (!predOutput.success) {
throw new Error(`An error occured at prediction: ${predOutput.error}.`)
throw new Error(`An error occured at prediction: ${predOutput.error.message}.`)
}
return predOutput.predictions
}
Expand Down
41 changes: 41 additions & 0 deletions packages/lang-server/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { LoggerLevel } from '@botpress/logger'
import path from 'path'
import { getAppDataPath } from './app-data'
import { LangServerOptions, DownloadOptions, LangArgv, DownloadArgv } from './typings'

const DEFAULT_LANG_DIR = () => {
const appDataPath = getAppDataPath()
return path.join(appDataPath, 'embeddings')
}

const DEFAULT_SERVER_OPTIONS = (): LangServerOptions => ({
port: 3100,
host: 'localhost',
langDir: DEFAULT_LANG_DIR(),
authToken: undefined,
adminToken: undefined,
limit: 0,
limitWindow: '1h',
metadataLocation: 'https://nyc3.digitaloceanspaces.com/botpress-public/embeddings/index.json',
offline: false,
dim: 100,
domain: 'bp',
verbose: LoggerLevel.Info,
logFilter: undefined
})

const DEFAULT_DOWNLOAD_OPTIONS = (lang: string): DownloadOptions => ({
langDir: DEFAULT_LANG_DIR(),
metadataLocation: 'https://nyc3.digitaloceanspaces.com/botpress-public/embeddings/index.json',
dim: 100,
domain: 'bp',
lang
})

export const getLangServerConfig = (argv: LangArgv): LangServerOptions => {
return { ...DEFAULT_SERVER_OPTIONS(), ...argv }
}

export const getDownloadConfig = (argv: DownloadArgv): DownloadOptions => {
return { ...DEFAULT_DOWNLOAD_OPTIONS(argv.lang), ...argv }
}
18 changes: 5 additions & 13 deletions packages/lang-server/src/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,19 @@ import { LanguageService } from '@botpress/nlu-engine'
import cliProgress from 'cli-progress'
import fse from 'fs-extra'
import _ from 'lodash'
import path from 'path'

import { getAppDataPath } from './app-data'
import DownloadManager from './application/download-manager'
import { getDownloadConfig } from './config'
import * as types from './typings'

interface Argv {
langDir?: string
lang: string
dim: number
domain: string
metadataLocation: string
}

export default async (options: Argv) => {
export const download: typeof types.download = async (argv: types.DownloadArgv) => {
const options = getDownloadConfig(argv)
const baseLogger = makeLogger({
level: LoggerLevel.Info,
filters: undefined
})

const appDataPath = getAppDataPath()
const languageDirectory = options.langDir || path.join(appDataPath, 'embeddings')
const languageDirectory = options.langDir
await fse.ensureDir(languageDirectory)

const launcherLogger = baseLogger.sub('Launcher')
Expand Down
27 changes: 5 additions & 22 deletions packages/lang-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import _ from 'lodash'
import path from 'path'

import API, { APIOptions } from './api'
import { getAppDataPath } from './app-data'
import { LangApplication } from './application'
import DownloadManager from './application/download-manager'
import { getLangServerConfig } from './config'
import { requireJSON } from './require-json'
import * as types from './typings'

const packageJsonPath = path.resolve(__dirname, '../package.json')
const packageJson = requireJSON<{ version: string }>(packageJsonPath)
Expand All @@ -18,25 +19,9 @@ if (!packageJson) {

const { version: pkgVersion } = packageJson

export { default as download } from './download'
export { download } from './download'
export const version = pkgVersion

export interface ArgV {
port: number
host: string
limit: number
limitWindow: string
langDir?: string
authToken?: string
adminToken?: string
metadataLocation: string
offline: boolean
dim: number
domain: string
verbose: number
logFilter: string[] | undefined
}

const wrapLogger = (logger: Logger): EngineLogger => {
return {
debug: (msg: string) => logger.debug(msg),
Expand All @@ -47,16 +32,14 @@ const wrapLogger = (logger: Logger): EngineLogger => {
}
}

export const run = async (options: ArgV) => {
export const run: typeof types.run = async (argv: types.LangArgv) => {
const options = getLangServerConfig(argv)
const baseLogger = makeLogger({
level: Number(options.verbose) !== NaN ? Number(options.verbose) : LoggerLevel.Info,
filters: options.logFilter,
prefix: 'LANG'
})

const appDataPath = getAppDataPath()
options.langDir = options.langDir || path.join(appDataPath, 'embeddings')

const launcherLogger = baseLogger.sub('Launcher')
// Launcher always display
launcherLogger.configure({
Expand Down
30 changes: 17 additions & 13 deletions packages/lang-server/src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
export const run: (argv: {
interface CommonOptions {
langDir: string
metadataLocation: string
dim: number
domain: string
}

export interface LangServerOptions extends CommonOptions {
port: number
host: string
limit: number
limitWindow: string
langDir?: string
authToken?: string
adminToken?: string
metadataLocation: string
offline: boolean
dim: number
domain: string
verbose: number
logFilter: string[] | undefined
}) => Promise<void>
logFilter?: string[]
}

export const download: (argv: {
langDir?: string
export interface DownloadOptions extends CommonOptions {
lang: string
dim: number
domain: string
metadataLocation: string
}) => Promise<void>
}

export type LangArgv = Partial<LangServerOptions>
export type DownloadArgv = Partial<CommonOptions> & { lang: string }

export const version: string
export const run: (argv: LangArgv) => Promise<void>
export const download: (argv: DownloadArgv) => Promise<void>
3 changes: 3 additions & 0 deletions packages/nlu-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
"@botpress/lang-server": "*",
"@botpress/logger": "*",
"@botpress/nlu-server": "*",
"decamelize": "5.0.1",
"json-schema": "^0.4.0",
"wtfnode": "^0.9.1",
"yargs": "^17.2.1"
},
"devDependencies": {
"@types/json-schema": "^7.0.9",
"@types/node": "^12.13.0",
"@types/wtfnode": "^0.7.0",
"@types/yargs": "^17.0.4",
Expand Down
16 changes: 16 additions & 0 deletions packages/nlu-cli/src/app-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import path from 'path'

export function getAppDataPath() {
const homeDir = process.env.APP_DATA_PATH || process.env.HOME || process.env.APPDATA
if (homeDir) {
if (process.platform === 'darwin') {
return path.join(homeDir, 'Library', 'Application Support', 'botpress')
}

return path.join(homeDir, 'botpress')
}

const errorMsg = `Could not determine your HOME directory.
Please set the environment variable "APP_DATA_PATH", then start Botpress`
throw new Error(errorMsg)
}
37 changes: 37 additions & 0 deletions packages/nlu-cli/src/config-file/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import fse from 'fs-extra'
import { validate } from 'json-schema'
import { YargsSchema, YargsArgv } from '../yargs-utils'
import { generateSchema } from './schema'

interface WriteConfigFileProps<S extends YargsSchema> {
schemaLocation: string
fileLocation: string
yargSchema: S
}

interface ReadConfigFileProps<S extends YargsSchema> {
fileLocation: string
yargSchema: S
}

export const writeConfigFile = async <S extends YargsSchema>(props: WriteConfigFileProps<S>): Promise<void> => {
const { yargSchema, schemaLocation, fileLocation } = props
const schema = generateSchema(yargSchema)
const jsonConfig = { $schema: schemaLocation }
await fse.writeFile(schemaLocation, JSON.stringify(schema, null, 2))
await fse.writeFile(fileLocation, JSON.stringify(jsonConfig, null, 2))
}

export const readConfigFile = async <S extends YargsSchema>(props: ReadConfigFileProps<S>): Promise<YargsArgv<S>> => {
const { fileLocation, yargSchema } = props
const configFileContent = await fse.readFile(fileLocation, 'utf8')
const { $schema, ...parsedConfigFile } = JSON.parse(configFileContent)
const schema = generateSchema(yargSchema)
const validationResult = validate(parsedConfigFile, schema)
const { valid, errors } = validationResult
if (!valid) {
const errorMsg = errors.map((err) => `${err.property} ${err.message}`).join('\n')
throw new Error(errorMsg)
}
return parsedConfigFile
}
19 changes: 19 additions & 0 deletions packages/nlu-cli/src/config-file/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { JSONSchema7, JSONSchema7Definition } from 'json-schema'
import { Dictionary } from 'lodash'
import { YargsSchema } from '../yargs-utils'

export const generateSchema = (yargSchema: YargsSchema): JSONSchema7 => {
const properties: Dictionary<JSONSchema7Definition> = {}
for (const param in yargSchema) {
const yargProp = yargSchema[param]
properties[param] = {
type: yargProp.type
}
}

const schema: JSONSchema7 = {
type: 'object',
properties
}
return schema
}
Loading

0 comments on commit 4f53fae

Please sign in to comment.