Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

When the model download was failed,I can’t retry or continue(no button),the only way is delete it. #45

Open
bladeswill opened this issue Dec 1, 2023 · 1 comment

Comments

@bladeswill
Copy link

If you have time, I hope to fix it, thank you very much

@bladeswill bladeswill changed the title When the model download was failed,I can’t retry or continue(no bottom),the only way is delete it. When the model download was failed,I can’t retry or continue(no button),the only way is delete it. Dec 1, 2023
@93andresen
Copy link

If you have time, I hope to fix it, thank you very much

I had the same problem. Very bad internet connection.
So I made this. It parses the path to know the download link and completes all unfinished models recursivly.

import os
import glob
import requests
from tqdm import tqdm
import threading
import logging
import queue
import json
import time
import argparse
import shutil  # New import for moving files

# Options Panel
LOG_DIR = r"c:\_\logs\complete_unfinished_downloads"
MAX_PARALLEL_DOWNLOADS = 5
FOLLOW_SYMLINKS = True  # Set to True to follow symlinks
OUTPUT_FILE = r"c:\_\wd\download_status.txt"  # Path to output file listing download status

def setup_logging():
    if not os.path.exists(LOG_DIR):
        os.makedirs(LOG_DIR)
    logging.basicConfig(filename=os.path.join(LOG_DIR, 'complete_unfinished_downloads.log'),
                        level=logging.INFO,
                        format='%(asctime)s %(levelname)s: %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')

def convert_to_url(filepath):
    # Split the filepath into parts
    parts = filepath.split("\\")
    # Extract the relevant parts for the URL
    user = parts[3]  # Adjusted index for user
    project = parts[4]  # Adjusted index for project
    filename = parts[-1]  # The filename remains the same
    # Construct the URL
    base_url = "https://huggingface.co"
    url = f"{base_url}/{user}/{project}/resolve/main/{filename}"
    return url


def download_file(url_queue, download_status):
    while not url_queue.empty():
        url, filepath = url_queue.get()
        resume_byte_pos = os.path.getsize(filepath) if os.path.exists(filepath) else 0
        headers = {'Range': f'bytes={resume_byte_pos}-'}

        try:
            response = requests.get(url, stream=True, headers=headers, timeout=30)  # Increased timeout
            response.raise_for_status()

            if response.status_code in [200, 206]:
                total_size_in_bytes = int(response.headers.get('content-length', 0)) + resume_byte_pos
                progress_bar = tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True)
                progress_bar.update(resume_byte_pos)

                with open(filepath, 'ab') as file:
                    for data in response.iter_content(chunk_size=1024):
                        progress_bar.update(len(data))
                        file.write(data)
                progress_bar.close()

                if total_size_in_bytes != 0 and progress_bar.n != total_size_in_bytes:
                    logging.error(f"Error in downloading {url}: Incomplete download")
                    download_status[filepath] = "Unfinished"
                else:
                    logging.info(f"Download completed for {url}")
                    download_status[filepath] = "Completed"

            else:
                logging.error(f"Error in downloading {url}: HTTP status code {response.status_code}")
                download_status[filepath] = "Error"

        except requests.exceptions.RequestException as e:
            logging.error(f"Error in downloading {url}: {e}")
            download_status[filepath] = f"Error - Exception {e}"

        finally:
            url_queue.task_done()


def process_folder(folder_path, url_queue):
    pattern = os.path.join(folder_path, '**', '*.gguf')
    files = glob.glob(pattern, recursive=True)
    if not FOLLOW_SYMLINKS:
        files = [f for f in files if not os.path.islink(f)]

    for file in files:
        url = convert_to_url(file)
        url_queue.put((url, file))

def write_download_status(download_status):
    with open(OUTPUT_FILE, 'w') as file:
        for filepath, status in download_status.items():
            file.write(f"{filepath}: {status}\n")

def move_unfinished_downloads(download_status, destination_folder):
    if not os.path.exists(destination_folder):
        os.makedirs(destination_folder)
    
    for filepath, status in download_status.items():
        if status != "Completed":
            try:
                destination_path = os.path.join(destination_folder, os.path.basename(filepath))
                shutil.move(filepath, destination_path)
                logging.info(f"Moved unfinished file {filepath} to {destination_path}")
            except Exception as e:
                logging.error(f"Error moving {filepath}: {e}")

def main(folders):
    setup_logging()
    download_status = {}

    url_queue = queue.Queue()
    for folder_path in folders:
        process_folder(folder_path, url_queue)

    threads = []
    for _ in range(MAX_PARALLEL_DOWNLOADS):
        thread = threading.Thread(target=download_file, args=(url_queue, download_status))
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()

    write_download_status(download_status)

    # New line to move unfinished downloads
    # move_unfinished_downloads(download_status, r'c:\_\models\unfinished')

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Complete Unfinished Downloads')
    parser.add_argument('folders', nargs='+', help='Paths to the folders containing .gguf files')
    args = parser.parse_args()
    main(args.folders)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants