pycityagent 1.0.0__py3-none-any.whl → 1.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycityagent/__init__.py +3 -1
- pycityagent/ac/__init__.py +3 -1
- pycityagent/ac/ac.py +56 -39
- pycityagent/ac/action.py +46 -5
- pycityagent/ac/action_stream.py +25 -0
- pycityagent/ac/citizen_actions/controled.py +16 -0
- pycityagent/ac/citizen_actions/converse.py +34 -0
- pycityagent/ac/citizen_actions/idle.py +20 -0
- pycityagent/ac/citizen_actions/shop.py +82 -0
- pycityagent/ac/citizen_actions/trip.py +41 -0
- pycityagent/ac/hub_actions.py +93 -0
- pycityagent/ac/sim_actions.py +80 -0
- pycityagent/agent.py +97 -143
- pycityagent/agent_citizen.py +158 -0
- pycityagent/agent_func.py +115 -0
- pycityagent/brain/__init__.py +1 -1
- pycityagent/brain/memory.py +200 -106
- pycityagent/brain/sence.py +385 -64
- pycityagent/cc/__init__.py +2 -2
- pycityagent/cc/cc.py +40 -36
- pycityagent/hubconnector/hubconnector.py +23 -31
- pycityagent/image/__init__.py +1 -1
- pycityagent/image/image.py +48 -44
- pycityagent/simulator.py +39 -39
- pycityagent/st/st.py +44 -7
- pycityagent/urbanllm/urbanllm.py +2 -2
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.1.dist-info}/METADATA +47 -19
- pycityagent-1.1.1.dist-info/RECORD +58 -0
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.1.dist-info}/WHEEL +1 -1
- pycityagent-1.0.0.dist-info/RECORD +0 -48
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.1.dist-info}/LICENSE +0 -0
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.1.dist-info}/top_level.txt +0 -0
pycityagent/__init__.py
CHANGED
pycityagent/ac/__init__.py
CHANGED
@@ -2,5 +2,7 @@
|
|
2
2
|
|
3
3
|
from .ac import *
|
4
4
|
from .action import *
|
5
|
+
from .hub_actions import *
|
6
|
+
from .sim_actions import *
|
5
7
|
|
6
|
-
__all__ = [ActionController, Action]
|
8
|
+
__all__ = [ActionController, Action, HubAction, SimAction, SendUserMessage, SendStreetview, SendPop, PositionUpdate, ShowPath, ShowPosition, SetSchedule, SendAgentMessage]
|
pycityagent/ac/ac.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
from typing import Any
|
2
|
-
from .
|
3
|
-
from .
|
4
|
-
from .
|
5
|
-
from .
|
6
|
-
from .
|
1
|
+
from typing import Any, Optional, Union
|
2
|
+
from .action import Action
|
3
|
+
from .citizen_actions.trip import TripAction
|
4
|
+
from .citizen_actions.shop import ShopAction
|
5
|
+
from .citizen_actions.converse import ConverseAction
|
6
|
+
from .citizen_actions.controled import ControledAction
|
7
|
+
from .citizen_actions.idle import IdleAction
|
7
8
|
|
8
9
|
class ActionController:
|
9
10
|
"""
|
@@ -11,40 +12,56 @@ class ActionController:
|
|
11
12
|
Agent Controller: Connect with AppHub and Simulator
|
12
13
|
Note: Actions are predefined. By now, user defined actions are not supported
|
13
14
|
"""
|
14
|
-
def __init__(self, agent
|
15
|
+
def __init__(self, agent) -> None:
|
15
16
|
self._agent = agent
|
16
|
-
self.
|
17
|
-
self.
|
18
|
-
self.
|
19
|
-
self._control = ControledAction(agent)
|
20
|
-
self._idle = IdleAction(agent)
|
21
|
-
self._config = config
|
17
|
+
self.action_chain = {}
|
18
|
+
self.reset_ac()
|
19
|
+
self._init_actions()
|
22
20
|
|
23
21
|
async def Run(self):
|
24
|
-
|
25
|
-
if self.
|
26
|
-
|
27
|
-
|
28
|
-
await self._trip()
|
29
|
-
elif self._agent.state == 'conve':
|
30
|
-
await self._converse()
|
31
|
-
elif self._agent.state == 'shop':
|
32
|
-
await self._shop()
|
33
|
-
elif self._agent.state == 'controled':
|
34
|
-
await self._control()
|
22
|
+
agent_state = self._agent.state
|
23
|
+
if agent_state in self.action_chain.keys():
|
24
|
+
for action in self.action_chain[agent_state]:
|
25
|
+
await action.Forward()
|
35
26
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
27
|
+
def clear_ac(self):
|
28
|
+
"""
|
29
|
+
清空AC
|
30
|
+
"""
|
31
|
+
self.action_chain.clear()
|
32
|
+
|
33
|
+
def reset_ac(self):
|
34
|
+
"""
|
35
|
+
重置Action Controller
|
36
|
+
Reset action controller
|
37
|
+
"""
|
38
|
+
self.action_chain.clear()
|
39
|
+
for state in self._agent._st.machine.states.keys():
|
40
|
+
self.action_chain[state] = []
|
41
|
+
|
42
|
+
def set_ac(self, states:list[str]):
|
43
|
+
"""
|
44
|
+
设置ac
|
45
|
+
"""
|
46
|
+
self.action_chain.clear()
|
47
|
+
for state in states:
|
48
|
+
self.action_chain[state] = []
|
49
|
+
|
50
|
+
def add_actions(self, state:str, actions:Union[Action, list[Action]]):
|
51
|
+
"""
|
52
|
+
添加Action到目标动作链
|
53
|
+
"""
|
54
|
+
if issubclass(type(actions), Action) or isinstance(actions, Action):
|
55
|
+
self.action_chain[state].append(actions)
|
56
|
+
else:
|
57
|
+
self.action_chain[state] += actions
|
58
|
+
|
59
|
+
def _init_actions(self):
|
60
|
+
"""
|
61
|
+
构建初始化动作链——适用于citizen类型的agent
|
62
|
+
"""
|
63
|
+
self.action_chain['trip'] = [TripAction(self._agent)]
|
64
|
+
self.action_chain['shop'] = [ShopAction(self._agent)]
|
65
|
+
self.action_chain['conve'] = [ConverseAction(self._agent)]
|
66
|
+
self.action_chain['controled'] = [ControledAction(self._agent)]
|
67
|
+
self.action_chain['idle'] = [IdleAction(self._agent)]
|
pycityagent/ac/action.py
CHANGED
@@ -1,14 +1,55 @@
|
|
1
1
|
from abc import ABC, abstractclassmethod
|
2
|
-
from typing import Any
|
2
|
+
from typing import Callable, Any
|
3
3
|
|
4
|
+
class ActionType:
|
5
|
+
"""
|
6
|
+
行动类型枚举 所有行动本质上为数据推送
|
7
|
+
Action Type enumeration, all actions are essentially data push
|
8
|
+
|
9
|
+
Types:
|
10
|
+
- Sim = 1, 用于表示与模拟器对接的行动
|
11
|
+
- Hub = 2, 用于表示与AppHub(前端)对接的行动
|
12
|
+
- Comp = 3, 表示综合类型 (可能同时包含与Sim以及Hub的交互)
|
13
|
+
"""
|
14
|
+
Sim = 1
|
15
|
+
Hub = 2
|
16
|
+
Comp = 3
|
4
17
|
class Action:
|
5
|
-
def __init__(self, agent) -> None:
|
6
|
-
'''
|
18
|
+
def __init__(self, agent, type:ActionType, source: str = None, before:Callable[[list], Any] = None) -> None:
|
19
|
+
'''
|
20
|
+
默认初始化
|
21
|
+
|
22
|
+
Args:
|
23
|
+
- agent (Agent): the related agent
|
24
|
+
- type (ActionType)
|
25
|
+
- source (str): 数据来源, 默认为None, 如果为None则会从接收用户传入的数据作为Forward函数参数, 否则从WM.Reason数据缓存中取对应数据作为参数
|
26
|
+
- before (function): 数据处理方法, 用于当Reason缓存中的参数与标准格式不符时使用
|
27
|
+
'''
|
7
28
|
self._agent = agent
|
29
|
+
self._type = type
|
30
|
+
self._source = source
|
31
|
+
self._before = before
|
32
|
+
|
33
|
+
def get_source(self):
|
34
|
+
"""
|
35
|
+
获取source数据
|
36
|
+
"""
|
37
|
+
if self._source != None:
|
38
|
+
source = self._agent.Brain.Memory.Working.Reason[self._source]
|
39
|
+
if self._before != None:
|
40
|
+
source = self._before(source)
|
41
|
+
return source
|
42
|
+
else:
|
43
|
+
return None
|
8
44
|
|
9
45
|
@abstractclassmethod
|
10
46
|
async def Forward(self):
|
11
47
|
'''接口函数'''
|
12
48
|
|
13
|
-
|
14
|
-
|
49
|
+
class SimAction(Action):
|
50
|
+
def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
|
51
|
+
super().__init__(agent, ActionType.Sim, source, before)
|
52
|
+
|
53
|
+
class HubAction(Action):
|
54
|
+
def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
|
55
|
+
super().__init__(agent, ActionType.Hub, source, before)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from abc import ABC, abstractclassmethod
|
2
|
+
from typing import Any, Optional
|
3
|
+
from action import Action
|
4
|
+
|
5
|
+
class ActionStream:
|
6
|
+
"""
|
7
|
+
可以将多个Action聚合在一起构成一个ActionStream, Stream中的Action会顺序执行
|
8
|
+
You can collect multiple Actions into a ActionStream, actions in stream will be activated in sequence
|
9
|
+
注意: 该部分内容目前没有使用
|
10
|
+
"""
|
11
|
+
def __init__(self, actions:Optional[list[Action]]=[]) -> None:
|
12
|
+
self.actions = actions
|
13
|
+
|
14
|
+
def add_actions(self, actions:list[Action]):
|
15
|
+
"""
|
16
|
+
添加Action至当前stream
|
17
|
+
|
18
|
+
Args:
|
19
|
+
- actions (list(Action)): a list of action
|
20
|
+
"""
|
21
|
+
self.actions += actions
|
22
|
+
|
23
|
+
def __call__(self) -> Any:
|
24
|
+
for action in self.actions:
|
25
|
+
action()
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import time
|
2
|
+
from typing import Callable, Any
|
3
|
+
|
4
|
+
from pycityagent.ac.action import ActionType
|
5
|
+
from ..action import Action
|
6
|
+
from pycitysim.apphub import AgentMessage
|
7
|
+
|
8
|
+
class ControledAction(Action):
|
9
|
+
'''Converse行为控制器'''
|
10
|
+
def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
|
11
|
+
super().__init__(agent, ActionType.Comp, sources, before)
|
12
|
+
|
13
|
+
async def Forward(self):
|
14
|
+
req = {'person_id': self._agent._id, 'schedules': []}
|
15
|
+
await self._agent._client.person_service.SetSchedule(req)
|
16
|
+
self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), '我已理解您的意思,正在修改我的行程', None, None)])
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import time
|
2
|
+
from typing import Callable, Any
|
3
|
+
|
4
|
+
from pycityagent.ac.action import ActionType
|
5
|
+
from ..action import Action
|
6
|
+
from pycitysim.apphub import AgentMessage
|
7
|
+
|
8
|
+
class ConverseAction(Action):
|
9
|
+
'''Converse行为控制器'''
|
10
|
+
def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
|
11
|
+
super().__init__(agent, ActionType.Comp, sources, before)
|
12
|
+
|
13
|
+
async def Forward(self):
|
14
|
+
target_agent_ids = self._agent.Brain.Memory.Working.Reason['agent_message_handle_resp'][0]
|
15
|
+
if len(target_agent_ids) == 0:
|
16
|
+
return
|
17
|
+
messages = self._agent.Brain.Memory.Working.Reason['agent_message_handle_resp'][1]
|
18
|
+
req = {'messages': []}
|
19
|
+
if len(target_agent_ids) != len(messages):
|
20
|
+
print("Warning: the number of target agent and message are not aligned, only sends matched messages")
|
21
|
+
rng = min(len(target_agent_ids), len(messages))
|
22
|
+
for i in range(rng):
|
23
|
+
dic = {}
|
24
|
+
dic['from'] = self._agent._id
|
25
|
+
dic['to'] = target_agent_ids[i]
|
26
|
+
dic['message'] = messages[i]
|
27
|
+
req['messages'].append(dic)
|
28
|
+
# * 发送至模拟器
|
29
|
+
await self._agent._client.social_service.Send(req=req)
|
30
|
+
|
31
|
+
# * 发送至AppHub
|
32
|
+
if self._agent.Hub != None and messages[0] != 'End':
|
33
|
+
# * 将信息中的第一条不同至pop
|
34
|
+
self._agent.Hub.Update(pop=messages[0])
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import time
|
2
|
+
from typing import Callable, Any
|
3
|
+
|
4
|
+
from pycityagent.ac.action import ActionType
|
5
|
+
from ..action import Action
|
6
|
+
from pycitysim.apphub import AgentMessage
|
7
|
+
|
8
|
+
class IdleAction(Action):
|
9
|
+
'''idle行为控制器'''
|
10
|
+
def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
|
11
|
+
super().__init__(agent, ActionType.Comp, sources, before)
|
12
|
+
|
13
|
+
async def Forward(self):
|
14
|
+
if len(self._agent.base['schedules']) > 0:
|
15
|
+
req = {'person_id': self._agent._id, 'schedules': []}
|
16
|
+
await self._agent._client.person_service.SetSchedule(req)
|
17
|
+
if self._agent.Hub != None:
|
18
|
+
self._agent.Hub.Update()
|
19
|
+
|
20
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
from typing import Callable, Any
|
2
|
+
from pycityagent.ac.action import ActionType
|
3
|
+
from ..action import Action
|
4
|
+
from pycitysim.apphub import AgentMessage
|
5
|
+
import time
|
6
|
+
|
7
|
+
def encap_msg(msg, role='user', **kwargs):
|
8
|
+
dialog = {'role': role, 'content': msg}
|
9
|
+
dialog.update(kwargs)
|
10
|
+
return dialog
|
11
|
+
|
12
|
+
class ShopAction(Action):
|
13
|
+
'''Shop行为控制器'''
|
14
|
+
def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
|
15
|
+
super().__init__(agent, ActionType.Comp, sources, before)
|
16
|
+
|
17
|
+
async def Forward(self):
|
18
|
+
# * 与模拟器对接 - 暂时没有
|
19
|
+
# * 与AppHub对接
|
20
|
+
profile = self._agent.Image.get_profile()
|
21
|
+
self.consumption(profile)
|
22
|
+
|
23
|
+
def consumption(self, profile, mall_info):
|
24
|
+
dialogs = []
|
25
|
+
system_prompt = f'''
|
26
|
+
你是一个在北京工作和生活的人。
|
27
|
+
{profile}
|
28
|
+
现在是2024年1月。
|
29
|
+
你需要为下一周的基本生活购买必需品。
|
30
|
+
'''
|
31
|
+
dialogs.append(encap_msg(system_prompt, 'system'))
|
32
|
+
actions_format = ['''{{'商品': 购买的商品的列表,'购买量': 每个商品的购买量,一个列表, '解释': '这种购买方式的原因'}}''']
|
33
|
+
actions_candidates = ['''【食品】
|
34
|
+
米:10元/公斤
|
35
|
+
面粉:7.5元/公斤
|
36
|
+
新鲜蔬菜(如菠菜):7元/500克
|
37
|
+
水果(如苹果):15元/公斤
|
38
|
+
猪肉:30元/公斤
|
39
|
+
鸡肉:20元/公斤
|
40
|
+
鸡蛋:1.5元/个
|
41
|
+
牛奶:10元/升''',
|
42
|
+
'''【清洁用品】
|
43
|
+
洗衣液:30元/瓶
|
44
|
+
洗洁精:20元/瓶
|
45
|
+
垃圾袋:0.3元/个''',
|
46
|
+
'''【个人护理用品】
|
47
|
+
牙膏:10元/支
|
48
|
+
洗发水:30元/瓶
|
49
|
+
沐浴露:35元/瓶
|
50
|
+
面巾纸:5元/包''',
|
51
|
+
'''【其他】
|
52
|
+
矿泉水:1.7元/瓶
|
53
|
+
面包:8元/个
|
54
|
+
辣条:3元/包''']
|
55
|
+
|
56
|
+
user_prompt = f'''
|
57
|
+
首先确定你的消费预算。以如下格式回答,不要有冗余的文本!
|
58
|
+
{{'消费预算': 一个代表购买必需品需要消耗的钱的数量的数字}}
|
59
|
+
'''
|
60
|
+
dialogs.append(encap_msg(user_prompt))
|
61
|
+
# * 对接一:确定消费预算
|
62
|
+
self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), '我正在确定消费预算......', None, None)])
|
63
|
+
msg = self._agent._soul.text_request(dialogs)
|
64
|
+
self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), f'我的消费预算是: {msg}'), None, None])
|
65
|
+
|
66
|
+
dialogs.append(encap_msg(msg, 'assistant'))
|
67
|
+
|
68
|
+
# * 对接二:购物选择
|
69
|
+
for cand in actions_candidates:
|
70
|
+
user_prompt = f'''
|
71
|
+
购物中心里有
|
72
|
+
{cand}
|
73
|
+
你要买哪些商品,以如下格式回答,不要有冗余的文本!
|
74
|
+
{actions_format[0]}
|
75
|
+
'''
|
76
|
+
self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), f'我看到了\n {cand}', None, None)])
|
77
|
+
dialogs.append(encap_msg(user_prompt))
|
78
|
+
msg = self._agent._soul.text_request(dialogs)
|
79
|
+
self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), f'我的购买选择是: {msg}', None, None)])
|
80
|
+
dialogs.append(encap_msg(msg, 'assistant'))
|
81
|
+
|
82
|
+
self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), '购物完成', None, None)])
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import time
|
2
|
+
from typing import Callable, Any
|
3
|
+
|
4
|
+
from pycityagent.ac.action import ActionType
|
5
|
+
from ..action import Action
|
6
|
+
from pycitysim.apphub import AgentMessage
|
7
|
+
|
8
|
+
class TripAction(Action):
|
9
|
+
'''Trip行为控制器'''
|
10
|
+
def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
|
11
|
+
super().__init__(agent, ActionType.Comp, sources, before)
|
12
|
+
|
13
|
+
async def Forward(self):
|
14
|
+
now = self._agent.Scheduler.now
|
15
|
+
if now.is_set:
|
16
|
+
# TODO: 目前仅支持传输一张图片至前端
|
17
|
+
'''之前已经将schedule同步至模拟器了'''
|
18
|
+
if self._agent.Hub != None:
|
19
|
+
self._agent.Hub.Update(streetview=self._agent.Brain.Sence.sence_buffer['streetview'][0])
|
20
|
+
else:
|
21
|
+
'''同步schedule至模拟器'''
|
22
|
+
self._agent.Scheduler.now.is_set = True
|
23
|
+
departure_time = now.time
|
24
|
+
mode = now.mode
|
25
|
+
aoi_id = now.target_id_aoi
|
26
|
+
poi_id = now.target_id_poi
|
27
|
+
end = {'aoi_position': {'aoi_id': aoi_id, 'poi_id': poi_id}}
|
28
|
+
activity = now.description
|
29
|
+
trips = [{'mode': mode, 'end': end, 'departure_time': departure_time, 'activity': activity}]
|
30
|
+
set_schedule = [{'trips': trips, 'loop_count': 1, 'departure_time': departure_time}]
|
31
|
+
|
32
|
+
# * 与模拟器对接
|
33
|
+
req = {'person_id': self._agent._id, 'schedules': set_schedule}
|
34
|
+
await self._agent._client.person_service.SetSchedule(req)
|
35
|
+
|
36
|
+
# * 与AppHub对接
|
37
|
+
if self._agent.Hub != None:
|
38
|
+
messages = [AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), f'已到达出发时间, {activity}', None, None)]
|
39
|
+
self._agent.Hub.Update(messages)
|
40
|
+
|
41
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
from typing import Callable, Optional, Any
|
2
|
+
from pycitysim.apphub import AgentMessage
|
3
|
+
from .action import HubAction
|
4
|
+
from PIL.Image import Image
|
5
|
+
|
6
|
+
class SendUserMessage(HubAction):
|
7
|
+
"""
|
8
|
+
发送用户可见信息
|
9
|
+
Send messages to user
|
10
|
+
"""
|
11
|
+
def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
|
12
|
+
super().__init__(agent, source, before)
|
13
|
+
|
14
|
+
async def Forward(self, messages: Optional[list[AgentMessage]] = None):
|
15
|
+
if not messages == None:
|
16
|
+
self._agent.Hub.Update(messages = messages)
|
17
|
+
elif self._source != None:
|
18
|
+
messages = self.get_source()
|
19
|
+
if messages != None:
|
20
|
+
self._agent.Hub.Update(messages = messages)
|
21
|
+
|
22
|
+
class SendStreetview(HubAction):
|
23
|
+
"""
|
24
|
+
发送街景图片至前端
|
25
|
+
Send streetview to frontend
|
26
|
+
"""
|
27
|
+
def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
|
28
|
+
super().__init__(agent, source, before)
|
29
|
+
|
30
|
+
async def Forward(self, images: Optional[list[Image]] = None):
|
31
|
+
# TODO: 目前只支持发送一张图片
|
32
|
+
if not images == None:
|
33
|
+
self._agent.Hub.Update(streetview = images[0])
|
34
|
+
elif self._source != None:
|
35
|
+
images = self.get_source()
|
36
|
+
if images != None:
|
37
|
+
self._agent.Hub.Update(streetview = images[0])
|
38
|
+
|
39
|
+
class SendPop(HubAction):
|
40
|
+
"""
|
41
|
+
发送Pop信息 - agent头顶气泡信息
|
42
|
+
Send pop message to frontend, pop message shows above the target agent
|
43
|
+
"""
|
44
|
+
def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
|
45
|
+
super().__init__(agent, source, before)
|
46
|
+
|
47
|
+
async def Forward(self, pop:Optional[str] = None):
|
48
|
+
if not pop == None:
|
49
|
+
self._agent.Hub.Update(pop = pop)
|
50
|
+
elif self._source != None:
|
51
|
+
pop = self.get_source()
|
52
|
+
if pop != None:
|
53
|
+
self._agent.Hub.Update(pop = pop)
|
54
|
+
|
55
|
+
class PositionUpdate(HubAction):
|
56
|
+
"""
|
57
|
+
同步当前agent的位置信息
|
58
|
+
Send the position of current agent to frontend
|
59
|
+
"""
|
60
|
+
def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
|
61
|
+
super().__init__(agent, source, before)
|
62
|
+
|
63
|
+
async def Forward(self, longlat: Optional[list[float]] = None):
|
64
|
+
if longlat != None:
|
65
|
+
self._agent.Hub.Update(longlat = longlat)
|
66
|
+
elif self._source != None:
|
67
|
+
longlat = self.get_source()
|
68
|
+
if longlat != None:
|
69
|
+
self._agent.Hub.Update(longlat = longlat)
|
70
|
+
|
71
|
+
class ShowPath(HubAction):
|
72
|
+
"""
|
73
|
+
在地图上展示路径信息
|
74
|
+
Show a path in frontend map
|
75
|
+
"""
|
76
|
+
def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
|
77
|
+
super().__init__(agent, source, before)
|
78
|
+
|
79
|
+
async def Forward(self):
|
80
|
+
# TODO: 相关功能完善
|
81
|
+
pass
|
82
|
+
|
83
|
+
class ShowPosition(HubAction):
|
84
|
+
"""
|
85
|
+
在地图上展示特定地点
|
86
|
+
Show a position in frontend map
|
87
|
+
"""
|
88
|
+
def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
|
89
|
+
super().__init__(agent, source, before)
|
90
|
+
|
91
|
+
async def Forward(self):
|
92
|
+
# TODO: 相关功能完善
|
93
|
+
pass
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import time
|
2
|
+
from typing import Callable, Optional, Any
|
3
|
+
from .action import SimAction
|
4
|
+
from ..brain.scheduler import TripSchedule
|
5
|
+
|
6
|
+
class SetSchedule(SimAction):
|
7
|
+
"""
|
8
|
+
用于将agent的行程信息同步至模拟器 —— 仅对citizen类型agent适用
|
9
|
+
Synchronize agent's schedule to simulator —— only avalable for citizen type of agent
|
10
|
+
"""
|
11
|
+
def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
|
12
|
+
super().__init__(agent, sources, before)
|
13
|
+
|
14
|
+
async def Forward(self, schedule: Optional[TripSchedule] = None):
|
15
|
+
"""
|
16
|
+
如果当前行程已经同步至模拟器: 跳过同步, 否则同步至模拟器
|
17
|
+
If current schedule has been synchronized to simulator: skip, else sync
|
18
|
+
"""
|
19
|
+
if not schedule == None:
|
20
|
+
if not schedule.is_set:
|
21
|
+
'''同步schedule至模拟器'''
|
22
|
+
self._agent.Scheduler.now.is_set = True
|
23
|
+
departure_time = schedule.time
|
24
|
+
mode = schedule.mode
|
25
|
+
aoi_id = schedule.target_id_aoi
|
26
|
+
poi_id = schedule.target_id_poi
|
27
|
+
end = {'aoi_position': {'aoi_id': aoi_id, 'poi_id': poi_id}}
|
28
|
+
activity = schedule.description
|
29
|
+
trips = [{'mode': mode, 'end': end, 'departure_time': departure_time, 'activity': activity}]
|
30
|
+
set_schedule = [{'trips': trips, 'loop_count': 1, 'departure_time': departure_time}]
|
31
|
+
|
32
|
+
# * 与模拟器对接
|
33
|
+
req = {'person_id': self._agent._id, 'schedules': set_schedule}
|
34
|
+
await self._agent._client.person_service.SetSchedule(req)
|
35
|
+
elif self._source != None:
|
36
|
+
schedule = self.get_source()
|
37
|
+
if schedule != None and not schedule.is_set:
|
38
|
+
'''同步schedule至模拟器'''
|
39
|
+
self._agent.Scheduler.now.is_set = True
|
40
|
+
departure_time = schedule.time
|
41
|
+
mode = schedule.mode
|
42
|
+
aoi_id = schedule.target_id_aoi
|
43
|
+
poi_id = schedule.target_id_poi
|
44
|
+
end = {'aoi_position': {'aoi_id': aoi_id, 'poi_id': poi_id}}
|
45
|
+
activity = schedule.description
|
46
|
+
trips = [{'mode': mode, 'end': end, 'departure_time': departure_time, 'activity': activity}]
|
47
|
+
set_schedule = [{'trips': trips, 'loop_count': 1, 'departure_time': departure_time}]
|
48
|
+
|
49
|
+
# * 与模拟器对接
|
50
|
+
req = {'person_id': self._agent._id, 'schedules': set_schedule}
|
51
|
+
await self._agent._client.person_service.SetSchedule(req)
|
52
|
+
|
53
|
+
|
54
|
+
class SendAgentMessage(SimAction):
|
55
|
+
"""
|
56
|
+
发送信息给其他agent
|
57
|
+
Send messages to other agents
|
58
|
+
"""
|
59
|
+
def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
|
60
|
+
super().__init__(agent, sources, before)
|
61
|
+
|
62
|
+
async def Forward(self, messages: Optional[dict] = None):
|
63
|
+
if not messages == None and len(messages) > 0:
|
64
|
+
req = {'messages': []}
|
65
|
+
for message in messages:
|
66
|
+
from_id = self._agent._id
|
67
|
+
to_id = message['id']
|
68
|
+
mes = message['message']
|
69
|
+
req['messages'].append({'from': from_id, 'to': to_id, 'message': mes})
|
70
|
+
await self._agent._client.social_service.Send(req)
|
71
|
+
elif self._source != None:
|
72
|
+
messages = self.get_source()
|
73
|
+
if not messages == None and len(messages) > 0:
|
74
|
+
req = {'messages': []}
|
75
|
+
for message in messages:
|
76
|
+
from_id = self._agent._id
|
77
|
+
to_id = message['id']
|
78
|
+
mes = message['message']
|
79
|
+
req['messages'].append({'from': from_id, 'to': to_id, 'message': mes})
|
80
|
+
await self._agent._client.social_service.Send(req)
|