hello

ollama 없이 모델 파일을 ollama에서 다운 받기

Share


import json
import os
import sys
from urllib.parse import urljoin, urlunparse

import requests
import urllib3

urllib3.disable_warnings()

DEFAULT_REGISTRY = "registry.ollama.ai"
DEFAULT_NAMESPACE = "library"
DEFAULT_TAG = "latest"
DEFAULT_PROTOCOL_SCHEME = "https"


class Manifest:
    def __init__(
        self,
        schema_version,
        media_type,
        config,
        layers,
        filepath=None,
        file_info=None,
        digest=None,
    ):
        self.schema_version = schema_version
        self.media_type = media_type
        self.config = config
        self.layers = layers
        self.filepath = filepath
        self.file_info = file_info
        self.digest = digest


class Layer:
    def __init__(self, mediaType, digest, size, source=None, status=None):
        self.media_type = mediaType
        self.digest = digest
        self.size = size
        self.source = source
        self.status = status


class ModelPath:
    def __init__(
        self,
        protocol_scheme=DEFAULT_PROTOCOL_SCHEME,
        registry=DEFAULT_REGISTRY,
        namespace=DEFAULT_NAMESPACE,
        repository="",
        tag=DEFAULT_TAG,
    ):
        self.protocol_scheme = protocol_scheme
        self.registry = registry
        self.namespace = namespace
        self.repository = repository
        self.tag = tag

    @classmethod
    def parse_model_path(cls, name):
        mp = cls()

        if "://" in name:
            mp.protocol_scheme, name = name.split("://", 1)

        name = name.replace(os.path.sep, "/")
        parts = name.split("/")

        if len(parts) == 3:
            mp.registry, mp.namespace, mp.repository = parts
        elif len(parts) == 2:
            mp.namespace, mp.repository = parts
        elif len(parts) == 1:
            mp.repository = parts[0]

        if ":" in mp.repository:
            mp.repository, mp.tag = mp.repository.split(":", 1)

        return mp

    def get_namespace_repository(self):
        return f"{self.namespace}/{self.repository}"

    def base_url(self):
        return urlunparse((self.protocol_scheme, self.registry, "", "", "", ""))


def get_manifest(model_path, reg_opts=None):
    request_url = urljoin(
        model_path.base_url(),
        f"v2/{model_path.get_namespace_repository()}/manifests/{model_path.tag}",
    )
    headers = {"Accept": "application/vnd.docker.distribution.manifest.v2+json"}

    try:
        response = requests.get(
            request_url,
            headers=headers,
            auth=reg_opts,
            verify=False,
            proxies={"https": "http://12.26.204.100:8080"},
        )
        response.raise_for_status()
    except requests.RequestException as e:
        print(f"매니페스트를 가져오는 중 오류 발생: {e}")
        return None, request_url

    try:
        manifest_data = response.json()
        config = Layer(**manifest_data.get("config", {}))
        layers = [Layer(**layer) for layer in manifest_data.get("layers", [])]
        manifest = Manifest(
            schema_version=manifest_data.get("schemaVersion"),
            media_type=config.media_type,
            config=config,
            layers=layers,
        )
        return manifest, request_url
    except json.JSONDecodeError as e:
        print(f"JSON 디코딩 오류: {e}")
        return None, request_url


def download_blob(blob_url, output_path, use_tqdm=True):

    try:
        if use_tqdm is None:
            from tqdm import tqdm

            use_tqdm = True
        else:
            use_tqdm = False
    except ImportError:
        use_tqdm = False

    try:
        with requests.get(
            blob_url,
            stream=True,
            verify=False,
            proxies={"https": "http://12.26.204.100:8080"},
        ) as response:
            response.raise_for_status()
            total_size = int(response.headers.get("content-length", 0))
            print(f"Downloading: {blob_url}..., {output_path}")

            with open(output_path, "wb") as file:
                if use_tqdm:
                    with tqdm(
                        desc=os.path.basename(output_path),
                        total=total_size,
                        unit="B",
                        unit_scale=True,
                        unit_divisor=1024,
                    ) as bar:
                        for chunk in response.iter_content(chunk_size=8192):
                            file.write(chunk)
                            bar.update(len(chunk))
                else:
                    print(f"다운로드 중: {os.path.basename(output_path)}")
                    for chunk in response.iter_content(chunk_size=8192):
                        file.write(chunk)
        print(f"Downloaded: {output_path}")
    except requests.RequestException as e:
        print(f"Error downloading blob from {blob_url}: {e}")


def download_model(model_name, output_dir):
    os.makedirs(output_dir, exist_ok=True)

    parsed_model_path = ModelPath.parse_model_path(model_name)
    manifest, manifest_link = get_manifest(parsed_model_path)

    if manifest is None:
        print(f"Failed to fetch manifest for model: {model_name}")
        sys.exit(1)

    layers = manifest.layers + [manifest.config]
    for layer in layers:
        if layer.media_type != "application/vnd.ollama.image.model":
            continue

        blob_url = urljoin(
            parsed_model_path.base_url(),
            f"v2/{parsed_model_path.get_namespace_repository()}/blobs/{layer.digest}",
        )

        output_path = os.path.join(output_dir, model_name.replace(":", "-") + ".gguf")
        if os.path.exists(output_path):
            print("Skipped " + output_path)
        else:
            download_blob(blob_url, output_path)

    print(f"All blobs for model {model_name} downloaded successfully.")


if __name__ == "__main__":
    model_name = "llama3.2:1b"
    output_folder = "temp"
    download_model(model_name, output_folder)

Read more

LLM 시대, 프롬프트 엔지니어링보다 '도메인 전문성'이 더 강력한 무기인 이유

최근 AI 도구들이 비약적으로 발전하면서 '프롬프트 엔지니어링'이라는 기술적 기법에 많은 관심이 쏠렸습니다. 하지만 실제 현업에서 LLM을 극한으로 활용해 고도의 결과물을 만들어내는 사람들의 공통점은 정교한 프롬프트 템플릿을 쓰는 능력이 아니라, 해당 분야에 대한 깊은 '도메인 전문성'을 갖추고 있다는 점입니다. 많은 이들이 LLM이 지식의 격차를 줄여준다고

By JHL

AI 코딩 에이전트 도입 시 고려해야 할 보안 제어 프레임워크: 속도와 안전의 균형 잡기

최근 Claude Code나 Kiro와 같은 AI 코딩 에이전트들이 단순한 코드 완성을 넘어, 자연어 프롬프트 하나로 수십 개의 PR을 생성하고 인프라를 수정하는 수준까지 발전했습니다. 하지만 이러한 생산성 향상은 '기계적 속도'라는 트레이드오프를 동반합니다. AI 에이전트는 조직의 보안 리스크나 컴플라이언스를 이해하지 못한 채 오직 '작업 완료'에만 최적화되어

By JHL

AI 벤치마크의 '포화 상태'와 평가 지표의 유효기간: 우리는 무엇을 믿어야 하는가

최근 LLM의 성능이 비약적으로 상승하면서, 역설적으로 우리가 모델의 성능을 측정하는 '자' 자체가 무용지물이 되는 현상이 가속화되고 있습니다. arXiv에 게재된 "When AI Benchmarks Plateau: A Systematic Study of Benchmark Saturation" 연구는 우리가 흔히 신뢰하는 벤치마크 점수가 왜 더 이상 모델 간의 변별력을 제공하지 못하는지, 그리고 이른바 '

By JHL

AI 에이전트 시대의 엔드포인트 보안: 실행 권한을 넘어 '행위 거버넌스'로

DevOps.com을 통해 Airlock Digital이 발표한 'Agentic AI Control & Governance' 솔루션 소식을 접했습니다. 이번 발표의 핵심은 단순히 '어떤 AI 소프트웨어를 실행할 것인가'라는 기존의 화이트리스트 방식(Application Control)을 넘어, 실행 중인 AI 에이전트가 '실제로 어떤 명령을 내리고 어떻게 행동하는가'를 실시간으로 제어하겠다는

By JHL