autonomous-app 0.3.18__py3-none-any.whl → 0.3.20__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.
- autonomous/__init__.py +1 -1
- autonomous/ai/audioagent.py +8 -0
- autonomous/ai/baseagent.py +12 -8
- autonomous/ai/jsonagent.py +0 -6
- autonomous/ai/models/aws.py +317 -0
- autonomous/ai/models/deepseek.py +99 -0
- autonomous/ai/models/gemini.py +299 -0
- autonomous/ai/models/local.py +99 -0
- autonomous/ai/models/openai.py +52 -29
- autonomous/ai/textagent.py +0 -6
- autonomous/db/fields.py +2 -3
- autonomous/db/queryset/base.py +1 -4
- autonomous/db/queryset/queryset.py +1 -0
- autonomous/db/queryset/transform.py +11 -10
- autonomous/model/autoattr.py +17 -3
- autonomous/model/automodel.py +23 -9
- {autonomous_app-0.3.18.dist-info → autonomous_app-0.3.20.dist-info}/METADATA +6 -24
- {autonomous_app-0.3.18.dist-info → autonomous_app-0.3.20.dist-info}/RECORD +20 -17
- {autonomous_app-0.3.18.dist-info → autonomous_app-0.3.20.dist-info}/WHEEL +1 -1
- autonomous_app-0.3.18.dist-info/LICENSE +0 -21
- {autonomous_app-0.3.18.dist-info → autonomous_app-0.3.20.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import io
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import random
|
|
6
|
+
import wave
|
|
7
|
+
from http import client
|
|
8
|
+
|
|
9
|
+
from google import genai
|
|
10
|
+
from google.genai import types
|
|
11
|
+
from PIL import Image as PILImage
|
|
12
|
+
from pydub import AudioSegment
|
|
13
|
+
|
|
14
|
+
from autonomous import log
|
|
15
|
+
from autonomous.model.autoattr import DictAttr, ListAttr, StringAttr
|
|
16
|
+
from autonomous.model.automodel import AutoModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class GeminiAIModel(AutoModel):
|
|
20
|
+
_client = None
|
|
21
|
+
_text_model = "gemini-3-pro-preview"
|
|
22
|
+
_summary_model = "gemini-2.5-flash"
|
|
23
|
+
_image_model = "gemini-3-pro-image-preview"
|
|
24
|
+
_json_model = "gemini-3-pro-preview"
|
|
25
|
+
_stt_model = "gemini-3-pro-preview"
|
|
26
|
+
_tts_model = "gemini-2.5-flash-preview-tts"
|
|
27
|
+
messages = ListAttr(StringAttr(default=[]))
|
|
28
|
+
name = StringAttr(default="agent")
|
|
29
|
+
instructions = StringAttr(
|
|
30
|
+
default="You are highly skilled AI trained to assist with various tasks."
|
|
31
|
+
)
|
|
32
|
+
description = StringAttr(
|
|
33
|
+
default="A helpful AI assistant trained to assist with various tasks."
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def client(self):
|
|
38
|
+
if not self._client:
|
|
39
|
+
# log("=== Initializing Gemini AI Client ===", _print=True)
|
|
40
|
+
self._client = genai.Client(api_key=os.environ.get("GOOGLEAI_KEY"))
|
|
41
|
+
# log("=== Gemini AI Client Initialized ===", _print=True)
|
|
42
|
+
return self._client
|
|
43
|
+
|
|
44
|
+
def _add_function(self, user_function):
|
|
45
|
+
# This function is now a bit more advanced to conform to the Tool Use schema
|
|
46
|
+
tool_schema = {
|
|
47
|
+
"name": user_function.get("name"),
|
|
48
|
+
"description": user_function.get("description"),
|
|
49
|
+
"parameters": user_function.get("parameters"),
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Validate that the schema has a name, description, and parameters
|
|
53
|
+
if not all(
|
|
54
|
+
[tool_schema["name"], tool_schema["description"], tool_schema["parameters"]]
|
|
55
|
+
):
|
|
56
|
+
raise ValueError(
|
|
57
|
+
"Tool schema must have a 'name', 'description', and 'parameters' field."
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return tool_schema
|
|
61
|
+
|
|
62
|
+
def _create_wav_header(
|
|
63
|
+
self, raw_audio_bytes, channels=1, rate=24000, sample_width=2
|
|
64
|
+
):
|
|
65
|
+
"""Creates an in-memory WAV file from raw PCM audio bytes."""
|
|
66
|
+
buffer = io.BytesIO()
|
|
67
|
+
with wave.open(buffer, "wb") as wav_file:
|
|
68
|
+
# Set audio parameters
|
|
69
|
+
wav_file.setnchannels(channels)
|
|
70
|
+
wav_file.setsampwidth(sample_width)
|
|
71
|
+
wav_file.setframerate(rate) # 16,000 Hz sample rate
|
|
72
|
+
|
|
73
|
+
# Write the raw audio data
|
|
74
|
+
wav_file.writeframes(raw_audio_bytes)
|
|
75
|
+
|
|
76
|
+
buffer.seek(0)
|
|
77
|
+
return buffer
|
|
78
|
+
|
|
79
|
+
def generate_json(self, message, function, additional_instructions=""):
|
|
80
|
+
# The API call must use the 'tools' parameter instead of 'response_json_schema'
|
|
81
|
+
function_definition = self._add_function(function)
|
|
82
|
+
|
|
83
|
+
response = self.client.models.generate_content(
|
|
84
|
+
model=self._json_model,
|
|
85
|
+
contents=message,
|
|
86
|
+
config=types.GenerateContentConfig(
|
|
87
|
+
system_instruction=f"{self.instructions}.{additional_instructions}",
|
|
88
|
+
tools=[types.Tool(function_declarations=[function_definition])],
|
|
89
|
+
tool_config={
|
|
90
|
+
"function_calling_config": {
|
|
91
|
+
"mode": "ANY", # Force a function call
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# The response is now a ToolCall, not a JSON string
|
|
98
|
+
try:
|
|
99
|
+
# log(response.candidates[0].content.parts[0].function_call, _print=True)
|
|
100
|
+
tool_call = response.candidates[0].content.parts[0].function_call
|
|
101
|
+
if tool_call and tool_call.name == function["name"]:
|
|
102
|
+
return tool_call.args
|
|
103
|
+
else:
|
|
104
|
+
log(
|
|
105
|
+
"==== Model did not return a tool call or returned the wrong one. ===="
|
|
106
|
+
)
|
|
107
|
+
log(f"Response: {response.text}", _print=True)
|
|
108
|
+
return {}
|
|
109
|
+
except Exception as e:
|
|
110
|
+
log(f"==== Failed to parse ToolCall response: {e} ====")
|
|
111
|
+
return {}
|
|
112
|
+
|
|
113
|
+
def generate_text(self, message, additional_instructions=""):
|
|
114
|
+
response = self.client.models.generate_content(
|
|
115
|
+
model=self._text_model,
|
|
116
|
+
config=types.GenerateContentConfig(
|
|
117
|
+
system_instruction=f"{self.instructions}.{additional_instructions}",
|
|
118
|
+
),
|
|
119
|
+
contents=message,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# log(results, _print=True)
|
|
123
|
+
# log("=================== END REPORT ===================", _print=True)
|
|
124
|
+
return response.text
|
|
125
|
+
|
|
126
|
+
def summarize_text(self, text, primer=""):
|
|
127
|
+
primer = primer or self.instructions
|
|
128
|
+
response = self.client.models.generate_content(
|
|
129
|
+
model=self._summary_model,
|
|
130
|
+
config=types.GenerateContentConfig(
|
|
131
|
+
system_instruction=f"{primer}",
|
|
132
|
+
),
|
|
133
|
+
contents=text,
|
|
134
|
+
)
|
|
135
|
+
log(response)
|
|
136
|
+
try:
|
|
137
|
+
result = response.candidates[0].content.parts[0].text
|
|
138
|
+
except Exception as e:
|
|
139
|
+
log(f"{type(e)}:{e}\n\n Unable to generate content ====")
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
return result
|
|
143
|
+
|
|
144
|
+
def generate_audio_text(
|
|
145
|
+
self, audio_file, prompt="Transcribe this audio clip", **kwargs
|
|
146
|
+
):
|
|
147
|
+
myfile = self.client.files.upload(
|
|
148
|
+
file=io.BytesIO(audio_file),
|
|
149
|
+
config={
|
|
150
|
+
"mime_type": "audio/mp3",
|
|
151
|
+
"display_name": kwargs.get("display_name", "audio.mp3"),
|
|
152
|
+
},
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
response = self.client.models.generate_content(
|
|
156
|
+
model=self._stt_model,
|
|
157
|
+
contents=[
|
|
158
|
+
prompt,
|
|
159
|
+
myfile,
|
|
160
|
+
],
|
|
161
|
+
)
|
|
162
|
+
return response.text
|
|
163
|
+
|
|
164
|
+
def generate_audio(self, prompt, voice=None):
|
|
165
|
+
voice = voice or random.choice(
|
|
166
|
+
[
|
|
167
|
+
"Zephyr",
|
|
168
|
+
"Puck",
|
|
169
|
+
"Charon",
|
|
170
|
+
"Kore",
|
|
171
|
+
"Fenrir",
|
|
172
|
+
"Leda",
|
|
173
|
+
"Orus",
|
|
174
|
+
"Aoede",
|
|
175
|
+
"Callirhoe",
|
|
176
|
+
"Autonoe",
|
|
177
|
+
"Enceladus",
|
|
178
|
+
"Iapetus",
|
|
179
|
+
"Umbriel",
|
|
180
|
+
"Algieba",
|
|
181
|
+
"Despina",
|
|
182
|
+
"Erinome",
|
|
183
|
+
"Algenib",
|
|
184
|
+
"Rasalgethi",
|
|
185
|
+
"Laomedeia",
|
|
186
|
+
"Achernar",
|
|
187
|
+
"Alnilam",
|
|
188
|
+
"Schedar",
|
|
189
|
+
"Gacrux",
|
|
190
|
+
"Pulcherrima",
|
|
191
|
+
"Achird",
|
|
192
|
+
"Zubenelgenubi",
|
|
193
|
+
"Vindemiatrix",
|
|
194
|
+
"Sadachbia",
|
|
195
|
+
"Sadaltager",
|
|
196
|
+
"Sulafar",
|
|
197
|
+
]
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
response = self.client.models.generate_content(
|
|
202
|
+
model=self._tts_model,
|
|
203
|
+
contents=prompt,
|
|
204
|
+
config=types.GenerateContentConfig(
|
|
205
|
+
response_modalities=["AUDIO"],
|
|
206
|
+
speech_config=types.SpeechConfig(
|
|
207
|
+
voice_config=types.VoiceConfig(
|
|
208
|
+
prebuilt_voice_config=types.PrebuiltVoiceConfig(
|
|
209
|
+
voice_name=voice,
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
),
|
|
213
|
+
),
|
|
214
|
+
)
|
|
215
|
+
blob = response.candidates[0].content.parts[0].inline_data
|
|
216
|
+
|
|
217
|
+
# Create a WAV file in memory from the raw audio bytes
|
|
218
|
+
wav_buffer = self._create_wav_header(blob.data)
|
|
219
|
+
|
|
220
|
+
# 2. Load the WAV audio using pydub, which will now correctly read the header
|
|
221
|
+
audio_segment = AudioSegment.from_file(wav_buffer, format="wav")
|
|
222
|
+
|
|
223
|
+
# 3. Create a new in-memory buffer for the MP3 output
|
|
224
|
+
mp3_buffer = io.BytesIO()
|
|
225
|
+
|
|
226
|
+
# 4. Export the audio segment directly to the in-memory buffer
|
|
227
|
+
audio_segment.export(mp3_buffer, format="mp3")
|
|
228
|
+
|
|
229
|
+
# 5. Return the bytes from the buffer, not the filename
|
|
230
|
+
return mp3_buffer.getvalue()
|
|
231
|
+
|
|
232
|
+
except Exception as e:
|
|
233
|
+
log(
|
|
234
|
+
f"==== Error: Unable to generate audio ====\n{type(e)}:{e}", _print=True
|
|
235
|
+
)
|
|
236
|
+
# You can return a default empty byte string or re-raise the exception
|
|
237
|
+
raise e
|
|
238
|
+
|
|
239
|
+
def generate_image(self, prompt, **kwargs):
|
|
240
|
+
image = None
|
|
241
|
+
contents = [prompt]
|
|
242
|
+
|
|
243
|
+
if kwargs.get("files"):
|
|
244
|
+
for fn, f in kwargs.get("files").items():
|
|
245
|
+
media = io.BytesIO(f)
|
|
246
|
+
myfile = self.client.files.upload(
|
|
247
|
+
file=media, config={"mime_type": "image/webp", "display_name": fn}
|
|
248
|
+
)
|
|
249
|
+
contents += [myfile]
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
# log(self._image_model, contents, _print=True)
|
|
253
|
+
response = self.client.models.generate_content(
|
|
254
|
+
model=self._image_model,
|
|
255
|
+
contents=contents,
|
|
256
|
+
config=types.GenerateContentConfig(
|
|
257
|
+
safety_settings=[
|
|
258
|
+
types.SafetySetting(
|
|
259
|
+
category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
|
|
260
|
+
threshold=types.HarmBlockThreshold.BLOCK_NONE,
|
|
261
|
+
),
|
|
262
|
+
types.SafetySetting(
|
|
263
|
+
category=types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
|
|
264
|
+
threshold=types.HarmBlockThreshold.BLOCK_NONE,
|
|
265
|
+
),
|
|
266
|
+
types.SafetySetting(
|
|
267
|
+
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
|
|
268
|
+
threshold=types.HarmBlockThreshold.BLOCK_NONE,
|
|
269
|
+
),
|
|
270
|
+
types.SafetySetting(
|
|
271
|
+
category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
|
|
272
|
+
threshold=types.HarmBlockThreshold.BLOCK_NONE,
|
|
273
|
+
),
|
|
274
|
+
types.SafetySetting(
|
|
275
|
+
category=types.HarmCategory.HARM_CATEGORY_CIVIC_INTEGRITY,
|
|
276
|
+
threshold=types.HarmBlockThreshold.BLOCK_NONE,
|
|
277
|
+
),
|
|
278
|
+
],
|
|
279
|
+
image_config=types.ImageConfig(
|
|
280
|
+
aspect_ratio=kwargs.get("aspect_ratio", "3:4"),
|
|
281
|
+
image_size=kwargs.get("image_size", "2K"),
|
|
282
|
+
),
|
|
283
|
+
),
|
|
284
|
+
)
|
|
285
|
+
# log(response, _print=True)
|
|
286
|
+
# log(response.candidates[0], _print=True)
|
|
287
|
+
image_parts = [
|
|
288
|
+
part.inline_data.data
|
|
289
|
+
for part in response.candidates[0].content.parts
|
|
290
|
+
if part.inline_data
|
|
291
|
+
]
|
|
292
|
+
image = image_parts[0]
|
|
293
|
+
except Exception as e:
|
|
294
|
+
log(
|
|
295
|
+
f"==== Error: Unable to create image ====\n\n{e}",
|
|
296
|
+
_print=True,
|
|
297
|
+
)
|
|
298
|
+
raise e
|
|
299
|
+
return image
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import random
|
|
5
|
+
import time
|
|
6
|
+
from base64 import b64decode
|
|
7
|
+
|
|
8
|
+
import openai
|
|
9
|
+
from ollama import ChatResponse, chat
|
|
10
|
+
|
|
11
|
+
from autonomous import log
|
|
12
|
+
from autonomous.model.autoattr import DictAttr, ListAttr, StringAttr
|
|
13
|
+
from autonomous.model.automodel import AutoModel
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class LocalAIModel(AutoModel):
|
|
17
|
+
_client = None
|
|
18
|
+
instructions = StringAttr(
|
|
19
|
+
default="You are highly skilled AI trained to assist with various tasks."
|
|
20
|
+
)
|
|
21
|
+
description = StringAttr(
|
|
22
|
+
default="A helpful AI assistant trained to assist with various tasks."
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def client(self):
|
|
27
|
+
if not self._client:
|
|
28
|
+
self._client = "deepseek-r1" # OpenAI(api_key=os.environ.get("OPENAI_KEY"))
|
|
29
|
+
return self._client
|
|
30
|
+
|
|
31
|
+
def clear_agent(self):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
def clear_agents(self):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
# def _get_agent_id(self):
|
|
38
|
+
# pass
|
|
39
|
+
|
|
40
|
+
# def _add_function(self, user_function):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
def _format_messages(self, messages):
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
def clear_files(self, file_id=None):
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
def attach_file(self, file_contents, filename="dbdata.json"):
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
def generate_json(self, messages, function, additional_instructions=""):
|
|
53
|
+
message = messages + additional_instructions
|
|
54
|
+
message += f"""
|
|
55
|
+
IMPORTANT: Respond in JSON FORMAT using the SCHEMA below. DO NOT add any text to the response outside of the supplied JSON schema:
|
|
56
|
+
{function}
|
|
57
|
+
"""
|
|
58
|
+
response: ChatResponse = chat(
|
|
59
|
+
model=self.client,
|
|
60
|
+
messages=[
|
|
61
|
+
{
|
|
62
|
+
"role": "user",
|
|
63
|
+
"content": message,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
)
|
|
67
|
+
return response.message.content
|
|
68
|
+
|
|
69
|
+
def generate_text(self, messages, additional_instructions=""):
|
|
70
|
+
message = messages + additional_instructions
|
|
71
|
+
response: ChatResponse = chat(
|
|
72
|
+
model=self.client,
|
|
73
|
+
messages=[
|
|
74
|
+
{
|
|
75
|
+
"role": "user",
|
|
76
|
+
"content": message,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
)
|
|
80
|
+
return response.message.content
|
|
81
|
+
|
|
82
|
+
def generate_audio(self, prompt, **kwargs):
|
|
83
|
+
raise NotImplementedError
|
|
84
|
+
|
|
85
|
+
def generate_image(self, prompt, **kwargs):
|
|
86
|
+
raise NotImplementedError
|
|
87
|
+
|
|
88
|
+
def summarize_text(self, text, primer=""):
|
|
89
|
+
response: ChatResponse = chat(
|
|
90
|
+
model=self.client,
|
|
91
|
+
messages=[
|
|
92
|
+
{
|
|
93
|
+
"role": "system",
|
|
94
|
+
"content": f"You are a highly skilled AI trained in language comprehension and summarization.{primer}",
|
|
95
|
+
},
|
|
96
|
+
{"role": "user", "content": text},
|
|
97
|
+
],
|
|
98
|
+
)
|
|
99
|
+
return response.message.content
|
autonomous/ai/models/openai.py
CHANGED
|
@@ -16,7 +16,7 @@ from autonomous.model.automodel import AutoModel
|
|
|
16
16
|
|
|
17
17
|
class OpenAIModel(AutoModel):
|
|
18
18
|
_client = None
|
|
19
|
-
_text_model = "
|
|
19
|
+
_text_model = "o3-mini"
|
|
20
20
|
_image_model = "dall-e-3"
|
|
21
21
|
_json_model = "gpt-4o"
|
|
22
22
|
agent_id = StringAttr()
|
|
@@ -40,7 +40,10 @@ class OpenAIModel(AutoModel):
|
|
|
40
40
|
def delete(self):
|
|
41
41
|
self.clear_files()
|
|
42
42
|
if self.agent_id:
|
|
43
|
-
|
|
43
|
+
try:
|
|
44
|
+
self.client.beta.assistants.delete(self.agent_id)
|
|
45
|
+
except openai_NotFoundError:
|
|
46
|
+
log(f"==== Agent with ID: {self.agent_id} not found ====")
|
|
44
47
|
return super().delete()
|
|
45
48
|
|
|
46
49
|
def clear_agent(self):
|
|
@@ -51,15 +54,16 @@ class OpenAIModel(AutoModel):
|
|
|
51
54
|
|
|
52
55
|
def clear_agents(self):
|
|
53
56
|
assistants = self.client.beta.assistants.list().data
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
if assistants:
|
|
58
|
+
log(assistants)
|
|
59
|
+
for assistant in assistants:
|
|
60
|
+
log(f"==== Deleting Agent with ID: {assistant.id} ====")
|
|
61
|
+
try:
|
|
62
|
+
self.client.beta.assistants.delete(assistant.id)
|
|
63
|
+
except openai_NotFoundError:
|
|
64
|
+
log(f"==== Agent with ID: {assistant.id} not found ====")
|
|
65
|
+
self.agent_id = ""
|
|
66
|
+
self.save()
|
|
63
67
|
|
|
64
68
|
def _get_agent_id(self):
|
|
65
69
|
try:
|
|
@@ -79,9 +83,9 @@ class OpenAIModel(AutoModel):
|
|
|
79
83
|
|
|
80
84
|
def clear_files(self, file_id=None):
|
|
81
85
|
if not file_id:
|
|
82
|
-
for vs in self.client.
|
|
86
|
+
for vs in self.client.vector_stores.list().data:
|
|
83
87
|
try:
|
|
84
|
-
self.client.
|
|
88
|
+
self.client.vector_stores.delete(vs.id)
|
|
85
89
|
except openai_NotFoundError:
|
|
86
90
|
log(f"==== Vector Store {vs.id} not found ====")
|
|
87
91
|
for sf in self.client.files.list().data:
|
|
@@ -97,8 +101,8 @@ class OpenAIModel(AutoModel):
|
|
|
97
101
|
self.tools["file_search"] = {"type": "file_search"}
|
|
98
102
|
# Create a vector store
|
|
99
103
|
try:
|
|
100
|
-
if vs := self.client.
|
|
101
|
-
self.vector_store = self.client.
|
|
104
|
+
if vs := self.client.vector_stores.list().data:
|
|
105
|
+
self.vector_store = self.client.vector_stores.retrieve(
|
|
102
106
|
vector_store_id=vs[0].id
|
|
103
107
|
).id
|
|
104
108
|
else:
|
|
@@ -106,17 +110,17 @@ class OpenAIModel(AutoModel):
|
|
|
106
110
|
self.client.files.delete(file_id=sf.id)
|
|
107
111
|
raise FileNotFoundError("No vector store found")
|
|
108
112
|
except FileNotFoundError:
|
|
109
|
-
self.vector_store = self.client.
|
|
113
|
+
self.vector_store = self.client.vector_stores.create(
|
|
110
114
|
name="World Reference",
|
|
111
115
|
expires_after={"anchor": "last_active_at", "days": 14},
|
|
112
116
|
).id
|
|
113
|
-
log(f"==== Vector Store ID: {self.vector_store}====")
|
|
117
|
+
log(f"==== Vector Store ID: {self.vector_store}====", _print=True)
|
|
114
118
|
# Attach File
|
|
115
119
|
file_obj = self.client.files.create(
|
|
116
120
|
file=(filename, file_contents), purpose="assistants"
|
|
117
121
|
)
|
|
118
|
-
log(f"==== FileStore ID: {file_obj.id}====")
|
|
119
|
-
self.client.
|
|
122
|
+
log(f"==== FileStore ID: {file_obj.id}====", _print=True)
|
|
123
|
+
self.client.vector_stores.files.create(
|
|
120
124
|
vector_store_id=self.vector_store,
|
|
121
125
|
file_id=file_obj.id,
|
|
122
126
|
)
|
|
@@ -198,14 +202,14 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with o
|
|
|
198
202
|
]:
|
|
199
203
|
running_job = False
|
|
200
204
|
|
|
201
|
-
except openai.BadRequestError as
|
|
205
|
+
except openai.BadRequestError as err:
|
|
202
206
|
# Handle specific bad request errors
|
|
203
|
-
|
|
204
|
-
if "already has an active run" in
|
|
207
|
+
log(f"==== Error: {err} ====", _print=True)
|
|
208
|
+
if "already has an active run" in str(err):
|
|
205
209
|
log("Previous run is still active. Waiting...", _print=True)
|
|
206
210
|
time.sleep(2) # wait before retrying or checking run status
|
|
207
211
|
else:
|
|
208
|
-
raise
|
|
212
|
+
raise err
|
|
209
213
|
|
|
210
214
|
# while run.status in ["queued", "in_progress"]:
|
|
211
215
|
# run = self.client.beta.threads.runs.retrieve(
|
|
@@ -217,7 +221,7 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with o
|
|
|
217
221
|
log(f"==== !!! ERROR !!!: {run.last_error} ====", _print=True)
|
|
218
222
|
return None
|
|
219
223
|
log("=================== RUN COMPLETED ===================", _print=True)
|
|
220
|
-
log(run.status, _print=True)
|
|
224
|
+
# log(run.status, _print=True)
|
|
221
225
|
if run.status == "completed":
|
|
222
226
|
response = self.client.beta.threads.messages.list(thread_id=thread.id)
|
|
223
227
|
results = response.data[0].content[0].text.value
|
|
@@ -236,8 +240,8 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with o
|
|
|
236
240
|
log(f"==== Invalid JSON:\n{results}", _print=True)
|
|
237
241
|
return {}
|
|
238
242
|
else:
|
|
239
|
-
log(f"==== Results: {results}", _print=True)
|
|
240
|
-
log("=================== END REPORT ===================", _print=True)
|
|
243
|
+
# log(f"==== Results: {results}", _print=True)
|
|
244
|
+
# log("=================== END REPORT ===================", _print=True)
|
|
241
245
|
return results
|
|
242
246
|
|
|
243
247
|
def generate_text(self, messages, additional_instructions=""):
|
|
@@ -278,16 +282,34 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with o
|
|
|
278
282
|
|
|
279
283
|
def generate_audio(self, prompt, **kwargs):
|
|
280
284
|
voice = kwargs.get("voice") or random.choice(
|
|
281
|
-
[
|
|
285
|
+
[
|
|
286
|
+
"alloy",
|
|
287
|
+
"ash",
|
|
288
|
+
"ballad",
|
|
289
|
+
"coral",
|
|
290
|
+
"echo",
|
|
291
|
+
"fable",
|
|
292
|
+
"onyx",
|
|
293
|
+
"nova",
|
|
294
|
+
"sage",
|
|
295
|
+
"shimmer",
|
|
296
|
+
]
|
|
282
297
|
)
|
|
283
298
|
response = self.client.audio.speech.create(
|
|
284
299
|
model="tts-1",
|
|
285
300
|
voice=voice,
|
|
286
301
|
input=prompt,
|
|
287
302
|
)
|
|
288
|
-
log(response, _print=True)
|
|
303
|
+
# log(response, _print=True)
|
|
289
304
|
return response.read()
|
|
290
305
|
|
|
306
|
+
def generate_audio_text(self, audio_file, **kwargs):
|
|
307
|
+
response = self.client.audio.transcriptions.create(
|
|
308
|
+
model="gpt-4o-transcribe", file=audio_file, language="en", **kwargs
|
|
309
|
+
)
|
|
310
|
+
log(response, _print=True)
|
|
311
|
+
return response.text
|
|
312
|
+
|
|
291
313
|
def generate_image(self, prompt, **kwargs):
|
|
292
314
|
image = None
|
|
293
315
|
try:
|
|
@@ -299,7 +321,8 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with o
|
|
|
299
321
|
)
|
|
300
322
|
image_dict = response.data[0]
|
|
301
323
|
except Exception as e:
|
|
302
|
-
|
|
324
|
+
log(f"==== Error: Unable to create image ====\n\n{e}", _print=True)
|
|
325
|
+
raise e
|
|
303
326
|
else:
|
|
304
327
|
image = b64decode(image_dict.b64_json)
|
|
305
328
|
return image
|
autonomous/ai/textagent.py
CHANGED
|
@@ -14,12 +14,6 @@ class TextAgent(BaseAgent):
|
|
|
14
14
|
default="A helpful AI assistant trained to assist with generating text according to the given requirements."
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
def clear_files(self, file_id=None):
|
|
18
|
-
return self.get_client().clear_files(file_id)
|
|
19
|
-
|
|
20
|
-
def attach_file(self, file_contents, filename="dbdata.json"):
|
|
21
|
-
return self.get_client().attach_file(file_contents, filename)
|
|
22
|
-
|
|
23
17
|
def summarize_text(self, text, primer=""):
|
|
24
18
|
return self.get_client().summarize_text(text, primer)
|
|
25
19
|
|
autonomous/db/fields.py
CHANGED
|
@@ -721,8 +721,7 @@ class EmbeddedDocumentField(BaseField):
|
|
|
721
721
|
or issubclass(document_type, EmbeddedDocument)
|
|
722
722
|
):
|
|
723
723
|
self.error(
|
|
724
|
-
"Invalid embedded document class provided to an "
|
|
725
|
-
"EmbeddedDocumentField"
|
|
724
|
+
"Invalid embedded document class provided to an EmbeddedDocumentField"
|
|
726
725
|
)
|
|
727
726
|
|
|
728
727
|
self.document_type_obj = document_type
|
|
@@ -1494,7 +1493,7 @@ class GenericReferenceField(BaseField):
|
|
|
1494
1493
|
get_document(value.get("_cls")), value.get("_ref")
|
|
1495
1494
|
)
|
|
1496
1495
|
except DoesNotExist:
|
|
1497
|
-
log(f"{value} DoesNotExist")
|
|
1496
|
+
# log(f"{value} DoesNotExist")
|
|
1498
1497
|
return
|
|
1499
1498
|
|
|
1500
1499
|
if isinstance(value, Document):
|
autonomous/db/queryset/base.py
CHANGED
|
@@ -117,10 +117,7 @@ class BaseQuerySet:
|
|
|
117
117
|
if q_obj:
|
|
118
118
|
# Make sure proper query object is passed.
|
|
119
119
|
if not isinstance(q_obj, QNode):
|
|
120
|
-
msg =
|
|
121
|
-
"Not a query object: %s. "
|
|
122
|
-
"Did you intend to use key=value?" % q_obj
|
|
123
|
-
)
|
|
120
|
+
msg = "Not a query object: %s. Did you intend to use key=value?" % q_obj
|
|
124
121
|
raise InvalidQueryError(msg)
|
|
125
122
|
query &= q_obj
|
|
126
123
|
|