pycityagent 2.0.0a66__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a67__cp311-cp311-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.
- pycityagent/agent/agent.py +157 -57
- pycityagent/agent/agent_base.py +316 -43
- pycityagent/cityagent/bankagent.py +49 -9
- pycityagent/cityagent/blocks/__init__.py +1 -2
- pycityagent/cityagent/blocks/cognition_block.py +54 -31
- pycityagent/cityagent/blocks/dispatcher.py +22 -17
- pycityagent/cityagent/blocks/economy_block.py +46 -32
- pycityagent/cityagent/blocks/mobility_block.py +130 -100
- pycityagent/cityagent/blocks/needs_block.py +101 -44
- pycityagent/cityagent/blocks/other_block.py +42 -33
- pycityagent/cityagent/blocks/plan_block.py +59 -42
- pycityagent/cityagent/blocks/social_block.py +167 -116
- pycityagent/cityagent/blocks/utils.py +13 -6
- pycityagent/cityagent/firmagent.py +17 -35
- pycityagent/cityagent/governmentagent.py +3 -3
- pycityagent/cityagent/initial.py +79 -44
- pycityagent/cityagent/memory_config.py +108 -88
- pycityagent/cityagent/message_intercept.py +0 -4
- pycityagent/cityagent/metrics.py +41 -0
- pycityagent/cityagent/nbsagent.py +24 -36
- pycityagent/cityagent/societyagent.py +7 -3
- pycityagent/cli/wrapper.py +2 -2
- pycityagent/economy/econ_client.py +407 -81
- pycityagent/environment/__init__.py +0 -3
- pycityagent/environment/sim/__init__.py +0 -3
- pycityagent/environment/sim/aoi_service.py +2 -2
- pycityagent/environment/sim/client.py +3 -31
- pycityagent/environment/sim/clock_service.py +2 -2
- pycityagent/environment/sim/lane_service.py +8 -8
- pycityagent/environment/sim/light_service.py +8 -8
- pycityagent/environment/sim/pause_service.py +9 -10
- pycityagent/environment/sim/person_service.py +20 -20
- pycityagent/environment/sim/road_service.py +2 -2
- pycityagent/environment/sim/sim_env.py +21 -5
- pycityagent/environment/sim/social_service.py +4 -4
- pycityagent/environment/simulator.py +249 -27
- pycityagent/environment/utils/__init__.py +2 -2
- pycityagent/environment/utils/geojson.py +2 -2
- pycityagent/environment/utils/grpc.py +4 -4
- pycityagent/environment/utils/map_utils.py +2 -2
- pycityagent/llm/embeddings.py +147 -28
- pycityagent/llm/llm.py +122 -77
- pycityagent/llm/llmconfig.py +5 -0
- pycityagent/llm/utils.py +4 -0
- pycityagent/memory/__init__.py +0 -4
- pycityagent/memory/const.py +2 -2
- pycityagent/memory/faiss_query.py +140 -61
- pycityagent/memory/memory.py +393 -90
- pycityagent/memory/memory_base.py +140 -34
- pycityagent/memory/profile.py +13 -13
- pycityagent/memory/self_define.py +13 -13
- pycityagent/memory/state.py +14 -14
- pycityagent/message/message_interceptor.py +253 -3
- pycityagent/message/messager.py +133 -6
- pycityagent/metrics/mlflow_client.py +47 -4
- pycityagent/pycityagent-sim +0 -0
- pycityagent/pycityagent-ui +0 -0
- pycityagent/simulation/__init__.py +3 -2
- pycityagent/simulation/agentgroup.py +145 -52
- pycityagent/simulation/simulation.py +257 -62
- pycityagent/survey/manager.py +45 -3
- pycityagent/survey/models.py +42 -2
- pycityagent/tools/__init__.py +1 -2
- pycityagent/tools/tool.py +93 -69
- pycityagent/utils/avro_schema.py +2 -2
- pycityagent/utils/parsers/code_block_parser.py +1 -1
- pycityagent/utils/parsers/json_parser.py +2 -2
- pycityagent/utils/parsers/parser_base.py +2 -2
- pycityagent/workflow/block.py +64 -13
- pycityagent/workflow/prompt.py +31 -23
- pycityagent/workflow/trigger.py +91 -24
- {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/METADATA +2 -2
- pycityagent-2.0.0a67.dist-info/RECORD +97 -0
- pycityagent/environment/interact/__init__.py +0 -0
- pycityagent/environment/interact/interact.py +0 -198
- pycityagent/environment/message/__init__.py +0 -0
- pycityagent/environment/sence/__init__.py +0 -0
- pycityagent/environment/sence/static.py +0 -416
- pycityagent/environment/sidecar/__init__.py +0 -8
- pycityagent/environment/sidecar/sidecarv2.py +0 -109
- pycityagent/environment/sim/economy_services.py +0 -192
- pycityagent/metrics/utils/const.py +0 -0
- pycityagent-2.0.0a66.dist-info/RECORD +0 -105
- {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a66.dist-info → pycityagent-2.0.0a67.dist-info}/top_level.txt +0 -0
pycityagent/llm/embeddings.py
CHANGED
@@ -15,6 +15,14 @@ __all__ = [
|
|
15
15
|
|
16
16
|
|
17
17
|
class SentenceEmbedding(Embeddings):
|
18
|
+
"""
|
19
|
+
Main class for generating sentence embeddings using a pre-trained language model.
|
20
|
+
|
21
|
+
- **Description**:
|
22
|
+
- This class initializes a tokenizer and a pre-trained model to generate embeddings for input texts.
|
23
|
+
- It supports automatic CUDA device allocation and handles caching of models locally.
|
24
|
+
"""
|
25
|
+
|
18
26
|
def __init__(
|
19
27
|
self,
|
20
28
|
pretrained_model_name_or_path: Union[str, os.PathLike] = "BAAI/bge-m3",
|
@@ -24,6 +32,17 @@ class SentenceEmbedding(Embeddings):
|
|
24
32
|
cache_dir: str = "./cache",
|
25
33
|
proxies: Optional[dict] = None,
|
26
34
|
):
|
35
|
+
"""
|
36
|
+
Initializes the SentenceEmbedding instance.
|
37
|
+
|
38
|
+
- **Parameters**:
|
39
|
+
- `pretrained_model_name_or_path`: Name or path of the pre-trained model. Default is "BAAI/bge-m3".
|
40
|
+
- `max_seq_len`: Maximum sequence length for inputs. Default is 8192.
|
41
|
+
- `auto_cuda`: Automatically move the model to available CUDA device if True. Default is False.
|
42
|
+
- `local_files_only`: Only try to load model from local files if True. Default is False.
|
43
|
+
- `cache_dir`: Directory to cache models. Default is "./cache".
|
44
|
+
- `proxies`: Proxy settings for HTTP/HTTPS. Default is None.
|
45
|
+
"""
|
27
46
|
os.makedirs(cache_dir, exist_ok=True)
|
28
47
|
self.tokenizer = AutoTokenizer.from_pretrained(
|
29
48
|
pretrained_model_name_or_path,
|
@@ -46,6 +65,15 @@ class SentenceEmbedding(Embeddings):
|
|
46
65
|
self.max_seq_len = max_seq_len
|
47
66
|
|
48
67
|
def _embed(self, texts: list[str]) -> list[list[float]]:
|
68
|
+
"""
|
69
|
+
Internal method to compute embeddings for a list of input texts.
|
70
|
+
|
71
|
+
- **Parameters**:
|
72
|
+
- `texts`: A list of strings representing the input texts.
|
73
|
+
|
74
|
+
- **Returns**:
|
75
|
+
- A list of lists containing floating-point numbers representing the embeddings.
|
76
|
+
"""
|
49
77
|
# Tokenize sentences
|
50
78
|
encoded_input = self.tokenizer(
|
51
79
|
texts, padding=True, truncation=True, return_tensors="pt"
|
@@ -73,27 +101,46 @@ class SentenceEmbedding(Embeddings):
|
|
73
101
|
return sentence_embeddings.tolist()
|
74
102
|
|
75
103
|
def embed_documents(self, texts: list[str]) -> list[list[float]]:
|
76
|
-
"""
|
104
|
+
"""
|
105
|
+
Embeds a list of documents.
|
106
|
+
|
107
|
+
- **Parameters**:
|
108
|
+
- `texts`: The documents to embed.
|
109
|
+
|
110
|
+
- **Returns**:
|
111
|
+
- A list of document embeddings.
|
112
|
+
"""
|
77
113
|
return self._embed(texts)
|
78
114
|
|
79
115
|
def embed_query(self, text: str) -> list[float]:
|
80
|
-
"""
|
116
|
+
"""
|
117
|
+
Embeds a single query text.
|
118
|
+
|
119
|
+
- **Parameters**:
|
120
|
+
- `text`: The query text to embed.
|
121
|
+
|
122
|
+
- **Returns**:
|
123
|
+
- The embedding of the query text.
|
124
|
+
"""
|
81
125
|
return self._embed([text])[0]
|
82
126
|
|
83
127
|
|
84
128
|
class SimpleEmbedding(Embeddings):
|
85
|
-
"""
|
129
|
+
"""
|
130
|
+
A simple in-memory embedding implementation using Bag of Words and TF-IDF for generating text vectors.
|
86
131
|
|
87
|
-
|
88
|
-
|
132
|
+
- **Description**:
|
133
|
+
- This class provides a basic approach to creating text embeddings based on term frequency-inverse document frequency (TF-IDF).
|
134
|
+
- It maintains an in-memory cache of computed embeddings and updates its vocabulary dynamically as new texts are processed.
|
89
135
|
"""
|
90
136
|
|
91
137
|
def __init__(self, vector_dim: int = 128, cache_size: int = 1000):
|
92
|
-
"""
|
138
|
+
"""
|
139
|
+
Initializes the SimpleEmbedding instance.
|
93
140
|
|
94
|
-
|
95
|
-
vector_dim
|
96
|
-
cache_size
|
141
|
+
- **Parameters**:
|
142
|
+
- `vector_dim`: Dimensionality of the vectors. Default is 128.
|
143
|
+
- `cache_size`: Cache size; oldest entries are removed when exceeded. Default is 1000.
|
97
144
|
"""
|
98
145
|
self.vector_dim = vector_dim
|
99
146
|
self.cache_size = cache_size
|
@@ -103,29 +150,73 @@ class SimpleEmbedding(Embeddings):
|
|
103
150
|
self._doc_count = 0 # 文档总数
|
104
151
|
|
105
152
|
def _text_to_hash(self, text: str) -> str:
|
106
|
-
"""
|
153
|
+
"""
|
154
|
+
Converts text into a hash value.
|
155
|
+
|
156
|
+
- **Parameters**:
|
157
|
+
- `text`: The input text to hash.
|
158
|
+
|
159
|
+
- **Returns**:
|
160
|
+
- A string representing the MD5 hash of the input text.
|
161
|
+
"""
|
107
162
|
return hashlib.md5(text.encode()).hexdigest()
|
108
163
|
|
109
164
|
def _tokenize(self, text: str) -> list[str]:
|
110
|
-
"""
|
165
|
+
"""
|
166
|
+
Performs simple tokenization on the input text.
|
167
|
+
|
168
|
+
- **Parameters**:
|
169
|
+
- `text`: The input text to tokenize.
|
170
|
+
|
171
|
+
- **Returns**:
|
172
|
+
- A list of tokens extracted from the input text.
|
173
|
+
"""
|
111
174
|
# 这里使用简单的空格分词,实际应用中可以使用更复杂的分词方法
|
112
175
|
return text.lower().split()
|
113
176
|
|
114
177
|
def _update_vocab(self, tokens: list[str]):
|
115
|
-
"""
|
178
|
+
"""
|
179
|
+
Updates the vocabulary with new tokens.
|
180
|
+
|
181
|
+
- **Description**:
|
182
|
+
- This method adds unique tokens from the input list to the vocabulary.
|
183
|
+
- It ensures that each token is only added once using a set for deduplication.
|
184
|
+
|
185
|
+
- **Parameters**:
|
186
|
+
- `tokens`: A list of strings representing the tokens to add to the vocabulary.
|
187
|
+
"""
|
116
188
|
for token in set(tokens): # 使用set去重
|
117
189
|
if token not in self._vocab:
|
118
190
|
self._vocab[token] = len(self._vocab)
|
119
191
|
|
120
192
|
def _update_idf(self, tokens: list[str]):
|
121
|
-
"""
|
193
|
+
"""
|
194
|
+
Updates the IDF values based on the tokens.
|
195
|
+
|
196
|
+
- **Description**:
|
197
|
+
- Increases the document count and updates the inverse document frequency (IDF) for each unique token.
|
198
|
+
|
199
|
+
- **Parameters**:
|
200
|
+
- `tokens`: A list of strings representing the tokens from a single document.
|
201
|
+
"""
|
122
202
|
self._doc_count += 1
|
123
203
|
unique_tokens = set(tokens)
|
124
204
|
for token in unique_tokens:
|
125
205
|
self._idf[token] = self._idf.get(token, 0) + 1
|
126
206
|
|
127
207
|
def _calculate_tf(self, tokens: list[str]) -> dict[str, float]:
|
128
|
-
"""
|
208
|
+
"""
|
209
|
+
Calculates term frequency (TF) for the tokens.
|
210
|
+
|
211
|
+
- **Description**:
|
212
|
+
- Computes the frequency of each token within the provided list and normalizes it by the total number of tokens.
|
213
|
+
|
214
|
+
- **Parameters**:
|
215
|
+
- `tokens`: A list of strings representing the tokens to calculate TF for.
|
216
|
+
|
217
|
+
- **Returns**:
|
218
|
+
- A dictionary mapping each token to its normalized term frequency.
|
219
|
+
"""
|
129
220
|
tf = {}
|
130
221
|
total_tokens = len(tokens)
|
131
222
|
for token in tokens:
|
@@ -136,7 +227,18 @@ class SimpleEmbedding(Embeddings):
|
|
136
227
|
return tf
|
137
228
|
|
138
229
|
def _calculate_tfidf(self, tokens: list[str]) -> list[float]:
|
139
|
-
"""
|
230
|
+
"""
|
231
|
+
Calculates the TF-IDF vector for the tokens.
|
232
|
+
|
233
|
+
- **Description**:
|
234
|
+
- Generates a vector representation of the input tokens using the Term Frequency-Inverse Document Frequency (TF-IDF) weighting scheme.
|
235
|
+
|
236
|
+
- **Parameters**:
|
237
|
+
- `tokens`: A list of strings representing the tokens to generate the TF-IDF vector for.
|
238
|
+
|
239
|
+
- **Returns**:
|
240
|
+
- A list of floating-point numbers representing the TF-IDF vector.
|
241
|
+
"""
|
140
242
|
vector = np.zeros(self.vector_dim)
|
141
243
|
tf = self._calculate_tf(tokens)
|
142
244
|
|
@@ -154,13 +256,19 @@ class SimpleEmbedding(Embeddings):
|
|
154
256
|
return list(vector)
|
155
257
|
|
156
258
|
def _embed(self, text: str) -> list[float]:
|
157
|
-
"""
|
259
|
+
"""
|
260
|
+
Generates a vector representation for the input text.
|
158
261
|
|
159
|
-
|
160
|
-
text
|
262
|
+
- **Description**:
|
263
|
+
- Creates an embedding for the given text by first checking if it's already cached,
|
264
|
+
then tokenizing, updating the vocabulary and IDF, calculating the TF-IDF vector,
|
265
|
+
and finally caching the result.
|
161
266
|
|
162
|
-
|
163
|
-
|
267
|
+
- **Parameters**:
|
268
|
+
- `text`: The input text to generate the vector for.
|
269
|
+
|
270
|
+
- **Returns**:
|
271
|
+
- A list of floating-point numbers representing the vector of the input text.
|
164
272
|
"""
|
165
273
|
# 检查缓存
|
166
274
|
text_hash = self._text_to_hash(text)
|
@@ -189,19 +297,30 @@ class SimpleEmbedding(Embeddings):
|
|
189
297
|
return list(vector)
|
190
298
|
|
191
299
|
def embed_documents(self, texts: list[str]) -> list[list[float]]:
|
192
|
-
"""
|
300
|
+
"""
|
301
|
+
Embeds a list of documents.
|
302
|
+
|
303
|
+
- **Parameters**:
|
304
|
+
- `texts`: A list of strings representing the documents to embed.
|
305
|
+
|
306
|
+
- **Returns**:
|
307
|
+
- A list of lists containing the embeddings of the documents.
|
308
|
+
"""
|
193
309
|
return [self._embed(text) for text in texts]
|
194
310
|
|
195
311
|
def embed_query(self, text: str) -> list[float]:
|
196
|
-
"""
|
312
|
+
"""
|
313
|
+
Embeds a single query text.
|
314
|
+
|
315
|
+
- **Parameters**:
|
316
|
+
- `text`: The query text to embed.
|
317
|
+
|
318
|
+
- **Returns**:
|
319
|
+
- A list of floating-point numbers representing the embedding of the query text.
|
320
|
+
"""
|
197
321
|
return self._embed(text)
|
198
322
|
|
323
|
+
|
199
324
|
if __name__ == "__main__":
|
200
|
-
# se = SentenceEmbedding(
|
201
|
-
# pretrained_model_name_or_path="ignore/BAAI--bge-m3", cache_dir="ignore"
|
202
|
-
# )
|
203
325
|
se = SimpleEmbedding()
|
204
326
|
print(se.embed_query("hello world"))
|
205
|
-
print(se.embed_query("hello world"))
|
206
|
-
print(se.embed_query("hello world"))
|
207
|
-
print(se.embed_query("hello world"))
|
pycityagent/llm/llm.py
CHANGED
@@ -1,14 +1,9 @@
|
|
1
1
|
"""UrbanLLM: 智能能力类及其定义"""
|
2
2
|
|
3
|
+
import asyncio
|
3
4
|
import json
|
4
5
|
import logging
|
5
|
-
|
6
|
-
from openai import APIConnectionError, AsyncOpenAI, OpenAI, OpenAIError
|
7
|
-
from zhipuai import ZhipuAI
|
8
|
-
|
9
|
-
logging.getLogger("zhipuai").setLevel(logging.WARNING)
|
10
|
-
|
11
|
-
import asyncio
|
6
|
+
import time
|
12
7
|
import os
|
13
8
|
from http import HTTPStatus
|
14
9
|
from io import BytesIO
|
@@ -17,20 +12,37 @@ from typing import Any, Optional, Union
|
|
17
12
|
import dashscope
|
18
13
|
import requests
|
19
14
|
from dashscope import ImageSynthesis
|
15
|
+
from openai import APIConnectionError, AsyncOpenAI, OpenAI, OpenAIError
|
20
16
|
from PIL import Image
|
17
|
+
from zhipuai import ZhipuAI
|
21
18
|
|
22
19
|
from .llmconfig import *
|
23
20
|
from .utils import *
|
24
21
|
|
22
|
+
logging.getLogger("zhipuai").setLevel(logging.WARNING)
|
25
23
|
os.environ["GRPC_VERBOSITY"] = "ERROR"
|
26
24
|
|
25
|
+
__all__ = [
|
26
|
+
"LLM",
|
27
|
+
]
|
28
|
+
|
29
|
+
|
27
30
|
class LLM:
|
28
31
|
"""
|
29
|
-
|
30
|
-
|
32
|
+
Main class for the Large Language Model (LLM) object used by Agent(Soul).
|
33
|
+
|
34
|
+
- **Description**:
|
35
|
+
- This class manages configurations and interactions with different large language model APIs.
|
36
|
+
- It initializes clients based on the specified request type and handles token usage and consumption reporting.
|
31
37
|
"""
|
32
38
|
|
33
39
|
def __init__(self, config: LLMConfig) -> None:
|
40
|
+
"""
|
41
|
+
Initializes the LLM instance.
|
42
|
+
|
43
|
+
- **Parameters**:
|
44
|
+
- `config`: An instance of `LLMConfig` containing configuration settings for the LLM.
|
45
|
+
"""
|
34
46
|
self.config = config
|
35
47
|
if config.text["request_type"] not in ["openai", "deepseek", "qwen", "zhipuai"]:
|
36
48
|
raise ValueError("Invalid request type for text request")
|
@@ -39,6 +51,7 @@ class LLM:
|
|
39
51
|
self.request_number = 0
|
40
52
|
self.semaphore = None
|
41
53
|
self._current_client_index = 0
|
54
|
+
self._log_list = []
|
42
55
|
|
43
56
|
api_keys = self.config.text["api_key"]
|
44
57
|
if not isinstance(api_keys, list):
|
@@ -75,10 +88,25 @@ class LLM:
|
|
75
88
|
"request_number": 0
|
76
89
|
})
|
77
90
|
|
91
|
+
def get_log_list(self):
|
92
|
+
return self._log_list
|
93
|
+
|
94
|
+
def clear_log_list(self):
|
95
|
+
self._log_list = []
|
96
|
+
|
78
97
|
def set_semaphore(self, number_of_coroutine: int):
|
98
|
+
"""
|
99
|
+
Sets the semaphore for controlling concurrent coroutines.
|
100
|
+
|
101
|
+
- **Parameters**:
|
102
|
+
- `number_of_coroutine`: The maximum number of concurrent coroutines allowed.
|
103
|
+
"""
|
79
104
|
self.semaphore = asyncio.Semaphore(number_of_coroutine)
|
80
105
|
|
81
106
|
def clear_semaphore(self):
|
107
|
+
"""
|
108
|
+
Clears the semaphore setting.
|
109
|
+
"""
|
82
110
|
self.semaphore = None
|
83
111
|
|
84
112
|
def clear_used(self):
|
@@ -104,7 +132,14 @@ class LLM:
|
|
104
132
|
self, input_price: Optional[float] = None, output_price: Optional[float] = None
|
105
133
|
):
|
106
134
|
"""
|
107
|
-
|
135
|
+
Displays token usage and optionally calculates the estimated cost based on provided prices.
|
136
|
+
|
137
|
+
- **Parameters**:
|
138
|
+
- `input_price`: Price per million prompt tokens. Default is None.
|
139
|
+
- `output_price`: Price per million completion tokens. Default is None.
|
140
|
+
|
141
|
+
- **Returns**:
|
142
|
+
- A dictionary summarizing the token usage and, if applicable, the estimated cost.
|
108
143
|
"""
|
109
144
|
total_stats = {
|
110
145
|
"total": 0,
|
@@ -144,7 +179,15 @@ class LLM:
|
|
144
179
|
return total_stats
|
145
180
|
|
146
181
|
def _get_next_client(self):
|
147
|
-
"""
|
182
|
+
"""
|
183
|
+
Retrieves the next client to be used for making requests.
|
184
|
+
|
185
|
+
- **Description**:
|
186
|
+
- This method cycles through the available clients in a round-robin fashion.
|
187
|
+
|
188
|
+
- **Returns**:
|
189
|
+
- The next client instance to be used for making requests.
|
190
|
+
"""
|
148
191
|
client = self._aclients[self._current_client_index]
|
149
192
|
self._current_client_index = (self._current_client_index + 1) % len(
|
150
193
|
self._aclients
|
@@ -165,8 +208,30 @@ class LLM:
|
|
165
208
|
tool_choice: Optional[dict[str, Any]] = None,
|
166
209
|
):
|
167
210
|
"""
|
168
|
-
|
211
|
+
Sends an asynchronous text request to the configured LLM API.
|
212
|
+
|
213
|
+
- **Description**:
|
214
|
+
- Attempts to send a text request up to `retries` times with exponential backoff on failure.
|
215
|
+
- Handles different request types and manages token usage statistics.
|
216
|
+
|
217
|
+
- **Parameters**:
|
218
|
+
- `dialog`: Messages to send as part of the chat completion request.
|
219
|
+
- `temperature`: Controls randomness in the model's output. Default is 1.
|
220
|
+
- `max_tokens`: Maximum number of tokens to generate in the response. Default is None.
|
221
|
+
- `top_p`: Limits the next token selection to a subset of tokens with a cumulative probability above this value. Default is None.
|
222
|
+
- `frequency_penalty`: Penalizes new tokens based on their existing frequency in the text so far. Default is None.
|
223
|
+
- `presence_penalty`: Penalizes new tokens based on whether they appear in the text so far. Default is None.
|
224
|
+
- `timeout`: Request timeout in seconds. Default is 300 seconds.
|
225
|
+
- `retries`: Number of retry attempts in case of failure. Default is 3.
|
226
|
+
- `tools`: List of dictionaries describing the tools that can be called by the model. Default is None.
|
227
|
+
- `tool_choice`: Dictionary specifying how the model should choose from the provided tools. Default is None.
|
228
|
+
|
229
|
+
- **Returns**:
|
230
|
+
- A string containing the message content or a dictionary with tool call arguments if tools are used.
|
231
|
+
- Raises exceptions if the request fails after all retry attempts.
|
169
232
|
"""
|
233
|
+
start_time = time.time()
|
234
|
+
log = {"request_time": start_time}
|
170
235
|
if (
|
171
236
|
self.config.text["request_type"] == "openai"
|
172
237
|
or self.config.text["request_type"] == "deepseek"
|
@@ -175,57 +240,35 @@ class LLM:
|
|
175
240
|
for attempt in range(retries):
|
176
241
|
try:
|
177
242
|
client = self._get_next_client()
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
243
|
+
response = await client.chat.completions.create(
|
244
|
+
model=self.config.text["model"],
|
245
|
+
messages=dialog,
|
246
|
+
temperature=temperature,
|
247
|
+
max_tokens=max_tokens,
|
248
|
+
top_p=top_p,
|
249
|
+
frequency_penalty=frequency_penalty, # type: ignore
|
250
|
+
presence_penalty=presence_penalty, # type: ignore
|
251
|
+
stream=False,
|
252
|
+
timeout=timeout,
|
253
|
+
tools=tools,
|
254
|
+
tool_choice=tool_choice,
|
255
|
+
) # type: ignore
|
256
|
+
self._client_usage[self._current_client_index]["prompt_tokens"] += response.usage.prompt_tokens # type: ignore
|
257
|
+
self._client_usage[self._current_client_index]["completion_tokens"] += response.usage.completion_tokens # type: ignore
|
258
|
+
self._client_usage[self._current_client_index]["request_number"] += 1
|
259
|
+
end_time = time.time()
|
260
|
+
log["consumption"] = end_time - start_time
|
261
|
+
log["input_tokens"] = response.usage.prompt_tokens
|
262
|
+
log["output_tokens"] = response.usage.completion_tokens
|
263
|
+
self._log_list.append(log)
|
264
|
+
if tools and response.choices[0].message.tool_calls:
|
265
|
+
return json.loads(
|
266
|
+
response.choices[0]
|
267
|
+
.message.tool_calls[0]
|
268
|
+
.function.arguments
|
269
|
+
)
|
204
270
|
else:
|
205
|
-
response
|
206
|
-
model=self.config.text["model"],
|
207
|
-
messages=dialog,
|
208
|
-
temperature=temperature,
|
209
|
-
max_tokens=max_tokens,
|
210
|
-
top_p=top_p,
|
211
|
-
frequency_penalty=frequency_penalty, # type: ignore
|
212
|
-
presence_penalty=presence_penalty, # type: ignore
|
213
|
-
stream=False,
|
214
|
-
timeout=timeout,
|
215
|
-
tools=tools,
|
216
|
-
tool_choice=tool_choice,
|
217
|
-
) # type: ignore
|
218
|
-
self._client_usage[self._current_client_index]["prompt_tokens"] += response.usage.prompt_tokens # type: ignore
|
219
|
-
self._client_usage[self._current_client_index]["completion_tokens"] += response.usage.completion_tokens # type: ignore
|
220
|
-
self._client_usage[self._current_client_index]["request_number"] += 1
|
221
|
-
if tools and response.choices[0].message.tool_calls:
|
222
|
-
return json.loads(
|
223
|
-
response.choices[0]
|
224
|
-
.message.tool_calls[0]
|
225
|
-
.function.arguments
|
226
|
-
)
|
227
|
-
else:
|
228
|
-
return response.choices[0].message.content
|
271
|
+
return response.choices[0].message.content
|
229
272
|
except APIConnectionError as e:
|
230
273
|
print("API connection error:", e)
|
231
274
|
if attempt < retries - 1:
|
@@ -273,6 +316,10 @@ class LLM:
|
|
273
316
|
self._client_usage[self._current_client_index]["prompt_tokens"] += result_response.usage.prompt_tokens # type: ignore
|
274
317
|
self._client_usage[self._current_client_index]["completion_tokens"] += result_response.usage.completion_tokens # type: ignore
|
275
318
|
self._client_usage[self._current_client_index]["request_number"] += 1
|
319
|
+
end_time = time.time()
|
320
|
+
log["used_time"] = end_time - start_time
|
321
|
+
log["token_consumption"] = result_response.usage.prompt_tokens + result_response.usage.completion_tokens
|
322
|
+
self._log_list.append(log)
|
276
323
|
if tools and result_response.choices[0].message.tool_calls: # type: ignore
|
277
324
|
return json.loads(
|
278
325
|
result_response.choices[0] # type: ignore
|
@@ -295,15 +342,14 @@ class LLM:
|
|
295
342
|
self, img_path: Union[str, list[str]], prompt: Optional[str] = None
|
296
343
|
) -> str:
|
297
344
|
"""
|
298
|
-
|
299
|
-
Image understanding
|
345
|
+
Analyzes and understands images using external APIs.
|
300
346
|
|
301
|
-
Args
|
302
|
-
|
303
|
-
|
347
|
+
- **Args**:
|
348
|
+
img_path (Union[str, list[str]]): Path or list of paths to the images for analysis.
|
349
|
+
prompt (Optional[str]): Guidance text for understanding the images.
|
304
350
|
|
305
|
-
Returns
|
306
|
-
|
351
|
+
- **Returns**:
|
352
|
+
str: The content derived from understanding the images.
|
307
353
|
"""
|
308
354
|
ppt = "如何理解这幅图像?"
|
309
355
|
if prompt != None:
|
@@ -376,16 +422,15 @@ class LLM:
|
|
376
422
|
|
377
423
|
async def img_generate(self, prompt: str, size: str = "512*512", quantity: int = 1):
|
378
424
|
"""
|
379
|
-
|
380
|
-
Image generation
|
425
|
+
Generates images based on a given prompt.
|
381
426
|
|
382
|
-
Args
|
383
|
-
|
384
|
-
|
385
|
-
|
427
|
+
- **Args**:
|
428
|
+
prompt (str): Prompt for generating images.
|
429
|
+
size (str): Size of the generated images, default is '512*512'.
|
430
|
+
quantity (int): Number of images to generate, default is 1.
|
386
431
|
|
387
|
-
Returns
|
388
|
-
|
432
|
+
- **Returns**:
|
433
|
+
list[PIL.Image.Image]: List of generated PIL Image objects.
|
389
434
|
"""
|
390
435
|
rsp = ImageSynthesis.call(
|
391
436
|
model=self.config.image_g["model"],
|
pycityagent/llm/llmconfig.py
CHANGED
pycityagent/llm/utils.py
CHANGED
pycityagent/memory/__init__.py
CHANGED
@@ -2,10 +2,6 @@
|
|
2
2
|
|
3
3
|
from .faiss_query import FaissQuery
|
4
4
|
from .memory import Memory
|
5
|
-
from .memory_base import MemoryBase, MemoryUnit
|
6
|
-
from .profile import ProfileMemory, ProfileMemoryUnit
|
7
|
-
from .self_define import DynamicMemory
|
8
|
-
from .state import StateMemory
|
9
5
|
|
10
6
|
__all__ = [
|
11
7
|
"Memory",
|
pycityagent/memory/const.py
CHANGED
@@ -8,9 +8,9 @@ PROFILE_ATTRIBUTES = {
|
|
8
8
|
"skill": str(),
|
9
9
|
"occupation": str(),
|
10
10
|
"family_consumption": str(),
|
11
|
-
"consumption":
|
11
|
+
"consumption": float(),
|
12
12
|
"personality": str(),
|
13
|
-
"income":
|
13
|
+
"income": float(),
|
14
14
|
"currency": float(),
|
15
15
|
"residence": str(),
|
16
16
|
"race": str(),
|