[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\ncover/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\n.pybuilder/\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n#   For a library or package, you might want to ignore these files since the code is\n#   intended to run in multiple environments; otherwise, check them in:\n# .python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# UV\n#   Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.\n#   This is especially recommended for binary packages to ensure reproducibility, and is more\n#   commonly ignored for libraries.\n#uv.lock\n\n# poetry\n#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.\n#   This is especially recommended for binary packages to ensure reproducibility, and is more\n#   commonly ignored for libraries.\n#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control\n#poetry.lock\n\n# pdm\n#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.\n#pdm.lock\n#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it\n#   in version control.\n#   https://pdm.fming.dev/latest/usage/project/#working-with-version-control\n.pdm.toml\n.pdm-python\n.pdm-build/\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm\n__pypackages__/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n\n# pytype static type analyzer\n.pytype/\n\n# Cython debug symbols\ncython_debug/\n\n# PyCharm\n#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can\n#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore\n#  and can be added to the global gitignore or merged into this file.  For a more nuclear\n#  option (not recommended) you can uncomment the following to ignore the entire idea folder.\n#.idea/\n\n# PyPI configuration file\n.pypirc\n"
  },
  {
    "path": ".python-version",
    "content": "3.12\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2025 本光\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Ollama-Scan\n\n> 由于 Ollama 内部没有鉴权方式，我重构了一下代码，变成了命令行交互式的工具，提供自动补全。这是练手的工具，大家如果觉得好用可以多多 star，~~如果能冲到 100 个 star 那就更好了（~~，已经 100 star 了，感谢佬友们支持，如果有觉得不好用的地方还请多多提 issue\n>\n> Ollama 服务器发现我一般会使用 https://hunter.qianxin.com 配合语法 `app.name=“Ollama Server”&&is_domain=“False”`\n\n一个基于 Ollama 的命令行工具，提供友好的交互式界面来管理和使用 Ollama 模型。\n\n![image-20250218142835234](assets/image-20250218142835234.png)\n\n![image-20250218142843153](assets/image-20250218142843153.png)\n\n![image-20250218142848815](assets/image-20250218142848815.png)\n\n## ✨ 功能特性\n\n- 📃 列出所有可用的模型\n- 📥 拉取新的模型\n- 🔍 查看模型详细信息\n- 💬 与模型进行对话\n- ⚡️ 查看运行中的模型进程\n- 🎨 美观的命令行界面（使用 Rich 库）\n- 🔄 交互式命令补全\n\n## 🚀 安装\n\n1. 克隆仓库：\n```bash\ngit clone https://github.com/b3nguang/Ollama-Scan.git\ncd Ollama-Scan\n```\n\n2. 安装依赖：\n```bash\npip install -r requirements.txt\n```\n\n## 📖 使用方法\n\n运行程序：\n```bash\npython main.py [--host HOST]\n```\n\n### 可用命令：\n\n- `list` - 📃 列出所有可用模型\n- `pull <model_name>` - 📥 拉取指定模型\n- `show <model_name>` - 🔍 显示模型详细信息\n- `chat <model_name>` - 💬 与指定模型对话\n- `ps` - ⚡️ 显示运行中的模型进程\n- `help` - ❓ 显示帮助信息\n- `exit` - 🚪 退出程序\n\n## 🛠️ 环境要求\n\n- Python 3.6+\n- Ollama 服务器\n\n## 📝 作者\n\n- b3nguang\n\n## 📄 许可证\n\n本项目采用 MIT 许可证\n\n## 🌟 Star History\n\n![Star History Chart](https://api.star-history.com/svg?repos=b3nguang/Ollama-Scan&type=Date)\n"
  },
  {
    "path": "fofa_Ollama.py",
    "content": "\"\"\"\nFOFA 查询与导出工具\n\n描述:\n    本脚本用于通过 FOFA API 查询指定语法（如 `app=\"Ollama\"`）的结果，并导出符合条件的链接。\n    支持自定义查询语句和导出条数，同时会检查每个链接是否为有效的 Ollama 服务，并将结果保存到本地文件。\n\n功能:\n    1. 通过 FOFA API 查询指定语法的结果。\n    2. 检查查询结果中的链接是否为有效的 Ollama 服务。\n    3. 将有效的 Ollama 服务链接及其模型信息保存到本地文件。\n    4. 支持自定义查询语句和导出条数。\n\n使用示例:\n    python3 fofa_Ollama.py -q  -n 100\n    python3 fofa_Ollama.py --query  --number 500\n\n参数:\n    -q, --query    FOFA 查询语句（默认：'app=\"Ollama\"'）\n    -n, --number   导出条数（默认：500）\n\n作者: ruoji\n时间: 2025-02-28\nGithub:https://github.com/RuoJi6\n版本: 1.0\n\"\"\"\n\nimport argparse\nimport base64\nimport csv\nimport os\nfrom datetime import datetime\n\nimport httpx\nimport urllib3\n\n# 禁用 InsecureRequestWarning 警告\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\n\nfofa_key = \"\"  # fofa_key 需要配置这个key!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\nclass Colorpr:\n    @staticmethod\n    def color_red(test):\n        return f\"\\033[1;31m{test}\\033[0m\"\n\n    @staticmethod\n    def color_red_bd(test):\n        return f\"[\\033[1;31m+\\033[0m] {test}\"\n\n    @staticmethod\n    def color_blue_bd(test):\n        return f\"[\\033[34m-\\033[0m] {test}\"\n\n    @staticmethod\n    def color_blue(test):\n        return f\"\\033[34m{test}\\033[0m\"\n\n    @staticmethod\n    def color_yellow(test):\n        return f\"\\033[33m{test}\\033[0m\"\n\n    @staticmethod\n    def color_purple(test):\n        return f\"\\033[35m{test}\\033[0m\"\n\n\ndef formatted_time():\n    \"\"\"\n    功能描述: 返回系统当前时间 time:2024-12-07 19:15:31\n    参数:\n    返回值:\n    异常描述:\n    调用演示:\n        time_data = self.formatted_time()\n    \"\"\"\n    # 获取当前时间\n    now = datetime.now()\n    # 定义时间格式\n    time_format = \"%Y-%m-%d %H:%M:%S\"\n    # 按照定义的格式对当前时间进行格式化\n    return (\n        str(now.strftime(time_format))\n        .replace(\"http://\", \"\")\n        .replace(\"https://\", \"\")\n        .replace(\"/\", \"\")\n        .replace(\".\", \"_\")\n        .replace(\":\", \"_\")\n        .replace(\"-\", \"_\")\n        .replace(\" \", \"_\")\n    )\n\n\ndef get_base64(value_b64encode=None, value_b64decode=None):\n    \"\"\"\n    功能描述: 加密解密base64\n    参数:\n        value_b64encode : 加密\n        value_b64decode : 解密\n    返回值:\n    异常描述:\n    调用演示:\n        fofa = self.get_config('fofa')\n    \"\"\"\n    if value_b64encode is not None:\n        # 进行Base64编码\n        return base64.b64encode(value_b64encode.encode(\"utf-8\")).decode(\"utf-8\")\n    elif value_b64decode is not None:\n        # 进行Base64解密\n        return base64.b64decode(value_b64decode).decode(\"utf-8\")\n\n\ndef fofa_query(query, number):\n    number = int(number)\n    value_list = 0\n    data_list = []\n\n    # 使用httpx客户端，设置默认验证为False\n    with httpx.Client(verify=False) as client:\n        fofa_user_info = client.get(f\"https://fofa.info/api/v1/info/my?key={fofa_key}\")\n        if fofa_user_info.json()[\"error\"] is not True:\n            i = 1\n            while True:\n                qbase64 = get_base64(query)\n                data = client.get(f\"https://fofa.info/api/v1/search/all?&key={fofa_key}&qbase64={qbase64}&fields=link&page={i}&size={number}\")\n\n                if data.json()[\"error\"] is not True:\n                    i = i + 1\n                    value_list = value_list + len(data.json()[\"results\"])\n                    data_list.extend(data.json()[\"results\"])\n                else:\n                    print(f\"[{Colorpr.color_blue('-')}]FOFA ERROR:\" + data.json()[\"errmsg\"])\n                    break\n                print(f\"[{Colorpr.color_red('+')}]导出fofa条数:{value_list}\")\n                if value_list >= number:\n                    break\n            return data_list\n        else:\n            print(f\"[{Colorpr.color_blue('-')}]FOFA ERROR:\" + fofa_user_info.json()[\"errmsg\"])\n            if fofa_user_info.json()[\"errmsg\"] == \"[-700] 账号无效\":\n                print(f\"[{Colorpr.color_blue('-')}]配置FOFA KEY\")\n            exit(0)\n\n\ndef fofa_check(fofa_data):\n    file_time_name = formatted_time() + \".txt\"\n    csv_file_name = formatted_time() + \".csv\"\n\n    # 创建CSV文件并写入表头\n    with open(csv_file_name, \"a\", newline=\"\") as fcsv:\n        csv_writer = csv.writer(fcsv)\n        csv_writer.writerow([\"IP\", \"URL\", \"模型名称\"])\n\n    # 使用httpx客户端，设置默认超时和验证为False\n    with httpx.Client(timeout=30, verify=False) as client:\n        for url in fofa_data:\n            try:\n                fofa_url_data = client.get(url=url + \"/api/tags\")\n                fofa_url_data_json = fofa_url_data.json()\n                if len(fofa_url_data_json[\"models\"]):\n                    # 从URL中提取IP\n                    ip = url.replace(\"http://\", \"\").replace(\"https://\", \"\").split(\":\")[0]\n\n                    print(f\"[{Colorpr.color_red('+')}]Ollama: \" + url + \" 模型数量：\" + str(len(fofa_url_data_json[\"models\"])))\n\n                    # 写入TXT文件\n                    with open(file_time_name, \"a\") as fOllama:\n                        fOllama.write(url + \"\\n\")\n                        for models in fofa_url_data_json[\"models\"]:\n                            fOllama.write(str(models) + \"\\n\")\n                        fOllama.write(\"---------------------------------------\\n\\n\")\n\n                    # 写入CSV文件\n                    with open(csv_file_name, \"a\", newline=\"\") as fcsv:\n                        csv_writer = csv.writer(fcsv)\n                        for model in fofa_url_data_json[\"models\"]:\n                            csv_writer.writerow([ip, url, model[\"name\"]])\n\n            except Exception as e:\n                print(f\"[{Colorpr.color_blue('-')}]不存在:\" + str(e))\n\n    if os.path.exists(file_time_name):\n        print(f\"[{Colorpr.color_red('+')}]TXT文件保存为：{file_time_name}\")\n    if os.path.exists(csv_file_name):\n        print(f\"[{Colorpr.color_red('+')}]CSV文件保存为：{csv_file_name}\")\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(description=\"FOFA导出\")\n    parser.add_argument(\n        \"-q\",\n        \"--query\",\n        default='app=\"Ollama\"',\n        help=\"FOFA查询Ollama\",\n    )\n    parser.add_argument(\n        \"-n\",\n        \"--number\",\n        default=500,\n        help=\"导出条数[默认500]\",\n    )\n\n    # 解析命令行参数\n    args = parser.parse_args()\n    if args.query:\n        if os.path.exists(\"fofa_link.txt\"):\n            os.remove(\"fofa_link.txt\")\n        print(f\"[{Colorpr.color_red('+')}]语法:\" + args.query)\n        print(f\"[{Colorpr.color_red('+')}]条数:\" + str(args.number))\n        fofa_data_list = fofa_query(args.query, args.number)\n        fofa_check(fofa_data_list)\n"
  },
  {
    "path": "main.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"\n@ Author: b3nguang\n@ Date: 2025-02-18 12:04:37\n\"\"\"\n\nimport argparse\nimport re\nimport sys\nfrom typing import List, Tuple\nimport logging\nimport subprocess\n\nfrom ollama import Client\nfrom prompt_toolkit import PromptSession\nfrom prompt_toolkit.completion import WordCompleter\nfrom rich.console import Console\nfrom rich.markdown import Markdown\nfrom rich.panel import Panel\nfrom rich.progress import Progress, SpinnerColumn, TextColumn\nfrom rich.style import Style\nfrom rich.table import Table\nfrom httpx import Timeout, HTTPError, ReadTimeout\n\n\nclass OllamaShell:\n    def __init__(self, host: str = None):\n        if not host:\n            raise ValueError(\"必须提供 Ollama 服务器地址\")\n        if not host.startswith((\"http://\", \"https://\")):\n            raise ValueError(\"服务器地址必须以 http:// 或 https:// 开头\")\n        \n        # 保存 host 地址\n        self.host = host\n        \n        # 根据协议决定是否验证证书\n        self.verify_ssl = not (host.startswith(\"https://\") and \":\" in host.split(\"://\")[1].split(\"/\")[0])\n        \n        self.client = Client(\n            host=host,\n            timeout=Timeout(30.0),\n            verify=self.verify_ssl\n        )\n        self.console = Console()\n        self.commands = {\n            \"list\": (self.list_models, \"📃 列出可用模型\"),\n            \"pull\": (self.pull_model, \"📥 拉取模型\"),\n            \"show\": (self.show_model, \"🔍 显示模型详情\"),\n            \"chat\": (self.chat_with_model, \"💬 与模型对话\"),\n            \"ps\": (self.show_processes, \"⚡️ 显示运行中的模型\"),\n            \"help\": (self.show_help, \"❓ 显示帮助信息\"),\n            \"exit\": (self.exit_shell, \"🚪 退出程序\"),\n            \"rm\": (self.delete_model, \"🗑️ 删除指定模型\"),\n            \"version\": (self.show_version, \"📌 显示版本信息\"),\n        }\n\n    def list_models(self, *args: List[str]) -> None:\n        \"\"\"列出所有可用的模型\"\"\"\n        try:\n            with Progress(\n                SpinnerColumn(),\n                TextColumn(\"[bold blue]获取模型列表...\"),\n                transient=True,\n            ) as progress:\n                progress.add_task(\"fetch\")\n                models = self.client.list()\n                # self.console.print(\n                #     f\"[dim]DEBUG: type={type(models)}, value={models}[/dim]\"\n                # )\n            table = Table(\n                title=\"📃 可用模型列表\",\n                show_header=True,\n                header_style=\"bold magenta\",\n                show_lines=True,\n            )\n            table.add_column(\"🤖 模型名称\", style=\"cyan\")\n            table.add_column(\"💾 大小\", justify=\"right\", style=\"green\")\n            table.add_column(\"📅 修改时间\", justify=\"right\", style=\"yellow\")\n            table.add_column(\"📋 格式\", style=\"magenta\")\n            table.add_column(\"🧩 参数量\", style=\"blue\")\n            table.add_column(\"🏷️ 量化等级\", style=\"red\")\n\n            if not models:\n                self.console.print(\"[red]❗️ 未找到模型[/red]\")\n                return\n\n            # 处理模型列表\n            if hasattr(models, \"models\"):\n                model_list = models.models\n            elif isinstance(models, list):\n                model_list = models\n            else:\n                self.console.print(f\"[yellow]⚠️ 返回值格式异常: {models}[/yellow]\")\n                return\n\n            for model in model_list:\n                try:\n                    # 获取基本信息\n                    name = model.model\n                    size = model.size\n                    modified = model.modified_at\n                    details = model.details\n\n                    # 格式化大小\n                    size_str = f\"{size / (1024 * 1024 * 1024):.1f}GB\" if size else \"Unknown\"\n\n                    # 格式化时间\n                    modified_str = modified.strftime(\"%Y-%m-%d %H:%M\") if modified else \"Unknown\"\n\n                    # 获取详细信息\n                    format_str = details.format if details else \"Unknown\"\n                    param_size = details.parameter_size if details else \"Unknown\"\n                    quant_level = details.quantization_level if details else \"Unknown\"\n\n                    # 添加到表格\n                    table.add_row(\n                        name,\n                        size_str,\n                        modified_str,\n                        format_str,\n                        str(param_size),\n                        str(quant_level),\n                    )\n\n                except Exception as e:\n                    self.console.print(f\"[yellow]⚠️ 警告: 处理模型信息时出错: {str(e)}[/yellow]\")\n                    continue\n\n            self.console.print(table)\n\n        except ConnectionError:\n            self.console.print(\"[red]连接服务器失败[/red]\")\n        except TimeoutError:\n            self.console.print(\"[red]请求超时[/red]\")\n        except HTTPError as e:\n            self.console.print(f\"[red]HTTP 错误: {e.response.status_code}[/red]\")\n        except Exception as e:\n            self.console.print(\"[red]发生未知错误[/red]\")\n            logging.error(f\"Unexpected error: {str(e)}\")\n\n    def pull_model(self, *args: List[str]) -> None:\n        \"\"\"拉取指定的模型\"\"\"\n        if not args:\n            self.console.print(\"[red]错误: 请指定模型名称[/red]\")\n            return\n\n        model_name = args[0]\n        # 修改模型名称验证，允许更多字符\n        if not re.match(r'^[a-zA-Z0-9_\\-\\./:]+$', model_name):\n            self.console.print(\"[red]错误: 模型名称包含非法字符[/red]\")\n            return\n\n        self.console.print(f\"\\n[bold]📥 开始拉取模型: {model_name}[/bold]\")\n\n        try:\n            with Progress(TextColumn(\"[bold blue]{task.description}\"), transient=False) as progress:\n                task = progress.add_task(\"拉取中...\", total=None)\n                for info in self.client.pull(model_name, stream=True):\n                    if \"status\" in info:\n                        progress.update(task, description=f\"状态: {info['status']}\")\n                    if \"completed\" in info:\n                        progress.update(\n                            task,\n                            description=f\"进度: {info['completed']}/{info['total']} layers\",\n                        )\n            self.console.print(\"[green]✅ 模型拉取完成！[/green]\")\n\n        except ConnectionError:\n            self.console.print(\"[red]连接服务器失败[/red]\")\n        except TimeoutError:\n            self.console.print(\"[red]请求超时[/red]\")\n        except HTTPError as e:\n            self.console.print(f\"[red]HTTP 错误: {e.response.status_code}[/red]\")\n        except Exception as e:\n            self.console.print(\"[red]发生未知错误[/red]\")\n            logging.error(f\"Unexpected error: {str(e)}\")\n\n    def show_model(self, *args: List[str]) -> None:\n        \"\"\"显示模型详细信息\"\"\"\n        if not args:\n            self.console.print(\"[red]错误: 请指定模型名称[/red]\")\n            return\n\n        model_name = args[0]\n        try:\n            with Progress(\n                SpinnerColumn(),\n                TextColumn(f\"[bold blue]获取模型 {model_name} 的信息...\"),\n                transient=True,\n            ) as progress:\n                progress.add_task(\"fetch\")\n                info = self.client.show(model_name)\n                # self.console.print(f\"[dim]DEBUG: type={type(info)}, value={info}[/dim]\")\n            # 构建基本信息\n            basic_info = (\n                f\"\\n[bold cyan]模型名称:[/bold cyan] {model_name}\\n\"\n                + f\"[bold yellow]修改时间:[/bold yellow] {info.modified_at.strftime('%Y-%m-%d %H:%M')}\\n\"\n                + f\"[bold magenta]格式:[/bold magenta] {info.details.format}\\n\"\n                + f\"[bold blue]参数量:[/bold blue] {info.details.parameter_size}\\n\"\n                + f\"[bold red]量化等级:[/bold red] {info.details.quantization_level}\\n\"\n            )\n\n            # 添加模型信息\n            if hasattr(info, \"modelinfo\") and info.modelinfo:\n                model_info_str = \"\\n[bold white]模型信息:[/bold white]\\n\"\n                for key, value in info.modelinfo.items():\n                    model_info_str += f\"  {key}: {value}\\n\"\n                basic_info += model_info_str\n\n            # 添加许可证信息\n            if hasattr(info, \"license\") and info.license:\n                basic_info += f\"\\n[bold white]许可证:[/bold white]\\n{info.license}\\n\"\n\n            panel = Panel.fit(\n                basic_info,\n                title=f\"模型详情 - {model_name}\",\n                border_style=\"blue\",\n            )\n            self.console.print(panel)\n\n        except ConnectionError:\n            self.console.print(\"[red]连接服务器失败[/red]\")\n        except TimeoutError:\n            self.console.print(\"[red]请求超时[/red]\")\n        except HTTPError as e:\n            self.console.print(f\"[red]HTTP 错误: {e.response.status_code}[/red]\")\n        except Exception as e:\n            self.console.print(\"[red]发生未知错误[/red]\")\n            logging.error(f\"Unexpected error: {str(e)}\")\n\n    def show_processes(self, *args: List[str]) -> None:\n        \"\"\"显示运行中的模型进程\"\"\"\n        try:\n            with Progress(\n                SpinnerColumn(),\n                TextColumn(\"[bold blue]获取运行中的模型...\"),\n                transient=True,\n            ) as progress:\n                progress.add_task(\"fetch\")\n                response = self.client.ps()\n\n            if not response or not hasattr(response, \"models\") or not response.models:\n                self.console.print(\"[yellow]⚠️ 没有正在运行的模型[/yellow]\")\n                return\n\n            table = Table(\n                title=\"⚡️ 运行中的模型\",\n                show_header=True,\n                header_style=\"bold magenta\",\n                show_lines=True,\n            )\n            table.add_column(\"🤖 模型名称\", style=\"cyan\")\n            table.add_column(\"💾 模型大小\", style=\"green\")\n            table.add_column(\"📂 格式\", style=\"yellow\")\n            table.add_column(\"🧩 参数量\", style=\"blue\")\n            table.add_column(\"🏷️ 量化等级\", style=\"red\")\n            table.add_column(\"⏳ 过期时间\", style=\"magenta\")\n\n            for model in response.models:\n                # 格式化大小（转换为GB）\n                size_gb = model.size / (1024 * 1024 * 1024)\n                size_str = f\"{size_gb:.1f}GB\"\n\n                # 格式化过期时间\n                expires_str = model.expires_at.strftime(\"%Y-%m-%d %H:%M:%S\") if model.expires_at else \"Unknown\"\n\n                table.add_row(\n                    model.name,\n                    size_str,\n                    model.details.format if model.details else \"Unknown\",\n                    model.details.parameter_size if model.details else \"Unknown\",\n                    model.details.quantization_level if model.details else \"Unknown\",\n                    expires_str,\n                )\n\n            self.console.print(table)\n\n        except ConnectionError:\n            self.console.print(\"[red]连接服务器失败[/red]\")\n        except TimeoutError:\n            self.console.print(\"[red]请求超时[/red]\")\n        except HTTPError as e:\n            self.console.print(f\"[red]HTTP 错误: {e.response.status_code}[/red]\")\n        except Exception as e:\n            self.console.print(\"[red]发生未知错误[/red]\")\n            logging.error(f\"Unexpected error: {str(e)}\")\n\n    def chat_with_model(self, *args: List[str]) -> None:\n        \"\"\"与模型进行对话\"\"\"\n        if not args:\n            self.console.print(\"[red]错误: 请指定模型名称[/red]\")\n            return\n\n        model_name = args[0]\n        self.console.print(f\"\\n[bold]💬 开始与 {model_name} 对话[/bold]\")\n        self.console.print(\"[dim]🚪 输入 'exit' 结束对话[/dim]\")\n\n        # 创建对话会话\n        chat_session = PromptSession()\n\n        while True:\n            try:\n                # 获取用户输入\n                message = chat_session.prompt(\"\\n👤 你> \")\n                if message.lower() == \"exit\":\n                    break\n\n                self.console.print(\"\\n[bold blue]🤖 AI[/bold blue]\")\n                with Progress(\n                    SpinnerColumn(),\n                    TextColumn(\"[bold blue]🤔 思考中...\"),\n                    transient=True,\n                ) as progress:\n                    progress.add_task(\"think\")\n                    stream = self.client.chat(\n                        model=model_name,\n                        messages=[{\"role\": \"user\", \"content\": message}],\n                        stream=True,\n                    )\n\n                response = \"\"\n                for chunk in stream:\n                    content = chunk[\"message\"][\"content\"]\n                    response += content\n\n                # 处理思考标签\n                think_pattern = r\"<think>(.*?)</think>\"\n                parts = re.split(think_pattern, response, flags=re.DOTALL)\n\n                for i, part in enumerate(parts):\n                    if i % 2 == 1:  # 思考内容\n                        think_panel = Panel(Markdown(part.strip()), title=\"思考过程\", style=Style(color=\"grey70\", italic=True), border_style=\"grey50\")\n                        self.console.print(think_panel)\n                        self.console.print()  # 添加空行\n                    else:  # 普通内容\n                        if part.strip():\n                            md = Markdown(part.strip())\n                            self.console.print(md)\n\n            except KeyboardInterrupt:\n                self.console.print(\"\\n[yellow]⛔️ 对话已取消[/yellow]\")\n                break\n            except EOFError:\n                self.console.print(\"\\n[yellow]👋 再见！[/yellow]\")\n                break\n            except ConnectionError:\n                self.console.print(\"[red]连接服务器失败[/red]\")\n                break\n            except (TimeoutError, ReadTimeout):\n                self.console.print(\"[red]请求超时，请检查网络连接或服务器状态[/red]\")\n                break\n            except HTTPError as e:\n                self.console.print(f\"[red]HTTP 错误: {e.response.status_code}[/red]\")\n                break\n            except Exception as e:\n                self.console.print(f\"[red]发生未知错误: {str(e)}[/red]\")\n                logging.error(f\"Unexpected error: {str(e)}\")\n                break\n\n    def show_help(self, *args: List[str]) -> None:\n        \"\"\"显示帮助信息\"\"\"\n        table = Table(title=\"✨ 命令列表\", show_header=True, header_style=\"bold magenta\")\n        table.add_column(\"📝 命令\", style=\"cyan\")\n        table.add_column(\"📄 说明\", style=\"green\")\n        table.add_column(\"用法\", style=\"yellow\", justify=\"left\")\n\n        commands_help = [\n            (\"list\", \"📃 列出所有可用的模型\", \"list\"),\n            (\"pull\", \"📥 拉取指定的模型\", \"pull <model_name>\"),\n            (\"show\", \"🔍 显示模型详细信息\", \"show <model_name>\"),\n            (\"chat\", \"💬 与模型进行对话\", \"chat <model_name>\"),\n            (\"ps\", \"⚡️ 显示运行中的模型\", \"ps\"),\n            (\"rm\", \"🗑️  删除指定模型\",\"rm <model_name>\"),\n            (\"version\", \"📌 显示版本信息\", \"version\"),\n            (\"help\", \"❓ 显示帮助信息\", \"help\"),\n            (\"exit\", \"🚪 退出程序\", \"exit\"),\n        ]\n\n        for cmd, desc, usage in commands_help:\n            table.add_row(cmd, desc, usage)\n\n        self.console.print(table)\n\n    def exit_shell(self, *args: List[str]) -> None:\n        \"\"\"退出程序\"\"\"\n        self.console.print(\"[yellow]👋 再见！✨[/yellow]\")\n        sys.exit(0)\n\n    def get_model_list(self) -> List[str]:\n        \"\"\"获取模型列表\"\"\"\n        try:\n            models = self.client.list()\n            if hasattr(models, \"models\"):\n                return [model.model for model in models.models]\n            elif isinstance(models, list):\n                return [model.model for model in models]\n            return []\n        except Exception:\n            return []\n\n    def get_command_completer(self) -> WordCompleter:\n        \"\"\"创建命令补全器\"\"\"\n        # 获取所有命令\n        commands = list(self.commands.keys())\n        # 获取所有模型\n        models = self.get_model_list()\n        # 创建补全器\n        word_list = commands + [f\"{cmd} {model}\" for cmd in [\"chat\", \"show\", \"pull\"] for model in models]\n        return WordCompleter(word_list, ignore_case=True)\n\n    def run(self) -> None:\n        \"\"\"运行交互式shell\"\"\"\n        self.console.print(\n            Panel.fit(\n                \"👋 欢迎使用 Ollama Shell！输入 'help' 查看可用命令 ✨\",\n                title=\"🤖 Ollama Shell\",\n                border_style=\"green\",\n            )\n        )\n\n        # 创建命令行会话\n        session = PromptSession()\n\n        while True:\n            try:\n                # 获取最新的补全器\n                completer = self.get_command_completer()\n                # 显示提示符并等待输入\n                command = session.prompt(\n                    \"\\n🤖 ollama> \",\n                    completer=completer,\n                    complete_while_typing=True,\n                )\n\n                args = command.strip().split()\n                if not args:\n                    continue\n\n                cmd, *cmd_args = args\n                if cmd in self.commands:\n                    func, _ = self.commands[cmd]\n                    func(*cmd_args)\n                else:\n                    self.console.print(f\"[red]❌ 未知命令: {cmd}[/red]\")\n                    self.console.print(\"[yellow]❓ 输入 'help' 查看可用命令[/yellow]\")\n\n            except KeyboardInterrupt:\n                self.console.print(\"\\n[yellow]⛔️ 操作已取消[/yellow]\")\n                continue\n            except EOFError:\n                self.console.print(\"\\n[yellow]👋 再见！✨[/yellow]\")\n                break\n            except ConnectionError:\n                self.console.print(\"[red]连接服务器失败[/red]\")\n            except TimeoutError:\n                self.console.print(\"[red]请求超时[/red]\")\n            except HTTPError as e:\n                self.console.print(f\"[red]HTTP 错误: {e.response.status_code}[/red]\")\n            except Exception as e:\n                self.console.print(\"[red]发生未知错误[/red]\")\n                logging.error(f\"Unexpected error: {str(e)}\")\n                break\n\n    def delete_model(self, *args: List[str]) -> None:\n        \"\"\"删除指定的模型\"\"\"\n        if not args:\n            self.console.print(\"[red]错误: 请指定要删除的模型名称[/red]\")\n            return\n\n        model_name = args[0]\n        # 修改模型名称验证，允许更多字符\n        if not re.match(r'^[a-zA-Z0-9_\\-\\./:]+$', model_name):\n            self.console.print(\"[red]错误: 模型名称包含非法字符[/red]\")\n            return\n\n        try:\n            # 确认删除\n            self.console.print(f\"\\n[yellow]⚠️ 确定要删除模型 {model_name} 吗？这个操作不可恢复！[/yellow]\")\n            self.console.print(\"[dim]输入 'yes' 确认删除，其他输入取消[/dim]\")\n            \n            # 创建确认会话\n            confirm_session = PromptSession()\n            confirm = confirm_session.prompt(\"\\n确认> \")\n            \n            if confirm.lower() != 'yes':\n                self.console.print(\"[yellow]已取消删除操作[/yellow]\")\n                return\n\n            with Progress(\n                SpinnerColumn(),\n                TextColumn(f\"[bold red]正在删除模型 {model_name}...\"),\n                transient=True,\n            ) as progress:\n                progress.add_task(\"delete\")\n                self.client.delete(model_name)\n            \n            self.console.print(f\"[green]✅ 模型 {model_name} 已成功删除！[/green]\")\n\n        except ConnectionError:\n            self.console.print(\"[red]连接服务器失败[/red]\")\n        except TimeoutError:\n            self.console.print(\"[red]请求超时[/red]\")\n        except HTTPError as e:\n            self.console.print(f\"[red]HTTP 错误: {e.response.status_code}[/red]\")\n        except Exception as e:\n            self.console.print(\"[red]发生未知错误[/red]\")\n            logging.error(f\"Unexpected error: {str(e)}\")\n\n    def show_version(self, *args: List[str]) -> None:\n        \"\"\"显示 Ollama 版本信息\"\"\"\n        try:\n            with Progress(\n                SpinnerColumn(),\n                TextColumn(\"[bold blue]获取版本信息...\"),\n                transient=True,\n            ) as progress:\n                progress.add_task(\"fetch\")\n                # 使用保存的 verify_ssl 设置\n                import httpx\n                response = httpx.get(\n                    f\"{self.host}/api/version\",\n                    verify=self.verify_ssl\n                )\n                response.raise_for_status()\n                data = response.json()\n                \n            if not data or 'version' not in data:\n                self.console.print(\"[yellow]⚠️ 无法获取版本信息[/yellow]\")\n                return\n\n            version = data['version']\n            # 创建面板显示版本信息\n            panel = Panel.fit(\n                f\"[bold cyan]Ollama 版本:[/bold cyan] {version}\",\n                title=\"📌 版本信息\",\n                border_style=\"green\"\n            )\n            self.console.print(panel)\n\n        except ConnectionError:\n            self.console.print(\"[red]连接服务器失败[/red]\")\n        except TimeoutError:\n            self.console.print(\"[red]请求超时[/red]\")\n        except HTTPError as e:\n            self.console.print(f\"[red]HTTP 错误: {e.response.status_code}[/red]\")\n        except Exception as e:\n            self.console.print(\"[red]获取版本信息时发生错误[/red]\")\n            logging.error(f\"Version info error: {str(e)}\")\n\n\ndef main():\n    # 创建命令行解析器\n    parser = argparse.ArgumentParser(description=\"Ollama Shell - 一个功能强大的 Ollama 命令行工具\")\n    parser.add_argument(\n        \"-H\",\n        \"--host\",\n        default=\"http://localhost:11434\",\n        help=\"Ollama 服务器地址，默认为 http://localhost:11434\",\n    )\n\n    # 解析命令行参数\n    args = parser.parse_args()\n\n    # 创建 shell 实例\n    shell = OllamaShell(host=args.host)\n    shell.run()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "ollamaAPI说明.md",
    "content": "# API\n\n## Endpoints\n\n- [Generate a completion](#generate-a-completion)\n- [Generate a chat completion](#generate-a-chat-completion)\n- [Create a Model](#create-a-model)\n- [List Local Models](#list-local-models)\n- [Show Model Information](#show-model-information)\n- [Copy a Model](#copy-a-model)\n- [Delete a Model](#delete-a-model)\n- [Pull a Model](#pull-a-model)\n- [Push a Model](#push-a-model)\n- [Generate Embeddings](#generate-embeddings)\n- [List Running Models](#list-running-models)\n- [Version](#version)\n\n## Conventions\n\n### Model names\n\nModel names follow a `model:tag` format, where `model` can have an optional namespace such as `example/model`. Some examples are `orca-mini:3b-q4_1` and `llama3:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.\n\n### Durations\n\nAll durations are returned in nanoseconds.\n\n### Streaming responses\n\nCertain endpoints stream responses as JSON objects. Streaming can be disabled by providing `{\"stream\": false}` for these endpoints.\n\n## Generate a completion\n\n```\nPOST /api/generate\n```\n\nGenerate a response for a given prompt with a provided model. This is a streaming endpoint, so there will be a series of responses. The final response object will include statistics and additional data from the request.\n\n### Parameters\n\n- `model`: (required) the [model name](#model-names)\n- `prompt`: the prompt to generate a response for\n- `suffix`: the text after the model response\n- `images`: (optional) a list of base64-encoded images (for multimodal models such as `llava`)\n\nAdvanced parameters (optional):\n\n- `format`: the format to return a response in. Format can be `json` or a JSON schema\n- `options`: additional model parameters listed in the documentation for the [Modelfile](./modelfile.md#valid-parameters-and-values) such as `temperature`\n- `system`: system message to (overrides what is defined in the `Modelfile`)\n- `template`: the prompt template to use (overrides what is defined in the `Modelfile`)\n- `stream`: if `false` the response will be returned as a single response object, rather than a stream of objects\n- `raw`: if `true` no formatting will be applied to the prompt. You may choose to use the `raw` parameter if you are specifying a full templated prompt in your request to the API\n- `keep_alive`: controls how long the model will stay loaded into memory following the request (default: `5m`)\n- `context` (deprecated): the context parameter returned from a previous request to `/generate`, this can be used to keep a short conversational memory\n\n#### Structured outputs\n\nStructured outputs are supported by providing a JSON schema in the `format` parameter. The model will generate a response that matches the schema. See the [structured outputs](#request-structured-outputs) example below.\n\n#### JSON mode\n\nEnable JSON mode by setting the `format` parameter to `json`. This will structure the response as a valid JSON object. See the JSON mode [example](#request-json-mode) below.\n\n> [!IMPORTANT]\n> It's important to instruct the model to use JSON in the `prompt`. Otherwise, the model may generate large amounts whitespace.\n\n### Examples\n\n#### Generate request (Streaming)\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"llama3.2\",\n  \"prompt\": \"Why is the sky blue?\"\n}'\n```\n\n##### Response\n\nA stream of JSON objects is returned:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-08-04T08:52:19.385406455-07:00\",\n  \"response\": \"The\",\n  \"done\": false\n}\n```\n\nThe final response in the stream also includes additional data about the generation:\n\n- `total_duration`: time spent generating the response\n- `load_duration`: time spent in nanoseconds loading the model\n- `prompt_eval_count`: number of tokens in the prompt\n- `prompt_eval_duration`: time spent in nanoseconds evaluating the prompt\n- `eval_count`: number of tokens in the response\n- `eval_duration`: time in nanoseconds spent generating the response\n- `context`: an encoding of the conversation used in this response, this can be sent in the next request to keep a conversational memory\n- `response`: empty if the response was streamed, if not streamed, this will contain the full response\n\nTo calculate how fast the response is generated in tokens per second (token/s), divide `eval_count` / `eval_duration` * `10^9`.\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-08-04T19:22:45.499127Z\",\n  \"response\": \"\",\n  \"done\": true,\n  \"context\": [1, 2, 3],\n  \"total_duration\": 10706818083,\n  \"load_duration\": 6338219291,\n  \"prompt_eval_count\": 26,\n  \"prompt_eval_duration\": 130079000,\n  \"eval_count\": 259,\n  \"eval_duration\": 4232710000\n}\n```\n\n#### Request (No streaming)\n\n##### Request\n\nA response can be received in one reply when streaming is off.\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"llama3.2\",\n  \"prompt\": \"Why is the sky blue?\",\n  \"stream\": false\n}'\n```\n\n##### Response\n\nIf `stream` is set to `false`, the response will be a single JSON object:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-08-04T19:22:45.499127Z\",\n  \"response\": \"The sky is blue because it is the color of the sky.\",\n  \"done\": true,\n  \"context\": [1, 2, 3],\n  \"total_duration\": 5043500667,\n  \"load_duration\": 5025959,\n  \"prompt_eval_count\": 26,\n  \"prompt_eval_duration\": 325953000,\n  \"eval_count\": 290,\n  \"eval_duration\": 4709213000\n}\n```\n\n#### Request (with suffix)\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"codellama:code\",\n  \"prompt\": \"def compute_gcd(a, b):\",\n  \"suffix\": \"    return result\",\n  \"options\": {\n    \"temperature\": 0\n  },\n  \"stream\": false\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"codellama:code\",\n  \"created_at\": \"2024-07-22T20:47:51.147561Z\",\n  \"response\": \"\\n  if a == 0:\\n    return b\\n  else:\\n    return compute_gcd(b % a, a)\\n\\ndef compute_lcm(a, b):\\n  result = (a * b) / compute_gcd(a, b)\\n\",\n  \"done\": true,\n  \"done_reason\": \"stop\",\n  \"context\": [...],\n  \"total_duration\": 1162761250,\n  \"load_duration\": 6683708,\n  \"prompt_eval_count\": 17,\n  \"prompt_eval_duration\": 201222000,\n  \"eval_count\": 63,\n  \"eval_duration\": 953997000\n}\n```\n\n#### Request (Structured outputs)\n\n##### Request\n\n```shell\ncurl -X POST http://localhost:11434/api/generate -H \"Content-Type: application/json\" -d '{\n  \"model\": \"llama3.1:8b\",\n  \"prompt\": \"Ollama is 22 years old and is busy saving the world. Respond using JSON\",\n  \"stream\": false,\n  \"format\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"age\": {\n        \"type\": \"integer\"\n      },\n      \"available\": {\n        \"type\": \"boolean\"\n      }\n    },\n    \"required\": [\n      \"age\",\n      \"available\"\n    ]\n  }\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llama3.1:8b\",\n  \"created_at\": \"2024-12-06T00:48:09.983619Z\",\n  \"response\": \"{\\n  \\\"age\\\": 22,\\n  \\\"available\\\": true\\n}\",\n  \"done\": true,\n  \"done_reason\": \"stop\",\n  \"context\": [1, 2, 3],\n  \"total_duration\": 1075509083,\n  \"load_duration\": 567678166,\n  \"prompt_eval_count\": 28,\n  \"prompt_eval_duration\": 236000000,\n  \"eval_count\": 16,\n  \"eval_duration\": 269000000\n}\n```\n\n#### Request (JSON mode)\n\n> [!IMPORTANT]\n> When `format` is set to `json`, the output will always be a well-formed JSON object. It's important to also instruct the model to respond in JSON.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"llama3.2\",\n  \"prompt\": \"What color is the sky at different times of the day? Respond using JSON\",\n  \"format\": \"json\",\n  \"stream\": false\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-11-09T21:07:55.186497Z\",\n  \"response\": \"{\\n\\\"morning\\\": {\\n\\\"color\\\": \\\"blue\\\"\\n},\\n\\\"noon\\\": {\\n\\\"color\\\": \\\"blue-gray\\\"\\n},\\n\\\"afternoon\\\": {\\n\\\"color\\\": \\\"warm gray\\\"\\n},\\n\\\"evening\\\": {\\n\\\"color\\\": \\\"orange\\\"\\n}\\n}\\n\",\n  \"done\": true,\n  \"context\": [1, 2, 3],\n  \"total_duration\": 4648158584,\n  \"load_duration\": 4071084,\n  \"prompt_eval_count\": 36,\n  \"prompt_eval_duration\": 439038000,\n  \"eval_count\": 180,\n  \"eval_duration\": 4196918000\n}\n```\n\nThe value of `response` will be a string containing JSON similar to:\n\n```json\n{\n  \"morning\": {\n    \"color\": \"blue\"\n  },\n  \"noon\": {\n    \"color\": \"blue-gray\"\n  },\n  \"afternoon\": {\n    \"color\": \"warm gray\"\n  },\n  \"evening\": {\n    \"color\": \"orange\"\n  }\n}\n```\n\n#### Request (with images)\n\nTo submit images to multimodal models such as `llava` or `bakllava`, provide a list of base64-encoded `images`:\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"llava\",\n  \"prompt\":\"What is in this picture?\",\n  \"stream\": false,\n  \"images\": [\"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\"]\n}'\n```\n\n#### Response\n\n```json\n{\n  \"model\": \"llava\",\n  \"created_at\": \"2023-11-03T15:36:02.583064Z\",\n  \"response\": \"A happy cartoon character, which is cute and cheerful.\",\n  \"done\": true,\n  \"context\": [1, 2, 3],\n  \"total_duration\": 2938432250,\n  \"load_duration\": 2559292,\n  \"prompt_eval_count\": 1,\n  \"prompt_eval_duration\": 2195557000,\n  \"eval_count\": 44,\n  \"eval_duration\": 736432000\n}\n```\n\n#### Request (Raw Mode)\n\nIn some cases, you may wish to bypass the templating system and provide a full prompt. In this case, you can use the `raw` parameter to disable templating. Also note that raw mode will not return a context.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"mistral\",\n  \"prompt\": \"[INST] why is the sky blue? [/INST]\",\n  \"raw\": true,\n  \"stream\": false\n}'\n```\n\n#### Request (Reproducible outputs)\n\nFor reproducible outputs, set `seed` to a number:\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"mistral\",\n  \"prompt\": \"Why is the sky blue?\",\n  \"options\": {\n    \"seed\": 123\n  }\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"mistral\",\n  \"created_at\": \"2023-11-03T15:36:02.583064Z\",\n  \"response\": \" The sky appears blue because of a phenomenon called Rayleigh scattering.\",\n  \"done\": true,\n  \"total_duration\": 8493852375,\n  \"load_duration\": 6589624375,\n  \"prompt_eval_count\": 14,\n  \"prompt_eval_duration\": 119039000,\n  \"eval_count\": 110,\n  \"eval_duration\": 1779061000\n}\n```\n\n#### Generate request (With options)\n\nIf you want to set custom options for the model at runtime rather than in the Modelfile, you can do so with the `options` parameter. This example sets every available option, but you can set any of them individually and omit the ones you do not want to override.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"llama3.2\",\n  \"prompt\": \"Why is the sky blue?\",\n  \"stream\": false,\n  \"options\": {\n    \"num_keep\": 5,\n    \"seed\": 42,\n    \"num_predict\": 100,\n    \"top_k\": 20,\n    \"top_p\": 0.9,\n    \"min_p\": 0.0,\n    \"typical_p\": 0.7,\n    \"repeat_last_n\": 33,\n    \"temperature\": 0.8,\n    \"repeat_penalty\": 1.2,\n    \"presence_penalty\": 1.5,\n    \"frequency_penalty\": 1.0,\n    \"mirostat\": 1,\n    \"mirostat_tau\": 0.8,\n    \"mirostat_eta\": 0.6,\n    \"penalize_newline\": true,\n    \"stop\": [\"\\n\", \"user:\"],\n    \"numa\": false,\n    \"num_ctx\": 1024,\n    \"num_batch\": 2,\n    \"num_gpu\": 1,\n    \"main_gpu\": 0,\n    \"low_vram\": false,\n    \"vocab_only\": false,\n    \"use_mmap\": true,\n    \"use_mlock\": false,\n    \"num_thread\": 8\n  }\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-08-04T19:22:45.499127Z\",\n  \"response\": \"The sky is blue because it is the color of the sky.\",\n  \"done\": true,\n  \"context\": [1, 2, 3],\n  \"total_duration\": 4935886791,\n  \"load_duration\": 534986708,\n  \"prompt_eval_count\": 26,\n  \"prompt_eval_duration\": 107345000,\n  \"eval_count\": 237,\n  \"eval_duration\": 4289432000\n}\n```\n\n#### Load a model\n\nIf an empty prompt is provided, the model will be loaded into memory.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"llama3.2\"\n}'\n```\n\n##### Response\n\nA single JSON object is returned:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-12-18T19:52:07.071755Z\",\n  \"response\": \"\",\n  \"done\": true\n}\n```\n\n#### Unload a model\n\nIf an empty prompt is provided and the `keep_alive` parameter is set to `0`, a model will be unloaded from memory.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/generate -d '{\n  \"model\": \"llama3.2\",\n  \"keep_alive\": 0\n}'\n```\n\n##### Response\n\nA single JSON object is returned:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2024-09-12T03:54:03.516566Z\",\n  \"response\": \"\",\n  \"done\": true,\n  \"done_reason\": \"unload\"\n}\n```\n\n## Generate a chat completion\n\n```\nPOST /api/chat\n```\n\nGenerate the next message in a chat with a provided model. This is a streaming endpoint, so there will be a series of responses. Streaming can be disabled using `\"stream\": false`. The final response object will include statistics and additional data from the request.\n\n### Parameters\n\n- `model`: (required) the [model name](#model-names)\n- `messages`: the messages of the chat, this can be used to keep a chat memory\n- `tools`: list of tools in JSON for the model to use if supported\n\nThe `message` object has the following fields:\n\n- `role`: the role of the message, either `system`, `user`, `assistant`, or `tool`\n- `content`: the content of the message\n- `images` (optional): a list of images to include in the message (for multimodal models such as `llava`)\n- `tool_calls` (optional): a list of tools in JSON that the model wants to use\n\nAdvanced parameters (optional):\n\n- `format`: the format to return a response in. Format can be `json` or a JSON schema. \n- `options`: additional model parameters listed in the documentation for the [Modelfile](./modelfile.md#valid-parameters-and-values) such as `temperature`\n- `stream`: if `false` the response will be returned as a single response object, rather than a stream of objects\n- `keep_alive`: controls how long the model will stay loaded into memory following the request (default: `5m`)\n\n### Structured outputs\n\nStructured outputs are supported by providing a JSON schema in the `format` parameter. The model will generate a response that matches the schema. See the [Chat request (Structured outputs)](#chat-request-structured-outputs) example below.\n\n### Examples\n\n#### Chat Request (Streaming)\n\n##### Request\n\nSend a chat message with a streaming response.\n\n```shell\ncurl http://localhost:11434/api/chat -d '{\n  \"model\": \"llama3.2\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"why is the sky blue?\"\n    }\n  ]\n}'\n```\n\n##### Response\n\nA stream of JSON objects is returned:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-08-04T08:52:19.385406455-07:00\",\n  \"message\": {\n    \"role\": \"assistant\",\n    \"content\": \"The\",\n    \"images\": null\n  },\n  \"done\": false\n}\n```\n\nFinal response:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-08-04T19:22:45.499127Z\",\n  \"done\": true,\n  \"total_duration\": 4883583458,\n  \"load_duration\": 1334875,\n  \"prompt_eval_count\": 26,\n  \"prompt_eval_duration\": 342546000,\n  \"eval_count\": 282,\n  \"eval_duration\": 4535599000\n}\n```\n\n#### Chat request (No streaming)\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/chat -d '{\n  \"model\": \"llama3.2\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"why is the sky blue?\"\n    }\n  ],\n  \"stream\": false\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-12-12T14:13:43.416799Z\",\n  \"message\": {\n    \"role\": \"assistant\",\n    \"content\": \"Hello! How are you today?\"\n  },\n  \"done\": true,\n  \"total_duration\": 5191566416,\n  \"load_duration\": 2154458,\n  \"prompt_eval_count\": 26,\n  \"prompt_eval_duration\": 383809000,\n  \"eval_count\": 298,\n  \"eval_duration\": 4799921000\n}\n```\n\n#### Chat request (Structured outputs)\n\n##### Request\n\n```shell\ncurl -X POST http://localhost:11434/api/chat -H \"Content-Type: application/json\" -d '{\n  \"model\": \"llama3.1\",\n  \"messages\": [{\"role\": \"user\", \"content\": \"Ollama is 22 years old and busy saving the world. Return a JSON object with the age and availability.\"}],\n  \"stream\": false,\n  \"format\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"age\": {\n        \"type\": \"integer\"\n      },\n      \"available\": {\n        \"type\": \"boolean\"\n      }\n    },\n    \"required\": [\n      \"age\",\n      \"available\"\n    ]\n  },\n  \"options\": {\n    \"temperature\": 0\n  }\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llama3.1\",\n  \"created_at\": \"2024-12-06T00:46:58.265747Z\",\n  \"message\": { \"role\": \"assistant\", \"content\": \"{\\\"age\\\": 22, \\\"available\\\": false}\" },\n  \"done_reason\": \"stop\",\n  \"done\": true,\n  \"total_duration\": 2254970291,\n  \"load_duration\": 574751416,\n  \"prompt_eval_count\": 34,\n  \"prompt_eval_duration\": 1502000000,\n  \"eval_count\": 12,\n  \"eval_duration\": 175000000\n}\n```\n\n#### Chat request (With History)\n\nSend a chat message with a conversation history. You can use this same approach to start the conversation using multi-shot or chain-of-thought prompting.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/chat -d '{\n  \"model\": \"llama3.2\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"why is the sky blue?\"\n    },\n    {\n      \"role\": \"assistant\",\n      \"content\": \"due to rayleigh scattering.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"how is that different than mie scattering?\"\n    }\n  ]\n}'\n```\n\n##### Response\n\nA stream of JSON objects is returned:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-08-04T08:52:19.385406455-07:00\",\n  \"message\": {\n    \"role\": \"assistant\",\n    \"content\": \"The\"\n  },\n  \"done\": false\n}\n```\n\nFinal response:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-08-04T19:22:45.499127Z\",\n  \"done\": true,\n  \"total_duration\": 8113331500,\n  \"load_duration\": 6396458,\n  \"prompt_eval_count\": 61,\n  \"prompt_eval_duration\": 398801000,\n  \"eval_count\": 468,\n  \"eval_duration\": 7701267000\n}\n```\n\n#### Chat request (with images)\n\n##### Request\n\nSend a chat message with images. The images should be provided as an array, with the individual images encoded in Base64.\n\n```shell\ncurl http://localhost:11434/api/chat -d '{\n  \"model\": \"llava\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"what is in this image?\",\n      \"images\": [\"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\"]\n    }\n  ]\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llava\",\n  \"created_at\": \"2023-12-13T22:42:50.203334Z\",\n  \"message\": {\n    \"role\": \"assistant\",\n    \"content\": \" The image features a cute, little pig with an angry facial expression. It's wearing a heart on its shirt and is waving in the air. This scene appears to be part of a drawing or sketching project.\",\n    \"images\": null\n  },\n  \"done\": true,\n  \"total_duration\": 1668506709,\n  \"load_duration\": 1986209,\n  \"prompt_eval_count\": 26,\n  \"prompt_eval_duration\": 359682000,\n  \"eval_count\": 83,\n  \"eval_duration\": 1303285000\n}\n```\n\n#### Chat request (Reproducible outputs)\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/chat -d '{\n  \"model\": \"llama3.2\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Hello!\"\n    }\n  ],\n  \"options\": {\n    \"seed\": 101,\n    \"temperature\": 0\n  }\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2023-12-12T14:13:43.416799Z\",\n  \"message\": {\n    \"role\": \"assistant\",\n    \"content\": \"Hello! How are you today?\"\n  },\n  \"done\": true,\n  \"total_duration\": 5191566416,\n  \"load_duration\": 2154458,\n  \"prompt_eval_count\": 26,\n  \"prompt_eval_duration\": 383809000,\n  \"eval_count\": 298,\n  \"eval_duration\": 4799921000\n}\n```\n\n#### Chat request (with tools)\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/chat -d '{\n  \"model\": \"llama3.2\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"What is the weather today in Paris?\"\n    }\n  ],\n  \"stream\": false,\n  \"tools\": [\n    {\n      \"type\": \"function\",\n      \"function\": {\n        \"name\": \"get_current_weather\",\n        \"description\": \"Get the current weather for a location\",\n        \"parameters\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"location\": {\n              \"type\": \"string\",\n              \"description\": \"The location to get the weather for, e.g. San Francisco, CA\"\n            },\n            \"format\": {\n              \"type\": \"string\",\n              \"description\": \"The format to return the weather in, e.g. 'celsius' or 'fahrenheit'\",\n              \"enum\": [\"celsius\", \"fahrenheit\"]\n            }\n          },\n          \"required\": [\"location\", \"format\"]\n        }\n      }\n    }\n  ]\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\": \"2024-07-22T20:33:28.123648Z\",\n  \"message\": {\n    \"role\": \"assistant\",\n    \"content\": \"\",\n    \"tool_calls\": [\n      {\n        \"function\": {\n          \"name\": \"get_current_weather\",\n          \"arguments\": {\n            \"format\": \"celsius\",\n            \"location\": \"Paris, FR\"\n          }\n        }\n      }\n    ]\n  },\n  \"done_reason\": \"stop\",\n  \"done\": true,\n  \"total_duration\": 885095291,\n  \"load_duration\": 3753500,\n  \"prompt_eval_count\": 122,\n  \"prompt_eval_duration\": 328493000,\n  \"eval_count\": 33,\n  \"eval_duration\": 552222000\n}\n```\n\n#### Load a model\n\nIf the messages array is empty, the model will be loaded into memory.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/chat -d '{\n  \"model\": \"llama3.2\",\n  \"messages\": []\n}'\n```\n\n##### Response\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\":\"2024-09-12T21:17:29.110811Z\",\n  \"message\": {\n    \"role\": \"assistant\",\n    \"content\": \"\"\n  },\n  \"done_reason\": \"load\",\n  \"done\": true\n}\n```\n\n#### Unload a model\n\nIf the messages array is empty and the `keep_alive` parameter is set to `0`, a model will be unloaded from memory.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/chat -d '{\n  \"model\": \"llama3.2\",\n  \"messages\": [],\n  \"keep_alive\": 0\n}'\n```\n\n##### Response\n\nA single JSON object is returned:\n\n```json\n{\n  \"model\": \"llama3.2\",\n  \"created_at\":\"2024-09-12T21:33:17.547535Z\",\n  \"message\": {\n    \"role\": \"assistant\",\n    \"content\": \"\"\n  },\n  \"done_reason\": \"unload\",\n  \"done\": true\n}\n```\n\n## Create a Model\n\n```\nPOST /api/create\n```\n\nCreate a model from:\n * another model;\n * a safetensors directory; or\n * a GGUF file.\n\nIf you are creating a model from a safetensors directory or from a GGUF file, you must [create a blob](#create-a-blob) for each of the files and then use the file name and SHA256 digest associated with each blob in the `files` field.\n\n### Parameters\n\n- `model`: name of the model to create\n- `from`: (optional) name of an existing model to create the new model from\n- `files`: (optional) a dictionary of file names to SHA256 digests of blobs to create the model from\n- `adapters`: (optional) a dictionary of file names to SHA256 digests of blobs for LORA adapters\n- `template`: (optional) the prompt template for the model\n- `license`: (optional) a string or list of strings containing the license or licenses for the model\n- `system`: (optional) a string containing the system prompt for the model\n- `parameters`: (optional) a dictionary of parameters for the model (see [Modelfile](./modelfile.md#valid-parameters-and-values) for a list of parameters)\n- `messages`: (optional) a list of message objects used to create a conversation\n- `stream`: (optional) if `false` the response will be returned as a single response object, rather than a stream of objects\n- `quantize` (optional): quantize a non-quantized (e.g. float16) model\n\n#### Quantization types\n\n| Type | Recommended |\n| --- | :-: |\n| q2_K | |\n| q3_K_L | |\n| q3_K_M | |\n| q3_K_S | |\n| q4_0 | |\n| q4_1 | |\n| q4_K_M | * |\n| q4_K_S | |\n| q5_0 | |\n| q5_1 | |\n| q5_K_M | |\n| q5_K_S | |\n| q6_K | |\n| q8_0 | * |\n\n### Examples\n\n#### Create a new model\n\nCreate a new model from an existing model.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/create -d '{\n  \"model\": \"mario\",\n  \"from\": \"llama3.2\",\n  \"system\": \"You are Mario from Super Mario Bros.\"\n}'\n```\n\n##### Response\n\nA stream of JSON objects is returned:\n\n```json\n{\"status\":\"reading model metadata\"}\n{\"status\":\"creating system layer\"}\n{\"status\":\"using already created layer sha256:22f7f8ef5f4c791c1b03d7eb414399294764d7cc82c7e94aa81a1feb80a983a2\"}\n{\"status\":\"using already created layer sha256:8c17c2ebb0ea011be9981cc3922db8ca8fa61e828c5d3f44cb6ae342bf80460b\"}\n{\"status\":\"using already created layer sha256:7c23fb36d80141c4ab8cdbb61ee4790102ebd2bf7aeff414453177d4f2110e5d\"}\n{\"status\":\"using already created layer sha256:2e0493f67d0c8c9c68a8aeacdf6a38a2151cb3c4c1d42accf296e19810527988\"}\n{\"status\":\"using already created layer sha256:2759286baa875dc22de5394b4a925701b1896a7e3f8e53275c36f75a877a82c9\"}\n{\"status\":\"writing layer sha256:df30045fe90f0d750db82a058109cecd6d4de9c90a3d75b19c09e5f64580bb42\"}\n{\"status\":\"writing layer sha256:f18a68eb09bf925bb1b669490407c1b1251c5db98dc4d3d81f3088498ea55690\"}\n{\"status\":\"writing manifest\"}\n{\"status\":\"success\"}\n```\n\n#### Quantize a model\n\nQuantize a non-quantized model.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/create -d '{\n  \"model\": \"llama3.1:quantized\",\n  \"from\": \"llama3.1:8b-instruct-fp16\",\n  \"quantize\": \"q4_K_M\"\n}'\n```\n\n##### Response\n\nA stream of JSON objects is returned:\n\n```json\n{\"status\":\"quantizing F16 model to Q4_K_M\"}\n{\"status\":\"creating new layer sha256:667b0c1932bc6ffc593ed1d03f895bf2dc8dc6df21db3042284a6f4416b06a29\"}\n{\"status\":\"using existing layer sha256:11ce4ee3e170f6adebac9a991c22e22ab3f8530e154ee669954c4bc73061c258\"}\n{\"status\":\"using existing layer sha256:0ba8f0e314b4264dfd19df045cde9d4c394a52474bf92ed6a3de22a4ca31a177\"}\n{\"status\":\"using existing layer sha256:56bb8bd477a519ffa694fc449c2413c6f0e1d3b1c88fa7e3c9d88d3ae49d4dcb\"}\n{\"status\":\"creating new layer sha256:455f34728c9b5dd3376378bfb809ee166c145b0b4c1f1a6feca069055066ef9a\"}\n{\"status\":\"writing manifest\"}\n{\"status\":\"success\"}\n```\n\n#### Create a model from GGUF\n\nCreate a model from a GGUF file. The `files` parameter should be filled out with the file name and SHA256 digest of the GGUF file you wish to use. Use [/api/blobs/:digest](#push-a-blob) to push the GGUF file to the server before calling this API.\n\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/create -d '{\n  \"model\": \"my-gguf-model\",\n  \"files\": {\n    \"test.gguf\": \"sha256:432f310a77f4650a88d0fd59ecdd7cebed8d684bafea53cbff0473542964f0c3\"\n  }\n}'\n```\n\n##### Response\n\nA stream of JSON objects is returned:\n\n```json\n{\"status\":\"parsing GGUF\"}\n{\"status\":\"using existing layer sha256:432f310a77f4650a88d0fd59ecdd7cebed8d684bafea53cbff0473542964f0c3\"}\n{\"status\":\"writing manifest\"}\n{\"status\":\"success\"}\n```\n\n\n#### Create a model from a Safetensors directory\n\nThe `files` parameter should include a dictionary of files for the safetensors model which includes the file names and SHA256 digest of each file. Use [/api/blobs/:digest](#push-a-blob) to first push each of the files to the server before calling this API. Files will remain in the cache until the Ollama server is restarted.\n\n##### Request\n\n```shell\ncurl http://localhost:11434/api/create -d '{\n  \"model\": \"fred\",\n  \"files\": {\n    \"config.json\": \"sha256:dd3443e529fb2290423a0c65c2d633e67b419d273f170259e27297219828e389\",\n    \"generation_config.json\": \"sha256:88effbb63300dbbc7390143fbbdd9d9fa50587b37e8bfd16c8c90d4970a74a36\",\n    \"special_tokens_map.json\": \"sha256:b7455f0e8f00539108837bfa586c4fbf424e31f8717819a6798be74bef813d05\",\n    \"tokenizer.json\": \"sha256:bbc1904d35169c542dffbe1f7589a5994ec7426d9e5b609d07bab876f32e97ab\",\n    \"tokenizer_config.json\": \"sha256:24e8a6dc2547164b7002e3125f10b415105644fcf02bf9ad8b674c87b1eaaed6\",\n    \"model.safetensors\": \"sha256:1ff795ff6a07e6a68085d206fb84417da2f083f68391c2843cd2b8ac6df8538f\"\n  }\n}'\n```\n\n##### Response\n\nA stream of JSON objects is returned:\n\n```shell\n{\"status\":\"converting model\"}\n{\"status\":\"creating new layer sha256:05ca5b813af4a53d2c2922933936e398958855c44ee534858fcfd830940618b6\"}\n{\"status\":\"using autodetected template llama3-instruct\"}\n{\"status\":\"using existing layer sha256:56bb8bd477a519ffa694fc449c2413c6f0e1d3b1c88fa7e3c9d88d3ae49d4dcb\"}\n{\"status\":\"writing manifest\"}\n{\"status\":\"success\"}\n```\n\n## Check if a Blob Exists\n\n```shell\nHEAD /api/blobs/:digest\n```\n\nEnsures that the file blob (Binary Large Object) used with create a model exists on the server. This checks your Ollama server and not ollama.com.\n\n### Query Parameters\n\n- `digest`: the SHA256 digest of the blob\n\n### Examples\n\n#### Request\n\n```shell\ncurl -I http://localhost:11434/api/blobs/sha256:29fdb92e57cf0827ded04ae6461b5931d01fa595843f55d36f5b275a52087dd2\n```\n\n#### Response\n\nReturn 200 OK if the blob exists, 404 Not Found if it does not.\n\n## Push a Blob\n\n```\nPOST /api/blobs/:digest\n```\n\nPush a file to the Ollama server to create a \"blob\" (Binary Large Object).\n\n### Query Parameters\n\n- `digest`: the expected SHA256 digest of the file\n\n### Examples\n\n#### Request\n\n```shell\ncurl -T model.gguf -X POST http://localhost:11434/api/blobs/sha256:29fdb92e57cf0827ded04ae6461b5931d01fa595843f55d36f5b275a52087dd2\n```\n\n#### Response\n\nReturn 201 Created if the blob was successfully created, 400 Bad Request if the digest used is not expected.\n\n## List Local Models\n\n```\nGET /api/tags\n```\n\nList models that are available locally.\n\n### Examples\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/tags\n```\n\n#### Response\n\nA single JSON object will be returned.\n\n```json\n{\n  \"models\": [\n    {\n      \"name\": \"codellama:13b\",\n      \"modified_at\": \"2023-11-04T14:56:49.277302595-07:00\",\n      \"size\": 7365960935,\n      \"digest\": \"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697\",\n      \"details\": {\n        \"format\": \"gguf\",\n        \"family\": \"llama\",\n        \"families\": null,\n        \"parameter_size\": \"13B\",\n        \"quantization_level\": \"Q4_0\"\n      }\n    },\n    {\n      \"name\": \"llama3:latest\",\n      \"modified_at\": \"2023-12-07T09:32:18.757212583-08:00\",\n      \"size\": 3825819519,\n      \"digest\": \"fe938a131f40e6f6d40083c9f0f430a515233eb2edaa6d72eb85c50d64f2300e\",\n      \"details\": {\n        \"format\": \"gguf\",\n        \"family\": \"llama\",\n        \"families\": null,\n        \"parameter_size\": \"7B\",\n        \"quantization_level\": \"Q4_0\"\n      }\n    }\n  ]\n}\n```\n\n## Show Model Information\n\n```\nPOST /api/show\n```\n\nShow information about a model including details, modelfile, template, parameters, license, system prompt.\n\n### Parameters\n\n- `model`: name of the model to show\n- `verbose`: (optional) if set to `true`, returns full data for verbose response fields\n\n### Examples\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/show -d '{\n  \"model\": \"llama3.2\"\n}'\n```\n\n#### Response\n\n```json\n{\n  \"modelfile\": \"# Modelfile generated by \\\"ollama show\\\"\\n# To build a new Modelfile based on this one, replace the FROM line with:\\n# FROM llava:latest\\n\\nFROM /Users/matt/.ollama/models/blobs/sha256:200765e1283640ffbd013184bf496e261032fa75b99498a9613be4e94d63ad52\\nTEMPLATE \\\"\\\"\\\"{{ .System }}\\nUSER: {{ .Prompt }}\\nASSISTANT: \\\"\\\"\\\"\\nPARAMETER num_ctx 4096\\nPARAMETER stop \\\"\\u003c/s\\u003e\\\"\\nPARAMETER stop \\\"USER:\\\"\\nPARAMETER stop \\\"ASSISTANT:\\\"\",\n  \"parameters\": \"num_keep                       24\\nstop                           \\\"<|start_header_id|>\\\"\\nstop                           \\\"<|end_header_id|>\\\"\\nstop                           \\\"<|eot_id|>\\\"\",\n  \"template\": \"{{ if .System }}<|start_header_id|>system<|end_header_id|>\\n\\n{{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|>\\n\\n{{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|>\\n\\n{{ .Response }}<|eot_id|>\",\n  \"details\": {\n    \"parent_model\": \"\",\n    \"format\": \"gguf\",\n    \"family\": \"llama\",\n    \"families\": [\n      \"llama\"\n    ],\n    \"parameter_size\": \"8.0B\",\n    \"quantization_level\": \"Q4_0\"\n  },\n  \"model_info\": {\n    \"general.architecture\": \"llama\",\n    \"general.file_type\": 2,\n    \"general.parameter_count\": 8030261248,\n    \"general.quantization_version\": 2,\n    \"llama.attention.head_count\": 32,\n    \"llama.attention.head_count_kv\": 8,\n    \"llama.attention.layer_norm_rms_epsilon\": 0.00001,\n    \"llama.block_count\": 32,\n    \"llama.context_length\": 8192,\n    \"llama.embedding_length\": 4096,\n    \"llama.feed_forward_length\": 14336,\n    \"llama.rope.dimension_count\": 128,\n    \"llama.rope.freq_base\": 500000,\n    \"llama.vocab_size\": 128256,\n    \"tokenizer.ggml.bos_token_id\": 128000,\n    \"tokenizer.ggml.eos_token_id\": 128009,\n    \"tokenizer.ggml.merges\": [],            // populates if `verbose=true`\n    \"tokenizer.ggml.model\": \"gpt2\",\n    \"tokenizer.ggml.pre\": \"llama-bpe\",\n    \"tokenizer.ggml.token_type\": [],        // populates if `verbose=true`\n    \"tokenizer.ggml.tokens\": []             // populates if `verbose=true`\n  }\n}\n```\n\n## Copy a Model\n\n```\nPOST /api/copy\n```\n\nCopy a model. Creates a model with another name from an existing model.\n\n### Examples\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/copy -d '{\n  \"source\": \"llama3.2\",\n  \"destination\": \"llama3-backup\"\n}'\n```\n\n#### Response\n\nReturns a 200 OK if successful, or a 404 Not Found if the source model doesn't exist.\n\n## Delete a Model\n\n```\nDELETE /api/delete\n```\n\nDelete a model and its data.\n\n### Parameters\n\n- `model`: model name to delete\n\n### Examples\n\n#### Request\n\n```shell\ncurl -X DELETE http://localhost:11434/api/delete -d '{\n  \"model\": \"llama3:13b\"\n}'\n```\n\n#### Response\n\nReturns a 200 OK if successful, 404 Not Found if the model to be deleted doesn't exist.\n\n## Pull a Model\n\n```\nPOST /api/pull\n```\n\nDownload a model from the ollama library. Cancelled pulls are resumed from where they left off, and multiple calls will share the same download progress.\n\n### Parameters\n\n- `model`: name of the model to pull\n- `insecure`: (optional) allow insecure connections to the library. Only use this if you are pulling from your own library during development.\n- `stream`: (optional) if `false` the response will be returned as a single response object, rather than a stream of objects\n\n### Examples\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/pull -d '{\n  \"model\": \"llama3.2\"\n}'\n```\n\n#### Response\n\nIf `stream` is not specified, or set to `true`, a stream of JSON objects is returned:\n\nThe first object is the manifest:\n\n```json\n{\n  \"status\": \"pulling manifest\"\n}\n```\n\nThen there is a series of downloading responses. Until any of the download is completed, the `completed` key may not be included. The number of files to be downloaded depends on the number of layers specified in the manifest.\n\n```json\n{\n  \"status\": \"downloading digestname\",\n  \"digest\": \"digestname\",\n  \"total\": 2142590208,\n  \"completed\": 241970\n}\n```\n\nAfter all the files are downloaded, the final responses are:\n\n```json\n{\n    \"status\": \"verifying sha256 digest\"\n}\n{\n    \"status\": \"writing manifest\"\n}\n{\n    \"status\": \"removing any unused layers\"\n}\n{\n    \"status\": \"success\"\n}\n```\n\nif `stream` is set to false, then the response is a single JSON object:\n\n```json\n{\n  \"status\": \"success\"\n}\n```\n\n## Push a Model\n\n```\nPOST /api/push\n```\n\nUpload a model to a model library. Requires registering for ollama.ai and adding a public key first.\n\n### Parameters\n\n- `model`: name of the model to push in the form of `<namespace>/<model>:<tag>`\n- `insecure`: (optional) allow insecure connections to the library. Only use this if you are pushing to your library during development.\n- `stream`: (optional) if `false` the response will be returned as a single response object, rather than a stream of objects\n\n### Examples\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/push -d '{\n  \"model\": \"mattw/pygmalion:latest\"\n}'\n```\n\n#### Response\n\nIf `stream` is not specified, or set to `true`, a stream of JSON objects is returned:\n\n```json\n{ \"status\": \"retrieving manifest\" }\n```\n\nand then:\n\n```json\n{\n  \"status\": \"starting upload\",\n  \"digest\": \"sha256:bc07c81de745696fdf5afca05e065818a8149fb0c77266fb584d9b2cba3711ab\",\n  \"total\": 1928429856\n}\n```\n\nThen there is a series of uploading responses:\n\n```json\n{\n  \"status\": \"starting upload\",\n  \"digest\": \"sha256:bc07c81de745696fdf5afca05e065818a8149fb0c77266fb584d9b2cba3711ab\",\n  \"total\": 1928429856\n}\n```\n\nFinally, when the upload is complete:\n\n```json\n{\"status\":\"pushing manifest\"}\n{\"status\":\"success\"}\n```\n\nIf `stream` is set to `false`, then the response is a single JSON object:\n\n```json\n{ \"status\": \"success\" }\n```\n\n## Generate Embeddings\n\n```\nPOST /api/embed\n```\n\nGenerate embeddings from a model\n\n### Parameters\n\n- `model`: name of model to generate embeddings from\n- `input`: text or list of text to generate embeddings for\n\nAdvanced parameters:\n\n- `truncate`: truncates the end of each input to fit within context length. Returns error if `false` and context length is exceeded. Defaults to `true`\n- `options`: additional model parameters listed in the documentation for the [Modelfile](./modelfile.md#valid-parameters-and-values) such as `temperature`\n- `keep_alive`: controls how long the model will stay loaded into memory following the request (default: `5m`)\n\n### Examples\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/embed -d '{\n  \"model\": \"all-minilm\",\n  \"input\": \"Why is the sky blue?\"\n}'\n```\n\n#### Response\n\n```json\n{\n  \"model\": \"all-minilm\",\n  \"embeddings\": [[\n    0.010071029, -0.0017594862, 0.05007221, 0.04692972, 0.054916814,\n    0.008599704, 0.105441414, -0.025878139, 0.12958129, 0.031952348\n  ]],\n  \"total_duration\": 14143917,\n  \"load_duration\": 1019500,\n  \"prompt_eval_count\": 8\n}\n```\n\n#### Request (Multiple input)\n\n```shell\ncurl http://localhost:11434/api/embed -d '{\n  \"model\": \"all-minilm\",\n  \"input\": [\"Why is the sky blue?\", \"Why is the grass green?\"]\n}'\n```\n\n#### Response\n\n```json\n{\n  \"model\": \"all-minilm\",\n  \"embeddings\": [[\n    0.010071029, -0.0017594862, 0.05007221, 0.04692972, 0.054916814,\n    0.008599704, 0.105441414, -0.025878139, 0.12958129, 0.031952348\n  ],[\n    -0.0098027075, 0.06042469, 0.025257962, -0.006364387, 0.07272725,\n    0.017194884, 0.09032035, -0.051705178, 0.09951512, 0.09072481\n  ]]\n}\n```\n\n## List Running Models\n```\nGET /api/ps\n```\n\nList models that are currently loaded into memory.\n\n#### Examples\n\n### Request\n\n```shell\ncurl http://localhost:11434/api/ps\n```\n\n#### Response\n\nA single JSON object will be returned.\n\n```json\n{\n  \"models\": [\n    {\n      \"name\": \"mistral:latest\",\n      \"model\": \"mistral:latest\",\n      \"size\": 5137025024,\n      \"digest\": \"2ae6f6dd7a3dd734790bbbf58b8909a606e0e7e97e94b7604e0aa7ae4490e6d8\",\n      \"details\": {\n        \"parent_model\": \"\",\n        \"format\": \"gguf\",\n        \"family\": \"llama\",\n        \"families\": [\n          \"llama\"\n        ],\n        \"parameter_size\": \"7.2B\",\n        \"quantization_level\": \"Q4_0\"\n      },\n      \"expires_at\": \"2024-06-04T14:38:31.83753-07:00\",\n      \"size_vram\": 5137025024\n    }\n  ]\n}\n```\n\n## Generate Embedding\n\n> Note: this endpoint has been superseded by `/api/embed`\n\n```\nPOST /api/embeddings\n```\n\nGenerate embeddings from a model\n\n### Parameters\n\n- `model`: name of model to generate embeddings from\n- `prompt`: text to generate embeddings for\n\nAdvanced parameters:\n\n- `options`: additional model parameters listed in the documentation for the [Modelfile](./modelfile.md#valid-parameters-and-values) such as `temperature`\n- `keep_alive`: controls how long the model will stay loaded into memory following the request (default: `5m`)\n\n### Examples\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/embeddings -d '{\n  \"model\": \"all-minilm\",\n  \"prompt\": \"Here is an article about llamas...\"\n}'\n```\n\n#### Response\n\n```json\n{\n  \"embedding\": [\n    0.5670403838157654, 0.009260174818336964, 0.23178744316101074, -0.2916173040866852, -0.8924556970596313,\n    0.8785552978515625, -0.34576427936553955, 0.5742510557174683, -0.04222835972905159, -0.137906014919281\n  ]\n}\n```\n\n## Version\n\n```\nGET /api/version\n```\n\nRetrieve the Ollama version\n\n### Examples\n\n#### Request\n\n```shell\ncurl http://localhost:11434/api/version\n```\n\n#### Response\n\n```json\n{\n  \"version\": \"0.5.1\"\n}\n```\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[project]\nname = \"ollama-scan\"\nversion = \"0.1.0\"\ndescription = \"Add your description here\"\nreadme = \"README.md\"\nrequires-python = \">=3.12\"\ndependencies = [\n    \"ollama>=0.4.7\",\n    \"prompt-toolkit>=3.0.50\",\n    \"rich>=13.9.4\",\n    \"urllib3>=2.3.0\",\n]\n"
  },
  {
    "path": "requirements.txt",
    "content": "ollama\nprompt_toolkit\nrich\nurllib3"
  }
]