1
1
mirror of https://github.com/leon-ai/leon.git synced 2024-09-19 22:07:10 +03:00

feat(server): bootstrap Node.js bridge entry point

This commit is contained in:
louistiti 2023-04-27 20:16:08 +08:00
parent 12e4b7bccf
commit 8b2f06e305
7 changed files with 60 additions and 21 deletions

1
.gitignore vendored
View File

@ -26,6 +26,7 @@ bridges/python/src/Pipfile.lock
tcp_server/src/Pipfile.lock tcp_server/src/Pipfile.lock
!tcp_server/**/.gitkeep !tcp_server/**/.gitkeep
!bridges/python/**/.gitkeep !bridges/python/**/.gitkeep
!bridges/nodejs/dist/*
!**/*.sample* !**/*.sample*
packages/**/config/config.json packages/**/config/config.json
skills/**/src/config.json skills/**/src/config.json

View File

View File

@ -0,0 +1 @@
// TODO

View File

@ -19,9 +19,11 @@ export const GITHUB_URL = 'https://github.com/leon-ai/leon'
*/ */
export const BINARIES_FOLDER_NAME = SystemHelper.getBinariesFolderName() export const BINARIES_FOLDER_NAME = SystemHelper.getBinariesFolderName()
export const PYTHON_BRIDGE_DIST_PATH = path.join('bridges', 'python', 'dist') export const PYTHON_BRIDGE_DIST_PATH = path.join('bridges', 'python', 'dist')
export const NODEJS_BRIDGE_DIST_PATH = path.join('bridges', 'nodejs', 'dist')
export const TCP_SERVER_DIST_PATH = path.join('tcp_server', 'dist') export const TCP_SERVER_DIST_PATH = path.join('tcp_server', 'dist')
export const PYTHON_BRIDGE_SRC_PATH = path.join('bridges', 'python', 'src') export const PYTHON_BRIDGE_SRC_PATH = path.join('bridges', 'python', 'src')
export const NODEJS_BRIDGE_SRC_PATH = path.join('bridges', 'nodejs', 'src')
export const TCP_SERVER_SRC_PATH = path.join('tcp_server', 'src') export const TCP_SERVER_SRC_PATH = path.join('tcp_server', 'src')
const PYTHON_BRIDGE_VERSION_FILE_PATH = path.join( const PYTHON_BRIDGE_VERSION_FILE_PATH = path.join(
@ -40,6 +42,7 @@ export const [, TCP_SERVER_VERSION] = fs
.split("'") .split("'")
export const PYTHON_BRIDGE_BIN_NAME = 'leon-python-bridge' export const PYTHON_BRIDGE_BIN_NAME = 'leon-python-bridge'
export const NODEJS_BRIDGE_BIN_NAME = 'leon-nodejs-bridge.js'
export const TCP_SERVER_BIN_NAME = 'leon-tcp-server' export const TCP_SERVER_BIN_NAME = 'leon-tcp-server'
export const TCP_SERVER_BIN_PATH = path.join( export const TCP_SERVER_BIN_PATH = path.join(
@ -52,6 +55,10 @@ export const PYTHON_BRIDGE_BIN_PATH = path.join(
BINARIES_FOLDER_NAME, BINARIES_FOLDER_NAME,
PYTHON_BRIDGE_BIN_NAME PYTHON_BRIDGE_BIN_NAME
) )
export const NODEJS_BRIDGE_BIN_PATH = `${process.execPath} ${path.join(
NODEJS_BRIDGE_DIST_PATH,
NODEJS_BRIDGE_BIN_NAME
)}`
export const LEON_VERSION = process.env['npm_package_version'] export const LEON_VERSION = process.env['npm_package_version']

View File

@ -9,15 +9,24 @@ import type {
NERCustomEntity, NERCustomEntity,
NLUResult NLUResult
} from '@/core/nlp/types' } from '@/core/nlp/types'
import type { SkillConfigSchema } from '@/schemas/skill-schemas' import type { SkillConfigSchema, SkillSchema } from '@/schemas/skill-schemas'
import type { import type {
BrainProcessResult, BrainProcessResult,
IntentObject, IntentObject,
SkillResult SkillResult
} from '@/core/brain/types' } from '@/core/brain/types'
import { SkillActionType, SkillOutputType } from '@/core/brain/types' import {
SkillActionTypes,
SkillBridges,
SkillOutputTypes
} from '@/core/brain/types'
import { langs } from '@@/core/langs.json' import { langs } from '@@/core/langs.json'
import { HAS_TTS, PYTHON_BRIDGE_BIN_PATH, TMP_PATH } from '@/constants' import {
HAS_TTS,
PYTHON_BRIDGE_BIN_PATH,
NODEJS_BRIDGE_BIN_PATH,
TMP_PATH
} from '@/constants'
import { SOCKET_SERVER, TTS } from '@/core' import { SOCKET_SERVER, TTS } from '@/core'
import { LangHelper } from '@/helpers/lang-helper' import { LangHelper } from '@/helpers/lang-helper'
import { LogHelper } from '@/helpers/log-helper' import { LogHelper } from '@/helpers/log-helper'
@ -190,7 +199,7 @@ export default class Brain {
const obj = JSON.parse(data.toString()) const obj = JSON.parse(data.toString())
if (typeof obj === 'object') { if (typeof obj === 'object') {
if (obj.output.type === SkillOutputType.Intermediate) { if (obj.output.type === SkillOutputTypes.Intermediate) {
LogHelper.title(`${this.skillFriendlyName} skill`) LogHelper.title(`${this.skillFriendlyName} skill`)
LogHelper.info(data.toString()) LogHelper.info(data.toString())
@ -258,6 +267,7 @@ export default class Brain {
*/ */
private async executeLogicActionSkill( private async executeLogicActionSkill(
nluResult: NLUResult, nluResult: NLUResult,
skillBridge: SkillSchema['bridge'],
utteranceId: string, utteranceId: string,
intentObjectPath: string intentObjectPath: string
): Promise<void> { ): Promise<void> {
@ -282,10 +292,20 @@ export default class Brain {
intentObjectPath, intentObjectPath,
JSON.stringify(intentObject) JSON.stringify(intentObject)
) )
this.skillProcess = spawn(
`${PYTHON_BRIDGE_BIN_PATH} "${intentObjectPath}"`, if (skillBridge === SkillBridges.Python) {
{ shell: true } this.skillProcess = spawn(
) `${PYTHON_BRIDGE_BIN_PATH} "${intentObjectPath}"`,
{ shell: true }
)
} else if (skillBridge === SkillBridges.NodeJS) {
this.skillProcess = spawn(
`${NODEJS_BRIDGE_BIN_PATH} "${intentObjectPath}"`,
{ shell: true }
)
} else {
LogHelper.error(`The skill bridge is not supported: ${skillBridge}`)
}
} catch (e) { } catch (e) {
LogHelper.error(`Failed to save intent object: ${e}`) LogHelper.error(`Failed to save intent object: ${e}`)
} }
@ -334,24 +354,25 @@ export default class Brain {
? actions[action.next_action] ? actions[action.next_action]
: null : null
if (actionType === SkillActionType.Logic) { if (actionType === SkillActionTypes.Logic) {
/** /**
* "Logic" action skill execution * "Logic" action skill execution
*/ */
await this.executeLogicActionSkill(
nluResult,
utteranceId,
intentObjectPath
)
const domainName = nluResult.classification.domain const domainName = nluResult.classification.domain
const skillName = nluResult.classification.skill const skillName = nluResult.classification.skill
const { name: domainFriendlyName } = const { name: domainFriendlyName } =
await SkillDomainHelper.getSkillDomainInfo(domainName) await SkillDomainHelper.getSkillDomainInfo(domainName)
const { name: skillFriendlyName } = const { name: skillFriendlyName, bridge: skillBridge } =
await SkillDomainHelper.getSkillInfo(domainName, skillName) await SkillDomainHelper.getSkillInfo(domainName, skillName)
await this.executeLogicActionSkill(
nluResult,
skillBridge,
utteranceId,
intentObjectPath
)
this.domainFriendlyName = domainFriendlyName this.domainFriendlyName = domainFriendlyName
this.skillFriendlyName = skillFriendlyName this.skillFriendlyName = skillFriendlyName
@ -387,7 +408,7 @@ export default class Brain {
// Synchronize the downloaded content if enabled // Synchronize the downloaded content if enabled
if ( if (
skillResult.output.type === SkillOutputType.End && skillResult.output.type === SkillOutputTypes.End &&
skillResult.output.options['synchronization'] && skillResult.output.options['synchronization'] &&
skillResult.output.options['synchronization'].enabled && skillResult.output.options['synchronization'].enabled &&
skillResult.output.options['synchronization'].enabled === skillResult.output.options['synchronization'].enabled ===

View File

@ -28,7 +28,7 @@ export interface SkillResult {
entities: NEREntity[] entities: NEREntity[]
slots: NLUSlots slots: NLUSlots
output: { output: {
type: SkillOutputType type: SkillOutputTypes
codes: string[] codes: string[]
speech: string speech: string
core: SkillCoreData | undefined core: SkillCoreData | undefined
@ -37,11 +37,15 @@ export interface SkillResult {
} }
} }
export enum SkillOutputType { export enum SkillBridges {
Python = 'python',
NodeJS = 'nodejs'
}
export enum SkillOutputTypes {
Intermediate = 'inter', Intermediate = 'inter',
End = 'end' End = 'end'
} }
export enum SkillActionType { export enum SkillActionTypes {
Logic = 'logic', Logic = 'logic',
Dialog = 'dialog' Dialog = 'dialog'
} }

View File

@ -2,8 +2,13 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import { globalResolverSchemaObject } from '@/schemas/global-data-schemas' import { globalResolverSchemaObject } from '@/schemas/global-data-schemas'
import { SkillBridges } from '@/core/brain/types'
const skillBridges = [Type.Literal('python'), Type.Null()] const skillBridges = [
Type.Literal(SkillBridges.Python),
Type.Literal(SkillBridges.NodeJS),
Type.Null()
]
const skillActionTypes = [ const skillActionTypes = [
Type.Literal('logic', { Type.Literal('logic', {
description: 'It runs the business logic implemented in actions via code.' description: 'It runs the business logic implemented in actions via code.'