ganesh-vilje commited on
Commit
b4b0135
·
1 Parent(s): f266ceb

feat: Complete file upload V3 integration

Browse files

Fix 4: Integrated Gradio file uploads with V3 architecture

What Changed:
- File uploads now go to S3 (sessions/{id}/files/{file_id}_{name})
- Creates records in MongoDB 'files' collection
- Generates presigned URLs (7-day expiry)
- Stores file metadata (file_id, size, mime_type, s3_key)
- Adds file_id reference to session
- Includes file_data in system messages
- Graceful fallback if S3 upload fails

Files Collection Now Populated:
- file_id, session_id, file_name
- s3_bucket, s3_key
- presigned_url, presigned_expires_at
- file_size, mime_type, uploaded_at

Benefits:
- Gradio UI and chat/unified API now in sync
- Files stored permanently in S3
- File access via presigned URLs
- Consistent behavior across interfaces

All 5 critical V3 fixes now complete!

Files changed (1) hide show
  1. app.py +129 -26
app.py CHANGED
@@ -752,7 +752,13 @@ def create_new_session():
752
 
753
 
754
  def handle_file_upload(file_path, session_id):
755
- """Handle file upload"""
 
 
 
 
 
 
756
  if not file_path:
757
  return None, json.dumps({
758
  "status": "error",
@@ -764,31 +770,128 @@ def handle_file_upload(file_path, session_id):
764
 
765
  file_name = os.path.basename(file_path)
766
 
767
- # Update session
768
- session_manager.update_session(session_id, {
769
- "current_file": file_path,
770
- "state": ConversationState.INITIAL
771
- })
772
-
773
- # Add system message
774
- session_manager.add_message(
775
- session_id,
776
- "system",
777
- f"File uploaded: {file_name}"
778
- )
779
-
780
- status = {
781
- "status": "success",
782
- "message": f"File '{file_name}' uploaded successfully",
783
- "file_info": {
784
- "name": file_name,
785
- "path": file_path,
786
- "size_bytes": os.path.getsize(file_path) if os.path.exists(file_path) else 0
787
- },
788
- "next_action": "💬 Now tell me what you'd like to do with this document"
789
- }
790
-
791
- return file_path, json.dumps(status, indent=2), session_id
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
792
 
793
 
794
  def format_chat_history(history, new_user_msg, new_assistant_msg):
 
752
 
753
 
754
  def handle_file_upload(file_path, session_id):
755
+ """
756
+ Handle file upload with V3 architecture integration
757
+ - Uploads file to S3
758
+ - Creates record in files collection
759
+ - Generates presigned URL
760
+ - Stores file metadata in MongoDB
761
+ """
762
  if not file_path:
763
  return None, json.dumps({
764
  "status": "error",
 
770
 
771
  file_name = os.path.basename(file_path)
772
 
773
+ try:
774
+ # V3: Upload to S3 and create file record
775
+ from services.s3_manager import get_s3_manager
776
+ from services.schemas import FileSchema, schema_to_dict
777
+ from datetime import datetime
778
+
779
+ s3 = get_s3_manager()
780
+ file_id = str(uuid.uuid4())
781
+ file_size = os.path.getsize(file_path) if os.path.exists(file_path) else 0
782
+
783
+ # Determine MIME type
784
+ mime_type = "application/pdf"
785
+ if file_path.lower().endswith(('.png', '.jpg', '.jpeg')):
786
+ mime_type = "image/jpeg"
787
+ elif file_path.lower().endswith('.gif'):
788
+ mime_type = "image/gif"
789
+
790
+ # Upload to S3
791
+ s3_key = f"sessions/{session_id}/files/{file_id}_{file_name}"
792
+ with open(file_path, 'rb') as f:
793
+ s3_result = s3.upload_file(
794
+ key=s3_key,
795
+ file_obj=f,
796
+ content_type=mime_type,
797
+ add_prefix=False
798
+ )
799
+
800
+ # Generate presigned URL (7-day max)
801
+ presigned = s3.generate_presigned_url(
802
+ s3_key,
803
+ expires_in=604800, # 7 days
804
+ add_prefix=False
805
+ )
806
+
807
+ # Create file record in MongoDB
808
+ mongodb_uri = os.getenv("MONGODB_URI")
809
+ mongodb_db = os.getenv("MONGODB_DB", "masterllm")
810
+ from pymongo import MongoClient
811
+
812
+ mongo_client = MongoClient(mongodb_uri)
813
+ files_collection = mongo_client[mongodb_db]["files"]
814
+
815
+ file_record = FileSchema(
816
+ file_id=file_id,
817
+ session_id=session_id,
818
+ uploaded_at=datetime.utcnow(),
819
+ file_name=file_name,
820
+ file_size=file_size,
821
+ mime_type=mime_type,
822
+ s3_bucket=s3.bucket_name,
823
+ s3_key=s3_key,
824
+ presigned_url=presigned["presigned_url"],
825
+ presigned_expires_at=presigned["presigned_expires_at"]
826
+ )
827
+
828
+ files_collection.insert_one(schema_to_dict(file_record))
829
+
830
+ print(f"✅ File uploaded to S3 and recorded: {file_id}")
831
+
832
+ # Update session with file reference
833
+ session_manager.update_session(session_id, {
834
+ "current_file": file_path, # Keep local path for backward compatibility
835
+ "current_file_id": file_id, # V3: file_id reference
836
+ "state": ConversationState.INITIAL
837
+ })
838
+
839
+ # Add system message with file info
840
+ session_manager.add_message(
841
+ session_id,
842
+ "system",
843
+ f"File uploaded: {file_name}",
844
+ file_data={"file_id": file_id, "file_name": file_name}
845
+ )
846
+
847
+ status = {
848
+ "status": "success",
849
+ "message": f"File '{file_name}' uploaded successfully",
850
+ "file_info": {
851
+ "file_id": file_id,
852
+ "name": file_name,
853
+ "size_bytes": file_size,
854
+ "s3_key": s3_key,
855
+ "presigned_url": presigned["presigned_url"],
856
+ "expires_at": presigned["presigned_expires_at"]
857
+ },
858
+ "next_action": "💬 Now tell me what you'd like to do with this document"
859
+ }
860
+
861
+ return file_path, json.dumps(status, indent=2), session_id
862
+
863
+ except Exception as e:
864
+ # Fallback to old behavior if V3 integration fails
865
+ print(f"⚠️ File upload V3 integration failed: {e}")
866
+ print(f" Falling back to local file path")
867
+
868
+ # Update session with local path only
869
+ session_manager.update_session(session_id, {
870
+ "current_file": file_path,
871
+ "state": ConversationState.INITIAL
872
+ })
873
+
874
+ # Add system message
875
+ session_manager.add_message(
876
+ session_id,
877
+ "system",
878
+ f"File uploaded: {file_name}"
879
+ )
880
+
881
+ status = {
882
+ "status": "partial_success",
883
+ "message": f"File '{file_name}' uploaded locally (S3 upload failed)",
884
+ "file_info": {
885
+ "name": file_name,
886
+ "path": file_path,
887
+ "size_bytes": os.path.getsize(file_path) if os.path.exists(file_path) else 0
888
+ },
889
+ "warning": str(e),
890
+ "next_action": "💬 Now tell me what you'd like to do with this document"
891
+ }
892
+
893
+ return file_path, json.dumps(status, indent=2), session_id
894
+
895
 
896
 
897
  def format_chat_history(history, new_user_msg, new_assistant_msg):