2023-08-22 17:11:20 -07:00
|
|
|
# basic environment class
|
|
|
|
|
# we have some built-in environment: Calender(include timer),Home(connect to IoT device in your home), ,KnwoledgeBase,FileSystem,
|
|
|
|
|
|
|
|
|
|
from abc import ABC, abstractmethod
|
2023-09-04 22:36:59 -07:00
|
|
|
from typing import Any, Callable, Optional,Dict,Awaitable,List
|
|
|
|
|
import logging
|
|
|
|
|
|
2023-09-10 20:50:37 -07:00
|
|
|
from .ai_function import AIFunction
|
|
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
logger = logging.getLogger(__name__)
|
2023-08-22 17:11:20 -07:00
|
|
|
|
2023-08-23 11:19:16 -07:00
|
|
|
class EnvironmentEvent(ABC):
|
2023-08-20 22:53:35 -07:00
|
|
|
@abstractmethod
|
|
|
|
|
def display(self) -> str:
|
2023-10-09 11:35:50 +08:00
|
|
|
pass
|
2023-08-20 22:53:35 -07:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
EnvironmentEventHandler = Callable[[str,EnvironmentEvent],Awaitable[Any]]
|
|
|
|
|
|
2023-08-23 11:19:16 -07:00
|
|
|
class Environment:
|
2023-09-04 22:36:59 -07:00
|
|
|
_all_env = {}
|
|
|
|
|
@classmethod
|
|
|
|
|
def get_env_by_id(cls,env_id:str):
|
|
|
|
|
return cls._all_env.get(env_id)
|
2023-10-09 11:35:50 +08:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
@classmethod
|
|
|
|
|
def set_env_by_id(cls,id,env):
|
|
|
|
|
assert id == env.get_id()
|
|
|
|
|
cls._all_env[env.get_id()] = env
|
|
|
|
|
|
|
|
|
|
def __init__(self,env_id:str) -> None:
|
|
|
|
|
self.env_id = env_id
|
|
|
|
|
self.values:Dict[str,str] = {}
|
|
|
|
|
self.get_handlers:Dict[str,Callable] = {}
|
|
|
|
|
self.owner_env:Dict[str,Environment] = {}
|
|
|
|
|
# self.valid_keys:Dict[str,bool] = None
|
|
|
|
|
self.event_handlers:Dict[str,List[EnvironmentEventHandler]]= {}
|
2023-08-20 22:53:35 -07:00
|
|
|
|
2023-09-10 20:50:37 -07:00
|
|
|
self.functions : Dict[str,AIFunction] = {}
|
|
|
|
|
|
2023-08-22 17:11:20 -07:00
|
|
|
def get_id(self) -> str:
|
2023-09-04 22:36:59 -07:00
|
|
|
return self.env_id
|
2023-10-09 11:35:50 +08:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
def add_owner_env(self,env) -> None:
|
|
|
|
|
self.owner_env[env.get_id()] = env
|
|
|
|
|
|
|
|
|
|
#@abstractmethod
|
|
|
|
|
#TODO: how to use env? different env has different prompt
|
|
|
|
|
#def get_env_prompt(self) -> str:
|
|
|
|
|
# pass
|
|
|
|
|
|
2023-09-10 20:50:37 -07:00
|
|
|
def add_ai_function(self,func:AIFunction) -> None:
|
|
|
|
|
if self.functions.get(func.get_name()) is not None:
|
|
|
|
|
logger.warn(f"add ai_function {func.get_name()} in env {self.env_id}:function already exist")
|
2023-10-09 11:35:50 +08:00
|
|
|
|
2023-09-10 20:50:37 -07:00
|
|
|
self.functions[func.get_name()] = func
|
|
|
|
|
|
|
|
|
|
def get_ai_function(self,func_name:str) -> AIFunction:
|
2023-10-09 11:35:50 +08:00
|
|
|
func = self.functions.get(func_name)
|
|
|
|
|
if func is not None:
|
|
|
|
|
return func
|
|
|
|
|
|
|
|
|
|
for owner_env in self.owner_env.values():
|
|
|
|
|
func = owner_env.get_ai_function(func_name)
|
|
|
|
|
if func is not None:
|
|
|
|
|
return func
|
|
|
|
|
|
|
|
|
|
return None
|
2023-09-10 20:50:37 -07:00
|
|
|
|
|
|
|
|
#def enable_ai_function(self,func_name:str) -> None:
|
|
|
|
|
# pass
|
|
|
|
|
|
|
|
|
|
#def disable_ai_function(self,func_name:str) -> None:
|
|
|
|
|
# pass
|
|
|
|
|
|
|
|
|
|
def get_all_ai_functions(self) -> List[AIFunction]:
|
2023-10-09 11:35:50 +08:00
|
|
|
func_list = []
|
|
|
|
|
func_list.extend(self.functions.values())
|
|
|
|
|
for owner_env in self.owner_env.values():
|
|
|
|
|
func_list.extend(owner_env.get_all_ai_functions())
|
|
|
|
|
return func_list
|
2023-09-10 20:50:37 -07:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
@abstractmethod
|
|
|
|
|
def _do_get_value(self,key:str) -> Optional[str]:
|
2023-08-22 17:11:20 -07:00
|
|
|
pass
|
|
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
def register_get_handler(self,key:str,handler:Callable) -> None:
|
|
|
|
|
h = self.get_handlers.get(key)
|
|
|
|
|
if h is not None:
|
|
|
|
|
logger.warn(f"register get_handler {key} in env {self.env_id}:handler already exist")
|
|
|
|
|
|
|
|
|
|
self.get_handlers[key] = handler
|
|
|
|
|
|
|
|
|
|
|
2023-08-22 17:11:20 -07:00
|
|
|
def attach_event_handler(self,event_id:str,handler:Callable) -> None:
|
2023-09-04 22:36:59 -07:00
|
|
|
handler_list = self.event_handlers.get(event_id)
|
|
|
|
|
if handler_list is None:
|
|
|
|
|
handler_list = []
|
|
|
|
|
self.event_handlers[event_id] = handler_list
|
|
|
|
|
|
|
|
|
|
handler_list.append(handler)
|
|
|
|
|
|
|
|
|
|
def remove_event_handler(self,event_id:str,handler:Callable) -> None:
|
|
|
|
|
handler_list = self.event_handlers.get(event_id)
|
|
|
|
|
if handler is not None:
|
|
|
|
|
handler_list.remove(handler)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
logger.warn(f"remove event_handler {event_id} in env {self.env_id}:handler not found")
|
2023-10-09 11:35:50 +08:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
async def fire_event(self,event_id:str,event:EnvironmentEvent) -> None:
|
|
|
|
|
handler_list = self.event_handlers.get(event_id)
|
|
|
|
|
if handler_list is not None:
|
|
|
|
|
for handler in handler_list:
|
|
|
|
|
await handler(self.env_id,event)
|
|
|
|
|
else:
|
2023-09-10 12:01:45 -07:00
|
|
|
logger.debug(f"fire event {event_id} in env {self.env_id}:handler not found")
|
2023-09-04 22:36:59 -07:00
|
|
|
return
|
2023-10-09 11:35:50 +08:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
def __getitem__(self, key):
|
|
|
|
|
return self.get_value(key)
|
2023-10-09 11:35:50 +08:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
def get_value(self,key:str) -> Optional[str]:
|
|
|
|
|
handler = self.get_handlers.get(key)
|
|
|
|
|
if handler is not None:
|
2023-09-17 13:16:21 +00:00
|
|
|
return handler()
|
2023-10-09 11:35:50 +08:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
s = self.values.get(key)
|
|
|
|
|
if isinstance(s,str):
|
|
|
|
|
return s
|
|
|
|
|
else:
|
|
|
|
|
logger.warn(f"get value {key} in env {self.env_id} failed!,type is not str")
|
|
|
|
|
|
|
|
|
|
s = self._do_get_value(key)
|
|
|
|
|
if s is not None:
|
2023-10-09 11:35:50 +08:00
|
|
|
return s
|
2023-09-04 22:36:59 -07:00
|
|
|
if self.owner_env is not None:
|
|
|
|
|
for env in self.owner_env.values():
|
|
|
|
|
s = env.get_value(key)
|
|
|
|
|
if s is not None:
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
logger.warn(f"get value {key} in env {self.env_id} failed!,not found")
|
|
|
|
|
return None
|
2023-10-09 11:35:50 +08:00
|
|
|
|
2023-09-04 22:36:59 -07:00
|
|
|
def set_value(self, key: str, str_value: str,is_storage:bool = True):
|
|
|
|
|
logger.info(f"set value {key} in env {self.env_id} to {str_value}")
|
|
|
|
|
self.values[key] = str_value
|
2023-08-22 17:11:20 -07:00
|
|
|
|