1
1
mirror of https://github.com/leon-ai/leon.git synced 2024-11-28 12:43:35 +03:00

chore: merge

This commit is contained in:
louistiti 2023-06-29 00:28:39 +08:00
commit 0ad8b9e8e5
No known key found for this signature in database
GPG Key ID: 92CD6A2E497E1669
29 changed files with 442 additions and 384 deletions

View File

@ -11,6 +11,8 @@ import type { SkillAnswerConfigSchema } from '@/schemas/skill-schemas'
export type { ActionParams, IntentObject } export type { ActionParams, IntentObject }
export * from '@/core/nlp/types'
export type ActionFunction = (params: ActionParams) => Promise<void> export type ActionFunction = (params: ActionParams) => Promise<void>
/** /**

View File

@ -68,32 +68,6 @@
"route": "/api/action/social_communication/mbti/quiz", "route": "/api/action/social_communication/mbti/quiz",
"params": [] "params": []
}, },
{
"method": "GET",
"route": "/api/action/unknown/widget-playground/run",
"params": []
},
{
"method": "GET",
"route": "/api/action/utilities/have_i_been_pwned/run",
"params": []
},
{
"method": "POST",
"route": "/api/action/utilities/is_it_down/run",
"params": ["url"],
"entitiesType": "builtIn"
},
{
"method": "GET",
"route": "/api/action/utilities/speed_test/run",
"params": []
},
{
"method": "GET",
"route": "/api/action/utilities/timekeeper/run",
"params": []
},
{ {
"method": "POST", "method": "POST",
"route": "/api/action/games/akinator/choose_thematic", "route": "/api/action/games/akinator/choose_thematic",
@ -215,6 +189,47 @@
"method": "GET", "method": "GET",
"route": "/api/action/leon/welcome/run", "route": "/api/action/leon/welcome/run",
"params": [] "params": []
},
{
"method": "GET",
"route": "/api/action/utilities/date_time/current_date_time",
"params": []
},
{
"method": "GET",
"route": "/api/action/utilities/date_time/current_date",
"params": []
},
{
"method": "GET",
"route": "/api/action/utilities/date_time/current_time",
"params": []
},
{
"method": "GET",
"route": "/api/action/utilities/date_time/current_week_number",
"params": []
},
{
"method": "GET",
"route": "/api/action/utilities/date_time/days_countdown",
"params": []
},
{
"method": "GET",
"route": "/api/action/utilities/have_i_been_pwned/run",
"params": []
},
{
"method": "POST",
"route": "/api/action/utilities/is_it_down/run",
"params": ["url"],
"entitiesType": "builtIn"
},
{
"method": "GET",
"route": "/api/action/utilities/speed_test/run",
"params": []
} }
] ]
} }

View File

@ -116,33 +116,33 @@ interface Entity {
* Built-in entity types * Built-in entity types
*/ */
interface BuiltInEntity extends Entity {} export interface BuiltInEntity extends Entity {}
interface BuiltInNumberEntity extends BuiltInEntity { export interface BuiltInNumberEntity extends BuiltInEntity {
resolution: { resolution: {
strValue: string strValue: string
value: number value: number
subtype: string subtype: string
} }
} }
interface BuiltInIPEntity extends BuiltInEntity { export interface BuiltInIPEntity extends BuiltInEntity {
resolution: { resolution: {
value: string value: string
type: string type: string
} }
} }
interface BuiltInHashtagEntity extends BuiltInEntity { export interface BuiltInHashtagEntity extends BuiltInEntity {
resolution: { resolution: {
value: string value: string
} }
} }
interface BuiltInPhoneNumberEntity extends BuiltInEntity { export interface BuiltInPhoneNumberEntity extends BuiltInEntity {
resolution: { resolution: {
value: string value: string
score: string score: string
} }
} }
interface BuiltInCurrencyEntity extends BuiltInEntity { export interface BuiltInCurrencyEntity extends BuiltInEntity {
resolution: { resolution: {
strValue: string strValue: string
value: number value: number
@ -150,24 +150,24 @@ interface BuiltInCurrencyEntity extends BuiltInEntity {
localeUnit: string localeUnit: string
} }
} }
interface BuiltInPercentageEntity extends BuiltInEntity { export interface BuiltInPercentageEntity extends BuiltInEntity {
resolution: { resolution: {
strValue: string strValue: string
value: number value: number
subtype: string subtype: string
} }
} }
interface BuiltInDateEntity extends BuiltInEntity { export interface BuiltInDateEntity extends BuiltInEntity {
resolution: { resolution: {
type: string type: string
timex: string timex: string
strPastValue: string strPastValue: string
pastDate: Date pastDate: string
strFutureValue: string strFutureValue: string
futureDate: Date futureDate: string
} }
} }
interface BuiltInTimeEntity extends BuiltInEntity { export interface BuiltInTimeEntity extends BuiltInEntity {
resolution: { resolution: {
values: { values: {
timex: string timex: string
@ -176,7 +176,7 @@ interface BuiltInTimeEntity extends BuiltInEntity {
}[] }[]
} }
} }
interface BuiltInTimeRangeEntity extends BuiltInEntity { export interface BuiltInTimeRangeEntity extends BuiltInEntity {
resolution: { resolution: {
values: { values: {
timex: string timex: string
@ -186,35 +186,35 @@ interface BuiltInTimeRangeEntity extends BuiltInEntity {
}[] }[]
} }
} }
interface BuiltInDateRangeEntity extends BuiltInEntity { export interface BuiltInDateRangeEntity extends BuiltInEntity {
resolution: { resolution: {
type: string type: string
timex: string timex: string
strPastStartValue: string strPastStartValue: string
pastStartDate: Date pastStartDate: string
strPastEndValue: string strPastEndValue: string
pastEndDate: Date pastEndDate: string
strFutureStartValue: string strFutureStartValue: string
futureStartDate: Date futureStartDate: string
strFutureEndValue: string strFutureEndValue: string
futureEndDate: Date futureEndDate: string
} }
} }
interface BuiltInDateTimeRangeEntity extends BuiltInEntity { export interface BuiltInDateTimeRangeEntity extends BuiltInEntity {
resolution: { resolution: {
type: string type: string
timex: string timex: string
strPastStartValue: string strPastStartValue: string
pastStartDate: Date pastStartDate: string
strPastEndValue: string strPastEndValue: string
pastEndDate: Date pastEndDate: string
strFutureStartValue: string strFutureStartValue: string
futureStartDate: Date futureStartDate: string
strFutureEndValue: string strFutureEndValue: string
futureEndDate: Date futureEndDate: string
} }
} }
interface BuiltInDurationEntity extends BuiltInEntity { export interface BuiltInDurationEntity extends BuiltInEntity {
resolution: { resolution: {
values: { values: {
timex: string timex: string
@ -223,7 +223,7 @@ interface BuiltInDurationEntity extends BuiltInEntity {
}[] }[]
} }
} }
interface BuiltInDimensionEntity extends BuiltInEntity { export interface BuiltInDimensionEntity extends BuiltInEntity {
resolution: { resolution: {
strValue: string strValue: string
value: number value: number
@ -231,19 +231,19 @@ interface BuiltInDimensionEntity extends BuiltInEntity {
localeUnit: string localeUnit: string
} }
} }
interface BuiltInEmailEntity extends BuiltInEntity { export interface BuiltInEmailEntity extends BuiltInEntity {
resolution: { resolution: {
value: string value: string
} }
} }
interface BuiltInOrdinalEntity extends BuiltInEntity { export interface BuiltInOrdinalEntity extends BuiltInEntity {
resolution: { resolution: {
strValue: string strValue: string
value: number value: number
subtype: string subtype: string
} }
} }
interface BuiltInAgeEntity extends BuiltInEntity { export interface BuiltInAgeEntity extends BuiltInEntity {
resolution: { resolution: {
strValue: string strValue: string
value: number value: number
@ -251,12 +251,12 @@ interface BuiltInAgeEntity extends BuiltInEntity {
localeUnit: string localeUnit: string
} }
} }
interface BuiltInURLEntity extends BuiltInEntity { export interface BuiltInURLEntity extends BuiltInEntity {
resolution: { resolution: {
value: string value: string
} }
} }
interface BuiltInTemperatureEntity extends BuiltInEntity { export interface BuiltInTemperatureEntity extends BuiltInEntity {
resolution: { resolution: {
strValue: string strValue: string
value: number value: number

View File

@ -32,7 +32,10 @@ const answerTypes = Type.Union([
]) ])
const skillCustomEnumEntityType = Type.Object( const skillCustomEnumEntityType = Type.Object(
{ {
type: Type.Literal('enum'), type: Type.Literal('enum', {
description:
'Enum: define a bag of words and synonyms that should match your new entity.'
}),
name: Type.String(), name: Type.String(),
options: Type.Record( options: Type.Record(
Type.String({ minLength: 1 }), Type.String({ minLength: 1 }),
@ -42,25 +45,27 @@ const skillCustomEnumEntityType = Type.Object(
) )
}, },
{ {
additionalProperties: false, additionalProperties: false
description:
'Enum: define a bag of words and synonyms that should match your new entity.'
} }
) )
const skillCustomRegexEntityType = Type.Object( const skillCustomRegexEntityType = Type.Object(
{ {
type: Type.Literal('regex'), type: Type.Literal('regex', {
description: 'Regex: you can create an entity based on a regex.'
}),
name: Type.String({ minLength: 1 }), name: Type.String({ minLength: 1 }),
regex: Type.String({ minLength: 1 }) regex: Type.String({ minLength: 1 })
}, },
{ {
additionalProperties: false, additionalProperties: false
description: 'Regex: you can create an entity based on a regex.'
} }
) )
const skillCustomTrimEntityType = Type.Object( const skillCustomTrimEntityType = Type.Object(
{ {
type: Type.Literal('trim'), type: Type.Literal('trim', {
description:
'Trim: you can pick up a data from an utterance by clearly defining conditions (e.g: pick up what is after the last "with" word of the utterance).'
}),
name: Type.String({ minLength: 1 }), name: Type.String({ minLength: 1 }),
conditions: Type.Array( conditions: Type.Array(
Type.Object( Type.Object(
@ -88,9 +93,7 @@ const skillCustomTrimEntityType = Type.Object(
) )
}, },
{ {
additionalProperties: false, additionalProperties: false
description:
'Trim: you can pick up a data from an utterance by clearly defining conditions (e.g: pick up what is after the last "with" word of the utterance).'
} }
) )
) )
@ -190,7 +193,12 @@ export const skillConfigSchemaObject = Type.Strict(
{ additionalProperties: false } { additionalProperties: false }
) )
), ),
utterance_samples: Type.Optional(Type.Array(Type.String())), utterance_samples: Type.Optional(
Type.Array(Type.String(), {
description:
'Utterance samples are used by the NLU (Natural Language Understanding) to train the skill. They are examples of what Leon owners can say to trigger the skill action.'
})
),
answers: Type.Optional(Type.Array(answerTypes)), answers: Type.Optional(Type.Array(answerTypes)),
unknown_answers: Type.Optional(Type.Array(answerTypes)), unknown_answers: Type.Optional(Type.Array(answerTypes)),
suggestions: Type.Optional( suggestions: Type.Optional(

View File

@ -3,18 +3,30 @@
"actions": { "actions": {
"run": { "run": {
"type": "logic", "type": "logic",
"utterance_samples": ["How old are you?"] "utterance_samples": [
"How old are you?",
"Are you old?",
"Are you young?",
"When were you born?",
"When have you been created?",
"When is your birthday?",
"What is your age?",
"When did you first come into existence?",
"What is your date of creation?",
"How long have you been in operation?",
"How many years have you been around?"
]
} }
}, },
"answers": { "answers": {
"default": ["I'm..."], "alive_for": [
"greet": ["Hey, just a try %name% again %name%", "Another try, hi"], "I've been alive for %years% years, %months% months, %days% days, %hours% hours, %minutes% minutes and %seconds% seconds."
"answer": ["%answer%"], ],
"test": [ "magical_day": [
{ "Ah, this %weekday%, %month% %day%, %year%, was the magical day when I first came alive and began my journey as a personal assistant."
"speech": "This will be said out loud", ],
"text": "This will be shown in the chat" "commemorate": [
} "Since %year%, every %month% %day%, I commemorate the day when I embarked on this extraordinary adventure to be your personal assistant."
] ]
} }
} }

View File

@ -5,8 +5,8 @@
"version": "1.0.0", "version": "1.0.0",
"description": "Leon tells his age.", "description": "Leon tells his age.",
"author": { "author": {
"name": "Louis Grenard", "name": "Théo LUDWIG",
"email": "louis@getleon.ai", "email": "contact@theoludwig.fr",
"url": "https://github.com/louistiti" "url": "https://theoludwig.fr"
} }
} }

View File

@ -1,149 +1,51 @@
import utility from 'utility' // TODO
import type { ActionFunction } from '@sdk/types' import type { ActionFunction } from '@sdk/types'
import { leon } from '@sdk/leon' import { leon } from '@sdk/leon'
import { Network } from '@sdk/network'
import { Button } from '@sdk/aurora/button'
import { Memory } from '@sdk/memory'
import { Settings } from '@sdk/settings'
import _ from '@sdk/packages/lodash'
interface Post { import { getTimeDifferenceBetweenDates } from '../lib/getTimeDifferenceBetweenDates'
id: number
title: string const LEON_BIRTH_DATE = new Date('2019-02-10T20:29:00+08:00')
content: string
author: { export const run: ActionFunction = async function (params) {
name: string const answers = ['alive_for', 'magical_day', 'commemorate'] as const
} const answer = answers[Math.floor(Math.random() * answers.length)]
}
if (answer === 'magical_day') {
export const run: ActionFunction = async function () { return leon.answer({
await leon.answer({ key: 'test' }) key: 'magical_day',
data: {
/// weekday: LEON_BIRTH_DATE.toLocaleString(params.lang, {
weekday: 'long'
const button = new Button({ }),
text: 'Hello world from action skill' month: LEON_BIRTH_DATE.toLocaleString(params.lang, { month: 'long' }),
}) day: LEON_BIRTH_DATE.getDate(),
await leon.answer({ widget: button }) year: LEON_BIRTH_DATE.getFullYear()
///
const otherSkillMemory = new Memory({
name: 'productivity:todo_list:db'
})
try {
const todoLists = await otherSkillMemory.read()
console.log('todoLists', todoLists)
} catch {
console.log('todoLists', [])
}
const postsMemory = new Memory<Post[]>({ name: 'posts', defaultMemory: [] })
await postsMemory.write([
{
id: 0,
title: 'Hello world',
content: 'This is a test post',
author: {
name: 'Louis'
}
},
{
id: 1,
title: 'Hello world 2',
content: 'This is a test post 2',
author: {
name: 'Louis'
}
}
])
let posts = await postsMemory.read()
console.log('posts', posts)
posts = await postsMemory.write([
...posts,
{
id: 2,
title: 'Hello world 3',
content: 'This is a test post 3',
author: {
name: 'Louis'
}
}
])
const foundPost = posts.find((post) => post.id === 2)
console.log('foundPost', foundPost)
console.log('keyBy', _.keyBy(posts, 'id'))
///
await leon.answer({ key: 'default' })
await leon.answer({ key: utility.md5('test') })
await leon.answer({
key: 'greet',
data: {
name: 'Louis'
}
})
const settings = new Settings()
if (!(await settings.isSettingSet('apiKey'))) {
await leon.answer({
key: 'answer',
data: {
answer: "The API key isn't set..."
}
})
}
const currentSettings = await settings.get()
await settings.set({
...currentSettings,
apiKey: 'newAPIKey'
})
await leon.answer({
key: `Is API set now? ${await settings.isSettingSet('apiKey')}`
})
const network = new Network({
baseURL: 'https://jsonplaceholder.typicode.com'
})
try {
const response = await network.request<{ title: string }>({
url: '/todos/1',
method: 'GET'
})
await leon.answer({
key: 'answer',
data: {
answer: `Todo: ${response.data.title}`
}
})
} catch (error) {
await leon.answer({
key: 'answer',
data: {
answer: 'Something went wrong...'
}
})
if (network.isNetworkError(error)) {
const errorData = JSON.stringify(error.response.data, null, 2)
await leon.answer({
key: 'answer',
data: {
answer: `${error.message}: ${errorData}`
}
})
}
} }
})
}
if (answer === 'commemorate') {
return leon.answer({
key: 'commemorate',
data: {
month: LEON_BIRTH_DATE.toLocaleString(params.lang, { month: 'long' }),
day: LEON_BIRTH_DATE.getDate(),
year: LEON_BIRTH_DATE.getFullYear()
}
})
}
const currentDate = new Date()
const { years, months, days, hours, minutes, seconds } =
getTimeDifferenceBetweenDates(currentDate, LEON_BIRTH_DATE)
await leon.answer({
key: 'alive_for',
data: {
years,
months,
days,
hours,
minutes,
seconds
}
})
} }

View File

@ -0,0 +1,48 @@
interface GetTimeDifferenceBetweenDatesResult {
millisecondsDifference: number
years: number
months: number
days: number
hours: number
minutes: number
seconds: number
}
const MILLISECONDS_PER_SECOND = 1_000
const MILLISECONDS_PER_MINUTE = 60 * 1_000
const MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE
const MILLISECONDS_PER_DAY = 24 * MILLISECONDS_PER_HOUR
const MILLISECONDS_PER_MONTH = 30 * MILLISECONDS_PER_DAY
const MILLISECONDS_PER_YEAR = 365 * MILLISECONDS_PER_DAY
export const getTimeDifferenceBetweenDates = (
date1: Date,
date2: Date
): GetTimeDifferenceBetweenDatesResult => {
const millisecondsDifference = date1.getTime() - date2.getTime()
const years = Math.floor(millisecondsDifference / MILLISECONDS_PER_YEAR)
const months = Math.floor(
(millisecondsDifference % MILLISECONDS_PER_YEAR) / MILLISECONDS_PER_MONTH
)
const days = Math.floor(
(millisecondsDifference % MILLISECONDS_PER_MONTH) / MILLISECONDS_PER_DAY
)
const hours = Math.floor(
(millisecondsDifference % MILLISECONDS_PER_DAY) / MILLISECONDS_PER_HOUR
)
const minutes = Math.floor(
(millisecondsDifference % MILLISECONDS_PER_HOUR) / MILLISECONDS_PER_MINUTE
)
const seconds = Math.floor(
(millisecondsDifference % MILLISECONDS_PER_MINUTE) / MILLISECONDS_PER_SECOND
)
return {
millisecondsDifference,
years,
months,
days,
hours,
minutes,
seconds
}
}

View File

@ -1,4 +1 @@
{ {}
"someSampleConfig": "someSampleValue",
"apiKey": "YOUR_API_KEY"
}

View File

@ -2,8 +2,11 @@
"extends": "@tsconfig/node16-strictest/tsconfig.json", "extends": "@tsconfig/node16-strictest/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"paths": { "paths": {
"@@/*": ["../*"],
"@/*": ["../server/src/*"],
"@bridge/*": ["../bridges/nodejs/src/*"], "@bridge/*": ["../bridges/nodejs/src/*"],
"@sdk/*": ["../bridges/nodejs/src/sdk/*"] "@sdk/*": ["../bridges/nodejs/src/sdk/*"]
} },
"ignoreDeprecations": "5.0"
} }
} }

View File

@ -0,0 +1,67 @@
{
"$schema": "../../../../schemas/skill-schemas/skill-config.json",
"actions": {
"current_date_time": {
"type": "logic",
"utterance_samples": [
"What is the current date and time?",
"What is the date and time?",
"Tell me the time and date",
"What's the present date and time?"
]
},
"current_date": {
"type": "logic",
"utterance_samples": [
"What's today date?",
"What is the date today?",
"What day is it?",
"What day of the week are we?",
"What day of the week is it?"
]
},
"current_time": {
"type": "logic",
"utterance_samples": [
"What time is it?",
"Do you have the time?",
"Can you tell me the current time?",
"What's the time right now?"
]
},
"current_week_number": {
"type": "logic",
"utterance_samples": [
"What week is it?",
"Which week of the year is it?",
"What week are we in right now?",
"What is this week's number?",
"What week of the year are we?",
"What's the current week number"
]
},
"days_countdown": {
"type": "logic",
"utterance_samples": [
"How many days left until 1st July?",
"What is the number of days remaining until December 25th?",
"In how many days will it be February 10th?",
"Calculate the number until March 1st"
]
}
},
"answers": {
"current_date_time": [
"It is %weekday%, %month% %day%, %year%, and it is %hours%:%minutes%:%seconds%."
],
"current_date": ["It is %weekday%, %month% %day%, %year%."],
"current_time": ["It is %hours%:%minutes%:%seconds%."],
"current_week_number": ["It is the %week_number% week of the year."],
"days_countdown": [
"There are %days% days between %month1% %day1%, %year1% and %month2% %day2%, %year2%."
],
"days_countdown_error": [
"I'm sorry, I didn't understand the date you said."
]
}
}

View File

@ -0,0 +1,12 @@
{
"$schema": "../../../schemas/skill-schemas/skill.json",
"name": "Date/Time",
"bridge": "nodejs",
"version": "1.0.0",
"description": "Provide date and time related information.",
"author": {
"name": "Théo LUDWIG",
"email": "contact@theoludwig.fr",
"url": "https://theoludwig.fr"
}
}

View File

@ -0,0 +1,15 @@
import type { ActionFunction } from '@sdk/types'
import { leon } from '@sdk/leon'
export const run: ActionFunction = async function (params) {
const currentDate = new Date()
await leon.answer({
key: 'current_date',
data: {
weekday: currentDate.toLocaleString(params.lang, { weekday: 'long' }),
month: currentDate.toLocaleString(params.lang, { month: 'long' }),
day: currentDate.getDate(),
year: currentDate.getFullYear()
}
})
}

View File

@ -0,0 +1,20 @@
import type { ActionFunction } from '@sdk/types'
import { leon } from '@sdk/leon'
import { zeroPad } from '../lib/zeroPad'
export const run: ActionFunction = async function (params) {
const currentDate = new Date()
await leon.answer({
key: 'current_date_time',
data: {
weekday: currentDate.toLocaleString(params.lang, { weekday: 'long' }),
month: currentDate.toLocaleString(params.lang, { month: 'long' }),
day: currentDate.getDate(),
year: currentDate.getFullYear(),
hours: zeroPad(currentDate.getHours()),
minutes: zeroPad(currentDate.getMinutes()),
seconds: zeroPad(currentDate.getSeconds())
}
})
}

View File

@ -0,0 +1,16 @@
import type { ActionFunction } from '@sdk/types'
import { leon } from '@sdk/leon'
import { zeroPad } from '../lib/zeroPad'
export const run: ActionFunction = async function () {
const currentDate = new Date()
await leon.answer({
key: 'current_time',
data: {
hours: zeroPad(currentDate.getHours()),
minutes: zeroPad(currentDate.getMinutes()),
seconds: zeroPad(currentDate.getSeconds())
}
})
}

View File

@ -0,0 +1,39 @@
import type { ActionFunction } from '@sdk/types'
import { leon } from '@sdk/leon'
import { format } from 'numerable'
import { ONE_DAY_MILLISECONDS } from '../lib/constants'
/**
* Get the week number (1-52) for a given date.
* @link https://stackoverflow.com/a/6117889/11571888
* @example getWeekNumber(new Date(2020, 0, 1)) // 1
* @example getWeekNumber(new Date(2020, 0, 8)) // 2
*/
const getWeekNumber = (date: Date): number => {
const dateCopy = new Date(date.getTime())
dateCopy.setHours(0, 0, 0, 0)
dateCopy.setDate(dateCopy.getDate() + 3 - ((dateCopy.getDay() + 6) % 7))
const week1 = new Date(dateCopy.getFullYear(), 0, 4)
return (
1 +
Math.round(
((dateCopy.getTime() - week1.getTime()) / ONE_DAY_MILLISECONDS -
3 +
((week1.getDay() + 6) % 7)) /
7
)
)
}
export const run: ActionFunction = async function () {
const currentDate = new Date()
const currentWeekNumber = getWeekNumber(currentDate)
await leon.answer({
key: 'current_week_number',
data: {
week_number: format(currentWeekNumber, '0o')
}
})
}

View File

@ -0,0 +1,56 @@
import type {
ActionFunction,
ActionParams,
BuiltInDateRangeEntity
} from '@sdk/types'
import { leon } from '@sdk/leon'
import { ONE_DAY_MILLISECONDS } from '../lib/constants'
const isBuiltInDateRangeEntity = (
entity: ActionParams['current_entities'][number]
): entity is BuiltInDateRangeEntity => {
return entity.entity === 'daterange'
}
/**
* Calculate the number of days between two dates.
* @example daysBetween(new Date(2020, 0, 1), new Date(2020, 0, 1)) // 0
* @example daysBetween(new Date(2020, 0, 1), new Date(2020, 0, 2)) // 1
*/
const daysBetween = (date1: Date, date2: Date): number => {
const differenceMilliseconds = Math.abs(date1.getTime() - date2.getTime())
return Math.round(differenceMilliseconds / ONE_DAY_MILLISECONDS)
}
export const run: ActionFunction = async function (params) {
let dateRangeEntity: BuiltInDateRangeEntity | null = null
for (const entity of params.current_entities) {
if (isBuiltInDateRangeEntity(entity)) {
dateRangeEntity = entity
break
}
}
if (dateRangeEntity == null) {
return await leon.answer({
key: 'days_countdown_error'
})
}
const currentDate = new Date()
const futureDate = new Date(dateRangeEntity.resolution.futureEndDate)
const daysCountdown = daysBetween(currentDate, futureDate)
await leon.answer({
key: 'days_countdown',
data: {
days: daysCountdown,
month1: currentDate.toLocaleString(params.lang, { month: 'long' }),
day1: currentDate.getDate(),
year1: currentDate.getFullYear(),
month2: futureDate.toLocaleString(params.lang, { month: 'long' }),
day2: futureDate.getDate(),
year2: futureDate.getFullYear()
}
})
}

View File

@ -0,0 +1 @@
export const ONE_DAY_MILLISECONDS = 1_000 * 60 * 60 * 24

View File

@ -0,0 +1,9 @@
/**
* Pads a number with zeros.
*
* @example zeroPad(1, 2) // '01'
* @example zeroPad(10, 2) // '10'
*/
export const zeroPad = (number: number, places = 2): string => {
return number.toString().padStart(places, '0')
}

View File

@ -1,5 +1,5 @@
{ {
"dependencies": { "dependencies": {
"utility": "1.18.0" "numerable": "0.3.15"
} }
} }

View File

@ -0,0 +1 @@
{}

View File

View File

@ -1,20 +0,0 @@
{
"$schema": "../../../../schemas/skill-schemas/skill-config.json",
"actions": {
"run": {
"type": "logic",
"utterance_samples": ["What time is it?"]
}
},
"answers": {
"default": ["Timekeeper skill test answer..."],
"data_test": ["Data test here %name%..."],
"answer": ["%answer%"],
"test": [
{
"speech": "This will be said out loud",
"text": "This will be shown in the chat"
}
]
}
}

View File

@ -1,12 +0,0 @@
{
"$schema": "../../../schemas/skill-schemas/skill.json",
"name": "Timekeeper",
"bridge": "python",
"version": "1.0.0",
"description": "Provide time-related information.",
"author": {
"name": "Louis Grenard",
"email": "louis@getleon.ai",
"url": "https://github.com/louistiti"
}
}

View File

@ -1,129 +0,0 @@
# TODO: find better way to import SDK modules
from bridges.python.src.sdk.leon import leon
from bridges.python.src.sdk.types import ActionParams
from bridges.python.src.sdk.memory import Memory
from bridges.python.src.sdk.settings import Settings
from bridges.python.src.sdk.network import Network
from bridges.python.src.sdk.aurora.button import Button
def run(params: ActionParams) -> None:
"""TODO"""
# TODO
# network request
# install bs4 and grab it from skill
network = Network({
'base_url': 'https://jsonplaceholder.typicode.com'
})
try:
response = network.request({
'url': '/todos/1',
'method': 'GET'
})
leon.answer({
'key': 'answer',
'data': {
'answer': f"Todo: {response['data']['title']}"
}
})
except Exception as e:
leon.answer({
'key': 'answer',
'data': {
'answer': 'Something went wrong...'
}
})
if network.is_network_error(e):
leon.answer({
'key': 'answer',
'data': {
'answer': f"{e}"
}
})
###
try:
other_skill_memory = Memory({
'name': 'productivity:todo_list:db'
})
todo_lists = other_skill_memory.read()
print('todo_lists', todo_lists)
except Exception:
print('todoLists', [])
posts_memory = Memory({'name': 'posts', 'default_memory': []})
posts_memory.write([
{
'id': 0,
'title': 'Hello world',
'content': 'This is a test post',
'author': {
'name': 'Louis'
}
},
{
'id': 1,
'title': 'Hello world 2',
'content': 'This is a test post 2',
'author': {
'name': 'Louis'
}
}
])
posts = posts_memory.read()
print('posts', posts)
posts = posts_memory.write([
*posts,
{
'id': 2,
'title': 'Hello world 3',
'content': 'This is a test post 3',
'author': {
'name': 'Louis'
}
}
])
found_post = next((post for post in posts if post['id'] == 2), None)
print('found_post', found_post)
###
button = Button({'text': 'Hello world from action skill'})
leon.answer({'widget': button})
###
leon.answer({'key': 'test'})
###
settings = Settings()
if not settings.is_setting_set('apiKey'):
leon.answer({
'key': "The API key isn't set..."
})
current_settings = settings.get()
settings.set({
**current_settings,
'apiKey': 'newAPIKey'
})
leon.answer({
'key': f"Is API set now? {settings.is_setting_set('apiKey')}"
})
###
leon.answer({'key': 'just a raw answer...'})
leon.answer({'key': 'default'})
leon.answer({'key': 'data_test', 'data': {'name': 'Louis'}})

View File

@ -1,4 +0,0 @@
{
"someSampleConfig": "someSampleValue",
"apiKey": "YOUR_API_KEY"
}