pycityagent 1.1.10__py3-none-any.whl → 1.1.11__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 +2 -1
- pycityagent/ac/citizen_actions/trip.py +2 -3
- pycityagent/ac/hub_actions.py +216 -16
- pycityagent/agent.py +2 -0
- pycityagent/agent_citizen.py +10 -2
- pycityagent/agent_func.py +16 -11
- pycityagent/agent_group.py +84 -0
- pycityagent/brain/brain.py +1 -0
- pycityagent/brain/memory.py +15 -15
- pycityagent/brain/scheduler.py +1 -1
- pycityagent/brain/sence.py +73 -63
- pycityagent/hubconnector/__init__.py +1 -1
- pycityagent/hubconnector/hubconnector.py +353 -8
- pycityagent/simulator.py +149 -7
- pycityagent/urbanllm/urbanllm.py +304 -4
- pycityagent/utils.py +34 -4
- {pycityagent-1.1.10.dist-info → pycityagent-1.1.11.dist-info}/METADATA +11 -11
- {pycityagent-1.1.10.dist-info → pycityagent-1.1.11.dist-info}/RECORD +21 -20
- {pycityagent-1.1.10.dist-info → pycityagent-1.1.11.dist-info}/WHEEL +1 -1
- {pycityagent-1.1.10.dist-info → pycityagent-1.1.11.dist-info}/LICENSE +0 -0
- {pycityagent-1.1.10.dist-info → pycityagent-1.1.11.dist-info}/top_level.txt +0 -0
pycityagent/brain/sence.py
CHANGED
@@ -25,7 +25,6 @@ class SencePlug:
|
|
25
25
|
- out (str): the output target in sence, the sence result will be insert to Sence.plug_buffer[out]
|
26
26
|
"""
|
27
27
|
def __init__(self, user_func, out:str) -> None:
|
28
|
-
# TODO: 添加合法性检查
|
29
28
|
self.user_func = user_func
|
30
29
|
self.out = out
|
31
30
|
|
@@ -144,10 +143,15 @@ class Sence(BrainFunction):
|
|
144
143
|
self.sence_buffer['time'] = self._agent._simulator.time
|
145
144
|
|
146
145
|
# * pois
|
147
|
-
if self._sence_contents == None or 'poi' in self._sence_contents:
|
148
|
-
self.
|
149
|
-
|
150
|
-
|
146
|
+
if self._sence_contents == None or 'poi' in self._sence_contents or 'poi_verbose' in self._sence_contents:
|
147
|
+
if self._sence_contents == None:
|
148
|
+
self.sence_buffer['pois'] = await self.PerceivePoi()
|
149
|
+
elif 'poi_verbose' in self._sence_contents:
|
150
|
+
self.sence_buffer['pois'] = await self.PerceivePoi_Verbose()
|
151
|
+
self.sence_buffer['poi_time_walk'] = sorted(self.sence_buffer['pois'], key=lambda x:x[2])
|
152
|
+
self.sence_buffer['poi_time_drive'] = sorted(self.sence_buffer['pois'], key=lambda x:x[4])
|
153
|
+
else:
|
154
|
+
self.sence_buffer['pois'] = await self.PerceivePoi()
|
151
155
|
|
152
156
|
# * reachable positions
|
153
157
|
if self._sence_contents == None or 'position' in self._sence_contents:
|
@@ -172,7 +176,7 @@ class Sence(BrainFunction):
|
|
172
176
|
|
173
177
|
# * streetview
|
174
178
|
if self._sence_contents == None or 'streetview' in self._sence_contents:
|
175
|
-
if self.enable_streeview:
|
179
|
+
if self.enable_streeview and 'lane_position' in self._agent.motion['position'].keys():
|
176
180
|
self.sence_buffer['streetview'] = self.PerceiveStreetView()
|
177
181
|
else:
|
178
182
|
self.sence_buffer['streetview'] = None
|
@@ -185,15 +189,15 @@ class Sence(BrainFunction):
|
|
185
189
|
self.sence_buffer['user_messages'] = []
|
186
190
|
|
187
191
|
# * agent message
|
188
|
-
if self._sence_contents == None or 'agent_message' in self._sence_contents:
|
189
|
-
|
192
|
+
# if self._sence_contents == None or 'agent_message' in self._sence_contents:
|
193
|
+
# self.sence_buffer['social_messages'] = await self.PerceiveMessageFromPerson()
|
190
194
|
|
191
195
|
# * 插件感知
|
192
|
-
if len(self.plugs) > 0:
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
196
|
+
# if len(self.plugs) > 0:
|
197
|
+
# for plug in self.plugs:
|
198
|
+
# out_key = plug.out
|
199
|
+
# out = plug.user_func(self.sence_buffer)
|
200
|
+
# self.plug_buffer[out_key] = out
|
197
201
|
|
198
202
|
# * AOI and POI Related
|
199
203
|
async def PerceiveAoi(self, only_person:bool=False):
|
@@ -350,11 +354,45 @@ class Sence(BrainFunction):
|
|
350
354
|
'longlat': longlat,
|
351
355
|
'type': type}]
|
352
356
|
return positions
|
353
|
-
|
357
|
+
|
354
358
|
async def PerceivePoi(self, radius:int=None, category:str=None):
|
355
359
|
"""
|
356
360
|
POI感知
|
357
361
|
Sence POI
|
362
|
+
Args:
|
363
|
+
- radius: 感知范围, 默认使用统一感知半径. Sence raduis, default use basic radius
|
364
|
+
- category: 6位数字类型编码, 如果为None则获取所有类型POI. 6-digit coding which represents the poi type, if None, then sence all type of poi
|
365
|
+
Returns:
|
366
|
+
- List[Tuple[Any, float]]: poi列表, 每个元素为(poi, 距离). poi list, each element is (poi, distance).
|
367
|
+
"""
|
368
|
+
radius_ = self._sence_radius
|
369
|
+
if radius != None:
|
370
|
+
radius_ = radius
|
371
|
+
if category != None:
|
372
|
+
category_prefix = category
|
373
|
+
resp = self._agent._simulator.map.query_pois(
|
374
|
+
center=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
375
|
+
radius=radius_,
|
376
|
+
category_prefix=category_prefix
|
377
|
+
)
|
378
|
+
else:
|
379
|
+
resp = []
|
380
|
+
for category_prefix in LEVEL_ONE_PRE:
|
381
|
+
resp += self._agent._simulator.map.query_pois(
|
382
|
+
center=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
383
|
+
radius=radius_,
|
384
|
+
category_prefix=category_prefix
|
385
|
+
)
|
386
|
+
# * 从六位代码转变为具体类型
|
387
|
+
for poi in resp:
|
388
|
+
cate_str = poi[0]['category']
|
389
|
+
poi[0]['category'] = POI_TYPE_DICT[cate_str]
|
390
|
+
return resp
|
391
|
+
|
392
|
+
async def PerceivePoi_Verbose(self, radius:int=None, category:str=None):
|
393
|
+
"""
|
394
|
+
POI感知
|
395
|
+
Sence POI
|
358
396
|
|
359
397
|
Args:
|
360
398
|
- radius: 感知范围, 默认使用统一感知半径. Sence raduis, default use basic radius
|
@@ -494,9 +532,6 @@ class Sence(BrainFunction):
|
|
494
532
|
# * StreetView Related
|
495
533
|
def PerceiveStreetView(
|
496
534
|
self,
|
497
|
-
# engine:str="baidumap",
|
498
|
-
heading:str="front",
|
499
|
-
save:bool=False,
|
500
535
|
save_dir:str=None
|
501
536
|
):
|
502
537
|
"""
|
@@ -524,52 +559,27 @@ class Sence(BrainFunction):
|
|
524
559
|
|
525
560
|
coords = [(self._agent.motion['position']['longlat_position']['longitude'], self._agent.motion['position']['longlat_position']['latitude'])]
|
526
561
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
sv.panorama.save("{}/{}_{}_panorama_{}.jpg".format(save_dir, self._agent.name, date_time))
|
549
|
-
for i in range(len(persp)):
|
550
|
-
persp[i].save("{}/{}_{}_persp_{}.jpg".format(save_dir, self._agent.name, date_time, i))
|
551
|
-
return persp
|
552
|
-
elif self._engine == "googlemap":
|
553
|
-
sv = GoogleStreetView.search(
|
554
|
-
points[0][0],
|
555
|
-
points[0][1],
|
556
|
-
proxies=self._googleProxy,
|
557
|
-
cache_dir=save_dir
|
558
|
-
)
|
559
|
-
eq = Equirectangular(sv)
|
560
|
-
persp = eq.get_perspective(120, heading_direction, 20, 256, 512)
|
561
|
-
if save:
|
562
|
-
date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
563
|
-
sv.panorama.save("{}/{}_{}_panorama_{}.jpg".format(save_dir, self._agent.name, date_time))
|
564
|
-
for i in range(len(persp)):
|
565
|
-
persp[i].save("{}/{}_{}_persp_{}.jpg".format(save_dir, self._agent.name, date_time, i))
|
566
|
-
return persp
|
567
|
-
|
568
|
-
# * Person Related
|
569
|
-
def PerceivePersonCircule(self, raduis=30):
|
570
|
-
"""Person环形感知"""
|
571
|
-
print("Not Implemented")
|
572
|
-
pass
|
562
|
+
heading_direction = self._agent.motion['direction']
|
563
|
+
try:
|
564
|
+
if self._engine == "baidumap":
|
565
|
+
points = wgs842bd09mc(coords, self._baiduAK)
|
566
|
+
sv = BaiduStreetView.search(points[0][0], points[0][1])
|
567
|
+
eq = Equirectangular(sv)
|
568
|
+
persp = eq.get_perspective(120, heading_direction, 0, 300, 2100)
|
569
|
+
return persp
|
570
|
+
elif self._engine == "googlemap":
|
571
|
+
sv = GoogleStreetView.search(
|
572
|
+
points[0][0],
|
573
|
+
points[0][1],
|
574
|
+
proxies=self._googleProxy,
|
575
|
+
cache_dir=save_dir
|
576
|
+
)
|
577
|
+
eq = Equirectangular(sv)
|
578
|
+
persp = eq.get_perspective(120, heading_direction, 0, 300, 2100)
|
579
|
+
return persp
|
580
|
+
except Exception as e:
|
581
|
+
print(f"Can't get streetview, error message: {e}")
|
582
|
+
return []
|
573
583
|
|
574
584
|
async def PerceivePersonInLanes(self, lane_ids:list[int], only_id:bool=False):
|
575
585
|
"""
|
@@ -1,10 +1,332 @@
|
|
1
1
|
"""Apphub客户端定义"""
|
2
2
|
|
3
|
+
import base64
|
4
|
+
from dataclasses import dataclass
|
5
|
+
from io import BytesIO
|
6
|
+
from typing import Any, Dict, Optional, List
|
7
|
+
|
8
|
+
import requests
|
9
|
+
from requests.auth import HTTPBasicAuth
|
3
10
|
from typing import Optional
|
4
11
|
import geojson
|
5
|
-
from
|
12
|
+
from geojson import Feature, FeatureCollection, Point, LineString
|
6
13
|
import PIL.Image as Image
|
7
|
-
import
|
14
|
+
import time
|
15
|
+
|
16
|
+
__all__ = ["HubConnector", "AppHubClient", "AgentMessage", "UserMessage", "Waypoint"]
|
17
|
+
|
18
|
+
def _image2base64(image: Image) -> str:
|
19
|
+
buffered = BytesIO()
|
20
|
+
image.save(buffered, format="PNG")
|
21
|
+
return base64.b64encode(buffered.getvalue()).decode("utf-8")
|
22
|
+
|
23
|
+
@dataclass
|
24
|
+
class AgentMessage:
|
25
|
+
id: int
|
26
|
+
"""
|
27
|
+
发送者Agent ID
|
28
|
+
Agent ID of sender
|
29
|
+
"""
|
30
|
+
timestamp: int
|
31
|
+
"""
|
32
|
+
消息时间戳(单位:毫秒)
|
33
|
+
Message timestamp (milliseconds)
|
34
|
+
"""
|
35
|
+
content: str
|
36
|
+
"""
|
37
|
+
消息内容
|
38
|
+
Message content
|
39
|
+
"""
|
40
|
+
images: Optional[List[Image.Image]]
|
41
|
+
"""
|
42
|
+
消息图片
|
43
|
+
Message images
|
44
|
+
"""
|
45
|
+
sub_messages: Optional[List["AgentMessage"]]
|
46
|
+
|
47
|
+
def to_dict(self):
|
48
|
+
d = {
|
49
|
+
"id": self.id,
|
50
|
+
"timestamp": self.timestamp,
|
51
|
+
"content": self.content,
|
52
|
+
}
|
53
|
+
if self.images is not None:
|
54
|
+
d["images"] = [_image2base64(image) for image in self.images]
|
55
|
+
if self.sub_messages is not None:
|
56
|
+
d["subMessages"] = [message.to_dict() for message in self.sub_messages]
|
57
|
+
return d
|
58
|
+
|
59
|
+
@dataclass
|
60
|
+
class Waypoint:
|
61
|
+
lnglat: List[float]
|
62
|
+
"""
|
63
|
+
坐标位置
|
64
|
+
"""
|
65
|
+
|
66
|
+
t: int
|
67
|
+
"""
|
68
|
+
时间
|
69
|
+
"""
|
70
|
+
|
71
|
+
|
72
|
+
@dataclass
|
73
|
+
class UserMessage:
|
74
|
+
id: int
|
75
|
+
"""
|
76
|
+
发送者User ID对应的Agent ID
|
77
|
+
Agent ID corresponding to the sender User ID
|
78
|
+
"""
|
79
|
+
timestamp: int
|
80
|
+
"""
|
81
|
+
消息时间戳(单位:毫秒)
|
82
|
+
Message timestamp (milliseconds)
|
83
|
+
"""
|
84
|
+
content: str
|
85
|
+
"""
|
86
|
+
消息内容
|
87
|
+
Message content
|
88
|
+
"""
|
89
|
+
|
90
|
+
|
91
|
+
class AppHubClient:
|
92
|
+
"""
|
93
|
+
AppHub客户端
|
94
|
+
AppHub client
|
95
|
+
|
96
|
+
# 操作流程
|
97
|
+
# Operating procedures
|
98
|
+
|
99
|
+
1. 初始化AppHubClient,填入从前端获得的app_id和app_secret
|
100
|
+
1. Initialize AppHubClient, fill in the app_id and app_secret obtained from the front end
|
101
|
+
2. 调用bind_person/bind_org绑定模拟器内的人,获得agent_id
|
102
|
+
2. Call bind_person/bind_org to bind the person in the simulator, and obtain the agent_id
|
103
|
+
3. 调用update_agent_map更新agent的地图内容,以改变agent在地图上的显示
|
104
|
+
3. Call update_agent_map to update the agent's map content, to change the agent's display on the map
|
105
|
+
4. 调用update_agent_messages更新agent的消息内容,以改变agent的消息内容
|
106
|
+
4. Call update_agent_messages to update the agent's message content, to change the agent's message content
|
107
|
+
5. 定期调用fetch_user_message获取用户发送给agent的消息,并进行处理
|
108
|
+
5. Call fetch_user_message regularly to obtain the messages sent by the user to the agent, and process them
|
109
|
+
6. 如果不再使用agent,调用release_agent释放agent,以允许其他app绑定
|
110
|
+
6. If the agent is no longer used, call release_agent to release the agent to allow other apps to bind.
|
111
|
+
"""
|
112
|
+
|
113
|
+
def __init__(
|
114
|
+
self,
|
115
|
+
app_hub_url: str,
|
116
|
+
app_id: int,
|
117
|
+
app_secret: str,
|
118
|
+
proxies: Optional[dict] = None,
|
119
|
+
):
|
120
|
+
"""
|
121
|
+
Args:
|
122
|
+
- app_id: app ID,从前端注册页面获取。app ID, obtained from the frontend registration page.
|
123
|
+
- app_secret: app secret,从前端注册页面获取。app secret, obtained from the frontend registration page.
|
124
|
+
"""
|
125
|
+
self.app_hub_url = app_hub_url
|
126
|
+
self.app_id = app_id
|
127
|
+
self.app_secret = app_secret
|
128
|
+
self.proxies = proxies
|
129
|
+
self.agents = {} # agent_id -> agent (bind body)
|
130
|
+
|
131
|
+
self._auth = HTTPBasicAuth(str(app_id), app_secret)
|
132
|
+
|
133
|
+
def _bind(self, foreign_id: int | None, type: str, name: str, avatar: Image) -> int:
|
134
|
+
if foreign_id == None:
|
135
|
+
foreign_id_ = -1
|
136
|
+
else:
|
137
|
+
foreign_id_ = foreign_id
|
138
|
+
body = {
|
139
|
+
"type": type,
|
140
|
+
"name": name,
|
141
|
+
"avatar": _image2base64(avatar),
|
142
|
+
"foreignID": foreign_id_,
|
143
|
+
}
|
144
|
+
res = requests.post(
|
145
|
+
self.app_hub_url + "/agents",
|
146
|
+
json=body,
|
147
|
+
auth=self._auth,
|
148
|
+
proxies=self.proxies,
|
149
|
+
timeout=5000
|
150
|
+
)
|
151
|
+
if res.status_code != 200:
|
152
|
+
raise Exception(f"[{res.status_code}] AppHub bind failed: " + res.text)
|
153
|
+
data = res.json()
|
154
|
+
agent_id = data["data"]["id"]
|
155
|
+
self.agents[agent_id] = body
|
156
|
+
return agent_id
|
157
|
+
|
158
|
+
def bind_person(self, person_id: int, name: str, avatar: Image):
|
159
|
+
"""
|
160
|
+
绑定模拟器内的人,只有绑定的person才能被访问
|
161
|
+
Bind person in the simulator. Only bound person can be accessed
|
162
|
+
|
163
|
+
Args:
|
164
|
+
- person_id: 模拟器内的人的ID。The ID of the person in the simulator.
|
165
|
+
- name: 人的名字(前端显示)。Person's name (displayed on the front end).
|
166
|
+
- avatar: 人的头像(前端显示)。Person's avatar (displayed on the front end).
|
167
|
+
|
168
|
+
Returns:
|
169
|
+
- agent_id: 绑定后的agent ID。the bound agent ID.
|
170
|
+
|
171
|
+
Raises:
|
172
|
+
- Exception: 绑定失败。Binding failed.
|
173
|
+
"""
|
174
|
+
return self._bind(person_id, "person", name, avatar)
|
175
|
+
|
176
|
+
def bind_org(self, org_id: int, name: str, avatar: Image):
|
177
|
+
"""
|
178
|
+
绑定模拟器内的组织,只有绑定的org才能被访问
|
179
|
+
Bind the organization in the simulator. Only the bound org can be accessed
|
180
|
+
|
181
|
+
Args:
|
182
|
+
- org_id: 模拟器内的组织的ID。ID of the organization in the simulator
|
183
|
+
- name: 组织的名字(前端显示)。Organization's name (displayed on the front end).
|
184
|
+
- avatar: 组织的头像(前端显示)。Organization's avatar (displayed on the front end).
|
185
|
+
|
186
|
+
Returns:
|
187
|
+
- agent_id: 绑定后的agent ID。the bound agent ID.
|
188
|
+
|
189
|
+
Raises:
|
190
|
+
- Exception: 绑定失败。Binding failed.
|
191
|
+
"""
|
192
|
+
return self._bind(org_id, "org", name, avatar)
|
193
|
+
|
194
|
+
def bind_func(self, name:str, avatar:Image):
|
195
|
+
"""
|
196
|
+
插入非模拟器相关的智能体——func类型智能体
|
197
|
+
|
198
|
+
Args:
|
199
|
+
- func_id (str): 该智能体的编号——唯一
|
200
|
+
- name (str): 该智能体的名字
|
201
|
+
- avatar (Image): 该智能体的头像
|
202
|
+
"""
|
203
|
+
return self._bind(None, "func", name, avatar)
|
204
|
+
|
205
|
+
def release_agent(self, agent_id: int) -> bool:
|
206
|
+
"""
|
207
|
+
释放agent(person/org), 释放后agent将不再被访问并允许其他app绑定
|
208
|
+
Release the agent (person/org). After the release, the agent will no longer be accessed and allows other apps to bind.
|
209
|
+
|
210
|
+
Args:
|
211
|
+
- agent_id: agent的ID。ID of the agent.
|
212
|
+
|
213
|
+
Returns:
|
214
|
+
- bool: 是否成功。whether succeed.
|
215
|
+
"""
|
216
|
+
res = requests.delete(
|
217
|
+
self.app_hub_url + "/agents/" + str(agent_id),
|
218
|
+
auth=self._auth,
|
219
|
+
proxies=self.proxies,
|
220
|
+
timeout=5000
|
221
|
+
)
|
222
|
+
return res.status_code == 200
|
223
|
+
|
224
|
+
def update_agent_map(
|
225
|
+
self,
|
226
|
+
agent_id: int,
|
227
|
+
lnglat: List[float],
|
228
|
+
geojsons: Optional[geojson.FeatureCollection] = None,
|
229
|
+
street_view: Optional[Image.Image] = None,
|
230
|
+
direction: Optional[float] = None,
|
231
|
+
popup: Optional[str] = None,
|
232
|
+
waypoints: Optional[List[Waypoint]] = None,
|
233
|
+
):
|
234
|
+
"""
|
235
|
+
更新agent的地图内容
|
236
|
+
Update the agent’s map content
|
237
|
+
|
238
|
+
Args:
|
239
|
+
- agent_id: agent的ID。ID of the agent.
|
240
|
+
- lnglat: 经纬度,格式为 [lng, lat]。Latitude and longitude in [lng, lat].
|
241
|
+
- geojsons: geojson FeatureCollection,用于在地图上显示点线面。geojson FeatureCollection, used to display points, lines and polygons on the map.
|
242
|
+
- street_view: 街景图片。Street view images.
|
243
|
+
- popup: 弹出框内容。Pop-up box content.
|
244
|
+
|
245
|
+
Raises:
|
246
|
+
- Exception: 更新失败。Updating failed.
|
247
|
+
"""
|
248
|
+
|
249
|
+
body: Dict[str, Any] = {
|
250
|
+
"lnglat": lnglat,
|
251
|
+
}
|
252
|
+
if geojsons is not None:
|
253
|
+
body["geojsons"] = geojsons
|
254
|
+
if street_view is not None:
|
255
|
+
body["streetView"] = _image2base64(street_view)
|
256
|
+
if direction is not None:
|
257
|
+
body["direction"] = direction
|
258
|
+
if popup is not None:
|
259
|
+
body["popup"] = popup
|
260
|
+
if waypoints is not None:
|
261
|
+
body["waypoints"] = [{'lnglat': wp.lnglat, 't': wp.t} for wp in waypoints]
|
262
|
+
waypoints[0].lnglat
|
263
|
+
|
264
|
+
res = requests.put(
|
265
|
+
self.app_hub_url + "/agents/" + str(agent_id) + "/map",
|
266
|
+
json=body,
|
267
|
+
auth=self._auth,
|
268
|
+
proxies=self.proxies,
|
269
|
+
timeout=5000
|
270
|
+
)
|
271
|
+
if res.status_code != 200:
|
272
|
+
raise Exception(
|
273
|
+
f"[{res.status_code}] AppHub update map failed: " + res.text
|
274
|
+
)
|
275
|
+
|
276
|
+
def update_agent_messages(self, agent_id: int, messages: List[AgentMessage]):
|
277
|
+
"""
|
278
|
+
更新agent的消息
|
279
|
+
Update agent's messages
|
280
|
+
|
281
|
+
Args:
|
282
|
+
- agent_id: agent的ID。ID of the agent.
|
283
|
+
- messages: 消息列表(注意顺序,最新的消息在最后)。Message list (note the order, the latest message at the end).
|
284
|
+
|
285
|
+
Raises:
|
286
|
+
- Exception: 更新失败。Updating failed.
|
287
|
+
"""
|
288
|
+
res = requests.put(
|
289
|
+
self.app_hub_url + "/agents/" + str(agent_id) + "/messages",
|
290
|
+
json={"messages": [message.to_dict() for message in messages]},
|
291
|
+
auth=self._auth,
|
292
|
+
proxies=self.proxies,
|
293
|
+
timeout=5000
|
294
|
+
)
|
295
|
+
if res.status_code != 200:
|
296
|
+
raise Exception(
|
297
|
+
f"[{res.status_code}] AppHub update messages failed: " + res.text
|
298
|
+
)
|
299
|
+
|
300
|
+
def fetch_user_messages(
|
301
|
+
self,
|
302
|
+
agent_id: int,
|
303
|
+
) -> List[UserMessage]:
|
304
|
+
"""
|
305
|
+
获取用户发送给agent的消息
|
306
|
+
Fetch the message sent by the user to the agent
|
307
|
+
|
308
|
+
Args:
|
309
|
+
- agent_id: agent的ID。ID of the agent.
|
310
|
+
|
311
|
+
Returns:
|
312
|
+
- messages: 消息列表。Message list.
|
313
|
+
|
314
|
+
Raises:
|
315
|
+
- Exception: 获取失败。Fetching failed.
|
316
|
+
"""
|
317
|
+
res = requests.post(
|
318
|
+
self.app_hub_url + "/agents/" + str(agent_id) + "/fetch-user-messages",
|
319
|
+
auth=self._auth,
|
320
|
+
proxies=self.proxies,
|
321
|
+
timeout=5000
|
322
|
+
)
|
323
|
+
if res.status_code != 200:
|
324
|
+
raise Exception(
|
325
|
+
f"[{res.status_code}] AppHub fetch messages failed: " + res.text
|
326
|
+
)
|
327
|
+
data = res.json()
|
328
|
+
return [UserMessage(**message) for message in data["data"]]
|
329
|
+
|
8
330
|
|
9
331
|
class HubConnector:
|
10
332
|
"""
|
@@ -62,12 +384,11 @@ class HubConnector:
|
|
62
384
|
Insert the Func Agent to AppHub
|
63
385
|
"""
|
64
386
|
self._agent_id = self._client.bind_func(
|
65
|
-
self._agent._id,
|
66
387
|
self._agent._name,
|
67
388
|
Image.open(self._profile_img)
|
68
389
|
)
|
69
390
|
|
70
|
-
def Update(self, messages:Optional[list[AgentMessage]]=None, streetview:Image
|
391
|
+
def Update(self, messages:Optional[list[AgentMessage]]=None, streetview:Image=None, longlat:list[float]=None, pop:str=None):
|
71
392
|
"""
|
72
393
|
交互更新
|
73
394
|
FrontEnd Related Update
|
@@ -79,7 +400,7 @@ class HubConnector:
|
|
79
400
|
- messages (Optional[list[AgentMessage]]):
|
80
401
|
- 需要传递到前端侧边栏的消息. Messsages that will be shown in the message bar in frontend
|
81
402
|
- 默认为None(即当前无需传递消息). Default: None(i.e. No new messages need to be shown in frontend)
|
82
|
-
- streetview (PIL.Image.Image):
|
403
|
+
- streetview (list[PIL.Image.Image]):
|
83
404
|
- 街景图片. Streetview Image
|
84
405
|
- 默认为None(即本次更新不展示街景). Default: None(i.e. No streetview in this update)
|
85
406
|
- longlat (list(float)):
|
@@ -93,19 +414,27 @@ class HubConnector:
|
|
93
414
|
print("AppHub: Not Bind Agent Yet")
|
94
415
|
return
|
95
416
|
else:
|
96
|
-
pop_ =
|
417
|
+
pop_ = None
|
97
418
|
if pop != None:
|
98
419
|
pop_ = self._agent.agent_name + ": " + pop
|
99
420
|
if longlat != None:
|
100
421
|
longlat_ = longlat
|
422
|
+
t_size = len(self._agent._history_trajectory)
|
423
|
+
self._agent._history_trajectory.append(Waypoint([longlat[0], longlat[1]], t_size*5000))
|
101
424
|
else:
|
102
425
|
longlat_ = [self._agent.motion['position']['longlat_position']['longitude'], self._agent.motion['position']['longlat_position']['latitude']]
|
103
|
-
|
426
|
+
|
427
|
+
if 'direction' in self._agent.motion.keys():
|
428
|
+
direction = self._agent.motion['direction']
|
429
|
+
else:
|
430
|
+
direction = None
|
104
431
|
self._client.update_agent_map(
|
105
432
|
agent_id = self._agent_id,
|
106
433
|
lnglat = longlat_,
|
434
|
+
direction=direction,
|
107
435
|
street_view=streetview,
|
108
|
-
popup=pop_
|
436
|
+
popup=pop_,
|
437
|
+
waypoints=self._agent._history_trajectory
|
109
438
|
)
|
110
439
|
if messages != None:
|
111
440
|
self.messageBuffer += messages
|
@@ -114,6 +443,22 @@ class HubConnector:
|
|
114
443
|
messages=self.messageBuffer
|
115
444
|
)
|
116
445
|
|
446
|
+
def ShowGeo(self, geojsons: geojson.FeatureCollection):
|
447
|
+
"""
|
448
|
+
- 发送地图展示要素
|
449
|
+
|
450
|
+
Args:
|
451
|
+
- geojsons (geojson.FeatureCollection): 需要展示的地图要素
|
452
|
+
"""
|
453
|
+
if self._client == None:
|
454
|
+
print("AppHub: Not Bind Agent Yet")
|
455
|
+
return
|
456
|
+
self._client.update_agent_map(
|
457
|
+
agent_id=self._agent_id,
|
458
|
+
lnglat=[self._agent.motion['position']['longlat_position']['longitude'], self._agent.motion['position']['longlat_position']['latitude']],
|
459
|
+
geojsons=geojsons
|
460
|
+
)
|
461
|
+
|
117
462
|
def GetMessageFromHub(self) -> list[UserMessage]:
|
118
463
|
"""
|
119
464
|
获取前端messages
|