pycityagent 1.0.0__py3-none-any.whl → 1.1.0__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/cc/cc.py CHANGED
@@ -5,7 +5,7 @@ from .trip import *
5
5
  from .conve import *
6
6
  from .user import *
7
7
 
8
- class Commond:
8
+ class Command:
9
9
  """
10
10
  BrainCommond: 即脑部发出的指令; The commond from Agent's Brain
11
11
 
@@ -18,19 +18,19 @@ class Commond:
18
18
  self.target = target
19
19
  self.user_func = user_func
20
20
 
21
- class CommondController:
21
+ class CommandController:
22
22
  """
23
23
  Commond控制器模组: 连接Brain以及StateTranformer
24
24
  Commond Controller module: Used to connect the Brain module and StateTransformer module
25
25
  """
26
- def __init__(self, agent, config=None) -> None:
26
+ def __init__(self, agent) -> None:
27
27
  '''默认初始化'''
28
28
  # TODO: config配置
29
29
  self._agent = agent
30
30
  self._brain = agent._brain
31
- self.commond_control = {}
31
+ self.command_line = {}
32
32
  """
33
- 控制序列: 与state关联的BrainCommond集合
33
+ 默认控制序列: 与state关联的BrainCommond集合
34
34
  Control Hub: connect the state with a BrainCommond collection
35
35
  Type: dict[str, list[BrainCommond]]
36
36
  Default:
@@ -40,33 +40,37 @@ class CommondController:
40
40
  - conve: [whetherUserControl, whetherStopConverse]
41
41
  - controled: [whetherEndControl]
42
42
  """
43
- if config != None:
44
- pass
45
- else:
46
- self.commond_control['idle'] = [
47
- Commond('gousercontrol', whetherUserControl),
48
- Commond('gotrip', whetherGoTrip),
49
- Commond('goshop', whetherGoShop),
50
- Commond('goconverse', whetherGoConverse)
51
- ]
52
- self.commond_control['trip'] = [
53
- Commond('gousercontrol', whetherUserControl),
54
- Commond('routefailed', whetherRouteFailed),
55
- Commond('arrived', whetherTripArrived)
56
- ]
57
- self.commond_control['shop'] = [
58
- Commond('gousercontrol', whetherUserControl),
59
- Commond('shopdone', whetherShopFinished)
60
- ]
61
- self.commond_control['conve'] = [
62
- Commond('gousercontrol', whetherUserControl),
63
- Commond('convedone', whetherStopConverse)
64
- ]
65
- self.commond_control['controled'] = [
66
- Commond('controlback', whetherEndControl)
67
- ]
68
43
 
69
- def insertCommond(self, target_state:list[str], commond:Commond):
44
+ self.command_line['idle'] = [
45
+ Command('gousercontrol', whetherUserControl),
46
+ Command('gotrip', whetherGoTrip),
47
+ Command('goshop', whetherGoShop),
48
+ Command('goconverse', whetherGoConverse)
49
+ ]
50
+ self.command_line['trip'] = [
51
+ Command('gousercontrol', whetherUserControl),
52
+ Command('routefailed', whetherRouteFailed),
53
+ Command('arrived', whetherTripArrived)
54
+ ]
55
+ self.command_line['shop'] = [
56
+ Command('gousercontrol', whetherUserControl),
57
+ Command('shopdone', whetherShopFinished)
58
+ ]
59
+ self.command_line['conve'] = [
60
+ Command('gousercontrol', whetherUserControl),
61
+ Command('convedone', whetherStopConverse)
62
+ ]
63
+ self.command_line['controled'] = [
64
+ Command('controlback', whetherEndControl)
65
+ ]
66
+
67
+ def reset_cc(self):
68
+ """
69
+ 重置命令控制器
70
+ """
71
+ self.command_line = {}
72
+
73
+ def insert_command(self, target_state:list[str], command:Command):
70
74
  """
71
75
  插入指令
72
76
  Insert Commond: This function will insert the commond to those control sequences show in target_state
@@ -76,10 +80,10 @@ class CommondController:
76
80
  - commond (Comond): the commond to be inserted
77
81
  """
78
82
  for target in target_state:
79
- if target in self.commond_control.keys():
80
- self.commond_control.append(commond)
83
+ if target in self.command_line.keys():
84
+ self.command_line[target].append(command)
81
85
  else:
82
- self.commond_control[target] = [commond]
86
+ self.command_line[target] = [command]
83
87
 
84
88
  async def Run(self):
85
89
  """
@@ -92,9 +96,9 @@ class CommondController:
92
96
  - If there is a 'True' of function, returns the target commond
93
97
  - Else, return 'nothing' commond
94
98
  """
95
- if self._agent.state not in self.commond_control.keys():
99
+ if self._agent.state not in self.command_line.keys():
96
100
  print(f"No commond control line match with current state: {self._agent.state}")
97
- control_line = self.commond_control[self._agent.state] # 获取agent状态对应的控制链
101
+ control_line = self.command_line[self._agent.state] # 获取agent状态对应的控制链
98
102
  for control in control_line:
99
103
  result = await control.user_func(self._agent.Brain.Memory.Working)
100
104
  if result:
@@ -18,21 +18,9 @@ class HubConnector:
18
18
  app_id=app_id,
19
19
  app_secret=app_secret
20
20
  )
21
- if agent == None:
22
- self._agent = None
23
- self._agent_id = None
24
- else:
25
- self._agent = agent
26
- try:
27
- self._agent_id = self._client.bind_person(
28
- self._agent.base['id'],
29
- self._agent.agent_name,
30
- Image.open(profile_img)
31
- )
32
- except Exception as e:
33
- traceback.print_exc()
34
- print(e)
35
- self._agent_id = 7
21
+ self._agent = agent
22
+ self._agent_id = None
23
+ self._profile_img = profile_img
36
24
  self.messageBuffer:list[AgentMessage] = []
37
25
  """
38
26
  用于存储历史前端交互信息
@@ -55,26 +43,29 @@ class HubConnector:
55
43
  app_secret=app_secret
56
44
  )
57
45
 
58
- def BindAgent(self, agent, profile_img:str):
46
+ def BindCitizenAgent(self):
59
47
  """
60
- 绑定Agent
48
+ 将CitizenAgent绑定到绑定Agent
61
49
  Bind an Agent through AppHub
62
-
63
- Args:
64
- - agent (Agent): the Agent needs to be bind with
65
- - profile_img (str) : the path of profile_img, which will be shown in frontend and dashboard
66
50
  """
67
- if self._client == None:
68
- print("Not Connect To AppHub Yet")
69
- return
70
- self._agent = agent
71
51
  self._agent_id = self._client.bind_person(
72
- self._agent.base['id'],
73
- self._agent.agent_name,
74
- Image.open(profile_img)
52
+ self._agent._id,
53
+ self._agent._name,
54
+ Image.open(self._profile_img)
55
+ )
56
+
57
+ def InsertFuncAgent(self):
58
+ """
59
+ 将FuncAgent插入到AppHub中
60
+ Insert the Func Agent to AppHub
61
+ """
62
+ self._agent_id = self._client.bind_func(
63
+ self._agent._id,
64
+ self._agent._name,
65
+ Image.open(self._profile_img)
75
66
  )
76
67
 
77
- def Update(self, messages:Optional[list[AgentMessage]]=None, streetview:Image=None, longlat:list[float]=None, pop:str=None):
68
+ def Update(self, messages:Optional[list[AgentMessage]]=None, streetview:Image.Image=None, longlat:list[float]=None, pop:str=None):
78
69
  """
79
70
  交互更新
80
71
  FrontEnd Related Update
@@ -100,12 +91,13 @@ class HubConnector:
100
91
  print("AppHub: Not Bind Agent Yet")
101
92
  return
102
93
  else:
103
- pop_ = self._agent.agent_name
94
+ pop_ = self._agent._name
104
95
  if pop != None:
105
96
  pop_ = self._agent.agent_name + ": " + pop
106
- longlat_ = [self._agent.motion['position']['longlat_position']['longitude'], self._agent.motion['position']['longlat_position']['latitude']]
107
97
  if longlat != None:
108
98
  longlat_ = longlat
99
+ else:
100
+ longlat_ = [self._agent.motion['position']['longlat_position']['longitude'], self._agent.motion['position']['longlat_position']['latitude']]
109
101
 
110
102
  self._client.update_agent_map(
111
103
  agent_id = self._agent_id,
@@ -1,3 +1,3 @@
1
1
  from .image import *
2
2
 
3
- __all__ = [AgentImage, AgentScratch]
3
+ __all__ = [Image, CitizenImage, Scratch, CitizenScratch]
@@ -2,29 +2,44 @@ from typing import Optional
2
2
  import json
3
3
  from abc import ABC, abstractclassmethod
4
4
 
5
- class ProfileTemplate:
5
+
6
+ class Image:
6
7
  """
7
- profile模板类
8
- The template class of Agent Profile
8
+ Image模块: 智能体画像
9
+ Agent's Image module: Defines the uniqueness of Agent
9
10
  """
10
- def __init__(self) -> None:
11
- pass
11
+ def __init__(self, agent) -> None:
12
+ self._agent = agent
13
+ self.scratch = Scratch()
14
+
15
+ def get_profile(self):
16
+ """
17
+ 获取Agent的Scratch Profile信息
18
+ Get the Scratch Profile message
12
19
 
13
- @abstractclassmethod
14
- def to_dialog(self) -> list[dict]:
20
+ Returns:
21
+ - (str)
15
22
  """
16
- 将Profile转化为LLM可用的dialog的抽象函数
17
- The abstract method that turns Agent's profile to LLM standard dialog
23
+ return self.scratch.get_profile_content()
24
+
25
+ def load_scratch(self, scratch_file:str):
18
26
  """
27
+ 加载基于文件的Profile加载
28
+ Load Profile based on file
19
29
 
20
- class AgentImage:
30
+ Args:
31
+ - scratch_file (str): the path of scratch_file
32
+ """
33
+ self.scratch.load(scratch_file)
34
+
35
+ class CitizenImage(Image):
21
36
  """
22
37
  Agent Image模块: 用户画像控制
23
38
  Agent's Image module: Defines the uniqueness of Agent
24
39
  """
25
40
  def __init__(self, agent, scratch_file:str=None, selfie:bool=False) -> None:
26
41
  self._agent = agent
27
- self.scratch = AgentScratch()
42
+ self.scratch = CitizenScratch()
28
43
  """
29
44
  Agent的Scratch信息: 用于描述Agent的基本属性
30
45
  Scratch: Used to describe the basic info of Agent
@@ -48,7 +63,7 @@ class AgentImage:
48
63
  if scratch_file != None:
49
64
  self.scratch.load(scratch_file)
50
65
  else:
51
- self.scratch.name = self._agent.agent_name
66
+ self.scratch.name = self._agent._name
52
67
  self.scratch.age = profile['age']
53
68
  education = profile['education']
54
69
  if education < 3:
@@ -72,26 +87,6 @@ class AgentImage:
72
87
  # TODO: 补充自拍
73
88
  pass
74
89
 
75
- def get_profile(self):
76
- """
77
- 获取Agent的Scratch Profile信息
78
- Get the Scratch Profile message
79
-
80
- Returns:
81
- - (str)
82
- """
83
- return self.scratch.get_profile_content()
84
-
85
- def load_scratch(self, scratch_file:str):
86
- """
87
- 加载基于文件的Profile加载
88
- Load Profile based on file
89
-
90
- Args:
91
- - scratch_file (str): the path of scratch_file
92
- """
93
- self.scratch.load(scratch_file)
94
-
95
90
  def load_selfie(self, selfie_file:str):
96
91
  """
97
92
  基于图像的Selfie加载
@@ -103,17 +98,8 @@ class AgentImage:
103
98
  """
104
99
  print("Not Implemented")
105
100
 
106
- class AgentScratch():
107
- def __init__(self, scratch:Optional[dict]=None) -> None:
108
- self.name = None
109
- self.age = None
110
- self.education = None
111
- self.gender = None
112
- self.consumption = None
113
- self.innate = ''
114
- self.learned = ''
115
- self.currently = ''
116
- self.lifestyle = ''
101
+ class Scratch:
102
+ def __init__(self, scratch: Optional[dict]=None) -> None:
117
103
  if scratch != None:
118
104
  self.forward(scratch)
119
105
 
@@ -133,6 +119,25 @@ class AgentScratch():
133
119
  json_str = f.read()
134
120
  scratch = json.loads(json_str)
135
121
  self.forward(scratch)
122
+
123
+ def get_profile_content(self):
124
+ text = ""
125
+ for attr_name, attr_value in self.__dict__.items():
126
+ text += f"{attr_name}: {attr_value}\n"
127
+ return text
128
+
129
+ class CitizenScratch(Scratch):
130
+ def __init__(self, scratch:Optional[dict]=None) -> None:
131
+ super().__init__(scratch=scratch)
132
+ self.name = None
133
+ self.age = None
134
+ self.education = None
135
+ self.gender = None
136
+ self.consumption = None
137
+ self.innate = ''
138
+ self.learned = ''
139
+ self.currently = ''
140
+ self.lifestyle = ''
136
141
 
137
142
  def get_str_lifestyle(self):
138
143
  return self.lifestyle
@@ -153,6 +158,5 @@ class AgentScratch():
153
158
  text += f'生活习惯: {self.lifestyle}\n'
154
159
  return text
155
160
 
156
-
157
161
  def __str__(self):
158
162
  return str(self.__dict__)
pycityagent/simulator.py CHANGED
@@ -1,10 +1,11 @@
1
1
  from pycitysim import *
2
- from pycitysim.sidecar import OnlyClientSidecar
2
+ from pycitysim.routing import RoutingClient
3
3
  from pycitysim.sim import CityClient
4
4
  from typing import Optional, Union
5
5
  from datetime import datetime, timedelta
6
6
  import asyncio
7
- from .agent import Agent
7
+ from .agent_citizen import CitizenAgent
8
+ from .agent_func import FuncAgent
8
9
 
9
10
  class SimPerceive:
10
11
  """
@@ -44,6 +45,7 @@ class Simulator:
44
45
  mongo_coll = config['map_request']['mongo_coll'],
45
46
  cache_dir = config['map_request']['cache_dir'],
46
47
  )
48
+ self.routing = RoutingClient(self.config['route_request']['server'], True)
47
49
  self.time = 0
48
50
 
49
51
  # * Agent相关
@@ -72,7 +74,7 @@ class Simulator:
72
74
  resp.motions = motions
73
75
  return resp
74
76
 
75
- async def GetAgent(self, name:str=None, id:int=None):
77
+ async def GetCitizenAgent(self, name:str, id:int):
76
78
  """
77
79
  获取agent
78
80
  Get Agent
@@ -82,46 +84,44 @@ class Simulator:
82
84
  - id int: 即绑定的person的id the id of person that you try to bind with
83
85
 
84
86
  Returns:
85
- - Agent
87
+ - CitizenAgent
86
88
  """
87
89
  await self.GetTime()
88
- name_ = "张三"
89
- if name != None:
90
- name_ = name
91
- if id == None:
92
- base = self._client.person_service.default_person()
93
- agent = Agent(
94
- name_,
95
- self.config['simulator']['server'],
96
- simulator=self,
97
- id=id,
98
- base=base,
99
- )
100
- else:
101
- resp = await self._client.person_service.GetPerson({"person_id": id})
102
- base = resp['base']
103
- motion = resp['motion']
104
- agent = Agent(
105
- name_,
106
- self.config['simulator']['server'],
107
- simulator=self,
108
- id=id,
109
- base=base,
110
- motion=motion,
111
- )
112
- if 'streetview_request' in self.config.keys():
113
- agent.Brain.Sence._streetview_engine = self.config['streetview_request']['engine']
114
- if agent.Brain.Sence._streetview_engine == 'baidumap':
115
- agent.Brain.Sence._streetviewAK = self.config['streetview_request']['mapAK']
116
- elif agent.Brain.Sence._streetview_engine == 'googlemap':
117
- if 'proxy' in self.config['streetview_request'].keys():
118
- agent.Brain.Sence._streetviewProxy = self.config['streetview_request']['proxy']
119
- else:
120
- agent.Brain.Sence._streetview_engine = ""
121
- print("Wrong Streetview Engine")
90
+ resp = await self._client.person_service.GetPerson({"person_id": id})
91
+ base = resp['base']
92
+ motion = resp['motion']
93
+ agent = CitizenAgent(
94
+ name,
95
+ self.config['simulator']['server'],
96
+ simulator=self,
97
+ id=id,
98
+ base=base,
99
+ motion=motion
100
+ )
101
+ agent.set_streetview_config(self.config['streetview_request'])
102
+ return agent
103
+
104
+ async def GetFuncAgent(self, id:int, name:str):
105
+ """
106
+ 获取一个Func Agent模板
107
+
108
+ Args:
109
+ - name (str): the name of your agent
110
+ - id (int): the unique id of agent
111
+
112
+ Returns:
113
+ - FuncAgent
114
+ """
115
+ agent = FuncAgent(
116
+ name,
117
+ id+10000000,
118
+ self.config['simulator']['server'],
119
+ simulator=self
120
+ )
121
+ agent.set_streetview_config(self.config['streetview_request'])
122
122
  return agent
123
123
 
124
- def InsertAgent(self, profile):
124
+ def InsertCitizenAgent(self, profile):
125
125
  """
126
126
  插入agent
127
127
  Insert Agent
pycityagent/st/st.py CHANGED
@@ -3,8 +3,8 @@ from abc import ABC, abstractmethod
3
3
 
4
4
  class StateTransformer:
5
5
  """
6
- State Transformer模块: 控制agent状态转移
7
- The State Transformer module: used to control the transformation of agent's state
6
+ 默认State Transformer模块: 控制agent状态转移
7
+ Default State Transformer module: used to control the transformation of agent's state
8
8
 
9
9
  Doc:
10
10
  - 基于transitions()构建 https://github.com/tyarkoni/transitions
@@ -42,14 +42,14 @@ class StateTransformer:
42
42
  - controlback: controled -> idle
43
43
  - Note: 目前不支持状态扩展
44
44
  """
45
- states = ['idle', 'trip', 'shop', 'conve', 'paused', 'controled']
45
+ _states = ['idle', 'trip', 'shop', 'conve', 'paused', 'controled']
46
46
 
47
47
  def __init__(self, config=None):
48
48
  self.pre_state = None
49
- # TODO: 后续添加扩展接口
50
49
  # Initialize the state machine
51
- self.machine = Machine(model=self, states=StateTransformer.states, initial='idle')
52
-
50
+ self.machine = Machine(states=StateTransformer._states, initial='idle')
51
+ self.machine._transition_queue
52
+
53
53
  # idle
54
54
  self.machine.add_transition(trigger='gotrip', source='idle', dest='trip')
55
55
  self.machine.add_transition(trigger='goshop', source='idle', dest='shop')
@@ -81,11 +81,45 @@ class StateTransformer:
81
81
  self.machine.add_transition(trigger='gousercontrol', source='*', dest='controled')
82
82
  self.machine.add_transition(trigger='controlback', source='controled', dest='idle')
83
83
 
84
+ def reset_state_transformer(self, states:list[str], initial:str):
85
+ """
86
+ 重置状态控制器——重置后状态转化器没有任何可用transition
87
+
88
+ Args:
89
+ - states (list[str]): a list of states
90
+ - initial (str): initial state
91
+ """
92
+ self.machine = Machine(states=states, initial=initial)
93
+ self.machine.add_transition(trigger='nothing', source='*', dest='=')
94
+
95
+
96
+ def add_transition(self, trigger:str, source: str, dest:str, before=None, after=None):
97
+ """
98
+ 添加状态转换
99
+ Add state transition
100
+
101
+ Args:
102
+ - trigger (str): 用于唤醒该状态转换器
103
+ - source (str): 源状态, 如为'*' 表示任意状态皆可作为源状态
104
+ - dest (str): 目标状态, 如为'=' 表示目标状态与原状态相同
105
+ - defore (func): 即状态转化后执行的操作
106
+ - after (func): 即状态转化前执行的操作
107
+ """
108
+ self.machine.add_transition(trigger=trigger, source=source, dest=dest, before=before, after=after)
109
+
84
110
  def state_remember(self):
111
+ """
112
+ 记住当前状态并存储于pre_state属性中
113
+ Remember current state and store it to 'pre_state' attribute
114
+ """
85
115
  if self.state != 'paused': # 避免重复Pause
86
116
  self.pre_state = self.state
87
117
 
88
118
  def pause_back(self):
119
+ """
120
+ 从原状态恢复, 即恢复为pre_state记录的状态
121
+ Recover from pre_state
122
+ """
89
123
  if self.pre_state == 'trip':
90
124
  self.active_trip()
91
125
  elif self.pre_state == 'shop':
@@ -93,4 +127,7 @@ class StateTransformer:
93
127
  elif self.pre_state == 'conve':
94
128
  self.active_conve()
95
129
  elif self.pre_sate == 'idle':
96
- self.active_idle()
130
+ self.active_idle()
131
+
132
+ def trigger(self, command:str):
133
+ self.machine.trigger(command)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycityagent
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: LLM-based城市模拟器agent构建库
5
5
  Author-email: Yuwei Yan <pinkgranite86@gmail.com>
6
6
  License: MIT License
@@ -39,7 +39,7 @@ Requires-Dist: geojson >=3.1.0
39
39
  Requires-Dist: numpy >=1.26.3
40
40
  Requires-Dist: openai >=1.8.0
41
41
  Requires-Dist: Pillow >=10.2.0
42
- Requires-Dist: pycitysim >=1.8.0
42
+ Requires-Dist: pycitysim >=1.12.2
43
43
  Requires-Dist: citystreetview >=1.1.0
44
44
  Requires-Dist: PyYAML >=6.0.1
45
45
  Requires-Dist: Requests >=2.31.0
@@ -92,10 +92,12 @@ citysim_request:
92
92
  map_request:
93
93
  mongo_coll: map_beijing_extend_20240205
94
94
  cache_dir: ./cache
95
+ route_request:
96
+ server: http://api-opencity-2x.fiblab.net:58082
95
97
  streetview_request:
96
98
  engine: baidumap / googlemap
97
- mapAK: your baidumap AK (if baidumap)
98
- proxy: your googlemap proxy (if googlemap, optional)
99
+ mapAK: baidumap api-key (if you use baidumap engine)
100
+ proxy: googlemap proxy (if you use googlemap engine)
99
101
 
100
102
  apphub_request:
101
103
  hub_url: https://api-opencity-2x.fiblab.net:58080
@@ -106,31 +108,56 @@ apphub_request:
106
108
  - Forget about **citysim_request**, let's focus on the other two.
107
109
 
108
110
  #### LLM_REQUEST
109
- - As you can tell, the whole CityAgent is based on the LLM, by now, there are three different parts of config items: **text_request**, **img_understand_request** and **img_generate_request**
111
+ - As you can see, the whole CityAgent is based on the LLM, by now, there are three different parts of config items: **text_request**, **img_understand_request** and **img_generate_request**
110
112
  - By now, we support [**qwen**](https://tongyi.aliyun.com/) and [**openai**](https://openai.com/)
111
113
  - `Notice: Our environments are basically conducted with qwen. If you prefer to use openai, then you may encounter hardships. AND fell free to issue us.`
112
114
  - Get your **api_key** and chooce your **model**s
113
115
 
114
- ### CITYSIM_REQUEST
115
- - There are no need to change the 'simulator' and 'map_request' config
116
- - 'streetview_request': this is the config used for streetview
117
- - By now, we support 'baidumap' and 'googlemap'
118
- - If you use 'baidumap', then you need to apply for a mapAK
119
- - If you use 'googlemap', then you can config your own proxy by 'proxy' attribute
116
+ #### CITYSIM_REQUEST
117
+ - Most of the configuration options in this part are determined, such as **simulator.server**, **map_request.mongo_coll**, **route_request.server**
118
+ - **map_request.cache_dir**: used for storing map data your machine, you can justify the target dir as you wish (**create the dir first**)
119
+ - **streetview_request**: used for obtaining streetview images, by now, we support baidumap engine and googlemap engine
120
+ - if you choose baidumap engine, you need to get a baidumap api-key
121
+ ``` yaml
122
+ streetview_request:
123
+ engine: baidumap
124
+ mapAK: xxxx
125
+ ```
126
+ - if you choose googlemap engine, you need to provide your proxy address, for example:
127
+ ``` yaml
128
+ streetview_request:
129
+ engine: googlemap
130
+ proxy:
131
+ http: http://xxxx
132
+ https: https://xxxx
133
+ ```
120
134
 
121
135
  #### APPHUB_REQUEST
122
- - This is basically used to connect with the backend.
136
+ - Used for creating the connection between backend server and client.
123
137
  - Put your **app_id** and **app_secret** here.
138
+ - Create your account and apply in [Opencity website](https://opencity.fiblab.net/)
124
139
 
125
140
  ### Installation
126
- - Install from **pip** easily.
127
- ```shell
128
- pip install pycityagent
129
- ```
141
+ #### PyPI Installation
142
+ - Install from **pip** easily.
143
+ ```shell
144
+ pip install pycityagent
145
+ ```
146
+
147
+ #### Install from source code
148
+ - Clone this repo
149
+ - Install required packages
150
+ ``` shell
151
+ pip install -r requirements.txt
152
+ ```
153
+ - Install **libGL.so.1**, if you ara using Linux with a suitable package manager: (apt for instance)
154
+ ``` shell
155
+ apt-get install libgl1
156
+ ```
130
157
 
131
158
  ### CODE and RUN
132
159
  - Check the **example** folder and copy files from it (`Remember replace the config file`)
133
- - Look at the Demo:
160
+ - Look at the Demo: (A citizen Agent demo)
134
161
  ```python
135
162
  import yaml
136
163
  from pycityagent.simulator import Simulator
@@ -147,7 +174,7 @@ async def main():
147
174
  smi = Simulator(config['citysim_request'])
148
175
 
149
176
  # get the person by person_id, return agent
150
- agent = await smi.GetAgent("name_of_agent", 8)
177
+ agent = await smi.GetCitizenAgent("name_of_agent", 8)
151
178
 
152
179
  # Help you build unique agent by scratch/profile
153
180
  agent.Image.load_scratch('scratch_template.json')
@@ -158,6 +185,7 @@ async def main():
158
185
 
159
186
  # Connect to apphub so you can interact with your agent in front end
160
187
  agent.ConnectToHub(config['apphub_request'])
188
+ agent.Bind()
161
189
 
162
190
  # Creat the soul (a LLM processor actually)
163
191
  llmConfig = LLMConfig(config['llm_request'])