1+ # /// script
2+ # dependencies = [
3+ # "requests",
4+ # ]
5+ # ///
6+
7+ import os
8+ import sys
9+ import json
10+ import argparse
11+ import requests
12+ from pathlib import Path
13+
14+
15+ def transform_filename (filepath : Path ) -> str :
16+ """
17+ Transform a file path to the required format:
18+ - Replace path separators with underscores
19+ """
20+ # Convert to string and replace path separators with underscores
21+ transformed = str (filepath ).replace ("/" , "_" ).replace ("\\ " , "_" )
22+
23+ return transformed
24+
25+
26+ def upload_file_to_deepset (filepath : Path , api_key : str , workspace : str ) -> bool :
27+ """
28+ Upload a single file to Deepset API.
29+ """
30+ # Read file content
31+ try :
32+ content = filepath .read_text (encoding = "utf-8" )
33+ except Exception as e :
34+ print (f"Error reading file { filepath } : { e } " )
35+ return False
36+
37+ # Transform filename
38+ transformed_name = transform_filename (filepath )
39+
40+ # Prepare metadata
41+ metadata : dict [str , str ] = {"original_file_path" : str (filepath )}
42+
43+ # Prepare API request
44+ url = f"https://api.cloud.deepset.ai/api/v1/workspaces/{ workspace } /files"
45+ params : dict [str , str ] = {"file_name" : transformed_name , "write_mode" : "OVERWRITE" }
46+
47+ headers : dict [str , str ] = {
48+ "accept" : "application/json" ,
49+ "authorization" : f"Bearer { api_key } " ,
50+ }
51+
52+ # Prepare multipart form data
53+ files : dict [str , tuple [None , str , str ]] = {
54+ "meta" : (None , json .dumps (metadata ), "application/json" ),
55+ "text" : (None , content , "text/plain" ),
56+ }
57+
58+ try :
59+ response = requests .post (url , params = params , headers = headers , files = files )
60+ response .raise_for_status ()
61+ print (f"Successfully uploaded: { filepath } as { transformed_name } " )
62+ return True
63+ except requests .exceptions .HTTPError :
64+ print (f"Failed to upload { filepath } : HTTP { response .status_code } " )
65+ print (f" Response: { response .text } " )
66+ return False
67+ except Exception as e :
68+ print (f"Failed to upload { filepath } : { e } " )
69+ return False
70+
71+
72+ def delete_files_from_deepset (
73+ filepaths : list [Path ], api_key : str , workspace : str
74+ ) -> bool :
75+ """
76+ Delete multiple files from Deepset API.
77+ """
78+ if not filepaths :
79+ return True
80+
81+ # Transform filenames
82+ transformed_names : list [str ] = [transform_filename (fp ) for fp in filepaths ]
83+
84+ # Prepare API request
85+ url = f"https://api.cloud.deepset.ai/api/v1/workspaces/{ workspace } /files"
86+
87+ headers : dict [str , str ] = {
88+ "accept" : "application/json" ,
89+ "authorization" : f"Bearer { api_key } " ,
90+ "content-type" : "application/json" ,
91+ }
92+
93+ data : dict [str , list [str ]] = {"names" : transformed_names }
94+
95+ try :
96+ response = requests .delete (url , headers = headers , json = data )
97+ response .raise_for_status ()
98+ print (f"Successfully deleted { len (transformed_names )} file(s):" )
99+ for original , transformed in zip (filepaths , transformed_names ):
100+ print (f" - { original } (as { transformed } )" )
101+ return True
102+ except requests .exceptions .HTTPError :
103+ print (f"Failed to delete files: HTTP { response .status_code } " )
104+ print (f" Response: { response .text } " )
105+ return False
106+ except Exception as e :
107+ print (f"Failed to delete files: { e } " )
108+ return False
109+
110+
111+ def main () -> None :
112+ """
113+ Main function to process and upload/delete files.
114+ """
115+ # Parse command line arguments
116+ parser = argparse .ArgumentParser (
117+ description = "Upload/delete Python files to/from Deepset"
118+ )
119+ parser .add_argument (
120+ "--changed" , nargs = "*" , default = [], help = "Changed or added files"
121+ )
122+ parser .add_argument ("--deleted" , nargs = "*" , default = [], help = "Deleted files" )
123+ args = parser .parse_args ()
124+
125+ # Get environment variables
126+ api_key : str | None = os .environ .get ("DEEPSET_API_KEY" )
127+ workspace : str = os .environ .get ("DEEPSET_WORKSPACE" )
128+
129+ if not api_key :
130+ print ("Error: DEEPSET_API_KEY environment variable not set" )
131+ sys .exit (1 )
132+
133+ # Process arguments and convert to Path objects
134+ changed_files : list [Path ] = [Path (f .strip ()) for f in args .changed if f .strip ()]
135+ deleted_files : list [Path ] = [Path (f .strip ()) for f in args .deleted if f .strip ()]
136+
137+ if not changed_files and not deleted_files :
138+ print ("No files to process" )
139+ sys .exit (0 )
140+
141+ print (f"Processing files in Deepset workspace: { workspace } " )
142+ print ("-" * 50 )
143+
144+ # Track results
145+ upload_success : int = 0
146+ upload_failed : list [Path ] = []
147+ delete_success : bool = False
148+
149+ # Handle deletions first
150+ if deleted_files :
151+ print (f"\n Deleting { len (deleted_files )} file(s)..." )
152+ delete_success = delete_files_from_deepset (deleted_files , api_key , workspace )
153+
154+ # Upload changed/new files
155+ if changed_files :
156+ print (f"\n Uploading { len (changed_files )} file(s)..." )
157+ for filepath in changed_files :
158+ if filepath .exists ():
159+ if upload_file_to_deepset (filepath , api_key , workspace ):
160+ upload_success += 1
161+ else :
162+ upload_failed .append (filepath )
163+ else :
164+ print (f"Skipping non-existent file: { filepath } " )
165+
166+ # Summary
167+ print ("-" * 50 )
168+ print ("Processing Summary:" )
169+ if changed_files :
170+ print (
171+ f" Uploads - Successful: { upload_success } , Failed: { len (upload_failed )} "
172+ )
173+ if deleted_files :
174+ print (
175+ f" Deletions - { 'Successful' if delete_success else 'Failed' } : { len (deleted_files )} file(s)"
176+ )
177+
178+ if upload_failed :
179+ print ("\n Failed uploads:" )
180+ for f in upload_failed :
181+ print (f" - { f } " )
182+
183+ # Exit with error if any operation failed
184+ if upload_failed or (deleted_files and not delete_success ):
185+ sys .exit (1 )
186+
187+ print ("\n All operations completed successfully!" )
188+
189+
190+ if __name__ == "__main__" :
191+ main ()
0 commit comments