@@ -69,9 +69,18 @@ class DownloadWorker(QObject):
6969
7070 def download_model (self , repo_id : str , filenames : list [str ], local_dir : str , token : str | None = None ):
7171 try :
72+ # 1. Check Directory Permissions early
73+ if not config .is_writable (local_dir ):
74+ self .progress_signal .emit ("Error: Access Denied! Run as Admin or choose different path." , 0 )
75+ self .finished_signal .emit (repo_id , False )
76+ return
77+
7278 os .makedirs (local_dir , exist_ok = True )
7379 log .info ("Starting granular download for %s into %s" , repo_id , local_dir )
7480
81+ # Robustness: Increase ETAG timeout for large files on restricted networks
82+ os .environ ["HF_HUB_ETAG_TIMEOUT" ] = "100"
83+
7584 # If no files specified, use snapshot_download (likely a complex repo like Qwen)
7685 if not filenames :
7786 self .progress_signal .emit (f"Verifying { repo_id } (Snapshot)..." , 30 )
@@ -97,14 +106,27 @@ def download_model(self, repo_id: str, filenames: list[str], local_dir: str, tok
97106 # Create a bridge for tqdm with multi-file context and byte-weighting
98107 bridge = ProgressBridge (fname , self .progress_signal , i , len (filenames ), weights )
99108
100- hf_hub_download (
101- repo_id = repo_id ,
102- filename = fname ,
103- local_dir = local_dir ,
104- token = None ,
105- local_dir_use_symlinks = False ,
106- tqdm_class = lambda ** kwargs : bridge # Inject our bridge as the tqdm class
107- )
109+ # Retry loop (5 attempts) for resilience against ConnectionReset/Firewall
110+ max_retries = 5
111+ for attempt in range (max_retries ):
112+ try :
113+ hf_hub_download (
114+ repo_id = repo_id ,
115+ filename = fname ,
116+ local_dir = local_dir ,
117+ token = None ,
118+ local_dir_use_symlinks = False ,
119+ tqdm_class = lambda ** kwargs : bridge # Inject our bridge as the tqdm class
120+ )
121+ break # Success!
122+ except Exception as e :
123+ if attempt < max_retries - 1 :
124+ log .warning ("Download attempt %d failed for %s: %s" , attempt + 1 , fname , e )
125+ self .progress_signal .emit (f"Retrying { fname } ({ attempt + 2 } /{ max_retries } )..." , 5 )
126+ import time
127+ time .sleep (2 ) # Exponential backoff would be better but fixed sleep is OK for now
128+ else :
129+ raise # Final attempt failed
108130
109131 self .progress_signal .emit ("Setup complete!" , 100 )
110132 self .finished_signal .emit (repo_id , True )
@@ -114,14 +136,17 @@ def download_model(self, repo_id: str, filenames: list[str], local_dir: str, tok
114136 error_msg = str (exc )
115137 log .error ("Download failed for %s: %s" , repo_id , error_msg )
116138
117- # DO NOT clean up directory anymore—we want to support resuming large files.
118- # hf_hub_download handles its own .incomplete files.
119-
120- if "401" in error_msg or "Unauthorized" in error_msg :
139+ # Diagnostic for common Windows failures
140+ if "SSL" in error_msg :
141+ display_msg = "Error: SSL/Certificate Mismatch. Check VPN/Firewall."
142+ elif "Connection reset" in error_msg or "10054" in error_msg :
143+ display_msg = "Error: Connection Reset by Firewall."
144+ elif "401" in error_msg or "Unauthorized" in error_msg :
121145 display_msg = "Error: Auth Required (Gated Model?)"
122146 elif "disk" in error_msg .lower () or "space" in error_msg .lower ():
123147 display_msg = "Error: Disk Full!"
124148 else :
149+ # Show more of the error to help debug
125150 display_msg = f"Error: { error_msg [:100 ]} " if len (error_msg ) > 100 else f"Error: { error_msg } "
126151
127152 self .progress_signal .emit (display_msg , 0 )
0 commit comments