Я пишу веб-автоматизацию для загрузки некоторых резюме на веб-сайт с помощью инструмента веб-автоматизации, использующего браузер, который использует LLM в качестве агента искусственного интеллекта. Загрузка файлов не поддерживается браузером и является встроенной функцией. Вот почему я написал для этого следующий сложный код, однако иногда он работает, а иногда нет.
например, 5 раз сработало хорошо, а один раз нет. вот журнал, связанный со временем сбоя:
Received task execution request with payload: {
"prompt": "go to https://joblookup.com/uk/employer/login website, login with test@test.com username and 123123 password. click on the application, download two of the applications by clicking on one download button then terminate the task.",
"task_id": "2",
"is_dynamic": true,
"capsolver": false,
"is_download": true,
"data": {}
}
go to https://joblookup.com/uk/employer/login website, login with test@test.com username and 123123 password. click on the application, download two of the applications by clicking on one download button then terminate the task.
Found matching workflow ID: N/A
INFO: 127.0.0.1:44532 - "POST /api/v1/execute-task HTTP/1.1" 200 OK
Starting automation process...
contexts initial: 0
INFO [agent] 🚀 Starting task:
Original Task: go to https://joblookup.com/uk/employer/login website, login with test@test.com username and 123123 password. click on the application, download two of the applications by clicking on one download button then terminate the task.
Data:
Please complete the task by following the step-by-step process outlined in the Previous Recording Context as a guide, but always prioritize and use the values provided in the 'Original Task' part.
NOTE: to populate the whole fields you need SCROLL DOWN to see all of them.
Note: if you see any Ad, just close it.
Note: there is no need to fill all fields that are unnecessary or in not into the above automation.
INFO [agent]
📍 Step 1
contexts after 5 sec: 1
INFO [agent] 🤷 Eval: Unknown - No previous actions to evaluate.
INFO [agent] 🧠 Memory: Starting task to log in to joblookup.com with provided credentials.
INFO [agent] 🎯 Next goal: Navigate to https://joblookup.com/uk/employer/login to begin login process.
INFO [agent] 🛠️ Action 1/1: {"go_to_url":{"url":"https://joblookup.com/uk/employer/login"}}
INFO [controller] 🔗 Navigated to https://joblookup.com/uk/employer/login
INFO [agent]
📍 Step 2
INFO [agent] 👍 Eval: Success - Navigated to the login page and identified email and password fields.
INFO [agent] 🧠 Memory: Navigated to the login page. Next, input email and password to log in.
INFO [agent] 🎯 Next goal: Input email and password, then click the Sign In button.
INFO [agent] 🛠️ Action 1/3: {"input_text":{"index":14,"text":"test@test.com"}}
INFO [agent] 🛠️ Action 2/3: {"input_text":{"index":16,"text":"123123"}}
INFO [agent] 🛠️ Action 3/3: {"click_element":{"index":19}}
INFO [controller] ⌨️ Input "test@test.com" into index 14
INFO [controller] ⌨️ Input "123123" into index 16
INFO [controller] 🖱️ Clicked button with index 19: Sign In
INFO [agent]
📍 Step 3
INFO [agent] 👍 Eval: Success - Successfully logged in and reached the dashboard.
INFO [agent] 🧠 Memory: Logged in and on the Employer Dashboard. Next, navigate to Applications to download applications.
INFO [agent] 🎯 Next goal: Click on the 'Applications' link to view applications.
INFO [agent] 🛠️ Action 1/1: {"click_element":{"index":17}}
INFO [controller] 🖱️ Clicked button with index 17: Applications
INFO [agent]
📍 Step 4
INFO [agent] 👍 Eval: Success - Reached the Applications page.
INFO [agent] 🧠 Memory: On the Applications page, ready to download applications.
INFO [agent] 🎯 Next goal: Download two applications by clicking on download buttons.
INFO [agent] 🛠️ Action 1/2: {"click_element":{"index":20}}
INFO [agent] 🛠️ Action 2/2: {"click_element":{"index":21}}
INFO [controller] 🖱️ Clicked button with index 20:
INFO [controller] Something new appeared after action 1 / 2
INFO [agent]
📍 Step 5
INFO [agent] 👍 Eval: Partial Success - First application downloaded. Ready to download the second application.
INFO [agent] 🧠 Memory: Downloaded one application. Ready to download the second application.
INFO [agent] 🎯 Next goal: Download the second application by clicking the next download button.
INFO [agent] 🛠️ Action 1/1: {"click_element":{"index":21}}
INFO [controller] 🖱️ Clicked button with index 21:
INFO [agent]
📍 Step 6
INFO [agent] 👍 Eval: Success - Second application downloaded successfully.
INFO [agent] 🧠 Memory: Downloaded two applications as required by the task.
INFO [agent] 🎯 Next goal: Complete the task as the main objective has been achieved.
INFO [agent] 🛠️ Action 1/1: {"done":{"text":"Successfully logged in to joblookup.com, navigated to the Applications page, and downloaded two applications as required."}}
INFO [agent] 📄 Result: Successfully logged in to joblookup.com, navigated to the Applications page, and downloaded two applications as required.
INFO [agent] ✅ Task completed successfully
INFO [agent] Created GIF at agent_history.gif
is_done=True extracted_content='Successfully logged in to joblookup.com, navigated to the Applications page, and downloaded two applications as required.' error=None include_in_memory=False
No files were downloaded during this session.
Automation result: {'result': 'Successfully logged in to joblookup.com, navigated to the Applications page, and downloaded two applications as required.', 'success': False, 'error': 'No files were downloaded during this session.'}
Sending webhook for valid result
Sending Webhook Payload:
{'data': {'candidate_update': True, 'task_id': '2'},
'message': 'No files were downloaded during this session.',
'success': False}
< /code>
и вот мои связанные коды: < /p>
main.py:
import httpx
import os
import json
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, APIRouter, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from pprint import pprint
from colored_print import log
from .modules.agents.browser_use_capsolver import main as browser_capsolver
from .modules.agents.browser_use_service import main as browser_main
from .modules.agents.browser_use_download import main as browser_download
from .modules.rag.faiss_module import get_full_recording
from .modules.static_automation.playwright_automation import post_job_on_jobspider
from . import utils
load_dotenv()
WEBHOOK_URL = "https://test.com/test"
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # In production, replace with specific origins
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
api_v1 = APIRouter(prefix="/api/v1")
class TaskRequest(BaseModel):
prompt: str
task_id: str
is_dynamic: bool = True
capsolver: bool | None = False
is_download: bool | None = False
data: dict | None = None
async def send_webhook(
task_id: str,
success: bool,
message: str,
webhook_url: str,
is_download: bool = False,
):
headers = {
"Content-Type": "application/json",
"Authorization": "Basic xxx"
}
data = {"task_id": task_id}
if is_download:
data["candidate_update"] = True
payload = {
"message": message,
"success": success,
"data": data
}
log.pink("Sending Webhook Payload:")
pprint(payload)
async with httpx.AsyncClient() as client:
await client.post(webhook_url, headers=headers, json=payload)
async def process_automation(
task: str,
task_id: str,
is_capsolver: bool,
webhook_url: str,
is_download: bool = False,
):
webhook_sent = False # Flag to track if webhook has been sent
try:
log.info("Starting automation process...")
if is_download:
result = await browser_download(task, task_id)
log.info(f"Automation result: {result}")
if isinstance(result, dict):
# Check if there's an error message that indicates failure
message = result.get("result") if result.get("success") else result.get("error", "Unknown error")
# Set success to False if message contains failure indicators
success = result.get("success", False) and "Failed" not in str(message) and "error" not in str(message).lower()
log.info("Sending webhook for valid result")
await send_webhook(
task_id=task_id,
success=success,
message=message,
webhook_url=webhook_url,
is_download=is_download,
)
webhook_sent = True # Set flag to true after successful webhook
else:
log.info("Sending webhook for invalid result format")
await send_webhook(
task_id=task_id,
success=False,
message="Invalid result format",
webhook_url=webhook_url,
is_download=is_download,
)
webhook_sent = True
except httpx.ConnectError as e:
log.error(f"Connection error occurred: {str(e)}")
# Handle connection-specific errors here if needed
except Exception as e:
log.error(f"Exception occurred: {str(e)}")
if not webhook_sent: # Only send webhook if it hasn't been sent yet
await send_webhook(
task_id=task_id,
success=False,
message=str(e),
webhook_url=webhook_url,
is_download=is_download,
)
@api_v1.post("/execute-task")
async def execute_task(request: TaskRequest, background_tasks: BackgroundTasks):
log.info(
f"Received task execution request with payload: {json.dumps(request.model_dump(), indent=2)}"
).store()
try:
if not request.is_dynamic:
# Static Task Handling: Automate job posting on JobSpider
...
# Dynamic Task Handling
recording_context = get_full_recording("data/dummy.json", request.prompt)
data_string = utils.format_data_to_string(request.data)
task = f"""
Original Task: {request.prompt}
Data:
{data_string}
{f'Previous Recording Context (for guidance only, do not use exact values): {recording_context}' if recording_context != "No matching workflow found." else ''}
Please complete the task by following the step-by-step process outlined in the Previous Recording Context as a guide, but always prioritize and use the values provided in the 'Original Task' part.
"""
background_tasks.add_task(
process_automation,
task,
request.task_id,
request.capsolver,
WEBHOOK_URL,
is_download=request.is_download,
)
return {
"status": "accepted",
"task_id": request.task_id,
"message": "Task is being processed asynchronously"
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
app.include_router(api_v1)
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
import os
import sys
from pathlib import Path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import asyncio
from langchain_openai import ChatOpenAI
# from langchain.callbacks import get_openai_callback
from typing import Dict, List
from colored_print import log
from browser_use import Agent, Controller
from browser_use.browser.browser import Browser, BrowserConfig
from browser_use.browser.context import BrowserContext
from .browser_use_service import MAX_STEPS
# Initialize controller first
browser = Browser(config=BrowserConfig(headless=False))
controller = Controller()
async def handle_download(download, task_id, downloaded_files):
try:
# Create downloads directory if it doesn't exist
log.info(f"Handling download for task {task_id}")
downloads_dir = Path(f"./downloads/{task_id}")
downloads_dir.mkdir(parents=True, exist_ok=True)
# Wait for the download to complete and get the path
original_path = await download.path()
if not original_path:
raise Exception("Download path is None")
log.info(f"Original path: {original_path}")
# Check if the file exists before moving
if not os.path.exists(original_path):
log.error(f"Downloaded file not found at {original_path}")
return # Early exit if file doesn't exist
# Create new path in downloads directory with .pdf postfix
new_path = downloads_dir / (os.path.basename(original_path) + '.pdf')
# Move the file to downloads directory
os.rename(original_path, new_path)
# Add the new path to downloaded files list
downloaded_files.append(str(new_path))
log.success(f"Downloaded and moved to: {new_path}")
except Exception as e:
log.error(f"Error handling download: {e}")
@controller.action(
'Upload file - the file name is inside the function - you only need to call this with the correct index',
requires_browser=True,
)
async def upload_file(index: int, browser: BrowserContext):
element = await browser.get_element_by_index(index)
my_file = Path.cwd() / 'examples/test_cv.txt'
if not element:
raise Exception(f'Element with index {index} not found')
await element.set_input_files(str(my_file.absolute()))
return f'Uploaded file to index {index}'
@controller.action('Close file dialog', requires_browser=True)
async def close_file_dialog(browser: BrowserContext):
page = await browser.get_current_page()
await page.keyboard.press('Escape')
def handle_page(new_page, task_id, downloaded_files):
log.info("New page created!")
new_page.on(
"download",
lambda download: asyncio.create_task(
handle_download(download, task_id, downloaded_files)
)
)
async def print_contexts_after_delay(
playwright_browser, task_id: str, downloaded_files: List[str]
):
await asyncio.sleep(5)
if len(playwright_browser.contexts) < 1:
raise Exception('No contexts found')
# Set up download handler at Playwright browser level
playwright_browser.contexts[0].on(
"page", lambda page: handle_page(page, task_id, downloaded_files)
)
log.info('contexts after 5 sec:', len(playwright_browser.contexts))
async def main(task: str, task_id: str):
model = ChatOpenAI(model='gpt-4o')
agent = Agent(
task=task,
llm=model,
controller=controller,
browser=browser,
)
# Initialize or clear the downloaded_files list for each task
downloaded_files = []
# Get the underlying Playwright browser instance
playwright_browser = await browser.get_playwright_browser()
log.info('contexts initial:', len(playwright_browser.contexts))
# Create task for delayed context printing
asyncio.create_task(
print_contexts_after_delay(playwright_browser, task_id, downloaded_files)
)
# Track token usage and cost
# with get_openai_callback() as cb:
# await agent.run()
# # Print usage statistics
# print("\nOpenAI API Usage Stats:")
# print(f"Total Tokens: {cb.total_tokens}")
# print(f"Prompt Tokens: {cb.prompt_tokens}")
# print(f"Completion Tokens: {cb.completion_tokens}")
# print(f"Total Cost (USD): ${cb.total_cost:.4f}")
# Run the agent
result = await agent.run(max_steps=MAX_STEPS)
history_file_path = 'AgentHistoryList.json'
agent.save_history(file_path=history_file_path)
is_complete: str | bool = result.history[-1].model_output.current_state.evaluation_previous_goal if result.history else False
max_steps_reached = len(result.history) >= MAX_STEPS
is_done = result.history[-1].result[-1].is_done
message = result.history[-1].result[-1].extracted_content
error = result.history[-1].result[-1].error
log.pink(result.history[-1].result[-1])
await browser.close()
# Print downloaded files
if downloaded_files:
log.info("\nDownloaded files:")
for file_path in downloaded_files:
log.info(file_path)
log.info(f"- {os.path.basename(file_path)}")
else:
log.error("\nNo files were downloaded during this session.")
is_done = False
error = "No files were downloaded during this session."
if max_steps_reached:
return {
"result": "Task exceeded maximum allowed steps",
"success": False,
"error": "Max steps exceeded without completion",
}
return {
"result": str(message),
"success": is_done,
"error": error,
}
< /code>
Полагаю, проблема связана с параллелизмом и асинхронными вещами. Или, может быть, связано с методом handle_download
.
Я прошу прощения за длинный и сложный вопрос, я не мог сделать его проще, очень извините.
Я пишу веб-автоматизацию для загрузки некоторых резюме на веб-сайт с помощью инструмента веб-автоматизации, использующего браузер, который использует LLM в качестве агента искусственного интеллекта. Загрузка файлов не поддерживается браузером и является встроенной функцией. Вот почему я написал для этого следующий сложный код, однако иногда он работает, а иногда нет. например, 5 раз сработало хорошо, а один раз нет. вот журнал, связанный со временем сбоя: [code]Received task execution request with payload: { "prompt": "go to https://joblookup.com/uk/employer/login website, login with test@test.com username and 123123 password. click on the application, download two of the applications by clicking on one download button then terminate the task.", "task_id": "2", "is_dynamic": true, "capsolver": false, "is_download": true, "data": {} } go to https://joblookup.com/uk/employer/login website, login with test@test.com username and 123123 password. click on the application, download two of the applications by clicking on one download button then terminate the task. Found matching workflow ID: N/A INFO: 127.0.0.1:44532 - "POST /api/v1/execute-task HTTP/1.1" 200 OK Starting automation process... contexts initial: 0 INFO [agent] 🚀 Starting task: Original Task: go to https://joblookup.com/uk/employer/login website, login with test@test.com username and 123123 password. click on the application, download two of the applications by clicking on one download button then terminate the task.
Data:
Please complete the task by following the step-by-step process outlined in the Previous Recording Context as a guide, but always prioritize and use the values provided in the 'Original Task' part.
NOTE: to populate the whole fields you need SCROLL DOWN to see all of them. Note: if you see any Ad, just close it. Note: there is no need to fill all fields that are unnecessary or in not into the above automation.
INFO [agent] 📍 Step 1 contexts after 5 sec: 1 INFO [agent] 🤷 Eval: Unknown - No previous actions to evaluate. INFO [agent] 🧠 Memory: Starting task to log in to joblookup.com with provided credentials. INFO [agent] 🎯 Next goal: Navigate to https://joblookup.com/uk/employer/login to begin login process. INFO [agent] 🛠️ Action 1/1: {"go_to_url":{"url":"https://joblookup.com/uk/employer/login"}} INFO [controller] 🔗 Navigated to https://joblookup.com/uk/employer/login INFO [agent] 📍 Step 2 INFO [agent] 👍 Eval: Success - Navigated to the login page and identified email and password fields. INFO [agent] 🧠 Memory: Navigated to the login page. Next, input email and password to log in. INFO [agent] 🎯 Next goal: Input email and password, then click the Sign In button. INFO [agent] 🛠️ Action 1/3: {"input_text":{"index":14,"text":"test@test.com"}} INFO [agent] 🛠️ Action 2/3: {"input_text":{"index":16,"text":"123123"}} INFO [agent] 🛠️ Action 3/3: {"click_element":{"index":19}} INFO [controller] ⌨️ Input "test@test.com" into index 14 INFO [controller] ⌨️ Input "123123" into index 16 INFO [controller] 🖱️ Clicked button with index 19: Sign In INFO [agent] 📍 Step 3 INFO [agent] 👍 Eval: Success - Successfully logged in and reached the dashboard. INFO [agent] 🧠 Memory: Logged in and on the Employer Dashboard. Next, navigate to Applications to download applications. INFO [agent] 🎯 Next goal: Click on the 'Applications' link to view applications. INFO [agent] 🛠️ Action 1/1: {"click_element":{"index":17}} INFO [controller] 🖱️ Clicked button with index 17: Applications INFO [agent] 📍 Step 4 INFO [agent] 👍 Eval: Success - Reached the Applications page. INFO [agent] 🧠 Memory: On the Applications page, ready to download applications. INFO [agent] 🎯 Next goal: Download two applications by clicking on download buttons. INFO [agent] 🛠️ Action 1/2: {"click_element":{"index":20}} INFO [agent] 🛠️ Action 2/2: {"click_element":{"index":21}} INFO [controller] 🖱️ Clicked button with index 20: INFO [controller] Something new appeared after action 1 / 2 INFO [agent] 📍 Step 5 INFO [agent] 👍 Eval: Partial Success - First application downloaded. Ready to download the second application. INFO [agent] 🧠 Memory: Downloaded one application. Ready to download the second application. INFO [agent] 🎯 Next goal: Download the second application by clicking the next download button. INFO [agent] 🛠️ Action 1/1: {"click_element":{"index":21}} INFO [controller] 🖱️ Clicked button with index 21: INFO [agent] 📍 Step 6 INFO [agent] 👍 Eval: Success - Second application downloaded successfully. INFO [agent] 🧠 Memory: Downloaded two applications as required by the task. INFO [agent] 🎯 Next goal: Complete the task as the main objective has been achieved. INFO [agent] 🛠️ Action 1/1: {"done":{"text":"Successfully logged in to joblookup.com, navigated to the Applications page, and downloaded two applications as required."}} INFO [agent] 📄 Result: Successfully logged in to joblookup.com, navigated to the Applications page, and downloaded two applications as required. INFO [agent] ✅ Task completed successfully INFO [agent] Created GIF at agent_history.gif is_done=True extracted_content='Successfully logged in to joblookup.com, navigated to the Applications page, and downloaded two applications as required.' error=None include_in_memory=False
No files were downloaded during this session. Automation result: {'result': 'Successfully logged in to joblookup.com, navigated to the Applications page, and downloaded two applications as required.', 'success': False, 'error': 'No files were downloaded during this session.'} Sending webhook for valid result Sending Webhook Payload: {'data': {'candidate_update': True, 'task_id': '2'}, 'message': 'No files were downloaded during this session.', 'success': False} < /code> и вот мои связанные коды: < /p> main.py: import httpx import os import json
from dotenv import load_dotenv from fastapi import FastAPI, HTTPException, APIRouter, BackgroundTasks from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from pprint import pprint from colored_print import log
from .modules.agents.browser_use_capsolver import main as browser_capsolver from .modules.agents.browser_use_service import main as browser_main from .modules.agents.browser_use_download import main as browser_download from .modules.rag.faiss_module import get_full_recording from .modules.static_automation.playwright_automation import post_job_on_jobspider from . import utils
load_dotenv()
WEBHOOK_URL = "https://test.com/test"
app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], # In production, replace with specific origins allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )
async with httpx.AsyncClient() as client: await client.post(webhook_url, headers=headers, json=payload)
async def process_automation( task: str, task_id: str, is_capsolver: bool, webhook_url: str, is_download: bool = False, ): webhook_sent = False # Flag to track if webhook has been sent
try: log.info("Starting automation process...") if is_download: result = await browser_download(task, task_id)
log.info(f"Automation result: {result}")
if isinstance(result, dict): # Check if there's an error message that indicates failure message = result.get("result") if result.get("success") else result.get("error", "Unknown error")
# Set success to False if message contains failure indicators success = result.get("success", False) and "Failed" not in str(message) and "error" not in str(message).lower()
log.info("Sending webhook for valid result") await send_webhook( task_id=task_id, success=success, message=message, webhook_url=webhook_url, is_download=is_download, ) webhook_sent = True # Set flag to true after successful webhook
else: log.info("Sending webhook for invalid result format") await send_webhook( task_id=task_id, success=False, message="Invalid result format", webhook_url=webhook_url, is_download=is_download, ) webhook_sent = True
except httpx.ConnectError as e: log.error(f"Connection error occurred: {str(e)}") # Handle connection-specific errors here if needed except Exception as e: log.error(f"Exception occurred: {str(e)}") if not webhook_sent: # Only send webhook if it hasn't been sent yet await send_webhook( task_id=task_id, success=False, message=str(e), webhook_url=webhook_url, is_download=is_download, )
@api_v1.post("/execute-task") async def execute_task(request: TaskRequest, background_tasks: BackgroundTasks): log.info( f"Received task execution request with payload: {json.dumps(request.model_dump(), indent=2)}" ).store() try: if not request.is_dynamic: # Static Task Handling: Automate job posting on JobSpider ...
data_string = utils.format_data_to_string(request.data) task = f""" Original Task: {request.prompt}
Data: {data_string}
{f'Previous Recording Context (for guidance only, do not use exact values): {recording_context}' if recording_context != "No matching workflow found." else ''}
Please complete the task by following the step-by-step process outlined in the Previous Recording Context as a guide, but always prioritize and use the values provided in the 'Original Task' part.
from langchain_openai import ChatOpenAI # from langchain.callbacks import get_openai_callback from typing import Dict, List from colored_print import log
from browser_use import Agent, Controller from browser_use.browser.browser import Browser, BrowserConfig from browser_use.browser.context import BrowserContext
from .browser_use_service import MAX_STEPS
# Initialize controller first browser = Browser(config=BrowserConfig(headless=False)) controller = Controller()
async def handle_download(download, task_id, downloaded_files): try: # Create downloads directory if it doesn't exist log.info(f"Handling download for task {task_id}") downloads_dir = Path(f"./downloads/{task_id}") downloads_dir.mkdir(parents=True, exist_ok=True)
# Wait for the download to complete and get the path original_path = await download.path() if not original_path: raise Exception("Download path is None")
log.info(f"Original path: {original_path}")
# Check if the file exists before moving if not os.path.exists(original_path): log.error(f"Downloaded file not found at {original_path}") return # Early exit if file doesn't exist
# Create new path in downloads directory with .pdf postfix new_path = downloads_dir / (os.path.basename(original_path) + '.pdf')
# Move the file to downloads directory os.rename(original_path, new_path)
# Add the new path to downloaded files list downloaded_files.append(str(new_path)) log.success(f"Downloaded and moved to: {new_path}")
except Exception as e: log.error(f"Error handling download: {e}")
@controller.action( 'Upload file - the file name is inside the function - you only need to call this with the correct index', requires_browser=True, ) async def upload_file(index: int, browser: BrowserContext): element = await browser.get_element_by_index(index) my_file = Path.cwd() / 'examples/test_cv.txt' if not element: raise Exception(f'Element with index {index} not found')
await element.set_input_files(str(my_file.absolute())) return f'Uploaded file to index {index}'
# Print downloaded files if downloaded_files: log.info("\nDownloaded files:") for file_path in downloaded_files: log.info(file_path) log.info(f"- {os.path.basename(file_path)}") else: log.error("\nNo files were downloaded during this session.") is_done = False error = "No files were downloaded during this session."
if max_steps_reached: return { "result": "Task exceeded maximum allowed steps", "success": False, "error": "Max steps exceeded without completion", }
return { "result": str(message), "success": is_done, "error": error, } < /code> Полагаю, проблема связана с параллелизмом и асинхронными вещами. Или, может быть, связано с методом handle_download [/code]. Я прошу прощения за длинный и сложный вопрос, я не мог сделать его проще, очень извините.