pycityagent 2.0.0a12__py3-none-any.whl → 2.0.0a14__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.
@@ -1,18 +1,21 @@
1
1
  import asyncio
2
2
  import json
3
3
  import logging
4
+ import os
5
+ from pathlib import Path
4
6
  import uuid
5
7
  from datetime import datetime
6
8
  import random
7
9
  from typing import Dict, List, Optional, Callable, Union,Any
10
+ import fastavro
8
11
  from mosstool.map._map_util.const import AOI_START_ID
9
12
  import pycityproto.city.economy.v2.economy_pb2 as economyv2
10
13
  from pycityagent.memory.memory import Memory
14
+ from pycityagent.message.messager import Messager
15
+ from pycityagent.survey import Survey
16
+ from pycityagent.utils.avro_schema import PROFILE_SCHEMA, DIALOG_SCHEMA, STATUS_SCHEMA, SURVEY_SCHEMA
11
17
 
12
18
  from ..agent import Agent, InstitutionAgent
13
- from .interview import InterviewManager
14
- from .survey import QuestionType, SurveyManager
15
- from .ui import InterviewUI
16
19
  from .agentgroup import AgentGroup
17
20
 
18
21
  logger = logging.getLogger(__name__)
@@ -44,10 +47,34 @@ class AgentSimulation:
44
47
  self._groups: Dict[str, AgentGroup] = {}
45
48
  self._agent_uuid2group: Dict[uuid.UUID, AgentGroup] = {}
46
49
  self._agent_uuids: List[uuid.UUID] = []
47
-
50
+ self._user_chat_topics: Dict[uuid.UUID, str] = {}
51
+ self._user_survey_topics: Dict[uuid.UUID, str] = {}
52
+ self._user_interview_topics: Dict[uuid.UUID, str] = {}
48
53
  self._loop = asyncio.get_event_loop()
49
- self._interview_manager = InterviewManager()
50
- self._survey_manager = SurveyManager()
54
+
55
+ self._messager = Messager(
56
+ hostname=config["simulator_request"]["mqtt"]["server"],
57
+ port=config["simulator_request"]["mqtt"]["port"],
58
+ username=config["simulator_request"]["mqtt"].get("username", None),
59
+ password=config["simulator_request"]["mqtt"].get("password", None),
60
+ )
61
+ asyncio.create_task(self._messager.connect())
62
+
63
+ self._enable_avro = config["storage"]["avro"]["enabled"]
64
+ self._avro_path = Path(config["storage"]["avro"]["path"])
65
+ self._avro_file = {
66
+ "profile": self._avro_path / f"{self.exp_id}_profile.avro",
67
+ "dialog": self._avro_path / f"{self.exp_id}_dialog.avro",
68
+ "status": self._avro_path / f"{self.exp_id}_status.avro",
69
+ "survey": self._avro_path / f"{self.exp_id}_survey.avro",
70
+ }
71
+
72
+ self._enable_pgsql = config["storage"]["pgsql"]["enabled"]
73
+ self._pgsql_host = config["storage"]["pgsql"]["host"]
74
+ self._pgsql_port = config["storage"]["pgsql"]["port"]
75
+ self._pgsql_database = config["storage"]["pgsql"]["database"]
76
+ self._pgsql_user = config["storage"]["pgsql"]["user"]
77
+ self._pgsql_password = config["storage"]["pgsql"]["password"]
51
78
 
52
79
  @property
53
80
  def agents(self):
@@ -126,6 +153,7 @@ class AgentSimulation:
126
153
  agent = agent_class(
127
154
  name=agent_name,
128
155
  memory=memory,
156
+ avro_file=self._avro_file,
129
157
  )
130
158
 
131
159
  self._agents[agent._uuid] = agent
@@ -145,7 +173,7 @@ class AgentSimulation:
145
173
  # 获取当前组的agents
146
174
  agents = list(self._agents.values())[start_idx:end_idx]
147
175
  group_name = f"AgentType_{i}_Group_{k}"
148
- group = AgentGroup.remote(agents, self.config, self.exp_id)
176
+ group = AgentGroup.remote(agents, self.config, self.exp_id, self._avro_file)
149
177
  self._groups[group_name] = group
150
178
  for agent in agents:
151
179
  self._agent_uuid2group[agent._uuid] = group
@@ -156,6 +184,42 @@ class AgentSimulation:
156
184
  for group in self._groups.values():
157
185
  init_tasks.append(group.init_agents.remote())
158
186
  await asyncio.gather(*init_tasks)
187
+ for uuid, agent in self._agents.items():
188
+ self._user_chat_topics[uuid] = f"exps/{self.exp_id}/agents/{uuid}/user-chat"
189
+ self._user_survey_topics[uuid] = f"exps/{self.exp_id}/agents/{uuid}/user-survey"
190
+
191
+ # save profile
192
+ if self._enable_avro:
193
+ self._avro_path.mkdir(parents=True, exist_ok=True)
194
+ # profile
195
+ filename = self._avro_file["profile"]
196
+ with open(filename, "wb") as f:
197
+ profiles = []
198
+ for agent in self._agents.values():
199
+ profile = await agent.memory._profile.export()
200
+ profile = profile[0]
201
+ profile['id'] = str(agent._uuid)
202
+ profiles.append(profile)
203
+ fastavro.writer(f, PROFILE_SCHEMA, profiles)
204
+
205
+ # dialog
206
+ filename = self._avro_file["dialog"]
207
+ with open(filename, "wb") as f:
208
+ dialogs = []
209
+ fastavro.writer(f, DIALOG_SCHEMA, dialogs)
210
+
211
+ # status
212
+ filename = self._avro_file["status"]
213
+ with open(filename, "wb") as f:
214
+ statuses = []
215
+ fastavro.writer(f, STATUS_SCHEMA, statuses)
216
+
217
+ # survey
218
+ filename = self._avro_file["survey"]
219
+ with open(filename, "wb") as f:
220
+ surveys = []
221
+ fastavro.writer(f, SURVEY_SCHEMA, surveys)
222
+
159
223
 
160
224
  async def gather(self, content: str):
161
225
  """收集智能体的特定信息"""
@@ -219,6 +283,7 @@ class AgentSimulation:
219
283
  }
220
284
 
221
285
  PROFILE = {
286
+ "name": "unknown",
222
287
  "gender": random.choice(["male", "female"]),
223
288
  "education": random.choice(
224
289
  ["Doctor", "Master", "Bachelor", "College", "High School"]
@@ -251,7 +316,7 @@ class AgentSimulation:
251
316
  "personality": random.choice(
252
317
  ["outgoint", "introvert", "ambivert", "extrovert"]
253
318
  ),
254
- "income": random.randint(1000, 10000),
319
+ "income": str(random.randint(1000, 10000)),
255
320
  "currency": random.randint(10000, 100000),
256
321
  "residence": random.choice(["city", "suburb", "rural"]),
257
322
  "race": random.choice(
@@ -285,6 +350,32 @@ class AgentSimulation:
285
350
  }
286
351
 
287
352
  return EXTRA_ATTRIBUTES, PROFILE, BASE
353
+
354
+ async def send_survey(self, survey: Survey, agent_uuids: Optional[List[uuid.UUID]] = None):
355
+ """发送问卷"""
356
+ survey = survey.to_dict()
357
+ if agent_uuids is None:
358
+ agent_uuids = self._agent_uuids
359
+ payload = {
360
+ "from": "none",
361
+ "survey_id": survey["id"],
362
+ "timestamp": int(datetime.now().timestamp() * 1000),
363
+ "data": survey,
364
+ }
365
+ for uuid in agent_uuids:
366
+ topic = self._user_survey_topics[uuid]
367
+ await self._messager.send_message(topic, payload)
368
+
369
+ async def send_interview_message(self, content: str, agent_uuids: Union[uuid.UUID, List[uuid.UUID]]):
370
+ """发送面试消息"""
371
+ payload = {
372
+ "from": "none",
373
+ "content": content,
374
+ "timestamp": int(datetime.now().timestamp() * 1000),
375
+ }
376
+ for uuid in agent_uuids:
377
+ topic = self._user_chat_topics[uuid]
378
+ await self._messager.send_message(topic, payload)
288
379
 
289
380
  async def step(self):
290
381
  """运行一步, 即每个智能体执行一次forward"""
@@ -0,0 +1,58 @@
1
+ from typing import List, Dict, Optional
2
+ from datetime import datetime
3
+ import uuid
4
+ import json
5
+ from .models import Survey, Question, QuestionType, Page
6
+
7
+
8
+ class SurveyManager:
9
+ def __init__(self):
10
+ self._surveys: Dict[str, Survey] = {}
11
+
12
+ def create_survey(
13
+ self, title: str, description: str, pages: List[dict]
14
+ ) -> Survey:
15
+ """创建新问卷"""
16
+ survey_id = uuid.uuid4()
17
+
18
+ # 转换页面和问题数据
19
+ survey_pages = []
20
+ for page_data in pages:
21
+ questions = []
22
+ for q in page_data["elements"]:
23
+ question = Question(
24
+ name=q["name"],
25
+ title=q["title"],
26
+ type=QuestionType(q["type"]),
27
+ required=q.get("required", True),
28
+ choices=q.get("choices", []),
29
+ columns=q.get("columns", []),
30
+ rows=q.get("rows", []),
31
+ min_rating=q.get("min_rating", 1),
32
+ max_rating=q.get("max_rating", 5),
33
+ )
34
+ questions.append(question)
35
+
36
+ page = Page(
37
+ name=page_data["name"],
38
+ elements=questions
39
+ )
40
+ survey_pages.append(page)
41
+
42
+ survey = Survey(
43
+ id=survey_id,
44
+ title=title,
45
+ description=description,
46
+ pages=survey_pages,
47
+ )
48
+
49
+ self._surveys[str(survey_id)] = survey
50
+ return survey
51
+
52
+ def get_survey(self, survey_id: str) -> Optional[Survey]:
53
+ """获取指定问卷"""
54
+ return self._surveys.get(survey_id)
55
+
56
+ def get_all_surveys(self) -> List[Survey]:
57
+ """获取所有问卷"""
58
+ return list(self._surveys.values())
@@ -0,0 +1,120 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import List, Dict, Optional
3
+ from datetime import datetime
4
+ from enum import Enum
5
+ import uuid
6
+ import json
7
+
8
+
9
+ class QuestionType(Enum):
10
+ TEXT = "text"
11
+ RADIO = "radiogroup"
12
+ CHECKBOX = "checkbox"
13
+ BOOLEAN = "boolean"
14
+ RATING = "rating"
15
+ MATRIX = "matrix"
16
+
17
+
18
+ @dataclass
19
+ class Question:
20
+ name: str
21
+ title: str
22
+ type: QuestionType
23
+ choices: List[str] = field(default_factory=list)
24
+ columns: List[str] = field(default_factory=list)
25
+ rows: List[str] = field(default_factory=list)
26
+ min_rating: int = 1
27
+ max_rating: int = 5
28
+
29
+ def to_dict(self) -> dict:
30
+ base_dict = {
31
+ "type": self.type.value,
32
+ "name": self.name,
33
+ "title": self.title,
34
+ }
35
+
36
+ if self.type in [QuestionType.RADIO, QuestionType.CHECKBOX]:
37
+ base_dict["choices"] = self.choices
38
+ elif self.type == QuestionType.MATRIX:
39
+ base_dict["columns"] = self.columns
40
+ base_dict["rows"] = self.rows
41
+ elif self.type == QuestionType.RATING:
42
+ base_dict["min_rating"] = self.min_rating
43
+ base_dict["max_rating"] = self.max_rating
44
+
45
+ return base_dict
46
+
47
+
48
+ @dataclass
49
+ class Page:
50
+ name: str
51
+ elements: List[Question]
52
+
53
+ def to_dict(self) -> dict:
54
+ return {
55
+ "name": self.name,
56
+ "elements": [q.to_dict() for q in self.elements]
57
+ }
58
+
59
+
60
+ @dataclass
61
+ class Survey:
62
+ id: uuid.UUID
63
+ title: str
64
+ description: str
65
+ pages: List[Page]
66
+ responses: Dict[str, dict] = field(default_factory=dict)
67
+ created_at: datetime = field(default_factory=datetime.now)
68
+
69
+ def to_dict(self) -> dict:
70
+ return {
71
+ "id": str(self.id),
72
+ "title": self.title,
73
+ "description": self.description,
74
+ "pages": [p.to_dict() for p in self.pages],
75
+ "response_count": len(self.responses),
76
+ }
77
+
78
+ def to_json(self) -> str:
79
+ """Convert the survey to a JSON string for MQTT transmission"""
80
+ survey_dict = {
81
+ "id": str(self.id),
82
+ "title": self.title,
83
+ "description": self.description,
84
+ "pages": [p.to_dict() for p in self.pages],
85
+ "responses": self.responses,
86
+ "created_at": self.created_at.isoformat()
87
+ }
88
+ return json.dumps(survey_dict)
89
+
90
+ @classmethod
91
+ def from_json(cls, json_str: str) -> 'Survey':
92
+ """Create a Survey instance from a JSON string"""
93
+ data = json.loads(json_str)
94
+ pages = [
95
+ Page(
96
+ name=p["name"],
97
+ elements=[
98
+ Question(
99
+ name=q["name"],
100
+ title=q["title"],
101
+ type=QuestionType(q["type"]),
102
+ required=q.get("required", True),
103
+ choices=q.get("choices", []),
104
+ columns=q.get("columns", []),
105
+ rows=q.get("rows", []),
106
+ min_rating=q.get("min_rating", 1),
107
+ max_rating=q.get("max_rating", 5)
108
+ ) for q in p["elements"]
109
+ ]
110
+ ) for p in data["pages"]
111
+ ]
112
+
113
+ return cls(
114
+ id=uuid.UUID(data["id"]),
115
+ title=data["title"],
116
+ description=data["description"],
117
+ pages=pages,
118
+ responses=data.get("responses", {}),
119
+ created_at=datetime.fromisoformat(data["created_at"])
120
+ )
@@ -0,0 +1,7 @@
1
+ from .avro_schema import PROFILE_SCHEMA, DIALOG_SCHEMA, STATUS_SCHEMA, SURVEY_SCHEMA
2
+ from .survey_util import process_survey_for_llm
3
+
4
+ __all__ = [
5
+ "PROFILE_SCHEMA", "DIALOG_SCHEMA", "STATUS_SCHEMA", "SURVEY_SCHEMA",
6
+ "process_survey_for_llm"
7
+ ]
@@ -0,0 +1,85 @@
1
+ PROFILE_SCHEMA = {
2
+ "doc": "Agent属性",
3
+ "name": "AgentProfile",
4
+ "namespace": "com.socialcity",
5
+ "type": "record",
6
+ "fields": [
7
+ {"name": "id", "type": "string"}, # uuid as string
8
+ {"name": "name", "type": "string"},
9
+ {"name": "gender", "type": "string"},
10
+ {"name": "age", "type": "float"},
11
+ {"name": "education", "type": "string"},
12
+ {"name": "skill", "type": "string"},
13
+ {"name": "occupation", "type": "string"},
14
+ {"name": "family_consumption", "type": "string"},
15
+ {"name": "consumption", "type": "string"},
16
+ {"name": "personality", "type": "string"},
17
+ {"name": "income", "type": "string"},
18
+ {"name": "currency", "type": "float"},
19
+ {"name": "residence", "type": "string"},
20
+ {"name": "race", "type": "string"},
21
+ {"name": "religion", "type": "string"},
22
+ {"name": "marital_status", "type": "string"},
23
+ ],
24
+ }
25
+
26
+ DIALOG_SCHEMA = {
27
+ "doc": "Agent对话",
28
+ "name": "AgentDialog",
29
+ "namespace": "com.socialcity",
30
+ "type": "record",
31
+ "fields": [
32
+ {"name": "id", "type": "string"}, # uuid as string
33
+ {"name": "day", "type": "int"},
34
+ {"name": "t", "type": "float"},
35
+ {"name": "type", "type": "int"},
36
+ {"name": "speaker", "type": "string"},
37
+ {"name": "content", "type": "string"},
38
+ {
39
+ "name": "created_at",
40
+ "type": {"type": "long", "logicalType": "timestamp-millis"},
41
+ },
42
+ ],
43
+ }
44
+
45
+ STATUS_SCHEMA = {
46
+ "doc": "Agent状态",
47
+ "name": "AgentStatus",
48
+ "namespace": "com.socialcity",
49
+ "type": "record",
50
+ "fields": [
51
+ {"name": "id", "type": "string"}, # uuid as string
52
+ {"name": "day", "type": "int"},
53
+ {"name": "t", "type": "float"},
54
+ {"name": "lng", "type": "double"},
55
+ {"name": "lat", "type": "double"},
56
+ {"name": "parent_id", "type": "int"},
57
+ {"name": "action", "type": "string"},
58
+ {"name": "hungry", "type": "float"},
59
+ {"name": "tired", "type": "float"},
60
+ {"name": "safe", "type": "float"},
61
+ {"name": "social", "type": "float"},
62
+ {
63
+ "name": "created_at",
64
+ "type": {"type": "long", "logicalType": "timestamp-millis"},
65
+ },
66
+ ],
67
+ }
68
+
69
+ SURVEY_SCHEMA = {
70
+ "doc": "Agent问卷",
71
+ "name": "AgentSurvey",
72
+ "namespace": "com.socialcity",
73
+ "type": "record",
74
+ "fields": [
75
+ {"name": "id", "type": "string"}, # uuid as string
76
+ {"name": "day", "type": "int"},
77
+ {"name": "t", "type": "float"},
78
+ {"name": "survey_id", "type": "string"},
79
+ {"name": "result", "type": "string"},
80
+ {
81
+ "name": "created_at",
82
+ "type": {"type": "long", "logicalType": "timestamp-millis"},
83
+ },
84
+ ],
85
+ }
@@ -0,0 +1,53 @@
1
+ def process_survey_for_llm(survey_dict: dict) -> str:
2
+ """
3
+ 将问卷字典转换为LLM可以逐题处理的格式,使用英文提示
4
+ """
5
+ prompt = f"""Survey Title: {survey_dict['title']}
6
+ Survey Description: {survey_dict['description']}
7
+
8
+ Please answer each question in the following format:
9
+
10
+ """
11
+
12
+ question_count = 1
13
+ for page in survey_dict['pages']:
14
+ for question in page['elements']:
15
+ prompt += f"Question {question_count}: {question['title']}\n"
16
+
17
+ # 根据不同类型的问题生成不同的提示
18
+ if question['type'] == 'radiogroup':
19
+ prompt += "Options: " + ", ".join(question['choices']) + "\n"
20
+ prompt += "Please select ONE option\n"
21
+
22
+ elif question['type'] == 'checkbox':
23
+ prompt += "Options: " + ", ".join(question['choices']) + "\n"
24
+ prompt += "You can select MULTIPLE options\n"
25
+
26
+ elif question['type'] == 'rating':
27
+ prompt += f"Rating range: {question.get('min_rating', 1)} - {question.get('max_rating', 5)}\n"
28
+ prompt += "Please provide a rating within the range\n"
29
+
30
+ elif question['type'] == 'matrix':
31
+ prompt += "Rows: " + ", ".join(question['rows']) + "\n"
32
+ prompt += "Columns: " + ", ".join(question['columns']) + "\n"
33
+ prompt += "Please select ONE column option for EACH row\n"
34
+
35
+ elif question['type'] == 'text':
36
+ prompt += "Please provide a text response\n"
37
+
38
+ elif question['type'] == 'boolean':
39
+ prompt += "Options: Yes, No\n"
40
+ prompt += "Please select either Yes or No\n"
41
+
42
+ prompt += "\nAnswer: [Your response here]\n\n---\n\n"
43
+ question_count += 1
44
+
45
+ # 添加总结提示
46
+ prompt += """Please ensure:
47
+ 1. All required questions are answered
48
+ 2. Responses match the question type requirements
49
+ 3. Answers are clear and specific
50
+
51
+ Format your responses exactly as requested above."""
52
+
53
+ return prompt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycityagent
3
- Version: 2.0.0a12
3
+ Version: 2.0.0a14
4
4
  Summary: LLM-based城市环境agent构建库
5
5
  License: MIT
6
6
  Author: Yuwei Yan
@@ -20,6 +20,7 @@ Requires-Dist: aiohttp (==3.10.10)
20
20
  Requires-Dist: aiomqtt (>=2.3.0,<3.0.0)
21
21
  Requires-Dist: citystreetview (==1.2.4)
22
22
  Requires-Dist: dashscope (==1.14.1)
23
+ Requires-Dist: fastavro (>=1.10.0,<2.0.0)
23
24
  Requires-Dist: geojson (==3.1.0)
24
25
  Requires-Dist: gradio (>=5.7.1,<6.0.0)
25
26
  Requires-Dist: grpcio (==1.67.1)
@@ -28,6 +29,7 @@ Requires-Dist: mosstool (==1.0.24)
28
29
  Requires-Dist: networkx (==3.2.1)
29
30
  Requires-Dist: numpy (>=1.20.0,<2.0.0)
30
31
  Requires-Dist: openai (>=1.58.1,<2.0.0)
32
+ Requires-Dist: pandavro (>=1.8.0,<2.0.0)
31
33
  Requires-Dist: poetry (>=1.2.2)
32
34
  Requires-Dist: protobuf (<=4.24.0)
33
35
  Requires-Dist: pycitydata (==1.0.0)
@@ -1,7 +1,7 @@
1
1
  pycityagent/__init__.py,sha256=n56bWkAUEcvjDsb7LcJpaGjlrriSKPnR0yBhwRfEYBA,212
2
- pycityagent/agent.py,sha256=h0p9G5bLlfiv4yB8bkc9l2Z4jpa7s4uYVwAT4IrxusY,17396
2
+ pycityagent/agent.py,sha256=0ZqHXImR05ETA0vt9t5GDS4AgYzza3-Zwuua2OckwTw,22788
3
3
  pycityagent/economy/__init__.py,sha256=aonY4WHnx-6EGJ4WKrx4S-2jAkYNLtqUA04jp6q8B7w,75
4
- pycityagent/economy/econ_client.py,sha256=qQb_kZneEXGBRaS_y5Jdoi95I8GyjKEsDSC4s6V6R7w,10829
4
+ pycityagent/economy/econ_client.py,sha256=wcuNtcpkSijJwNkt2mXw3SshYy4SBy6qbvJ0VQ7Aovo,10854
5
5
  pycityagent/environment/__init__.py,sha256=awHxlOud-btWbk0FCS4RmGJ13W84oVCkbGfcrhKqihA,240
6
6
  pycityagent/environment/interact/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  pycityagent/environment/interact/interact.py,sha256=ifxPPzuHeqLHIZ_6zvfXMoBOnBsXNIP4bYp7OJ7pnEQ,6588
@@ -36,7 +36,7 @@ pycityagent/llm/llm.py,sha256=BtxBvPK4tb8QlZIfxO5XJ73lKXwF8L31LqVbejWB8eo,15121
36
36
  pycityagent/llm/llmconfig.py,sha256=4Ylf4OFSBEFy8jrOneeX0HvPhWEaF5jGvy1HkXK08Ro,436
37
37
  pycityagent/llm/utils.py,sha256=hoNPhvomb1u6lhFX0GctFipw74hVKb7bvUBDqwBzBYw,160
38
38
  pycityagent/memory/__init__.py,sha256=Hs2NhYpIG-lvpwPWwj4DydB1sxtjz7cuA4iDAzCXnjI,243
39
- pycityagent/memory/const.py,sha256=m9AidLs7Zu28StpvYetclqx-1qQcy3bYvwagcXB3a04,913
39
+ pycityagent/memory/const.py,sha256=6zpJPJXWoH9-yf4RARYYff586agCoud9BRn7sPERB1g,932
40
40
  pycityagent/memory/memory.py,sha256=sDbaqr1Koqf_9joMtG9PmmVxJZ6Rq7nAZO6EO0OdVgo,18148
41
41
  pycityagent/memory/memory_base.py,sha256=bd2q0qNu5hCRd2u4cPxE3bBA2OaoAD1oR4-vbRdbd_s,5594
42
42
  pycityagent/memory/profile.py,sha256=s4LnxSPGSjIGZXHXkkd8mMa6uYYZrytgyQdWjcaqGf4,5182
@@ -46,25 +46,24 @@ pycityagent/memory/utils.py,sha256=wLNlNlZ-AY9VB8kbUIy0UQSYh26FOQABbhmKQkit5o8,8
46
46
  pycityagent/message/__init__.py,sha256=TCjazxqb5DVwbTu1fF0sNvaH_EPXVuj2XQ0p6W-QCLU,55
47
47
  pycityagent/message/messager.py,sha256=Iv4pK83JvHAQSZyGNACryPBey2wRoiok3Hb1eIwHbww,2506
48
48
  pycityagent/simulation/__init__.py,sha256=jYaqaNpzM5M_e_ykISS_M-mIyYdzJXJWhgpfBpA6l5k,111
49
- pycityagent/simulation/agentgroup.py,sha256=DzZooUZstnhObO3X7NjB9-8zBofEu_1NevaIhspuGME,6113
50
- pycityagent/simulation/interview.py,sha256=S2uv8MFCB4-u_4Q202VFoPJOIleqpKK9Piju0BDSb_0,1158
51
- pycityagent/simulation/simulation.py,sha256=4BHavfSHPM81Y5Su-MzzBYM0sR9cHRk4YOv-VkRkzrA,11595
52
- pycityagent/simulation/survey/__init__.py,sha256=rxwou8U9KeFSP7rMzXtmtp2fVFZxK4Trzi-psx9LPIs,153
53
- pycityagent/simulation/survey/manager.py,sha256=Tqini-4-uBZDsChVVL4ezlgXatnrxAfvceAZZRP8E48,2062
54
- pycityagent/simulation/survey/models.py,sha256=sY4OrrG1h9iBnjBsyDage4T3mUFPBHHZQe-ORtwSjKc,1305
55
- pycityagent/simulation/ui/__init__.py,sha256=4aevYl09KSku2NEpFZhyFNxI1qlswbrAFwhF_YhxFTo,62
56
- pycityagent/simulation/ui/interface.py,sha256=cSQRQhuA5Gj-X7anuN9tmRpG6-I8QYOuswjIWUeSvio,21636
57
- pycityagent/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
+ pycityagent/simulation/agentgroup.py,sha256=ZJIeQbFmFwK3iUiwUpa4TG-k1Eb4vOTgy5ybv-CE1Rc,7797
50
+ pycityagent/simulation/simulation.py,sha256=rDQRgKmJkjfeQtvXyW9LeqBVVX0iFh6snBEsdg1bCag,15574
51
+ pycityagent/survey/__init__.py,sha256=rxwou8U9KeFSP7rMzXtmtp2fVFZxK4Trzi-psx9LPIs,153
52
+ pycityagent/survey/manager.py,sha256=N4-Q8vve4L-PLaFikAgVB4Z8BNyFDEd6WjEk3AyMTgs,1764
53
+ pycityagent/survey/models.py,sha256=Z2gHEazQRj0TkTz5qbh4Uy_JrU_FZGWpOLwjN0RoUrY,3547
54
+ pycityagent/utils/__init__.py,sha256=_0AV01UAHp4pTj2mlJ4m8LTH0toWL9j3DouNC6sDuUQ,249
55
+ pycityagent/utils/avro_schema.py,sha256=MsRG0CsYAn2UjSlSXgCF8-3076VywpALEmz1mW-UJB0,2789
58
56
  pycityagent/utils/decorators.py,sha256=Gk3r41hfk6awui40tbwpq3C7wC7jHaRmLRlcJFlLQCE,3160
59
57
  pycityagent/utils/parsers/__init__.py,sha256=AN2xgiPxszWK4rpX7zrqRsqNwfGF3WnCA5-PFTvbaKk,281
60
58
  pycityagent/utils/parsers/code_block_parser.py,sha256=Cs2Z_hm9VfNCpPPll1TwteaJF-HAQPs-3RApsOekFm4,1173
61
59
  pycityagent/utils/parsers/json_parser.py,sha256=FZ3XN1g8z4Dr2TFraUOoah1oQcze4fPd2m01hHoX0Mo,2917
62
60
  pycityagent/utils/parsers/parser_base.py,sha256=k6DVqwAMK3jJdOP4IeLE-aFPm3V2F-St5qRBuRdx4aU,1742
61
+ pycityagent/utils/survey_util.py,sha256=Be9nptmu2JtesFNemPgORh_2GsN7rcDYGQS9Zfvc5OI,2169
63
62
  pycityagent/workflow/__init__.py,sha256=EyCcjB6LyBim-5iAOPe4m2qfvghEPqu1ZdGfy4KPeZ8,551
64
63
  pycityagent/workflow/block.py,sha256=6EmiRMLdOZC1wMlmLMIjfrp9TuiI7Gw4s3nnXVMbrnw,6031
65
64
  pycityagent/workflow/prompt.py,sha256=tY69nDO8fgYfF_dOA-iceR8pAhkYmCqoox8uRPqEuGY,2956
66
65
  pycityagent/workflow/tool.py,sha256=wD9WZ5rma6HCKugtHTwbShNE0f-Rjlwvn_1be3fCAsk,6682
67
66
  pycityagent/workflow/trigger.py,sha256=t5X_i0WtL32bipZSsq_E3UUyYYudYLxQUpvxbgClp2s,5683
68
- pycityagent-2.0.0a12.dist-info/METADATA,sha256=DNsYXJBF2nVXYdiNJrhDty3AwVMkqmPbnm_Ld-Vtt8k,7622
69
- pycityagent-2.0.0a12.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
70
- pycityagent-2.0.0a12.dist-info/RECORD,,
67
+ pycityagent-2.0.0a14.dist-info/METADATA,sha256=O6cGdAHKuG6W0Ya_Du_wEP8_xfM4xmOetYWb6rPj-WM,7705
68
+ pycityagent-2.0.0a14.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
69
+ pycityagent-2.0.0a14.dist-info/RECORD,,
@@ -1,40 +0,0 @@
1
- from dataclasses import dataclass
2
- from datetime import datetime
3
- from typing import List, Optional
4
-
5
-
6
- @dataclass
7
- class InterviewRecord:
8
- """采访记录"""
9
-
10
- timestamp: datetime
11
- agent_name: str
12
- question: str
13
- response: str
14
- blocking: bool
15
-
16
-
17
- class InterviewManager:
18
- """采访管理器"""
19
-
20
- def __init__(self):
21
- self._history: List[InterviewRecord] = []
22
-
23
- def add_record(self, agent_name: str, question: str, response: str, blocking: bool):
24
- """添加采访记录"""
25
- record = InterviewRecord(
26
- timestamp=datetime.now(),
27
- agent_name=agent_name,
28
- question=question,
29
- response=response,
30
- blocking=blocking,
31
- )
32
- self._history.append(record)
33
-
34
- def get_agent_history(self, agent_name: str) -> List[InterviewRecord]:
35
- """获取指定智能体的采访历史"""
36
- return [r for r in self._history if r.agent_name == agent_name]
37
-
38
- def get_recent_history(self, limit: int = 10) -> List[InterviewRecord]:
39
- """获取最近的采访记录"""
40
- return sorted(self._history, key=lambda x: x.timestamp, reverse=True)[:limit]