Skip to content

Commit 3789d2e

Browse files
Updated the technique for handling multiple file uploads from the user (#2126)
* Fixed multiple file uploads to be sent through a single request to backend for further processing and storing * Fixed multiple file uploads to be sent through a single request to backend for further processing and storing * Fixed multiple file uploads to be sent through a single request to backend for further processing and storing * Made duplicate multiple keyword fixes * Added back drag and drop functionality and it keeps the multiple file uploads
1 parent d544695 commit 3789d2e

File tree

2 files changed

+324
-51
lines changed

2 files changed

+324
-51
lines changed

application/api/user/attachments/routes.py

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,32 @@ class StoreAttachment(Resource):
2525
api.model(
2626
"AttachmentModel",
2727
{
28-
"file": fields.Raw(required=True, description="File to upload"),
28+
"file": fields.Raw(required=True, description="File(s) to upload"),
2929
"api_key": fields.String(
3030
required=False, description="API key (optional)"
3131
),
3232
},
3333
)
3434
)
3535
@api.doc(
36-
description="Stores a single attachment without vectorization or training. Supports user or API key authentication."
36+
description="Stores one or multiple attachments without vectorization or training. Supports user or API key authentication."
3737
)
3838
def post(self):
3939
decoded_token = getattr(request, "decoded_token", None)
4040
api_key = request.form.get("api_key") or request.args.get("api_key")
41-
file = request.files.get("file")
42-
43-
if not file or file.filename == "":
41+
42+
files = request.files.getlist("file")
43+
if not files:
44+
single_file = request.files.get("file")
45+
if single_file:
46+
files = [single_file]
47+
48+
if not files or all(f.filename == "" for f in files):
4449
return make_response(
45-
jsonify({"status": "error", "message": "Missing file"}),
50+
jsonify({"status": "error", "message": "Missing file(s)"}),
4651
400,
4752
)
53+
4854
user = None
4955
if decoded_token:
5056
user = safe_filename(decoded_token.get("sub"))
@@ -59,32 +65,74 @@ def post(self):
5965
return make_response(
6066
jsonify({"success": False, "message": "Authentication required"}), 401
6167
)
68+
6269
try:
63-
attachment_id = ObjectId()
64-
original_filename = safe_filename(os.path.basename(file.filename))
65-
relative_path = f"{settings.UPLOAD_FOLDER}/{user}/attachments/{str(attachment_id)}/{original_filename}"
66-
67-
metadata = storage.save_file(file, relative_path)
68-
69-
file_info = {
70-
"filename": original_filename,
71-
"attachment_id": str(attachment_id),
72-
"path": relative_path,
73-
"metadata": metadata,
74-
}
75-
76-
task = store_attachment.delay(file_info, user)
70+
tasks = []
71+
errors = []
72+
original_file_count = len(files)
73+
74+
for idx, file in enumerate(files):
75+
try:
76+
attachment_id = ObjectId()
77+
original_filename = safe_filename(os.path.basename(file.filename))
78+
relative_path = f"{settings.UPLOAD_FOLDER}/{user}/attachments/{str(attachment_id)}/{original_filename}"
79+
80+
metadata = storage.save_file(file, relative_path)
81+
file_info = {
82+
"filename": original_filename,
83+
"attachment_id": str(attachment_id),
84+
"path": relative_path,
85+
"metadata": metadata,
86+
}
7787

78-
return make_response(
79-
jsonify(
80-
{
81-
"success": True,
88+
task = store_attachment.delay(file_info, user)
89+
tasks.append({
8290
"task_id": task.id,
83-
"message": "File uploaded successfully. Processing started.",
84-
}
85-
),
86-
200,
87-
)
91+
"filename": original_filename,
92+
"attachment_id": str(attachment_id),
93+
})
94+
except Exception as file_err:
95+
current_app.logger.error(f"Error processing file {idx} ({file.filename}): {file_err}", exc_info=True)
96+
errors.append({
97+
"filename": file.filename,
98+
"error": str(file_err)
99+
})
100+
101+
if not tasks:
102+
error_msg = "No valid files to upload"
103+
if errors:
104+
error_msg += f". Errors: {errors}"
105+
return make_response(
106+
jsonify({"status": "error", "message": error_msg, "errors": errors}),
107+
400,
108+
)
109+
110+
if original_file_count == 1 and len(tasks) == 1:
111+
current_app.logger.info("Returning single task_id response")
112+
return make_response(
113+
jsonify(
114+
{
115+
"success": True,
116+
"task_id": tasks[0]["task_id"],
117+
"message": "File uploaded successfully. Processing started.",
118+
}
119+
),
120+
200,
121+
)
122+
else:
123+
response_data = {
124+
"success": True,
125+
"tasks": tasks,
126+
"message": f"{len(tasks)} file(s) uploaded successfully. Processing started.",
127+
}
128+
if errors:
129+
response_data["errors"] = errors
130+
response_data["message"] += f" {len(errors)} file(s) failed."
131+
132+
return make_response(
133+
jsonify(response_data),
134+
200,
135+
)
88136
except Exception as err:
89137
current_app.logger.error(f"Error storing attachment: {err}", exc_info=True)
90138
return make_response(jsonify({"success": False, "error": str(err)}), 400)
@@ -130,15 +178,11 @@ class TextToSpeech(Resource):
130178
@api.expect(tts_model)
131179
@api.doc(description="Synthesize audio speech from text")
132180
def post(self):
133-
from application.utils import clean_text_for_tts
134-
135181
data = request.get_json()
136182
text = data["text"]
137-
cleaned_text = clean_text_for_tts(text)
138-
139183
try:
140184
tts_instance = TTSCreator.create_tts(settings.TTS_PROVIDER)
141-
audio_base64, detected_language = tts_instance.text_to_speech(cleaned_text)
185+
audio_base64, detected_language = tts_instance.text_to_speech(text)
142186
return make_response(
143187
jsonify(
144188
{

0 commit comments

Comments
 (0)