pycityagent 1.0.0__py3-none-any.whl → 2.0.0a2__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.
Files changed (110) hide show
  1. pycityagent/__init__.py +7 -3
  2. pycityagent/agent.py +180 -284
  3. pycityagent/economy/__init__.py +5 -0
  4. pycityagent/economy/econ_client.py +307 -0
  5. pycityagent/environment/__init__.py +7 -0
  6. pycityagent/environment/interact/interact.py +141 -0
  7. pycityagent/environment/sence/__init__.py +0 -0
  8. pycityagent/{brain → environment/sence}/static.py +1 -1
  9. pycityagent/environment/sidecar/__init__.py +8 -0
  10. pycityagent/environment/sidecar/sidecarv2.py +109 -0
  11. pycityagent/environment/sim/__init__.py +29 -0
  12. pycityagent/environment/sim/aoi_service.py +38 -0
  13. pycityagent/environment/sim/client.py +126 -0
  14. pycityagent/environment/sim/clock_service.py +43 -0
  15. pycityagent/environment/sim/economy_services.py +191 -0
  16. pycityagent/environment/sim/lane_service.py +110 -0
  17. pycityagent/environment/sim/light_service.py +120 -0
  18. pycityagent/environment/sim/person_service.py +294 -0
  19. pycityagent/environment/sim/road_service.py +38 -0
  20. pycityagent/environment/sim/sim_env.py +145 -0
  21. pycityagent/environment/sim/social_service.py +58 -0
  22. pycityagent/environment/simulator.py +320 -0
  23. pycityagent/environment/utils/__init__.py +10 -0
  24. pycityagent/environment/utils/base64.py +16 -0
  25. pycityagent/environment/utils/const.py +242 -0
  26. pycityagent/environment/utils/geojson.py +26 -0
  27. pycityagent/environment/utils/grpc.py +57 -0
  28. pycityagent/environment/utils/map_utils.py +157 -0
  29. pycityagent/environment/utils/port.py +11 -0
  30. pycityagent/environment/utils/protobuf.py +39 -0
  31. pycityagent/llm/__init__.py +6 -0
  32. pycityagent/llm/embedding.py +136 -0
  33. pycityagent/llm/llm.py +430 -0
  34. pycityagent/llm/llmconfig.py +15 -0
  35. pycityagent/llm/utils.py +6 -0
  36. pycityagent/memory/__init__.py +11 -0
  37. pycityagent/memory/const.py +41 -0
  38. pycityagent/memory/memory.py +453 -0
  39. pycityagent/memory/memory_base.py +168 -0
  40. pycityagent/memory/profile.py +165 -0
  41. pycityagent/memory/self_define.py +165 -0
  42. pycityagent/memory/state.py +173 -0
  43. pycityagent/memory/utils.py +27 -0
  44. pycityagent/message/__init__.py +0 -0
  45. pycityagent/simulation/__init__.py +7 -0
  46. pycityagent/simulation/interview.py +36 -0
  47. pycityagent/simulation/simulation.py +352 -0
  48. pycityagent/simulation/survey/__init__.py +9 -0
  49. pycityagent/simulation/survey/manager.py +67 -0
  50. pycityagent/simulation/survey/models.py +49 -0
  51. pycityagent/simulation/ui/__init__.py +3 -0
  52. pycityagent/simulation/ui/interface.py +602 -0
  53. pycityagent/utils/__init__.py +0 -0
  54. pycityagent/utils/decorators.py +89 -0
  55. pycityagent/utils/parsers/__init__.py +12 -0
  56. pycityagent/utils/parsers/code_block_parser.py +37 -0
  57. pycityagent/utils/parsers/json_parser.py +86 -0
  58. pycityagent/utils/parsers/parser_base.py +60 -0
  59. pycityagent/workflow/__init__.py +24 -0
  60. pycityagent/workflow/block.py +164 -0
  61. pycityagent/workflow/prompt.py +72 -0
  62. pycityagent/workflow/tool.py +246 -0
  63. pycityagent/workflow/trigger.py +150 -0
  64. pycityagent-2.0.0a2.dist-info/METADATA +208 -0
  65. pycityagent-2.0.0a2.dist-info/RECORD +69 -0
  66. {pycityagent-1.0.0.dist-info → pycityagent-2.0.0a2.dist-info}/WHEEL +1 -2
  67. pycityagent/ac/__init__.py +0 -6
  68. pycityagent/ac/ac.py +0 -50
  69. pycityagent/ac/action.py +0 -14
  70. pycityagent/ac/controled.py +0 -13
  71. pycityagent/ac/converse.py +0 -31
  72. pycityagent/ac/idle.py +0 -17
  73. pycityagent/ac/shop.py +0 -80
  74. pycityagent/ac/trip.py +0 -37
  75. pycityagent/brain/__init__.py +0 -10
  76. pycityagent/brain/brain.py +0 -52
  77. pycityagent/brain/brainfc.py +0 -10
  78. pycityagent/brain/memory.py +0 -541
  79. pycityagent/brain/persistence/social.py +0 -1
  80. pycityagent/brain/persistence/spatial.py +0 -14
  81. pycityagent/brain/reason/shop.py +0 -37
  82. pycityagent/brain/reason/social.py +0 -148
  83. pycityagent/brain/reason/trip.py +0 -67
  84. pycityagent/brain/reason/user.py +0 -122
  85. pycityagent/brain/retrive/social.py +0 -6
  86. pycityagent/brain/scheduler.py +0 -408
  87. pycityagent/brain/sence.py +0 -375
  88. pycityagent/cc/__init__.py +0 -5
  89. pycityagent/cc/cc.py +0 -102
  90. pycityagent/cc/conve.py +0 -6
  91. pycityagent/cc/idle.py +0 -20
  92. pycityagent/cc/shop.py +0 -6
  93. pycityagent/cc/trip.py +0 -13
  94. pycityagent/cc/user.py +0 -13
  95. pycityagent/hubconnector/__init__.py +0 -3
  96. pycityagent/hubconnector/hubconnector.py +0 -137
  97. pycityagent/image/__init__.py +0 -3
  98. pycityagent/image/image.py +0 -158
  99. pycityagent/simulator.py +0 -161
  100. pycityagent/st/__init__.py +0 -4
  101. pycityagent/st/st.py +0 -96
  102. pycityagent/urbanllm/__init__.py +0 -3
  103. pycityagent/urbanllm/urbanllm.py +0 -132
  104. pycityagent-1.0.0.dist-info/LICENSE +0 -21
  105. pycityagent-1.0.0.dist-info/METADATA +0 -181
  106. pycityagent-1.0.0.dist-info/RECORD +0 -48
  107. pycityagent-1.0.0.dist-info/top_level.txt +0 -1
  108. /pycityagent/{brain/persistence/__init__.py → config.py} +0 -0
  109. /pycityagent/{brain/reason → environment/interact}/__init__.py +0 -0
  110. /pycityagent/{brain/retrive → environment/message}/__init__.py +0 -0
@@ -0,0 +1,294 @@
1
+ import warnings
2
+ from typing import Any, Awaitable, Coroutine, Dict, Union, cast
3
+
4
+ import grpc
5
+ from google.protobuf.json_format import ParseDict
6
+ from mosstool.trip.generator import default_person_template_generator
7
+ from mosstool.util.format_converter import pb2dict
8
+ from pycityproto.city.person.v2 import person_pb2 as person_pb2
9
+ from pycityproto.city.person.v2 import person_service_pb2 as person_service
10
+ from pycityproto.city.person.v2 import person_service_pb2_grpc as person_grpc
11
+
12
+ from ..utils.protobuf import async_parse
13
+
14
+ __all__ = ["PersonService"]
15
+
16
+
17
+ class PersonService:
18
+ """
19
+ 交通模拟person服务
20
+ Traffic simulation person service
21
+ """
22
+
23
+ def __init__(self, aio_channel: grpc.aio.Channel):
24
+ self._aio_stub = person_grpc.PersonServiceStub(aio_channel)
25
+
26
+ @staticmethod
27
+ def default_person() -> person_pb2.Person:
28
+ """
29
+ 获取person基本模板
30
+ Get person basic template
31
+
32
+ 需要补充的字段有person.home,person.schedules,person.labels
33
+ The fields that need to be supplemented are person.home, person.schedules, person.labels
34
+ """
35
+ person = default_person_template_generator()
36
+ return person
37
+
38
+ @staticmethod
39
+ def default_dict_person() -> dict:
40
+ """
41
+ 获取person基本模板,字典格式
42
+ Get person basic template in dict format.
43
+
44
+ 需要补充的字段有person.home,person.schedules,person.labels
45
+ The fields that need to be supplemented are person.home, person.schedules, person.labels
46
+ """
47
+ person = default_person_template_generator()
48
+ return pb2dict(person)
49
+
50
+ def GetPerson(
51
+ self,
52
+ req: Union[person_service.GetPersonRequest, dict],
53
+ dict_return: bool = True,
54
+ ) -> Coroutine[Any, Any, Union[Dict[str, Any], person_service.GetPersonResponse]]:
55
+ """
56
+ 获取person信息
57
+ Get person information
58
+
59
+ Args:
60
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.GetPersonRequest
61
+
62
+ Returns:
63
+ - https://cityproto.sim.fiblab.net/#city.person.v2.GetPersonResponse
64
+ """
65
+ if type(req) != person_service.GetPersonRequest:
66
+ req = ParseDict(req, person_service.GetPersonRequest())
67
+ res = cast(
68
+ Awaitable[person_service.GetPersonResponse], self._aio_stub.GetPerson(req)
69
+ )
70
+ return async_parse(res, dict_return)
71
+
72
+ def AddPerson(
73
+ self,
74
+ req: Union[person_service.AddPersonRequest, dict],
75
+ dict_return: bool = True,
76
+ ) -> Coroutine[Any, Any, Union[Dict[str, Any], person_service.AddPersonResponse]]:
77
+ """
78
+ 新增person
79
+ Add a new person
80
+
81
+ Args:
82
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.AddPersonRequest
83
+
84
+ Returns:
85
+ - https://cityproto.sim.fiblab.net/#city.person.v2.AddPersonResponse
86
+ """
87
+ if type(req) != person_service.AddPersonRequest:
88
+ req = ParseDict(req, person_service.AddPersonRequest())
89
+ res = cast(
90
+ Awaitable[person_service.AddPersonResponse], self._aio_stub.AddPerson(req)
91
+ )
92
+ return async_parse(res, dict_return)
93
+
94
+ def SetSchedule(
95
+ self,
96
+ req: Union[person_service.SetScheduleRequest, dict],
97
+ dict_return: bool = True,
98
+ ) -> Coroutine[Any, Any, Union[Dict[str, Any], person_service.SetScheduleResponse]]:
99
+ """
100
+ 修改person的schedule
101
+ set person's schedule
102
+
103
+ Args:
104
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.SetScheduleRequest
105
+
106
+ Returns:
107
+ - https://cityproto.sim.fiblab.net/#city.person.v2.SetScheduleResponse
108
+ """
109
+ if type(req) != person_service.SetScheduleRequest:
110
+ req = ParseDict(req, person_service.SetScheduleRequest())
111
+ res = cast(
112
+ Awaitable[person_service.SetScheduleResponse],
113
+ self._aio_stub.SetSchedule(req),
114
+ )
115
+ return async_parse(res, dict_return)
116
+
117
+ def GetPersons(
118
+ self,
119
+ req: Union[person_service.GetPersonsRequest, dict],
120
+ dict_return: bool = True,
121
+ ) -> Coroutine[Any, Any, Union[Dict[str, Any], person_service.GetPersonsResponse]]:
122
+ """
123
+ 获取多个person信息
124
+ Get information of multiple persons
125
+
126
+ Args:
127
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.GetPersonsRequest
128
+
129
+ Returns:
130
+ - https://cityproto.sim.fiblab.net/#city.person.v2.GetPersonsResponse
131
+ """
132
+ if type(req) != person_service.GetPersonsRequest:
133
+ req = ParseDict(req, person_service.GetPersonsRequest())
134
+ res = cast(
135
+ Awaitable[person_service.GetPersonsResponse],
136
+ self._aio_stub.GetPersons(req),
137
+ )
138
+ return async_parse(res, dict_return)
139
+
140
+ def GetPersonByLongLatBBox(
141
+ self,
142
+ req: Union[person_service.GetPersonByLongLatBBoxRequest, dict],
143
+ dict_return: bool = True,
144
+ ) -> Coroutine[
145
+ Any, Any, Union[Dict[str, Any], person_service.GetPersonByLongLatBBoxResponse]
146
+ ]:
147
+ """
148
+ 获取特定区域内的person
149
+ Get persons in a specific region
150
+
151
+ Args:
152
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.GetPersonByLongLatBBoxRequest
153
+
154
+ Returns:
155
+ - https://cityproto.sim.fiblab.net/#city.person.v2.GetPersonByLongLatBBoxResponse
156
+ """
157
+ if type(req) != person_service.GetPersonByLongLatBBoxRequest:
158
+ req = ParseDict(req, person_service.GetPersonByLongLatBBoxRequest())
159
+ res = cast(
160
+ Awaitable[person_service.GetPersonByLongLatBBoxResponse],
161
+ self._aio_stub.GetPersonByLongLatBBox(req),
162
+ )
163
+ return async_parse(res, dict_return)
164
+
165
+ def GetAllVehicles(
166
+ self,
167
+ req: Union[person_service.GetAllVehiclesRequest, dict],
168
+ dict_return: bool = True,
169
+ ) -> Coroutine[
170
+ Any, Any, Union[Dict[str, Any], person_service.GetAllVehiclesResponse]
171
+ ]:
172
+ """
173
+ 获取所有车辆
174
+ Get all vehicles
175
+
176
+ Args:
177
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.GetAllVehiclesRequest
178
+
179
+ Returns:
180
+ - https://cityproto.sim.fiblab.net/#city.person.v2.GetAllVehiclesResponse
181
+ """
182
+ if type(req) != person_service.GetAllVehiclesRequest:
183
+ req = ParseDict(req, person_service.GetAllVehiclesRequest())
184
+ res = cast(
185
+ Awaitable[person_service.GetAllVehiclesResponse],
186
+ self._aio_stub.GetAllVehicles(req),
187
+ )
188
+ return async_parse(res, dict_return)
189
+
190
+ def ResetPersonPosition(
191
+ self,
192
+ req: Union[person_service.ResetPersonPositionRequest, dict],
193
+ dict_return: bool = True,
194
+ ) -> Coroutine[
195
+ Any, Any, Union[Dict[str, Any], person_service.ResetPersonPositionResponse]
196
+ ]:
197
+ """
198
+ 重置人的位置(将停止当前正在进行的出行,转为sleep状态)
199
+ Reset person's position (stop the current trip and switch to sleep status)
200
+
201
+ Args:
202
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.ResetPersonPositionRequest
203
+
204
+ Returns:
205
+ - https://cityproto.sim.fiblab.net/#city.person.v2.ResetPersonPositionResponse
206
+ """
207
+ if type(req) != person_service.ResetPersonPositionRequest:
208
+ req = ParseDict(req, person_service.ResetPersonPositionRequest())
209
+ res = cast(
210
+ Awaitable[person_service.ResetPersonPositionResponse],
211
+ self._aio_stub.ResetPersonPosition(req),
212
+ )
213
+ return async_parse(res, dict_return)
214
+
215
+ # RL接口
216
+
217
+ def SetControlledVehicleIDs(
218
+ self,
219
+ req: Union[person_service.SetControlledVehicleIDsRequest, dict],
220
+ dict_return: bool = True,
221
+ ) -> Coroutine[
222
+ Any, Any, Union[Dict[str, Any], person_service.SetControlledVehicleIDsResponse]
223
+ ]:
224
+ """
225
+ 设置由外部控制行为的vehicle
226
+ Set controlled vehicle ID
227
+
228
+ Args:
229
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.SetControlledVehicleIDsRequest
230
+
231
+ Returns:
232
+ - https://cityproto.sim.fiblab.net/#city.person.v2.SetControlledVehicleIDsResponse
233
+ """
234
+ if type(req) != person_service.SetControlledVehicleIDsRequest:
235
+ req = ParseDict(req, person_service.SetControlledVehicleIDsRequest())
236
+ res = cast(
237
+ Awaitable[person_service.SetControlledVehicleIDsResponse],
238
+ self._aio_stub.SetControlledVehicleIDs(req),
239
+ )
240
+ return async_parse(res, dict_return)
241
+
242
+ def FetchControlledVehicleEnvs(
243
+ self,
244
+ req: Union[person_service.FetchControlledVehicleEnvsRequest, dict],
245
+ dict_return: bool = True,
246
+ ) -> Coroutine[
247
+ Any,
248
+ Any,
249
+ Union[Dict[str, Any], person_service.FetchControlledVehicleEnvsResponse],
250
+ ]:
251
+ """
252
+ 获取由外部控制行为的vehicle的环境信息
253
+ Fetch controlled vehicle environment information
254
+
255
+ Args:
256
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.FetchControlledVehicleEnvsRequest
257
+
258
+ Returns:
259
+ - https://cityproto.sim.fiblab.net/#city.person.v2.FetchControlledVehicleEnvsResponse
260
+ """
261
+ if type(req) != person_service.FetchControlledVehicleEnvsRequest:
262
+ req = ParseDict(req, person_service.FetchControlledVehicleEnvsRequest())
263
+ res = cast(
264
+ Awaitable[person_service.FetchControlledVehicleEnvsResponse],
265
+ self._aio_stub.FetchControlledVehicleEnvs(req),
266
+ )
267
+ return async_parse(res, dict_return)
268
+
269
+ def SetControlledVehicleActions(
270
+ self,
271
+ req: Union[person_service.SetControlledVehicleActionsRequest, dict],
272
+ dict_return: bool = True,
273
+ ) -> Coroutine[
274
+ Any,
275
+ Any,
276
+ Union[Dict[str, Any], person_service.SetControlledVehicleActionsResponse],
277
+ ]:
278
+ """
279
+ 设置由外部控制行为的vehicle的行为
280
+ Set controlled vehicle actions
281
+
282
+ Args:
283
+ - req (dict): https://cityproto.sim.fiblab.net/#city.person.v2.SetControlledVehicleActionsRequest
284
+
285
+ Returns:
286
+ - https://cityproto.sim.fiblab.net/#city.person.v2.SetControlledVehicleActionsResponse
287
+ """
288
+ if type(req) != person_service.SetControlledVehicleActionsRequest:
289
+ req = ParseDict(req, person_service.SetControlledVehicleActionsRequest())
290
+ res = cast(
291
+ Awaitable[person_service.SetControlledVehicleActionsResponse],
292
+ self._aio_stub.SetControlledVehicleActions(req),
293
+ )
294
+ return async_parse(res, dict_return)
@@ -0,0 +1,38 @@
1
+ from typing import Any, Awaitable, Coroutine, cast, Union, Dict
2
+
3
+ import grpc
4
+ from google.protobuf.json_format import ParseDict
5
+ from pycityproto.city.map.v2 import road_service_pb2 as road_service
6
+ from pycityproto.city.map.v2 import road_service_pb2_grpc as road_grpc
7
+
8
+ from ..utils.protobuf import async_parse
9
+
10
+ __all__ = ["RoadService"]
11
+
12
+
13
+ class RoadService:
14
+ """
15
+ 交通模拟road服务
16
+ Traffic simulation road service
17
+ """
18
+
19
+ def __init__(self, aio_channel: grpc.aio.Channel):
20
+ self._aio_stub = road_grpc.RoadServiceStub(aio_channel)
21
+
22
+ def GetRoad(
23
+ self, req: Union[road_service.GetRoadRequest, dict], dict_return: bool = True
24
+ ) -> Coroutine[Any, Any, Union[Dict[str, Any], road_service.GetRoadResponse]]:
25
+ """
26
+ 查询道路信息
27
+ Query road information
28
+
29
+ Args:
30
+ - req (dict): https://cityproto.sim.fiblab.net/#city.map.v2.GetRoadRequest
31
+
32
+ Returns:
33
+ - https://cityproto.sim.fiblab.net/#city.map.v2.GetRoadResponse
34
+ """
35
+ if type(req) != road_service.GetRoadRequest:
36
+ req = ParseDict(req, road_service.GetRoadRequest())
37
+ res = cast(Awaitable[road_service.GetRoadResponse], self._aio_stub.GetRoad(req))
38
+ return async_parse(res, dict_return)
@@ -0,0 +1,145 @@
1
+ import logging
2
+ import os
3
+ import time
4
+ import atexit
5
+ from subprocess import DEVNULL, Popen
6
+ from typing import Optional
7
+
8
+ from pycitydata.map import Map
9
+
10
+ from ..utils import encode_to_base64, find_free_port
11
+
12
+ __all__ = ["ControlSimEnv"]
13
+
14
+
15
+ def _generate_yaml_config(map_file: str, start_step: int, total_step: int) -> str:
16
+ map_file = os.path.abspath(map_file)
17
+ return f"""
18
+ input:
19
+ # 地图
20
+ map:
21
+ file: "{map_file}"
22
+
23
+ control:
24
+ step:
25
+ # 模拟器起始步
26
+ start: {start_step}
27
+ # 模拟总步数,结束步为起始步+总步数
28
+ total: {total_step}
29
+ # 每步的时间间隔
30
+ interval: 1
31
+ skip_overtime_trip_when_init: true
32
+ enable_platoon: false
33
+ enable_indoor: false
34
+ prefer_fixed_light: true
35
+ enable_collision_avoidance: false # 计算性能下降10倍,需要保证subloop>=5
36
+ enable_go_astray: true # 引入串行的路径规划调用,计算性能下降(幅度不确定)
37
+ lane_change_model: earliest # mobil (主动变道+强制变道,默认值) earliest (总是尽可能早地变道)
38
+
39
+ output:
40
+ """
41
+
42
+
43
+ class ControlSimEnv:
44
+ def __init__(
45
+ self,
46
+ task_name: str,
47
+ map_file: str,
48
+ # person_file,
49
+ start_step: int,
50
+ total_step: int,
51
+ log_dir: str,
52
+ min_step_time: int = 1000,
53
+ timeout: int = 5,
54
+ simuletgo_addr: Optional[str] = None,
55
+ ):
56
+ self._task_name = task_name
57
+ self._map_file = map_file
58
+ # self._person_file = person_file
59
+ self._start_step = start_step
60
+ self._total_step = total_step
61
+ self._log_dir = log_dir
62
+ self._min_step_time = min_step_time
63
+ self._timeout = timeout
64
+ self.m = Map(pb_path=map_file)
65
+ """
66
+ 地图数据
67
+ """
68
+
69
+ # 检查二进制文件是否存在
70
+ # simulet-go: ~/.local/bin/simulet-go
71
+ self._simuletgo_path = os.path.expanduser("~/.local/bin/simulet-go")
72
+ if not os.path.exists(os.path.expanduser(self._simuletgo_path)):
73
+ raise FileNotFoundError("simulet-go not found, please install it first")
74
+
75
+ self._simuletgo_config = _generate_yaml_config(map_file, start_step, total_step)
76
+ self.simuletgo_port = None
77
+ self._simuletgo_proc = None
78
+ self._traffic_client = None
79
+
80
+ os.makedirs(log_dir, exist_ok=True)
81
+
82
+ self.simuletgo_addr = self.reset(simuletgo_addr)
83
+
84
+ def reset(
85
+ self,
86
+ simuletgo_addr: Optional[str] = None,
87
+ ):
88
+ """
89
+ Args:
90
+ - simuletgo_addr: str, simulet-go的地址。如果为None,则启动一个新的simulet-go
91
+ """
92
+
93
+ # 三个地址必须同时为None或者同时不为None
94
+ if simuletgo_addr is None:
95
+ # 1. 启动simulet-go
96
+ # ./simulet-go -config-data configbase64 -job test -syncer http://localhost:53001 -listen :51102
97
+ assert self.simuletgo_port is None
98
+ assert self._simuletgo_proc is None
99
+ self.simuletgo_port = find_free_port()
100
+ config_base64 = encode_to_base64(self._simuletgo_config)
101
+ self._simuletgo_proc = Popen(
102
+ [
103
+ self._simuletgo_path,
104
+ "-config-data",
105
+ config_base64,
106
+ "-job",
107
+ self._task_name,
108
+ "-listen",
109
+ f":{self.simuletgo_port}",
110
+ "-run.min_step_time",
111
+ f"{self._min_step_time}",
112
+ "-output",
113
+ self._log_dir,
114
+ "-cache",
115
+ "",
116
+ "-log.level",
117
+ "error",
118
+ ],
119
+ # 忽略输出
120
+ # stdout=DEVNULL,
121
+ )
122
+ logging.info(
123
+ f"start simulet-go at localhost:{self.simuletgo_port}, PID={self._simuletgo_proc.pid}"
124
+ )
125
+ simuletgo_addr = f"http://localhost:{self.simuletgo_port}"
126
+ atexit.register(self.close)
127
+ time.sleep(1)
128
+ elif simuletgo_addr is not None:
129
+ pass
130
+ else:
131
+ # raise ValueError(
132
+ # "simuletgo_addr, syncer_addr, routing_addr must be all None or all not None"
133
+ # )
134
+ pass
135
+ return simuletgo_addr
136
+
137
+ def close(self):
138
+ if self._simuletgo_proc is not None:
139
+ self._simuletgo_proc.terminate()
140
+ simuletgo_code = self._simuletgo_proc.wait()
141
+ logging.info(f"simulet-go exit with code {simuletgo_code}")
142
+
143
+ self.simuletgo_port = None
144
+ self._simuletgo_proc = None
145
+ self._traffic_client = None
@@ -0,0 +1,58 @@
1
+ from typing import Any, Awaitable, Coroutine, cast, Union, Dict
2
+
3
+ import grpc
4
+ from google.protobuf.json_format import ParseDict
5
+ from pycityproto.city.social.v1 import social_service_pb2 as social_service
6
+ from pycityproto.city.social.v1 import social_service_pb2_grpc as social_grpc
7
+
8
+ from ..utils.protobuf import async_parse
9
+
10
+ __all__ = ["SocialService"]
11
+
12
+
13
+ class SocialService:
14
+ """
15
+ 城市模拟社交服务
16
+ City simulation social service
17
+ """
18
+
19
+ def __init__(self, aio_channel: grpc.aio.Channel):
20
+ self._aio_stub = social_grpc.SocialServiceStub(aio_channel)
21
+
22
+ def Send(
23
+ self, req: Union[social_service.SendRequest, dict], dict_return: bool = True
24
+ ) -> Coroutine[Any, Any, Union[Dict[str, Any], social_service.SendResponse]]:
25
+ """
26
+ 发送消息
27
+ Send message
28
+
29
+ Args:
30
+ - req (dict): https://cityproto.sim.fiblab.net/#city.social.v1.SendRequest
31
+
32
+ Returns:
33
+ - https://cityproto.sim.fiblab.net/#city.social.v1.SendResponse
34
+ """
35
+ if type(req) != social_service.SendRequest:
36
+ req = ParseDict(req, social_service.SendRequest())
37
+ res = cast(Awaitable[social_service.SendResponse], self._aio_stub.Send(req))
38
+ return async_parse(res, dict_return)
39
+
40
+ def Receive(
41
+ self, req: Union[social_service.ReceiveRequest, dict], dict_return: bool = True
42
+ ) -> Coroutine[Any, Any, Union[Dict[str, Any], social_service.ReceiveResponse]]:
43
+ """
44
+ 接收消息
45
+ Receive message
46
+
47
+ Args:
48
+ - req (dict): https://cityproto.sim.fiblab.net/#city.social.v1.ReceiveRequest
49
+
50
+ Returns:
51
+ - https://cityproto.sim.fiblab.net/#city.social.v1.ReceiveResponse
52
+ """
53
+ if type(req) != social_service.ReceiveRequest:
54
+ req = ParseDict(req, social_service.ReceiveRequest())
55
+ res = cast(
56
+ Awaitable[social_service.ReceiveResponse], self._aio_stub.Receive(req)
57
+ )
58
+ return async_parse(res, dict_return)