mirror of
https://github.com/leon-ai/leon.git
synced 2024-12-25 17:54:43 +03:00
feat: new onFetch
skill API and more
This commit is contained in:
parent
9aa9e0ba49
commit
8bca0595b4
@ -128,7 +128,7 @@ export default class Chatbot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await axios.get(
|
const data = await axios.get(
|
||||||
`${this.serverURL}/api/v1/fetch-widget?skill_action=${widgetContainer.onFetchAction}&widget_id=${widgetContainer.widgetId}`
|
`${this.serverURL}/api/v1/fetch-widget?skill_action=${widgetContainer.onFetch.actionName}&widget_id=${widgetContainer.widgetId}`
|
||||||
)
|
)
|
||||||
const fetchedWidget = data.data.widget
|
const fetchedWidget = data.data.widget
|
||||||
const reactNode = fetchedWidget
|
const reactNode = fetchedWidget
|
||||||
@ -201,7 +201,7 @@ export default class Chatbot {
|
|||||||
/**
|
/**
|
||||||
* On widget fetching, render the loader
|
* On widget fetching, render the loader
|
||||||
*/
|
*/
|
||||||
if (isCreatingFromLoadingFeed && parsedWidget.onFetchAction) {
|
if (isCreatingFromLoadingFeed && parsedWidget.onFetch) {
|
||||||
const root = createRoot(container)
|
const root = createRoot(container)
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
@ -217,7 +217,7 @@ export default class Chatbot {
|
|||||||
WIDGETS_TO_FETCH.push({
|
WIDGETS_TO_FETCH.push({
|
||||||
reactRootNode: root,
|
reactRootNode: root,
|
||||||
widgetId: parsedWidget.id,
|
widgetId: parsedWidget.id,
|
||||||
onFetchAction: parsedWidget.onFetchAction
|
onFetch: parsedWidget.onFetch
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -133,7 +133,7 @@ class Leon {
|
|||||||
actionName: `${INTENT_OBJECT.domain}:${INTENT_OBJECT.skill}:${INTENT_OBJECT.action}`,
|
actionName: `${INTENT_OBJECT.domain}:${INTENT_OBJECT.skill}:${INTENT_OBJECT.action}`,
|
||||||
widget: answerInput.widget.widget,
|
widget: answerInput.widget.widget,
|
||||||
id: answerInput.widget.id,
|
id: answerInput.widget.id,
|
||||||
onFetchAction: answerInput.widget.onFetchAction,
|
onFetch: answerInput.widget.onFetch ?? null,
|
||||||
componentTree: new WidgetWrapper({
|
componentTree: new WidgetWrapper({
|
||||||
...answerInput.widget.wrapperProps,
|
...answerInput.widget.wrapperProps,
|
||||||
children: [answerInput.widget.render()]
|
children: [answerInput.widget.render()]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { INTENT_OBJECT } from '@bridge/constants'
|
import { INTENT_OBJECT } from '@bridge/constants'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the widget ID if any
|
* Get the widget id if any
|
||||||
* @example getWidgetId() // 'timerwidget-5q1xlzeh
|
* @example getWidgetId() // 'timerwidget-5q1xlzeh
|
||||||
*/
|
*/
|
||||||
export function getWidgetId(): string | null {
|
export function getWidgetId(): string | null {
|
||||||
|
@ -5,11 +5,6 @@ import { WidgetComponent } from '@sdk/widget-component'
|
|||||||
|
|
||||||
type UtteranceSender = 'leon' | 'owner'
|
type UtteranceSender = 'leon' | 'owner'
|
||||||
|
|
||||||
interface FetchWidgetDataWidgetEventMethodParams {
|
|
||||||
actionName: string
|
|
||||||
widgetId: string
|
|
||||||
dataToSet: string[]
|
|
||||||
}
|
|
||||||
interface SendUtteranceWidgetEventMethodParams {
|
interface SendUtteranceWidgetEventMethodParams {
|
||||||
from: UtteranceSender
|
from: UtteranceSender
|
||||||
utterance: string
|
utterance: string
|
||||||
@ -28,11 +23,13 @@ export interface WidgetEventMethod {
|
|||||||
methodParams:
|
methodParams:
|
||||||
| SendUtteranceWidgetEventMethodParams
|
| SendUtteranceWidgetEventMethodParams
|
||||||
| RunSkillActionWidgetEventMethodParams
|
| RunSkillActionWidgetEventMethodParams
|
||||||
| FetchWidgetDataWidgetEventMethodParams
|
|
||||||
}
|
}
|
||||||
export interface WidgetOptions<T = unknown> {
|
export interface WidgetOptions<T = unknown> {
|
||||||
wrapperProps?: Omit<WidgetWrapperProps, 'children'>
|
wrapperProps?: Omit<WidgetWrapperProps, 'children'>
|
||||||
onFetchAction?: string
|
onFetch?: {
|
||||||
|
widgetId?: string | undefined
|
||||||
|
actionName: string
|
||||||
|
}
|
||||||
params: T
|
params: T
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +37,7 @@ export abstract class Widget<T = unknown> {
|
|||||||
public actionName: string
|
public actionName: string
|
||||||
public id: string
|
public id: string
|
||||||
public widget: string
|
public widget: string
|
||||||
public onFetchAction: string | null = null
|
public onFetch: WidgetOptions<T>['onFetch'] | null = null
|
||||||
public wrapperProps: WidgetOptions<T>['wrapperProps']
|
public wrapperProps: WidgetOptions<T>['wrapperProps']
|
||||||
public params: WidgetOptions<T>['params']
|
public params: WidgetOptions<T>['params']
|
||||||
|
|
||||||
@ -48,15 +45,20 @@ export abstract class Widget<T = unknown> {
|
|||||||
if (options?.wrapperProps) {
|
if (options?.wrapperProps) {
|
||||||
this.wrapperProps = options.wrapperProps
|
this.wrapperProps = options.wrapperProps
|
||||||
}
|
}
|
||||||
if (options?.onFetchAction) {
|
|
||||||
this.onFetchAction = `${INTENT_OBJECT.domain}:${INTENT_OBJECT.skill}:${options.onFetchAction}`
|
|
||||||
}
|
|
||||||
this.actionName = `${INTENT_OBJECT.domain}:${INTENT_OBJECT.skill}:${INTENT_OBJECT.action}`
|
this.actionName = `${INTENT_OBJECT.domain}:${INTENT_OBJECT.skill}:${INTENT_OBJECT.action}`
|
||||||
|
this.params = options.params
|
||||||
this.widget = this.constructor.name
|
this.widget = this.constructor.name
|
||||||
this.id = `${this.widget.toLowerCase()}-${Math.random()
|
if (options?.onFetch) {
|
||||||
|
this.onFetch = {
|
||||||
|
widgetId: options.onFetch.widgetId,
|
||||||
|
actionName: `${INTENT_OBJECT.domain}:${INTENT_OBJECT.skill}:${options.onFetch.actionName}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.id =
|
||||||
|
options.onFetch?.widgetId ||
|
||||||
|
`${this.widget.toLowerCase()}-${Math.random()
|
||||||
.toString(36)
|
.toString(36)
|
||||||
.substring(2, 10)}`
|
.substring(2, 10)}`
|
||||||
this.params = options.params
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,12 +84,12 @@ class Leon:
|
|||||||
'actionName': f"{INTENT_OBJECT['domain']}:{INTENT_OBJECT['skill']}:{INTENT_OBJECT['action']}",
|
'actionName': f"{INTENT_OBJECT['domain']}:{INTENT_OBJECT['skill']}:{INTENT_OBJECT['action']}",
|
||||||
'widget': widget.widget,
|
'widget': widget.widget,
|
||||||
'id': widget.id,
|
'id': widget.id,
|
||||||
'onFetchAction': widget.on_fetch_action,
|
'onFetch': widget.on_fetch if hasattr(widget, 'on_fetch') else None,
|
||||||
'componentTree': WidgetWrapper({
|
'componentTree': WidgetWrapper({
|
||||||
**wrapper_props,
|
**wrapper_props,
|
||||||
'children': [widget.render()]
|
'children': [widget.render()]
|
||||||
}).__dict__(),
|
}).__dict__(),
|
||||||
'supportedEvents': SUPPORTED_WIDGET_EVENTS # You might need to define this constant
|
'supportedEvents': SUPPORTED_WIDGET_EVENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
answer_object = {
|
answer_object = {
|
||||||
|
@ -2,6 +2,7 @@ from typing import Any, Optional, Generic, TypeVar, Literal, TypedDict, Union, D
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
import random
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
from .widget_component import WidgetComponent
|
from .widget_component import WidgetComponent
|
||||||
from ..constants import SKILL_CONFIG, INTENT_OBJECT
|
from ..constants import SKILL_CONFIG, INTENT_OBJECT
|
||||||
@ -11,12 +12,6 @@ T = TypeVar('T')
|
|||||||
UtteranceSender = Literal['leon', 'owner']
|
UtteranceSender = Literal['leon', 'owner']
|
||||||
|
|
||||||
|
|
||||||
class FetchWidgetDataWidgetEventMethodParams(TypedDict):
|
|
||||||
action_name: str
|
|
||||||
widget_id: str
|
|
||||||
data_to_set: list[str]
|
|
||||||
|
|
||||||
|
|
||||||
class SendUtteranceWidgetEventMethodParams(TypedDict):
|
class SendUtteranceWidgetEventMethodParams(TypedDict):
|
||||||
from_: UtteranceSender
|
from_: UtteranceSender
|
||||||
utterance: str
|
utterance: str
|
||||||
@ -36,8 +31,7 @@ class WidgetEventMethod(TypedDict):
|
|||||||
methodName: Literal['send_utterance', 'run_skill_action']
|
methodName: Literal['send_utterance', 'run_skill_action']
|
||||||
methodParams: Union[
|
methodParams: Union[
|
||||||
SendUtteranceWidgetEventMethodParams,
|
SendUtteranceWidgetEventMethodParams,
|
||||||
RunSkillActionWidgetEventMethodParams,
|
RunSkillActionWidgetEventMethodParams
|
||||||
FetchWidgetDataWidgetEventMethodParams
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -45,18 +39,23 @@ class WidgetEventMethod(TypedDict):
|
|||||||
class WidgetOptions(Generic[T]):
|
class WidgetOptions(Generic[T]):
|
||||||
wrapper_props: dict[str, Any] = None
|
wrapper_props: dict[str, Any] = None
|
||||||
params: T = None
|
params: T = None
|
||||||
on_fetch_action: Optional[str] = None
|
on_fetch: Optional[dict[str, Any]] = None
|
||||||
|
|
||||||
|
|
||||||
class Widget(ABC, Generic[T]):
|
class Widget(ABC, Generic[T]):
|
||||||
def __init__(self, options: WidgetOptions[T]):
|
def __init__(self, options: WidgetOptions[T]):
|
||||||
self.action_name = f"{INTENT_OBJECT['domain']}:{INTENT_OBJECT['skill']}:{INTENT_OBJECT['action']}"
|
if options.wrapper_props:
|
||||||
self.widget = self.__class__.__name__
|
|
||||||
self.id = f"{self.widget.lower()}-{random.randint(100000, 999999)}"
|
|
||||||
self.wrapper_props = options.wrapper_props
|
self.wrapper_props = options.wrapper_props
|
||||||
|
self.action_name = f"{INTENT_OBJECT['domain']}:{INTENT_OBJECT['skill']}:{INTENT_OBJECT['action']}"
|
||||||
self.params = options.params
|
self.params = options.params
|
||||||
self.on_fetch_action = f"{INTENT_OBJECT['domain']}:{INTENT_OBJECT['skill']}:{options.on_fetch_action}" \
|
self.widget = self.__class__.__name__
|
||||||
if options.on_fetch_action else None
|
if options.on_fetch:
|
||||||
|
self.on_fetch = {
|
||||||
|
'widgetId': options.on_fetch.get('widget_id'),
|
||||||
|
'actionName': f"{INTENT_OBJECT['domain']}:{INTENT_OBJECT['skill']}:{options.on_fetch.get('action_name')}"
|
||||||
|
}
|
||||||
|
self.id = options.on_fetch.get('widget_id') if options.on_fetch \
|
||||||
|
else f"{self.widget.lower()}-{''.join(random.choices(string.ascii_lowercase + string.digits, k=8))}"
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def render(self) -> WidgetComponent:
|
def render(self) -> WidgetComponent:
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
from typing import TypeVar, Generic, TypedDict, List, Any
|
from typing import TypeVar, Generic, TypedDict, List, Any
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
|
||||||
@ -12,8 +14,6 @@ SUPPORTED_WIDGET_EVENTS = [
|
|||||||
|
|
||||||
|
|
||||||
def generate_id() -> str:
|
def generate_id() -> str:
|
||||||
import random
|
|
||||||
import string
|
|
||||||
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=5))
|
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=5))
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,64 +52,6 @@
|
|||||||
"route": "/api/action/games/rochambeau/rematch",
|
"route": "/api/action/games/rochambeau/rematch",
|
||||||
"params": []
|
"params": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"route": "/api/action/news/github_trends/run",
|
|
||||||
"params": ["number", "daterange"],
|
|
||||||
"entitiesType": "builtIn"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"route": "/api/action/news/product_hunt_trends/run",
|
|
||||||
"params": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"route": "/api/action/productivity/todo_list/create_list",
|
|
||||||
"params": ["list"],
|
|
||||||
"entitiesType": "trim"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"route": "/api/action/productivity/todo_list/view_lists",
|
|
||||||
"params": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"route": "/api/action/productivity/todo_list/view_list",
|
|
||||||
"params": ["list"],
|
|
||||||
"entitiesType": "trim"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"route": "/api/action/productivity/todo_list/rename_list",
|
|
||||||
"params": ["old_list", "new_list"],
|
|
||||||
"entitiesType": "trim"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"route": "/api/action/productivity/todo_list/delete_list",
|
|
||||||
"params": ["list"],
|
|
||||||
"entitiesType": "trim"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"route": "/api/action/productivity/todo_list/add_todos",
|
|
||||||
"params": ["todos", "list"],
|
|
||||||
"entitiesType": "trim"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"route": "/api/action/productivity/todo_list/complete_todos",
|
|
||||||
"params": ["todos", "list"],
|
|
||||||
"entitiesType": "trim"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"route": "/api/action/productivity/todo_list/uncheck_todos",
|
|
||||||
"params": ["todos", "list"],
|
|
||||||
"entitiesType": "trim"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"route": "/api/action/leon/age/run",
|
"route": "/api/action/leon/age/run",
|
||||||
@ -185,11 +127,64 @@
|
|||||||
"route": "/api/action/leon/thanks/run",
|
"route": "/api/action/leon/thanks/run",
|
||||||
"params": []
|
"params": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"route": "/api/action/news/github_trends/run",
|
||||||
|
"params": ["number", "daterange"],
|
||||||
|
"entitiesType": "builtIn"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"route": "/api/action/unknown/widget-playground/run",
|
"route": "/api/action/news/product_hunt_trends/run",
|
||||||
"params": []
|
"params": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"route": "/api/action/productivity/todo_list/create_list",
|
||||||
|
"params": ["list"],
|
||||||
|
"entitiesType": "trim"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"route": "/api/action/productivity/todo_list/view_lists",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"route": "/api/action/productivity/todo_list/view_list",
|
||||||
|
"params": ["list"],
|
||||||
|
"entitiesType": "trim"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"route": "/api/action/productivity/todo_list/rename_list",
|
||||||
|
"params": ["old_list", "new_list"],
|
||||||
|
"entitiesType": "trim"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"route": "/api/action/productivity/todo_list/delete_list",
|
||||||
|
"params": ["list"],
|
||||||
|
"entitiesType": "trim"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"route": "/api/action/productivity/todo_list/add_todos",
|
||||||
|
"params": ["todos", "list"],
|
||||||
|
"entitiesType": "trim"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"route": "/api/action/productivity/todo_list/complete_todos",
|
||||||
|
"params": ["todos", "list"],
|
||||||
|
"entitiesType": "trim"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"route": "/api/action/productivity/todo_list/uncheck_todos",
|
||||||
|
"params": ["todos", "list"],
|
||||||
|
"entitiesType": "trim"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"route": "/api/action/social_communication/conversation/setup",
|
"route": "/api/action/social_communication/conversation/setup",
|
||||||
@ -215,6 +210,11 @@
|
|||||||
"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",
|
"method": "GET",
|
||||||
"route": "/api/action/utilities/date_time/current_date_time",
|
"route": "/api/action/utilities/date_time/current_date_time",
|
||||||
|
@ -98,7 +98,10 @@ export interface SkillAnswerOutput extends IntentObject {
|
|||||||
id: string
|
id: string
|
||||||
componentTree: WidgetWrapper
|
componentTree: WidgetWrapper
|
||||||
supportedEvents: typeof SUPPORTED_WIDGET_EVENTS
|
supportedEvents: typeof SUPPORTED_WIDGET_EVENTS
|
||||||
onFetchAction: string | null
|
onFetch: {
|
||||||
|
widgetId?: string
|
||||||
|
actionName: string
|
||||||
|
} | null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
from bridges.python.src.sdk.leon import leon
|
from bridges.python.src.sdk.leon import leon
|
||||||
from bridges.python.src.sdk.types import ActionParams
|
from bridges.python.src.sdk.types import ActionParams
|
||||||
|
from bridges.python.src.sdk.widget import WidgetOptions
|
||||||
|
from ..widgets.todos_list_widget import TodosListWidget
|
||||||
from ..lib import memory
|
from ..lib import memory
|
||||||
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
@ -25,7 +27,11 @@ def run(params: ActionParams) -> None:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
memory.create_todo_list(list_name)
|
todos_list_widget = TodosListWidget(WidgetOptions())
|
||||||
|
memory.create_todo_list(
|
||||||
|
todos_list_widget.id,
|
||||||
|
list_name
|
||||||
|
)
|
||||||
|
|
||||||
leon.answer({
|
leon.answer({
|
||||||
'key': 'list_created',
|
'key': 'list_created',
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from bridges.python.src.sdk.leon import leon
|
from bridges.python.src.sdk.leon import leon
|
||||||
|
from bridges.python.src.sdk.toolbox import get_widget_id
|
||||||
from bridges.python.src.sdk.types import ActionParams
|
from bridges.python.src.sdk.types import ActionParams
|
||||||
from bridges.python.src.sdk.widget import WidgetOptions
|
from bridges.python.src.sdk.widget import WidgetOptions
|
||||||
from ..widgets.todos_list_widget import TodosListWidget, TodosListWidgetParams
|
from ..widgets.todos_list_widget import TodosListWidget
|
||||||
from ..lib import memory
|
from ..lib import memory
|
||||||
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
@ -10,6 +11,7 @@ from typing import Union
|
|||||||
def run(params: ActionParams) -> None:
|
def run(params: ActionParams) -> None:
|
||||||
"""View a to-do list"""
|
"""View a to-do list"""
|
||||||
|
|
||||||
|
widget_id = get_widget_id()
|
||||||
list_name: Union[str, None] = None
|
list_name: Union[str, None] = None
|
||||||
|
|
||||||
for item in params['entities']:
|
for item in params['entities']:
|
||||||
@ -27,6 +29,7 @@ def run(params: ActionParams) -> None:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# TODO: if widget_id, get list by widget_id, otherwise get by list_name
|
||||||
todos = memory.get_todo_items(list_name)
|
todos = memory.get_todo_items(list_name)
|
||||||
|
|
||||||
if len(todos) == 0:
|
if len(todos) == 0:
|
||||||
@ -37,10 +40,15 @@ def run(params: ActionParams) -> None:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
todos_list_options: WidgetOptions[TodosListWidgetParams] = WidgetOptions(
|
todos_list_widget = TodosListWidget(
|
||||||
|
WidgetOptions(
|
||||||
wrapper_props={'noPadding': True},
|
wrapper_props={'noPadding': True},
|
||||||
params={'list_name': list_name, 'todos': todos}
|
params={'list_name': list_name, 'todos': todos},
|
||||||
|
on_fetch={
|
||||||
|
'widget_id': widget_id,
|
||||||
|
'action_name': 'view_list'
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
todos_list_widget = TodosListWidget(todos_list_options)
|
|
||||||
|
|
||||||
leon.answer({'widget': todos_list_widget})
|
leon.answer({'widget': todos_list_widget})
|
||||||
|
@ -15,13 +15,14 @@ todo_items_memory = Memory({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class TodoList(TypedDict):
|
class TodoListMemory(TypedDict):
|
||||||
|
widget_id: str
|
||||||
name: str
|
name: str
|
||||||
created_at: str
|
created_at: str
|
||||||
updated_at: str
|
updated_at: str
|
||||||
|
|
||||||
|
|
||||||
class TodoItem(TypedDict):
|
class TodoItemMemory(TypedDict):
|
||||||
todo_list_name: str
|
todo_list_name: str
|
||||||
name: str
|
name: str
|
||||||
is_completed: bool
|
is_completed: bool
|
||||||
@ -29,21 +30,22 @@ class TodoItem(TypedDict):
|
|||||||
updated_at: str
|
updated_at: str
|
||||||
|
|
||||||
|
|
||||||
def create_todo_list(name: str) -> None:
|
def create_todo_list(widget_id: str, name: str) -> None:
|
||||||
"""Create a new todo list"""
|
"""Create a new todo list"""
|
||||||
|
|
||||||
datetime_now = datetime.now().isoformat()
|
datetime_now = datetime.now().isoformat()
|
||||||
todo_list = TodoList(
|
todo_list = TodoListMemory(
|
||||||
|
widget_id=widget_id,
|
||||||
name=name,
|
name=name,
|
||||||
created_at=datetime_now,
|
created_at=datetime_now,
|
||||||
updated_at=datetime_now
|
updated_at=datetime_now
|
||||||
)
|
)
|
||||||
todo_lists: list[TodoList] = todo_lists_memory.read()
|
todo_lists: list[TodoListMemory] = todo_lists_memory.read()
|
||||||
todo_lists.append(todo_list)
|
todo_lists.append(todo_list)
|
||||||
todo_lists_memory.write(todo_lists)
|
todo_lists_memory.write(todo_lists)
|
||||||
|
|
||||||
|
|
||||||
def get_todo_lists() -> list[TodoList]:
|
def get_todo_lists() -> list[TodoListMemory]:
|
||||||
"""Get all todo lists"""
|
"""Get all todo lists"""
|
||||||
|
|
||||||
return todo_lists_memory.read()
|
return todo_lists_memory.read()
|
||||||
@ -52,7 +54,7 @@ def get_todo_lists() -> list[TodoList]:
|
|||||||
def update_todo_list(old_name: str, new_name: str) -> None:
|
def update_todo_list(old_name: str, new_name: str) -> None:
|
||||||
"""Update a todo list name"""
|
"""Update a todo list name"""
|
||||||
|
|
||||||
todo_lists: list[TodoList] = todo_lists_memory.read()
|
todo_lists: list[TodoListMemory] = todo_lists_memory.read()
|
||||||
for todo_list in todo_lists:
|
for todo_list in todo_lists:
|
||||||
if todo_list['name'] == old_name:
|
if todo_list['name'] == old_name:
|
||||||
todo_list['name'] = new_name
|
todo_list['name'] = new_name
|
||||||
@ -60,7 +62,7 @@ def update_todo_list(old_name: str, new_name: str) -> None:
|
|||||||
break
|
break
|
||||||
todo_lists_memory.write(todo_lists)
|
todo_lists_memory.write(todo_lists)
|
||||||
|
|
||||||
todo_items: list[TodoItem] = todo_items_memory.read()
|
todo_items: list[TodoItemMemory] = todo_items_memory.read()
|
||||||
for todo_item in todo_items:
|
for todo_item in todo_items:
|
||||||
if todo_item['todo_list_name'] == old_name:
|
if todo_item['todo_list_name'] == old_name:
|
||||||
todo_item['todo_list_name'] = new_name
|
todo_item['todo_list_name'] = new_name
|
||||||
@ -71,14 +73,14 @@ def update_todo_list(old_name: str, new_name: str) -> None:
|
|||||||
def delete_todo_list(name: str) -> None:
|
def delete_todo_list(name: str) -> None:
|
||||||
"""Delete a todo list and its todos"""
|
"""Delete a todo list and its todos"""
|
||||||
|
|
||||||
todo_lists: list[TodoList] = todo_lists_memory.read()
|
todo_lists: list[TodoListMemory] = todo_lists_memory.read()
|
||||||
for todo_list in todo_lists:
|
for todo_list in todo_lists:
|
||||||
if todo_list['name'] == name:
|
if todo_list['name'] == name:
|
||||||
todo_lists.remove(todo_list)
|
todo_lists.remove(todo_list)
|
||||||
break
|
break
|
||||||
todo_lists_memory.write(todo_lists)
|
todo_lists_memory.write(todo_lists)
|
||||||
|
|
||||||
todo_items: list[TodoItem] = todo_items_memory.read()
|
todo_items: list[TodoItemMemory] = todo_items_memory.read()
|
||||||
for todo_item in todo_items:
|
for todo_item in todo_items:
|
||||||
if todo_item['todo_list_name'] == name:
|
if todo_item['todo_list_name'] == name:
|
||||||
todo_items.remove(todo_item)
|
todo_items.remove(todo_item)
|
||||||
@ -94,7 +96,7 @@ def count_todo_lists() -> int:
|
|||||||
def has_todo_list(name: str) -> bool:
|
def has_todo_list(name: str) -> bool:
|
||||||
"""Check if a todo list already exist"""
|
"""Check if a todo list already exist"""
|
||||||
|
|
||||||
todo_lists: list[TodoList] = todo_lists_memory.read()
|
todo_lists: list[TodoListMemory] = todo_lists_memory.read()
|
||||||
for todo_list in todo_lists:
|
for todo_list in todo_lists:
|
||||||
if todo_list['name'] == name:
|
if todo_list['name'] == name:
|
||||||
return True
|
return True
|
||||||
@ -107,22 +109,22 @@ def create_todo_item(todo_list_name: str, name: str) -> None:
|
|||||||
if not has_todo_list(todo_list_name):
|
if not has_todo_list(todo_list_name):
|
||||||
create_todo_list(todo_list_name)
|
create_todo_list(todo_list_name)
|
||||||
datetime_now = datetime.now().isoformat()
|
datetime_now = datetime.now().isoformat()
|
||||||
todo_item = TodoItem(
|
todo_item = TodoItemMemory(
|
||||||
todo_list_name=todo_list_name,
|
todo_list_name=todo_list_name,
|
||||||
name=name,
|
name=name,
|
||||||
is_completed=False,
|
is_completed=False,
|
||||||
created_at=datetime_now,
|
created_at=datetime_now,
|
||||||
updated_at=datetime_now
|
updated_at=datetime_now
|
||||||
)
|
)
|
||||||
todo_items: list[TodoItem] = todo_items_memory.read()
|
todo_items: list[TodoItemMemory] = todo_items_memory.read()
|
||||||
todo_items.append(todo_item)
|
todo_items.append(todo_item)
|
||||||
todo_items_memory.write(todo_items)
|
todo_items_memory.write(todo_items)
|
||||||
|
|
||||||
|
|
||||||
def get_todo_items(todo_list_name: str) -> list[TodoItem]:
|
def get_todo_items(todo_list_name: str) -> list[TodoItemMemory]:
|
||||||
"""Get all todo items of a todo list"""
|
"""Get all todo items of a todo list"""
|
||||||
|
|
||||||
todo_items: list[TodoItem] = todo_items_memory.read()
|
todo_items: list[TodoItemMemory] = todo_items_memory.read()
|
||||||
return [todo_item for todo_item in todo_items if todo_item['todo_list_name'] == todo_list_name]
|
return [todo_item for todo_item in todo_items if todo_item['todo_list_name'] == todo_list_name]
|
||||||
|
|
||||||
|
|
||||||
@ -132,24 +134,24 @@ def count_todo_items(todo_list_name: str) -> int:
|
|||||||
return len(get_todo_items(todo_list_name))
|
return len(get_todo_items(todo_list_name))
|
||||||
|
|
||||||
|
|
||||||
def get_completed_todo_items(todo_list_name: str) -> list[TodoItem]:
|
def get_completed_todo_items(todo_list_name: str) -> list[TodoItemMemory]:
|
||||||
"""Get all completed todo items of a todo list"""
|
"""Get all completed todo items of a todo list"""
|
||||||
|
|
||||||
todo_items: list[TodoItem] = todo_items_memory.read()
|
todo_items: list[TodoItemMemory] = todo_items_memory.read()
|
||||||
return [todo_item for todo_item in todo_items if todo_item['todo_list_name'] == todo_list_name and todo_item['is_completed']]
|
return [todo_item for todo_item in todo_items if todo_item['todo_list_name'] == todo_list_name and todo_item['is_completed']]
|
||||||
|
|
||||||
|
|
||||||
def get_uncompleted_todo_items(todo_list_name: str) -> list[TodoItem]:
|
def get_uncompleted_todo_items(todo_list_name: str) -> list[TodoItemMemory]:
|
||||||
"""Get all uncompleted todo items of a todo list"""
|
"""Get all uncompleted todo items of a todo list"""
|
||||||
|
|
||||||
todo_items: list[TodoItem] = todo_items_memory.read()
|
todo_items: list[TodoItemMemory] = todo_items_memory.read()
|
||||||
return [todo_item for todo_item in todo_items if todo_item['todo_list_name'] == todo_list_name and not todo_item['is_completed']]
|
return [todo_item for todo_item in todo_items if todo_item['todo_list_name'] == todo_list_name and not todo_item['is_completed']]
|
||||||
|
|
||||||
|
|
||||||
def complete_todo_item(todo_list_name: str, name: str) -> None:
|
def complete_todo_item(todo_list_name: str, name: str) -> None:
|
||||||
"""Complete a todo item"""
|
"""Complete a todo item"""
|
||||||
|
|
||||||
todo_items: list[TodoItem] = todo_items_memory.read()
|
todo_items: list[TodoItemMemory] = todo_items_memory.read()
|
||||||
for todo_item in todo_items:
|
for todo_item in todo_items:
|
||||||
if todo_item['todo_list_name'] == todo_list_name and todo_item['name'] == name:
|
if todo_item['todo_list_name'] == todo_list_name and todo_item['name'] == name:
|
||||||
todo_item['is_completed'] = True
|
todo_item['is_completed'] = True
|
||||||
@ -161,7 +163,7 @@ def complete_todo_item(todo_list_name: str, name: str) -> None:
|
|||||||
def uncomplete_todo_item(todo_list_name: str, name: str) -> None:
|
def uncomplete_todo_item(todo_list_name: str, name: str) -> None:
|
||||||
"""Uncomplete a todo item"""
|
"""Uncomplete a todo item"""
|
||||||
|
|
||||||
todo_items: list[TodoItem] = todo_items_memory.read()
|
todo_items: list[TodoItemMemory] = todo_items_memory.read()
|
||||||
for todo_item in todo_items:
|
for todo_item in todo_items:
|
||||||
if todo_item['todo_list_name'] == todo_list_name and todo_item['name'] == name:
|
if todo_item['todo_list_name'] == todo_list_name and todo_item['name'] == name:
|
||||||
todo_item['is_completed'] = False
|
todo_item['is_completed'] = False
|
||||||
|
@ -14,6 +14,7 @@ class TodoType(TypedDict):
|
|||||||
|
|
||||||
|
|
||||||
class TodosListWidgetParams(TypedDict):
|
class TodosListWidgetParams(TypedDict):
|
||||||
|
id: str
|
||||||
list_name: str
|
list_name: str
|
||||||
todos: list[TodoType]
|
todos: list[TodoType]
|
||||||
|
|
||||||
|
@ -24,13 +24,15 @@ export const run: ActionFunction = async function () {
|
|||||||
|
|
||||||
const timerWidget = new TimerWidget({
|
const timerWidget = new TimerWidget({
|
||||||
params: {
|
params: {
|
||||||
id: widgetId ?? timerMemory.widgetId,
|
|
||||||
seconds: remainingTime,
|
seconds: remainingTime,
|
||||||
initialProgress,
|
initialProgress,
|
||||||
initialDuration: duration,
|
initialDuration: duration,
|
||||||
interval
|
interval
|
||||||
},
|
},
|
||||||
onFetchAction: 'check_timer'
|
onFetch: {
|
||||||
|
widgetId: widgetId ?? timerMemory.widgetId,
|
||||||
|
actionName: 'check_timer'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await leon.answer({ widget: timerWidget })
|
await leon.answer({ widget: timerWidget })
|
||||||
|
@ -29,18 +29,16 @@ export const run: ActionFunction = async function (params) {
|
|||||||
initialProgress: 0,
|
initialProgress: 0,
|
||||||
interval
|
interval
|
||||||
},
|
},
|
||||||
onFetchAction: 'check_timer'
|
onFetch: {
|
||||||
|
actionName: 'check_timer'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await createTimerMemory(timerWidget.id, seconds, interval)
|
await Promise.all([
|
||||||
|
createTimerMemory(timerWidget.id, seconds, interval),
|
||||||
// TODO: return a speech without new utterance
|
leon.answer({
|
||||||
/*await leon.answer({
|
|
||||||
widget: timerWidget,
|
|
||||||
speech: 'I set a timer for ... ...'
|
|
||||||
})*/
|
|
||||||
await leon.answer({
|
|
||||||
widget: timerWidget,
|
widget: timerWidget,
|
||||||
key: 'timer_set'
|
key: 'timer_set'
|
||||||
})
|
})
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
@ -8,16 +8,11 @@ interface Params {
|
|||||||
interval: number
|
interval: number
|
||||||
initialProgress: number
|
initialProgress: number
|
||||||
initialDuration?: number
|
initialDuration?: number
|
||||||
id?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TimerWidget extends Widget<Params> {
|
export class TimerWidget extends Widget<Params> {
|
||||||
constructor(options: WidgetOptions<Params>) {
|
constructor(options: WidgetOptions<Params>) {
|
||||||
super(options)
|
super(options)
|
||||||
|
|
||||||
if (options.params.id) {
|
|
||||||
this.id = options.params.id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): WidgetComponent {
|
public render(): WidgetComponent {
|
||||||
|
Loading…
Reference in New Issue
Block a user