dhisana 0.0.1.dev4__tar.gz → 0.0.1.dev5__tar.gz
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.
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/PKG-INFO +1 -1
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/setup.py +1 -1
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/ui/components.py +1 -1
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/openai_helpers.py +51 -39
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana.egg-info/PKG-INFO +1 -1
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/README.md +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/pyproject.toml +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/setup.cfg +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/__init__.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/cli/__init__.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/cli/cli.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/cli/datasets.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/cli/models.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/cli/predictions.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/ui/__init__.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/__init__.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/agent_tools.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/assistant_tool_tag.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana/utils/tools_json.py +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana.egg-info/SOURCES.txt +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana.egg-info/dependency_links.txt +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana.egg-info/entry_points.txt +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana.egg-info/requires.txt +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/src/dhisana.egg-info/top_level.txt +0 -0
- {dhisana-0.0.1.dev4 → dhisana-0.0.1.dev5}/tests/test_agent_tools.py +0 -0
|
@@ -110,7 +110,7 @@ class Chart(Component):
|
|
|
110
110
|
|
|
111
111
|
|
|
112
112
|
class Form(Component):
|
|
113
|
-
def __init__(self, children: List[Component], on_submit: str):
|
|
113
|
+
def __init__(self, children: List[Component], on_submit: List[str]):
|
|
114
114
|
self.children = children
|
|
115
115
|
self.on_submit = on_submit
|
|
116
116
|
|
|
@@ -58,6 +58,8 @@ async def run_assistant(client, assistant, thread, prompt, response_type, allowe
|
|
|
58
58
|
while run.status == 'requires_action':
|
|
59
59
|
if iteration_count >= max_iterations:
|
|
60
60
|
print("Exceeded maximum number of iterations for requires_action.")
|
|
61
|
+
# Cancel the run before returning
|
|
62
|
+
await client.beta.threads.runs.cancel(run_id=run.id)
|
|
61
63
|
return "Error: Exceeded maximum number of iterations for requires_action."
|
|
62
64
|
|
|
63
65
|
tool_outputs = await handle_required_action(run)
|
|
@@ -69,6 +71,7 @@ async def run_assistant(client, assistant, thread, prompt, response_type, allowe
|
|
|
69
71
|
return await handle_run_completion(client, thread, run)
|
|
70
72
|
|
|
71
73
|
|
|
74
|
+
|
|
72
75
|
async def send_initial_message(client, thread, prompt):
|
|
73
76
|
client.beta.threads.messages.create(
|
|
74
77
|
thread_id=thread.id,
|
|
@@ -103,6 +106,7 @@ async def handle_required_action(run):
|
|
|
103
106
|
tool_outputs = []
|
|
104
107
|
current_batch_size = 0
|
|
105
108
|
max_batch_size = 256 * 1024 # 256 KB
|
|
109
|
+
print(f"Handling required action")
|
|
106
110
|
|
|
107
111
|
if hasattr(run, 'required_action') and hasattr(run.required_action, 'submit_tool_outputs'):
|
|
108
112
|
for tool in run.required_action.submit_tool_outputs.tool_calls:
|
|
@@ -243,24 +247,19 @@ async def process_agent_request(row_batch: List[Dict], workflow: Dict, custom_in
|
|
|
243
247
|
model="gpt-4o-2024-08-06"
|
|
244
248
|
)
|
|
245
249
|
thread = client.beta.threads.create()
|
|
246
|
-
|
|
247
250
|
parsed_outputs = []
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
# Collect the final output
|
|
261
|
-
parsed_outputs.append(task_outputs)
|
|
262
|
-
except Exception as e:
|
|
263
|
-
print(f"Error processing row {row}: {e}")
|
|
251
|
+
task_outputs = {} # Dictionary to store outputs of tasks
|
|
252
|
+
input_list = {}
|
|
253
|
+
input_list['initial_input_list'] = {
|
|
254
|
+
"data": row_batch,
|
|
255
|
+
"format": "list"
|
|
256
|
+
}
|
|
257
|
+
task_outputs['initial_input'] = input_list
|
|
258
|
+
for task in workflow['tasks']:
|
|
259
|
+
# Process each task
|
|
260
|
+
task_outputs = await process_task(client, assistant, thread, task, task_outputs)
|
|
261
|
+
# Collect the final output
|
|
262
|
+
parsed_outputs.append(task_outputs)
|
|
264
263
|
return parsed_outputs
|
|
265
264
|
except Exception as e:
|
|
266
265
|
print(f"An error occurred: {e}")
|
|
@@ -272,24 +271,20 @@ async def process_agent_request(row_batch: List[Dict], workflow: Dict, custom_in
|
|
|
272
271
|
print(f"Error deleting assistant: {e}")
|
|
273
272
|
|
|
274
273
|
|
|
275
|
-
async def process_task(client, assistant, thread,
|
|
274
|
+
async def process_task(client, assistant, thread, task, task_outputs):
|
|
276
275
|
"""
|
|
277
276
|
Process a single task in the workflow.
|
|
278
277
|
"""
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
task_inputs = await prepare_task_inputs(row, task, task_outputs)
|
|
278
|
+
# Prepare inputs
|
|
279
|
+
task_inputs = await prepare_task_inputs(task, task_outputs)
|
|
282
280
|
|
|
283
|
-
|
|
284
|
-
|
|
281
|
+
# Run the operation
|
|
282
|
+
output = await run_task_operation(client, assistant, thread, task, task_inputs)
|
|
285
283
|
|
|
286
|
-
|
|
287
|
-
|
|
284
|
+
# Store outputs
|
|
285
|
+
await store_task_outputs(task, output, task_outputs)
|
|
288
286
|
|
|
289
|
-
|
|
290
|
-
except Exception as e:
|
|
291
|
-
print(f"Error processing task {task['id']}: {e}")
|
|
292
|
-
return task_outputs
|
|
287
|
+
return task_outputs
|
|
293
288
|
|
|
294
289
|
async def read_csv_rows(file_path):
|
|
295
290
|
rows = []
|
|
@@ -299,7 +294,7 @@ async def read_csv_rows(file_path):
|
|
|
299
294
|
rows.append(row)
|
|
300
295
|
return rows
|
|
301
296
|
|
|
302
|
-
async def prepare_task_inputs(
|
|
297
|
+
async def prepare_task_inputs(task, task_outputs):
|
|
303
298
|
"""
|
|
304
299
|
Prepare the inputs for a task based on its input specifications.
|
|
305
300
|
"""
|
|
@@ -309,15 +304,11 @@ async def prepare_task_inputs(row, task, task_outputs):
|
|
|
309
304
|
source = input_spec.get('source', {})
|
|
310
305
|
source_type = source.get('type', '')
|
|
311
306
|
format = input_spec.get('format', 'list')
|
|
312
|
-
if source_type == '
|
|
313
|
-
# External source, get from initial input
|
|
314
|
-
input_data = row.get(input_name, row)
|
|
315
|
-
elif source_type == 'task_output':
|
|
307
|
+
if source_type == 'task_output':
|
|
316
308
|
# Get from previous task output
|
|
317
309
|
task_id = source.get('task_id')
|
|
318
310
|
output_key = source.get('output_key')
|
|
319
|
-
previous_task_output = task_outputs.get(task_id, {})
|
|
320
|
-
print(f"Previous task output: {previous_task_output} Output key: {output_key}")
|
|
311
|
+
previous_task_output = task_outputs.get(task_id, {})
|
|
321
312
|
if isinstance(previous_task_output, dict):
|
|
322
313
|
output_item = previous_task_output.get(output_key)
|
|
323
314
|
input_data = output_item['data']
|
|
@@ -361,14 +352,17 @@ async def run_task_operation(client, assistant, thread, task, task_inputs):
|
|
|
361
352
|
args = operation.get('args', [])
|
|
362
353
|
# Prepare prompt by substituting inputs
|
|
363
354
|
|
|
364
|
-
|
|
355
|
+
|
|
365
356
|
for key, value in task_inputs.items():
|
|
366
357
|
format = value.get('format', 'list')
|
|
367
358
|
if format == 'list':
|
|
368
|
-
|
|
359
|
+
items = value.get('data')
|
|
360
|
+
for item in items:
|
|
361
|
+
formatted_prompt = prompt_template
|
|
369
362
|
formatted_prompt = formatted_prompt.replace(
|
|
370
363
|
"{{ inputs." + key + " }}", json.dumps(item))
|
|
371
364
|
# Run assistant with prompt
|
|
365
|
+
print(formatted_prompt)
|
|
372
366
|
output = await extract_and_structure_data(
|
|
373
367
|
client, assistant, thread, formatted_prompt, task_inputs, response_type, allowed_tools)
|
|
374
368
|
outputs.append(output)
|
|
@@ -419,7 +413,7 @@ async def store_task_outputs(task, output, task_outputs):
|
|
|
419
413
|
local_path = path
|
|
420
414
|
|
|
421
415
|
if dest_type == 'google_drive':
|
|
422
|
-
local_path = os.path.join('/tmp', path)
|
|
416
|
+
local_path = os.path.join('/tmp', task['id'], path)
|
|
423
417
|
|
|
424
418
|
if dest_type == 'google_drive' or dest_type == 'local_path':
|
|
425
419
|
directory = os.path.dirname(local_path)
|
|
@@ -429,6 +423,9 @@ async def store_task_outputs(task, output, task_outputs):
|
|
|
429
423
|
if output.get("format", "") == 'list':
|
|
430
424
|
data_list = [json.loads(item) for item in output.get("data", [])]
|
|
431
425
|
if data_list:
|
|
426
|
+
dedup_by = output_spec.get('deduplication_properties', [])
|
|
427
|
+
if dedup_by:
|
|
428
|
+
data_list = deduplicate_list_by_properties(data_list, dedup_by)
|
|
432
429
|
# Filter headers to include only simple types
|
|
433
430
|
headers = [key for key, value in data_list[0].items() if isinstance(value, (str, int, float, bool))]
|
|
434
431
|
writer = csv.DictWriter(file, fieldnames=headers)
|
|
@@ -450,6 +447,21 @@ async def store_task_outputs(task, output, task_outputs):
|
|
|
450
447
|
# If no outputs are defined, store the output under the task id
|
|
451
448
|
task_outputs[task['id']] = output
|
|
452
449
|
|
|
450
|
+
def deduplicate_list_by_properties(data_list, properties):
|
|
451
|
+
"""
|
|
452
|
+
Deduplicate a list of dictionaries by a list of properties in order.
|
|
453
|
+
"""
|
|
454
|
+
for property_name in properties:
|
|
455
|
+
seen = set()
|
|
456
|
+
deduplicated_list = []
|
|
457
|
+
for item in data_list:
|
|
458
|
+
value = item.get(property_name)
|
|
459
|
+
if value not in seen:
|
|
460
|
+
seen.add(value)
|
|
461
|
+
deduplicated_list.append(item)
|
|
462
|
+
data_list = deduplicated_list
|
|
463
|
+
return data_list
|
|
464
|
+
|
|
453
465
|
async def write_to_google_drive(cloud_path, local_path):
|
|
454
466
|
# Placeholder function for writing to Google Drive
|
|
455
467
|
await write_content_to_googledrive(cloud_path, local_path)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|