pycityagent 2.0.0a66__cp310-cp310-macosx_11_0_arm64.whl → 2.0.0a67__cp310-cp310-macosx_11_0_arm64.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 (87) hide show
  1. pycityagent/agent/agent.py +157 -57
  2. pycityagent/agent/agent_base.py +316 -43
  3. pycityagent/cityagent/bankagent.py +49 -9
  4. pycityagent/cityagent/blocks/__init__.py +1 -2
  5. pycityagent/cityagent/blocks/cognition_block.py +54 -31
  6. pycityagent/cityagent/blocks/dispatcher.py +22 -17
  7. pycityagent/cityagent/blocks/economy_block.py +46 -32
  8. pycityagent/cityagent/blocks/mobility_block.py +130 -100
  9. pycityagent/cityagent/blocks/needs_block.py +101 -44
  10. pycityagent/cityagent/blocks/other_block.py +42 -33
  11. pycityagent/cityagent/blocks/plan_block.py +59 -42
  12. pycityagent/cityagent/blocks/social_block.py +167 -116
  13. pycityagent/cityagent/blocks/utils.py +13 -6
  14. pycityagent/cityagent/firmagent.py +17 -35
  15. pycityagent/cityagent/governmentagent.py +3 -3
  16. pycityagent/cityagent/initial.py +79 -44
  17. pycityagent/cityagent/memory_config.py +108 -88
  18. pycityagent/cityagent/message_intercept.py +0 -4
  19. pycityagent/cityagent/metrics.py +41 -0
  20. pycityagent/cityagent/nbsagent.py +24 -36
  21. pycityagent/cityagent/societyagent.py +7 -3
  22. pycityagent/cli/wrapper.py +2 -2
  23. pycityagent/economy/econ_client.py +407 -81
  24. pycityagent/environment/__init__.py +0 -3
  25. pycityagent/environment/sim/__init__.py +0 -3
  26. pycityagent/environment/sim/aoi_service.py +2 -2
  27. pycityagent/environment/sim/client.py +3 -31
  28. pycityagent/environment/sim/clock_service.py +2 -2
  29. pycityagent/environment/sim/lane_service.py +8 -8
  30. pycityagent/environment/sim/light_service.py +8 -8
  31. pycityagent/environment/sim/pause_service.py +9 -10
  32. pycityagent/environment/sim/person_service.py +20 -20
  33. pycityagent/environment/sim/road_service.py +2 -2
  34. pycityagent/environment/sim/sim_env.py +21 -5
  35. pycityagent/environment/sim/social_service.py +4 -4
  36. pycityagent/environment/simulator.py +249 -27
  37. pycityagent/environment/utils/__init__.py +2 -2
  38. pycityagent/environment/utils/geojson.py +2 -2
  39. pycityagent/environment/utils/grpc.py +4 -4
  40. pycityagent/environment/utils/map_utils.py +2 -2
  41. pycityagent/llm/embeddings.py +147 -28
  42. pycityagent/llm/llm.py +122 -77
  43. pycityagent/llm/llmconfig.py +5 -0
  44. pycityagent/llm/utils.py +4 -0
  45. pycityagent/memory/__init__.py +0 -4
  46. pycityagent/memory/const.py +2 -2
  47. pycityagent/memory/faiss_query.py +140 -61
  48. pycityagent/memory/memory.py +393 -90
  49. pycityagent/memory/memory_base.py +140 -34
  50. pycityagent/memory/profile.py +13 -13
  51. pycityagent/memory/self_define.py +13 -13
  52. pycityagent/memory/state.py +14 -14
  53. pycityagent/message/message_interceptor.py +253 -3
  54. pycityagent/message/messager.py +133 -6
  55. pycityagent/metrics/mlflow_client.py +47 -4
  56. pycityagent/pycityagent-sim +0 -0
  57. pycityagent/pycityagent-ui +0 -0
  58. pycityagent/simulation/__init__.py +3 -2
  59. pycityagent/simulation/agentgroup.py +145 -52
  60. pycityagent/simulation/simulation.py +257 -62
  61. pycityagent/survey/manager.py +45 -3
  62. pycityagent/survey/models.py +42 -2
  63. pycityagent/tools/__init__.py +1 -2
  64. pycityagent/tools/tool.py +93 -69
  65. pycityagent/utils/avro_schema.py +2 -2
  66. pycityagent/utils/parsers/code_block_parser.py +1 -1
  67. pycityagent/utils/parsers/json_parser.py +2 -2
  68. pycityagent/utils/parsers/parser_base.py +2 -2
  69. pycityagent/workflow/block.py +64 -13
  70. pycityagent/workflow/prompt.py +31 -23
  71. pycityagent/workflow/trigger.py +91 -24
  72. {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/METADATA +2 -2
  73. pycityagent-2.0.0a67.dist-info/RECORD +97 -0
  74. pycityagent/environment/interact/__init__.py +0 -0
  75. pycityagent/environment/interact/interact.py +0 -198
  76. pycityagent/environment/message/__init__.py +0 -0
  77. pycityagent/environment/sence/__init__.py +0 -0
  78. pycityagent/environment/sence/static.py +0 -416
  79. pycityagent/environment/sidecar/__init__.py +0 -8
  80. pycityagent/environment/sidecar/sidecarv2.py +0 -109
  81. pycityagent/environment/sim/economy_services.py +0 -192
  82. pycityagent/metrics/utils/const.py +0 -0
  83. pycityagent-2.0.0a66.dist-info/RECORD +0 -105
  84. {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/LICENSE +0 -0
  85. {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/WHEEL +0 -0
  86. {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/entry_points.txt +0 -0
  87. {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/top_level.txt +0 -0
@@ -4,6 +4,7 @@ import asyncio
4
4
  import logging
5
5
  import os
6
6
  from datetime import datetime, timedelta
7
+ import time
7
8
  from typing import Any, Optional, Union, cast
8
9
 
9
10
  from mosstool.type import TripMode
@@ -20,11 +21,18 @@ from .utils.const import *
20
21
 
21
22
  logger = logging.getLogger("pycityagent")
22
23
 
24
+ __all__ = [
25
+ "Simulator",
26
+ ]
27
+
23
28
 
24
29
  class Simulator:
25
30
  """
26
- - 模拟器主类
27
- - Simulator Class
31
+ Main class of the simulator.
32
+
33
+ - **Description**:
34
+ - This class is the core of the simulator, responsible for initializing and managing the simulation environment.
35
+ - It reads parameters from a configuration dictionary, initializes map data, and starts or connects to a simulation server as needed.
28
36
  """
29
37
 
30
38
  def __init__(self, config: dict, secure: bool = False) -> None:
@@ -106,33 +114,74 @@ class Simulator:
106
114
  poi["id"]: poi["aoi_id"] for _, poi in self.map.pois.items()
107
115
  }
108
116
  self._environment_prompt:dict[str, str] = {}
117
+ self._log_list = []
118
+
119
+ def get_log_list(self):
120
+ return self._log_list
121
+
122
+ def clear_log_list(self):
123
+ self._log_list = []
109
124
 
110
125
  @property
111
- def environment(self):
126
+ def environment(self) -> dict[str, str]:
127
+ """
128
+ Get the current state of environment variables.
129
+ """
112
130
  return self._environment_prompt
113
-
131
+
114
132
  def set_environment(self, environment: dict[str, str]):
133
+ """
134
+ Set the entire dictionary of environment variables.
135
+
136
+ - **Args**:
137
+ - `environment` (`Dict[str, str]`): Key-value pairs of environment variables.
138
+ """
115
139
  self._environment_prompt = environment
116
140
 
117
- def sence(self, key: str):
141
+ def sence(self, key: str) -> str:
142
+ """
143
+ Retrieve the value of an environment variable by its key.
144
+
145
+ - **Args**:
146
+ - `key` (`str`): The key of the environment variable.
147
+
148
+ - **Returns**:
149
+ - `str`: The value of the corresponding key, or an empty string if not found.
150
+ """
118
151
  return self._environment_prompt.get(key, "")
119
-
152
+
120
153
  def update_environment(self, key: str, value: str):
154
+ """
155
+ Update the value of a single environment variable.
156
+
157
+ - **Args**:
158
+ - `key` (`str`): The key of the environment variable.
159
+ - `value` (`str`): The new value to set.
160
+ """
121
161
  self._environment_prompt[key] = value
122
162
 
123
163
  # * Agent相关
124
164
  def find_agents_by_area(self, req: dict, status=None):
125
165
  """
126
- 通过区域范围查找agent/person
127
- Get agents/persons in the provided area
166
+ Find agents/persons within a specified area.
128
167
 
129
- Args:
130
- - req (dict): 用于描述区域的请求 https://cityproto.sim.fiblab.net/#city.person.1.GetPersonByLongLatBBoxRequest
131
- - status (int): 用于限制agent/person状态 if 'status' is not None, then you get those persons in 'status' https://cityproto.sim.fiblab.net/#city.agent.v2.Status
168
+ - **Args**:
169
+ - `req` (`dict`): A dictionary that describes the area. Refer to
170
+ https://cityproto.sim.fiblab.net/#city.person.1.GetPersonByLongLatBBoxRequest.
171
+ - `status` (`Optional[int]`): An integer representing the status of the agents/persons to filter by.
172
+ If provided, only persons with the given status will be returned.
173
+ Refer to https://cityproto.sim.fiblab.net/#city.agent.v2.Status.
132
174
 
133
- Returns:
134
- - https://cityproto.sim.fiblab.net/#city.person.1.GetPersonByLongLatBBoxResponse
175
+ - **Returns**:
176
+ - The response from the GetPersonByLongLatBBox method, possibly filtered by status.
177
+ Refer to https://cityproto.sim.fiblab.net/#city.person.1.GetPersonByLongLatBBoxResponse.
135
178
  """
179
+ start_time = time.time()
180
+ log = {
181
+ "req": "find_agents_by_area",
182
+ "start_time": start_time,
183
+ "consumption": 0
184
+ }
136
185
  loop = asyncio.get_event_loop()
137
186
  resp = loop.run_until_complete(
138
187
  self._client.person_service.GetPersonByLongLatBBox(req=req)
@@ -146,6 +195,8 @@ class Simulator:
146
195
  if agent.status in status:
147
196
  motions.append(agent)
148
197
  resp.motions = motions # type: ignore
198
+ log["consumption"] = time.time() - start_time
199
+ self._log_list.append(log)
149
200
  return resp
150
201
 
151
202
  def get_poi_categories(
@@ -153,6 +204,23 @@ class Simulator:
153
204
  center: Optional[Union[tuple[float, float], Point]] = None,
154
205
  radius: Optional[float] = None,
155
206
  ) -> list[str]:
207
+ """
208
+ Retrieve unique categories of Points of Interest (POIs) around a central point.
209
+
210
+ - **Args**:
211
+ - `center` (`Optional[Union[Tuple[float, float], Point]]`): The central point as a tuple or Point object.
212
+ Defaults to (0, 0) if not provided.
213
+ - `radius` (`Optional[float]`): The search radius in meters. If not provided, all POIs are considered.
214
+
215
+ - **Returns**:
216
+ - `List[str]`: A list of unique POI category names.
217
+ """
218
+ start_time = time.time()
219
+ log = {
220
+ "req": "get_poi_categories",
221
+ "start_time": start_time,
222
+ "consumption": 0
223
+ }
156
224
  categories: list[str] = []
157
225
  if center is None:
158
226
  center = (0, 0)
@@ -164,23 +232,31 @@ class Simulator:
164
232
  for poi in _pois:
165
233
  catg = poi["category"]
166
234
  categories.append(catg.split("|")[-1])
235
+ log["consumption"] = time.time() - start_time
236
+ self._log_list.append(log)
167
237
  return list(set(categories))
168
238
 
169
239
  async def get_time(
170
240
  self, format_time: bool = False, format: str = "%H:%M:%S"
171
241
  ) -> Union[int, str]:
172
242
  """
173
- 获取模拟器当前时间 Get current time of simulator
174
- 默认返回以00:00:00为始的, 以s为单位的时间(int)
175
- 支持格式化时间
243
+ Get the current time of the simulator.
176
244
 
177
- Args:
178
- - format_time (bool): 是否格式化 format or not
179
- - format (str): 格式化模板,默认为"Hour:Minute:Second" the formation
245
+ By default, returns the number of seconds since midnight. Supports formatted output.
180
246
 
181
- Returns:
182
- - time Union[int, str]: 时间 time in second(int) or formatted time(str)
247
+ - **Args**:
248
+ - `format_time` (`bool`): Whether to return the time in a formatted string. Defaults to `False`.
249
+ - `format` (`str`): The format string for formatting the time. Defaults to "%H:%M:%S".
250
+
251
+ - **Returns**:
252
+ - `Union[int, str]`: The current simulation time either as an integer representing seconds since midnight or as a formatted string.
183
253
  """
254
+ start_time = time.time()
255
+ log = {
256
+ "req": "get_time",
257
+ "start_time": start_time,
258
+ "consumption": 0
259
+ }
184
260
  now = await self._client.clock_service.Now({})
185
261
  now = cast(dict[str, int], now)
186
262
  self.time = now["t"]
@@ -189,44 +265,133 @@ class Simulator:
189
265
  start_of_day = datetime.combine(current_date, datetime.min.time())
190
266
  current_time = start_of_day + timedelta(seconds=now["t"])
191
267
  formatted_time = current_time.strftime(format)
268
+ log["consumption"] = time.time() - start_time
269
+ self._log_list.append(log)
192
270
  return formatted_time
193
271
  else:
272
+ log["consumption"] = time.time() - start_time
273
+ self._log_list.append(log)
194
274
  return int(now["t"])
195
275
 
196
276
  async def pause(self):
277
+ """
278
+ Pause the simulation.
279
+
280
+ This method sends a request to the simulator's pause service to pause the simulation.
281
+ """
282
+ start_time = time.time()
283
+ log = {
284
+ "req": "pause",
285
+ "start_time": start_time,
286
+ "consumption": 0
287
+ }
197
288
  await self._client.pause_service.pause()
289
+ log["consumption"] = time.time() - start_time
290
+ self._log_list.append(log)
198
291
 
199
292
  async def resume(self):
293
+ """
294
+ Resume the simulation.
295
+
296
+ This method sends a request to the simulator's pause service to resume the simulation.
297
+ """
298
+ start_time = time.time()
299
+ log = {
300
+ "req": "resume",
301
+ "start_time": start_time,
302
+ "consumption": 0
303
+ }
200
304
  await self._client.pause_service.resume()
305
+ log["consumption"] = time.time() - start_time
306
+ self._log_list.append(log)
201
307
 
202
308
  async def get_simulator_day(self) -> int:
203
309
  """
204
- 获取模拟器到第几日
310
+ Get the current day of the simulation.
311
+
312
+ - **Returns**:
313
+ - `int`: The day number since the start of the simulation.
205
314
  """
315
+ start_time = time.time()
316
+ log = {
317
+ "req": "get_simulator_day",
318
+ "start_time": start_time,
319
+ "consumption": 0
320
+ }
206
321
  now = await self._client.clock_service.Now({})
207
322
  now = cast(dict[str, int], now)
208
323
  day = now["day"]
324
+ log["consumption"] = time.time() - start_time
325
+ self._log_list.append(log)
209
326
  return day
210
327
 
211
328
  async def get_simulator_second_from_start_of_day(self) -> int:
212
329
  """
213
- 获取模拟器从00:00:00到当前的秒数
330
+ Get the number of seconds elapsed from the start of the current day in the simulation.
331
+
332
+ - **Returns**:
333
+ - `int`: The number of seconds from 00:00:00 of the current day.
214
334
  """
335
+ start_time = time.time()
336
+ log = {
337
+ "req": "get_simulator_second_from_start_of_day",
338
+ "start_time": start_time,
339
+ "consumption": 0
340
+ }
215
341
  now = await self._client.clock_service.Now({})
216
342
  now = cast(dict[str, int], now)
343
+ log["consumption"] = time.time() - start_time
344
+ self._log_list.append(log)
217
345
  return now["t"] % 86400
218
346
 
219
347
  async def get_person(self, person_id: int) -> dict:
220
- return await self._client.person_service.GetPerson(
348
+ """
349
+ Retrieve information about a specific person by ID.
350
+
351
+ - **Args**:
352
+ - `person_id` (`int`): The ID of the person to retrieve information for.
353
+
354
+ - **Returns**:
355
+ - `Dict`: Information about the specified person.
356
+ """
357
+ start_time = time.time()
358
+ log = {
359
+ "req": "get_person",
360
+ "start_time": start_time,
361
+ "consumption": 0
362
+ }
363
+ person = await self._client.person_service.GetPerson(
221
364
  req={"person_id": person_id}
222
365
  ) # type:ignore
366
+ log["consumption"] = time.time() - start_time
367
+ self._log_list.append(log)
368
+ return person
223
369
 
224
370
  async def add_person(self, person: Any) -> dict:
371
+ """
372
+ Add a new person to the simulation.
373
+
374
+ - **Args**:
375
+ - `person` (`Any`): The person object to add. If it's an instance of `person_pb2.Person`,
376
+ it will be wrapped in an `AddPersonRequest`. Otherwise, `person` is expected to already be a valid request object.
377
+
378
+ - **Returns**:
379
+ - `Dict`: Response from adding the person.
380
+ """
381
+ start_time = time.time()
382
+ log = {
383
+ "req": "add_person",
384
+ "start_time": start_time,
385
+ "consumption": 0
386
+ }
225
387
  if isinstance(person, person_pb2.Person):
226
388
  req = person_service.AddPersonRequest(person=person)
227
389
  else:
228
390
  req = person
229
- return await self._client.person_service.AddPerson(req) # type:ignore
391
+ person_id = await self._client.person_service.AddPerson(req) # type:ignore
392
+ log["consumption"] = time.time() - start_time
393
+ self._log_list.append(log)
394
+ return person_id
230
395
 
231
396
  async def set_aoi_schedules(
232
397
  self,
@@ -237,6 +402,24 @@ class Simulator:
237
402
  departure_times: Optional[list[float]] = None,
238
403
  modes: Optional[list[TripMode]] = None,
239
404
  ):
405
+ """
406
+ Set schedules for a person to visit Areas of Interest (AOIs).
407
+
408
+ - **Args**:
409
+ - `person_id` (`int`): The ID of the person whose schedule is being set.
410
+ - `target_positions` (`Union[List[Union[int, Tuple[int, int]]], Union[int, Tuple[int, int]]]`):
411
+ A list of AOI or POI IDs or tuples of (AOI ID, POI ID) that the person will visit.
412
+ - `departure_times` (`Optional[List[float]]`): Departure times for each trip in the schedule.
413
+ If not provided, current time will be used for all trips.
414
+ - `modes` (`Optional[List[TripMode]]`): Travel modes for each trip.
415
+ Defaults to `TRIP_MODE_DRIVE_ONLY` if not specified.
416
+ """
417
+ start_time = time.time()
418
+ log = {
419
+ "req": "set_aoi_schedules",
420
+ "start_time": start_time,
421
+ "consumption": 0
422
+ }
240
423
  cur_time = float(await self.get_time())
241
424
  if not isinstance(target_positions, list):
242
425
  target_positions = [target_positions]
@@ -286,6 +469,8 @@ class Simulator:
286
469
  )
287
470
  req = {"person_id": person_id, "schedules": _schedules}
288
471
  await self._client.person_service.SetSchedule(req)
472
+ log["consumption"] = time.time() - start_time
473
+ self._log_list.append(log)
289
474
 
290
475
  async def reset_person_position(
291
476
  self,
@@ -295,6 +480,22 @@ class Simulator:
295
480
  lane_id: Optional[int] = None,
296
481
  s: Optional[float] = None,
297
482
  ):
483
+ """
484
+ Reset the position of a person within the simulation.
485
+
486
+ - **Args**:
487
+ - `person_id` (`int`): The ID of the person whose position is being reset.
488
+ - `aoi_id` (`Optional[int]`): The ID of the Area of Interest (AOI) where the person should be placed.
489
+ - `poi_id` (`Optional[int]`): The ID of the Point of Interest (POI) within the AOI.
490
+ - `lane_id` (`Optional[int]`): The ID of the lane on which the person should be placed.
491
+ - `s` (`Optional[float]`): The longitudinal position along the lane.
492
+ """
493
+ start_time = time.time()
494
+ log = {
495
+ "req": "reset_person_position",
496
+ "start_time": start_time,
497
+ "consumption": 0
498
+ }
298
499
  reset_position = {}
299
500
  if aoi_id is not None:
300
501
  reset_position["aoi_position"] = {"aoi_id": aoi_id}
@@ -323,6 +524,8 @@ class Simulator:
323
524
  logger.debug(
324
525
  f"Neither aoi or lane pos provided for person {person_id} position reset!!"
325
526
  )
527
+ log["consumption"] = time.time() - start_time
528
+ self._log_list.append(log)
326
529
 
327
530
  def get_around_poi(
328
531
  self,
@@ -330,9 +533,26 @@ class Simulator:
330
533
  radius: float,
331
534
  poi_type: Union[str, list[str]],
332
535
  ) -> list[dict]:
536
+ """
537
+ Get Points of Interest (POIs) around a central point based on type.
538
+
539
+ - **Args**:
540
+ - `center` (`Union[Tuple[float, float], Point]`): The central point as a tuple or Point object.
541
+ - `radius` (`float`): The search radius in meters.
542
+ - `poi_type` (`Union[str, List[str]]`): The category or categories of POIs to filter by.
543
+
544
+ - **Returns**:
545
+ - `List[Dict]`: A list of dictionaries containing information about the POIs found.
546
+ """
547
+ start_time = time.time()
548
+ log = {
549
+ "req": "get_around_poi",
550
+ "start_time": start_time,
551
+ "consumption": 0
552
+ }
333
553
  if isinstance(poi_type, str):
334
554
  poi_type = [poi_type]
335
- transformed_poi_type = []
555
+ transformed_poi_type: list[str] = []
336
556
  for t in poi_type:
337
557
  if t not in self.poi_cate:
338
558
  transformed_poi_type.append(t)
@@ -352,4 +572,6 @@ class Simulator:
352
572
  if catg.split("|")[-1] not in poi_type_set:
353
573
  continue
354
574
  pois.append(poi)
355
- return pois
575
+ log["consumption"] = time.time() - start_time
576
+ self._log_list.append(log)
577
+ return pois
@@ -4,11 +4,11 @@ utilities
4
4
  """
5
5
 
6
6
  from .geojson import wrap_feature_collection
7
- from .base64 import encode_to_base64
8
7
  from .port import find_free_port
8
+ from .base64 import encode_to_base64
9
9
 
10
10
  __all__ = [
11
11
  "wrap_feature_collection",
12
12
  "find_free_port",
13
- "find_free_port",
13
+ "encode_to_base64",
14
14
  ]
@@ -6,11 +6,11 @@ def wrap_feature_collection(features: list[dict], name: str):
6
6
  将 GeoJSON Feature 集合包装为 FeatureCollection
7
7
  Wrap GeoJSON Feature collection as FeatureCollection
8
8
 
9
- Args:
9
+ - **Args**:
10
10
  - features: GeoJSON Feature 集合。GeoJSON Feature collection.
11
11
  - name: FeatureCollection 名称。FeatureCollection name.
12
12
 
13
- Returns:
13
+ - **Returns**:
14
14
  - dict: GeoJSON FeatureCollection
15
15
  """
16
16
  return {
@@ -8,11 +8,11 @@ def create_channel(server_address: str, secure: bool = False) -> grpc.Channel:
8
8
  创建一个grpc的channel
9
9
  Create a grpc channel
10
10
 
11
- Args:
11
+ - **Args**:
12
12
  - server_address (str): 服务器地址。server address.
13
13
  - secure (bool, optional): 是否使用安全连接. Defaults to False. Whether to use a secure connection. Defaults to False.
14
14
 
15
- Returns:
15
+ - **Returns**:
16
16
  - grpc.Channel: grpc的channel。grpc channel.
17
17
  """
18
18
  if server_address.startswith("http://"):
@@ -35,11 +35,11 @@ def create_aio_channel(server_address: str, secure: bool = False) -> grpc.aio.Ch
35
35
  创建一个grpc的异步channel
36
36
  Create a grpc asynchronous channel
37
37
 
38
- Args:
38
+ - **Args**:
39
39
  - server_address (str): 服务器地址。server address.
40
40
  - secure (bool, optional): 是否使用安全连接. Defaults to False. Whether to use a secure connection. Defaults to False.
41
41
 
42
- Returns:
42
+ - **Returns**:
43
43
  - grpc.aio.Channel: grpc的异步channel。grpc asynchronous channel.
44
44
  """
45
45
  if server_address.startswith("http://"):
@@ -13,12 +13,12 @@ def point_on_line_given_distance(start_node, end_node, distance):
13
13
  Given two points (start_point and end_point) defining a line, and a distance s to travel along the line,
14
14
  return the coordinates of the point reached after traveling s units along the line, starting from start_point.
15
15
 
16
- Args:
16
+ - **Args**:
17
17
  start_point (tuple): tuple of (x, y) representing the starting point on the line.
18
18
  end_point (tuple): tuple of (x, y) representing the ending point on the line.
19
19
  distance (float): Distance to travel along the line, starting from start_point.
20
20
 
21
- Returns:
21
+ - **Returns**:
22
22
  tuple: tuple of (x, y) representing the new point reached after traveling s units along the line.
23
23
  """
24
24