Jarvis can update contract, aios_shell can update contract.
This commit is contained in:
@@ -49,7 +49,7 @@ class ContactManager:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def get_instance(cls,filename=None) -> "ContactManager":
|
def get_instance(cls,filename=None) -> "ContactManager":
|
||||||
if cls._instance is None:
|
if cls._instance is None:
|
||||||
cls._instance = ContactManager(filename)
|
cls._instance = ContactManager(str(filename))
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
def __init__(self, filename="contacts.toml"):
|
def __init__(self, filename="contacts.toml"):
|
||||||
@@ -79,6 +79,21 @@ class ContactManager:
|
|||||||
with open(self.filename, "w") as f:
|
with open(self.filename, "w") as f:
|
||||||
toml.dump(data, f)
|
toml.dump(data, f)
|
||||||
|
|
||||||
|
def set_contact(self, name:str, new_contact:Contact):
|
||||||
|
assert name == new_contact.name
|
||||||
|
for i, contact in enumerate(self.contacts):
|
||||||
|
if contact.name == name:
|
||||||
|
self.contacts[i] = new_contact
|
||||||
|
self.save_data()
|
||||||
|
return True
|
||||||
|
for i, member in enumerate(self.family_members):
|
||||||
|
if member.name == name:
|
||||||
|
self.family_members[i] = new_contact
|
||||||
|
self.save_data()
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def add_contact(self, name:str, new_contact:Contact):
|
def add_contact(self, name:str, new_contact:Contact):
|
||||||
assert name == new_contact.name
|
assert name == new_contact.name
|
||||||
self.contacts.append(new_contact)
|
self.contacts.append(new_contact)
|
||||||
|
|||||||
@@ -176,5 +176,5 @@ class GoogleTextToSpeechNode(ComputeNode):
|
|||||||
user_config = AIStorage.get_instance().get_user_config()
|
user_config = AIStorage.get_instance().get_user_config()
|
||||||
user_config.add_user_config("google_application_credentials",
|
user_config.add_user_config("google_application_credentials",
|
||||||
"google application credentials, please visit:https://cloud.google.com/text-to-speech/docs/before-you-begin",
|
"google application credentials, please visit:https://cloud.google.com/text-to-speech/docs/before-you-begin",
|
||||||
False,
|
True,
|
||||||
None)
|
None)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class Local_Stability_ComputeNode(ComputeNode):
|
|||||||
user_config = AIStorage.get_instance().get_user_config()
|
user_config = AIStorage.get_instance().get_user_config()
|
||||||
if os.getenv("LOCAL_STABILITY_URL") is None:
|
if os.getenv("LOCAL_STABILITY_URL") is None:
|
||||||
user_config.add_user_config(
|
user_config.add_user_config(
|
||||||
"local_stability_url", "local stability url", False, None)
|
"local_stability_url", "local stability url", True, None)
|
||||||
if os.getenv("TEXT2IMG_OUTPUT_DIR") is None:
|
if os.getenv("TEXT2IMG_OUTPUT_DIR") is None:
|
||||||
home_dir = Path.home()
|
home_dir = Path.home()
|
||||||
output_dir = Path.joinpath(home_dir, "text2img_output")
|
output_dir = Path.joinpath(home_dir, "text2img_output")
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ class ResourceLocation:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class FeatureItem:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
class UserConfigItem:
|
class UserConfigItem:
|
||||||
def __init__(self,desc:str=None) -> None:
|
def __init__(self,desc:str=None) -> None:
|
||||||
self.default_value = None
|
self.default_value = None
|
||||||
@@ -142,6 +146,18 @@ class AIStorage:
|
|||||||
await self.user_config.load_value_from_file(self.get_system_dir() + "/system.cfg.toml")
|
await self.user_config.load_value_from_file(self.get_system_dir() + "/system.cfg.toml")
|
||||||
await self.user_config.load_value_from_file(self.user_config.user_config_path,True)
|
await self.user_config.load_value_from_file(self.user_config.user_config_path,True)
|
||||||
|
|
||||||
|
async def enable_feature(self,feature_name:str) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def disable_feature(self,feature_name:str) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def set_feature_init_result(self,feature_name:str,result:bool) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def is_feature_enable(self,feature_name:str) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
def get_user_config(self) -> UserConfig:
|
def get_user_config(self) -> UserConfig:
|
||||||
return self.user_config
|
return self.user_config
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from telegram.ext import Updater
|
|||||||
from telegram.error import Forbidden, NetworkError
|
from telegram.error import Forbidden, NetworkError
|
||||||
|
|
||||||
from .tunnel import AgentTunnel
|
from .tunnel import AgentTunnel
|
||||||
|
from .storage import AIStorage
|
||||||
from .contact_manager import ContactManager,Contact,FamilyMember
|
from .contact_manager import ContactManager,Contact,FamilyMember
|
||||||
from .agent_message import AgentMsg
|
from .agent_message import AgentMsg
|
||||||
|
|
||||||
@@ -119,6 +120,10 @@ class TelegramTunnel(AgentTunnel):
|
|||||||
|
|
||||||
cm : ContactManager = ContactManager.get_instance()
|
cm : ContactManager = ContactManager.get_instance()
|
||||||
reomte_user_name = f"{update.effective_user.id}@telegram"
|
reomte_user_name = f"{update.effective_user.id}@telegram"
|
||||||
|
#owner_tg_username = AIStorage.get_instance().get_user_config().get_value("telegram")
|
||||||
|
#owner_name = AIStorage.get_instance().get_user_config().get_value("username")
|
||||||
|
|
||||||
|
|
||||||
contact : Contact = cm.find_contact_by_telegram(update.effective_user.username)
|
contact : Contact = cm.find_contact_by_telegram(update.effective_user.username)
|
||||||
if contact is None:
|
if contact is None:
|
||||||
contact = cm.find_contact_by_telegram(str(update.effective_user.id))
|
contact = cm.find_contact_by_telegram(str(update.effective_user.id))
|
||||||
@@ -136,8 +141,7 @@ class TelegramTunnel(AgentTunnel):
|
|||||||
contact.added_by = self.target_id
|
contact.added_by = self.target_id
|
||||||
cm.add_contact(contact.name, contact)
|
cm.add_contact(contact.name, contact)
|
||||||
reomte_user_name = contact.name
|
reomte_user_name = contact.name
|
||||||
|
|
||||||
# create gust account?
|
|
||||||
agent_msg = await self.conver_tg_msg_to_agent_msg(update)
|
agent_msg = await self.conver_tg_msg_to_agent_msg(update)
|
||||||
agent_msg.sender = reomte_user_name
|
agent_msg.sender = reomte_user_name
|
||||||
self.ai_bus.register_message_handler(reomte_user_name, self._process_message)
|
self.ai_bus.register_message_handler(reomte_user_name, self._process_message)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from .compute_kernel import ComputeKernel
|
|||||||
from .environment import Environment,EnvironmentEvent
|
from .environment import Environment,EnvironmentEvent
|
||||||
from .ai_function import SimpleAIFunction
|
from .ai_function import SimpleAIFunction
|
||||||
from .storage import AIStorage
|
from .storage import AIStorage
|
||||||
|
from .contact_manager import ContactManager,Contact,FamilyMember
|
||||||
|
|
||||||
import aiosqlite
|
import aiosqlite
|
||||||
|
|
||||||
@@ -93,6 +94,17 @@ class CalenderEnvironment(Environment):
|
|||||||
"Draw a picture according to the description",
|
"Draw a picture according to the description",
|
||||||
self._paint,paint_param))
|
self._paint,paint_param))
|
||||||
|
|
||||||
|
self.add_ai_function(SimpleAIFunction("get_contact",
|
||||||
|
"get contact info",
|
||||||
|
self._get_contact,{"name":"name of contact"}))
|
||||||
|
|
||||||
|
self.add_ai_function(SimpleAIFunction("set_contact",
|
||||||
|
"set contact info",
|
||||||
|
self._set_contact,{"name":"name of contact","contact_info":"A json to descrpit contact"}))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#self.add_ai_function(SimpleAIFunction("user_confirm",
|
#self.add_ai_function(SimpleAIFunction("user_confirm",
|
||||||
# "user confirm",
|
# "user confirm",
|
||||||
# self._user_confirm))
|
# self._user_confirm))
|
||||||
@@ -222,6 +234,45 @@ class CalenderEnvironment(Environment):
|
|||||||
|
|
||||||
def _do_get_value(self,key:str) -> Optional[str]:
|
def _do_get_value(self,key:str) -> Optional[str]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
async def _get_contact(self,name:str) -> str:
|
||||||
|
cm = ContactManager.get_instance()
|
||||||
|
contact : Contact = cm.find_contact_by_name(name)
|
||||||
|
if contact:
|
||||||
|
s = json.dumps(contact.to_dict())
|
||||||
|
return f"Execute get_contact OK , contact {name} is {s}"
|
||||||
|
else:
|
||||||
|
return f"Execute get_contact OK , contact {name} not found!"
|
||||||
|
|
||||||
|
async def _set_contact(self,name:str,contact_info:str) -> str:
|
||||||
|
cm = ContactManager.get_instance()
|
||||||
|
contact = cm.find_contact_by_name(name)
|
||||||
|
contact_info = json.loads(contact_info)
|
||||||
|
if contact is None:
|
||||||
|
contact = Contact(name)
|
||||||
|
contact.email = contact_info.get("email")
|
||||||
|
contact.telegram = contact_info.get("telegram")
|
||||||
|
contact.notes = contact_info.get("notes")
|
||||||
|
contact.added_by = self.env_id
|
||||||
|
|
||||||
|
cm.add_contact(name,contact)
|
||||||
|
|
||||||
|
return f"Execute set_contact OK , new contact {name} added!"
|
||||||
|
else:
|
||||||
|
if contact_info.get("email") is not None:
|
||||||
|
contact.email = contact_info.get("email")
|
||||||
|
if contact_info.get("telegram") is not None:
|
||||||
|
contact.telegram = contact_info.get("telegram")
|
||||||
|
if contact_info.get("notes") is not None:
|
||||||
|
contact.notes = contact_info.get("notes")
|
||||||
|
|
||||||
|
contact.added_by = self.env_id
|
||||||
|
cm.set_contact(name,contact)
|
||||||
|
|
||||||
|
return f"Execute set_contact OK , contact {name} updated!"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def start(self) -> None:
|
async def start(self) -> None:
|
||||||
if self.is_run:
|
if self.is_run:
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ sys.path.append(directory + '/../../')
|
|||||||
|
|
||||||
|
|
||||||
from aios_kernel import AIOS_Version,UserConfigItem,AIStorage,Workflow,AIAgent,AgentMsg,AgentMsgStatus,ComputeKernel,OpenAI_ComputeNode,AIBus,AIChatSession,AgentTunnel,TelegramTunnel,CalenderEnvironment,Environment,EmailTunnel,LocalLlama_ComputeNode,Local_Stability_ComputeNode
|
from aios_kernel import AIOS_Version,UserConfigItem,AIStorage,Workflow,AIAgent,AgentMsg,AgentMsgStatus,ComputeKernel,OpenAI_ComputeNode,AIBus,AIChatSession,AgentTunnel,TelegramTunnel,CalenderEnvironment,Environment,EmailTunnel,LocalLlama_ComputeNode,Local_Stability_ComputeNode
|
||||||
|
from aios_kernel import ContactManager,Contact
|
||||||
import proxy
|
import proxy
|
||||||
from aios_kernel import *
|
from aios_kernel import *
|
||||||
|
|
||||||
@@ -51,8 +52,14 @@ class AIOS_Shell:
|
|||||||
self.is_working = True
|
self.is_working = True
|
||||||
|
|
||||||
def declare_all_user_config(self):
|
def declare_all_user_config(self):
|
||||||
|
cm_path = AIStorage.get_instance().get_myai_dir() / "contacts.toml"
|
||||||
|
cm = ContactManager.get_instance(cm_path)
|
||||||
|
cm.load_data()
|
||||||
|
|
||||||
user_config = AIStorage.get_instance().get_user_config()
|
user_config = AIStorage.get_instance().get_user_config()
|
||||||
user_config.add_user_config("username","username is your full name when using AIOS",False,None,)
|
user_config.add_user_config("username","username is your full name when using AIOS",False,None)
|
||||||
|
user_config.add_user_config("telegram","Your telgram username",False,None)
|
||||||
|
user_config.add_user_config("email","Your email",False,None)
|
||||||
|
|
||||||
openai_node = OpenAI_ComputeNode.get_instance()
|
openai_node = OpenAI_ComputeNode.get_instance()
|
||||||
openai_node.declare_user_config()
|
openai_node.declare_user_config()
|
||||||
@@ -88,6 +95,17 @@ class AIOS_Shell:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def initial(self) -> bool:
|
async def initial(self) -> bool:
|
||||||
|
cm = ContactManager.get_instance()
|
||||||
|
owenr = cm.find_contact_by_name(self.username)
|
||||||
|
if owenr is None:
|
||||||
|
owenr = Contact(self.username)
|
||||||
|
owenr.added_by = self.username
|
||||||
|
owenr.is_family_member = True
|
||||||
|
owenr.email = AIStorage.get_instance().get_user_config().get_value("email")
|
||||||
|
owenr.telegram = AIStorage.get_instance().get_user_config().get_value("telegram")
|
||||||
|
|
||||||
|
cm.add_contact(self.username,owenr)
|
||||||
|
|
||||||
cal_env = CalenderEnvironment("calender")
|
cal_env = CalenderEnvironment("calender")
|
||||||
await cal_env.start()
|
await cal_env.start()
|
||||||
Environment.set_env_by_id("calender",cal_env)
|
Environment.set_env_by_id("calender",cal_env)
|
||||||
@@ -99,6 +117,7 @@ class AIOS_Shell:
|
|||||||
await AgentManager.get_instance().initial()
|
await AgentManager.get_instance().initial()
|
||||||
await WorkflowManager.get_instance().initial()
|
await WorkflowManager.get_instance().initial()
|
||||||
|
|
||||||
|
|
||||||
open_ai_node = OpenAI_ComputeNode.get_instance()
|
open_ai_node = OpenAI_ComputeNode.get_instance()
|
||||||
if await open_ai_node.initial() is not True:
|
if await open_ai_node.initial() is not True:
|
||||||
logger.error("openai node initial failed!")
|
logger.error("openai node initial failed!")
|
||||||
@@ -120,7 +139,7 @@ class AIOS_Shell:
|
|||||||
local_sd_node = Local_Stability_ComputeNode.get_instance()
|
local_sd_node = Local_Stability_ComputeNode.get_instance()
|
||||||
if await local_sd_node.initial() is not True:
|
if await local_sd_node.initial() is not True:
|
||||||
logger.error("local stability node initial failed!")
|
logger.error("local stability node initial failed!")
|
||||||
return False
|
|
||||||
ComputeKernel.get_instance().add_compute_node(local_sd_node)
|
ComputeKernel.get_instance().add_compute_node(local_sd_node)
|
||||||
|
|
||||||
await ComputeKernel.get_instance().start()
|
await ComputeKernel.get_instance().start()
|
||||||
@@ -164,6 +183,7 @@ class AIOS_Shell:
|
|||||||
|
|
||||||
async def _user_process_msg(self,msg:AgentMsg) -> AgentMsg:
|
async def _user_process_msg(self,msg:AgentMsg) -> AgentMsg:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
async def get_tunnel_config_from_input(self,tunnel_target,tunnel_type):
|
async def get_tunnel_config_from_input(self,tunnel_target,tunnel_type):
|
||||||
tunnel_config = {}
|
tunnel_config = {}
|
||||||
@@ -206,6 +226,59 @@ class AIOS_Shell:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"load tunnels config from {tunnels_config_path} failed!")
|
logger.warning(f"load tunnels config from {tunnels_config_path} failed!")
|
||||||
|
|
||||||
|
async def handle_contact_commands(self,args):
|
||||||
|
cm = ContactManager.get_instance()
|
||||||
|
if len(args) < 1:
|
||||||
|
return FormattedText([("class:error", f'/contact $contact_name, Like /contact "Jim Green"')])
|
||||||
|
contact_name = args[0]
|
||||||
|
contact = cm.find_contact_by_name(contact_name)
|
||||||
|
is_update = False
|
||||||
|
if contact is not None:
|
||||||
|
#show old info and ask user to update or remove
|
||||||
|
is_update = True
|
||||||
|
op_str = await try_get_input(f"Contact {contact_name} already exist, update or remove? (u/r)")
|
||||||
|
if op_str is None:
|
||||||
|
return None
|
||||||
|
if op_str == "r":
|
||||||
|
cm.remove_contact(contact_name)
|
||||||
|
return FormattedText([("class:title", f"remove {contact_name} success!")])
|
||||||
|
else:
|
||||||
|
print(f"old info: {contact}")
|
||||||
|
else:
|
||||||
|
contact = Contact(contact_name)
|
||||||
|
|
||||||
|
contact.is_family_member = False
|
||||||
|
is_family_member = await try_get_input(f"Is {contact_name} your family member? (y/n)")
|
||||||
|
if is_family_member is not None:
|
||||||
|
if is_family_member == "y" or is_family_member == "Y":
|
||||||
|
contact.is_family_member = True
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
contact_telegram = await try_get_input(f"Input {contact_name}'s telegram username:")
|
||||||
|
if contact_telegram is None:
|
||||||
|
return None
|
||||||
|
contact.telegram = contact_telegram
|
||||||
|
|
||||||
|
contact_email = await try_get_input(f"Input {contact_name}'s email:")
|
||||||
|
if contact_email is None:
|
||||||
|
return None
|
||||||
|
contact.email = contact_email
|
||||||
|
|
||||||
|
contact_phone = await try_get_input(f"Input {contact_name}'s phone (optional):")
|
||||||
|
if contact_phone is not None:
|
||||||
|
contact.phone = contact_phone
|
||||||
|
|
||||||
|
contact_note = await try_get_input(f"Input {contact_name}'s note (optional):")
|
||||||
|
if contact_note is not None:
|
||||||
|
contact.note = contact_note
|
||||||
|
|
||||||
|
contact.added_by = self.username
|
||||||
|
if is_update:
|
||||||
|
cm.set_contact(contact_name,contact)
|
||||||
|
else:
|
||||||
|
cm.add_contact(contact_name,contact)
|
||||||
|
|
||||||
async def handle_knowledge_commands(self, args):
|
async def handle_knowledge_commands(self, args):
|
||||||
show_text = FormattedText([("class:title", "sub command not support!\n"
|
show_text = FormattedText([("class:title", "sub command not support!\n"
|
||||||
"/knowledge add email | dir\n"
|
"/knowledge add email | dir\n"
|
||||||
@@ -228,7 +301,7 @@ class AIOS_Shell:
|
|||||||
if error is not None:
|
if error is not None:
|
||||||
return FormattedText([("class:title", f"/knowledge add email failed {error}\n")])
|
return FormattedText([("class:title", f"/knowledge add email failed {error}\n")])
|
||||||
else:
|
else:
|
||||||
KnowledgePipline.get_instance().save_config()
|
KnowledgePipline.get_instance().save_cosnfig()
|
||||||
if args[1] == "dir":
|
if args[1] == "dir":
|
||||||
config = dict()
|
config = dict()
|
||||||
for key, item in KnowledgeDirSource.user_config_items():
|
for key, item in KnowledgeDirSource.user_config_items():
|
||||||
@@ -299,11 +372,19 @@ class AIOS_Shell:
|
|||||||
return show_text
|
return show_text
|
||||||
case 'knowledge':
|
case 'knowledge':
|
||||||
return await self.handle_knowledge_commands(args)
|
return await self.handle_knowledge_commands(args)
|
||||||
|
case 'contact':
|
||||||
|
return await self.handle_contact_commands(args)
|
||||||
case 'open':
|
case 'open':
|
||||||
if len(args) >= 1:
|
if len(args) >= 1:
|
||||||
target_id = args[0]
|
target_id = args[0]
|
||||||
|
else:
|
||||||
|
show_text = FormattedText([("class:error", "/open Need Target Agent/Workflow ID! like /open Jarvis default")])
|
||||||
|
return show_text
|
||||||
|
|
||||||
if len(args) >= 2:
|
if len(args) >= 2:
|
||||||
topic = args[1]
|
topic = args[1]
|
||||||
|
else:
|
||||||
|
topic = "default"
|
||||||
|
|
||||||
self.current_target = target_id
|
self.current_target = target_id
|
||||||
self.current_topic = topic
|
self.current_topic = topic
|
||||||
@@ -382,6 +463,12 @@ async def try_get_input(desc:str,check_func:callable = None) -> str:
|
|||||||
async def get_user_config_from_input(check_result:dict) -> bool:
|
async def get_user_config_from_input(check_result:dict) -> bool:
|
||||||
for key,item in check_result.items():
|
for key,item in check_result.items():
|
||||||
user_input = await try_get_input(f"System config {key} ({item.desc}) not define!")
|
user_input = await try_get_input(f"System config {key} ({item.desc}) not define!")
|
||||||
|
if user_input is None:
|
||||||
|
if item.is_optional:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
True
|
||||||
|
|
||||||
if len(user_input) > 0:
|
if len(user_input) > 0:
|
||||||
AIStorage.get_instance().get_user_config().set_value(key,user_input)
|
AIStorage.get_instance().get_user_config().set_value(key,user_input)
|
||||||
|
|
||||||
@@ -478,6 +565,7 @@ async def main():
|
|||||||
'/history $num $offset',
|
'/history $num $offset',
|
||||||
'/login $username',
|
'/login $username',
|
||||||
'/connect $target',
|
'/connect $target',
|
||||||
|
'/contact $name',
|
||||||
'/knowledge add email | dir',
|
'/knowledge add email | dir',
|
||||||
'/knowledge journal [$topn]',
|
'/knowledge journal [$topn]',
|
||||||
'/knowledge query $query'
|
'/knowledge query $query'
|
||||||
|
|||||||
Reference in New Issue
Block a user