@@ -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