| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import json |
| import os.path |
| import sys |
| import time |
| import traceback |
|
|
| if "/www/server/panel/class" not in sys.path: |
| sys.path.append('/www/server/panel/class') |
|
|
| import public |
| from mod.project.docker.app.base import App |
|
|
| class OllamaBase(App): |
| def __init__(self): |
| super(OllamaBase, self).__init__() |
| self.ollama_port = "11434" |
| self.ollama_local_url = "http://127.0.0.1:{}".format(self.ollama_port) |
|
|
| def set_ollama_port(self, port): |
| self.ollama_port = port |
| self.ollama_local_url = self.ollama_local_url.format(port) |
| return self |
|
|
| def set_ollama_local_url(self, port): |
| self.ollama_local_url = "http://127.0.0.1:{}".format(port) |
| return self |
|
|
|
|
| class OllamaMod(OllamaBase): |
|
|
| def __init__(self): |
| super(OllamaMod, self).__init__() |
|
|
| |
| |
| def list_local_models(self): |
| uri = "/api/tags" |
|
|
| ps_json, stderr = public.ExecShell("docker-compose -p {service_name} ps --format json | {grep_v}".format( |
| service_name=self.service_name.lower(), |
| grep_v=self.grep_version, |
| )) |
| if "Segmentation fault" in ps_json: |
| return [] |
|
|
| if not ps_json.startswith("["): |
| ps = json.loads("[" + ps_json.strip().replace("\n", ",") + "]") |
| else: |
| ps = json.loads(ps_json.strip().replace("\n", ",")) |
|
|
| try: |
| p_port = "11434" |
| for i in ps: |
| if "ollama/ollama" in i["Image"]: |
| if len(i["Publishers"]) == 0: break |
| p_port = i["Publishers"][0]["PublishedPort"] |
| except: |
| p_port = "11434" |
|
|
| self.set_ollama_local_url(p_port) |
| url = self.ollama_local_url + uri |
| response = public.HttpGet(url) |
| if not response: return [] |
| response = json.loads(response) |
|
|
| if "models" in response: |
| models = response["models"] |
| for i in models: |
| i["version"] = i["name"].split(":")[-1] if ":" in i["name"] else i["name"] |
| i["l_name"] = i["name"].split(":")[0] if ":" in i["name"] else i["name"] |
| return models |
| return [] |
|
|
| |
| |
| def show_model_info(self, get): |
| ''' |
| @name 获取指定模型的信息 |
| ''' |
| get.model_name = get.get("model_name", None) |
| if get.model_name is None: |
| return public.returnResult(False, "model_name参数不能为空") |
| get.model_version = get.get("model_version", None) |
| if get.model_version is None: |
| return public.returnResult(False, "model_version参数不能为空") |
| get.service_name = get.get("service_name", None) |
| if get.service_name is None: |
| return public.returnResult(False, "service_name参数不能为空") |
|
|
| self.set_service_name(get.service_name) |
| uri = "/api/show" |
| ps_json, stderr = public.ExecShell("docker-compose -p {service_name} ps --format json | {grep_v}".format( |
| service_name=self.service_name.lower(), |
| grep_v=self.grep_version, |
| )) |
| if "Segmentation fault" in ps_json: |
| return [] |
|
|
| if not ps_json.startswith("["): |
| ps = json.loads("[" + ps_json.strip().replace("\n", ",") + "]") |
| else: |
| ps = json.loads(ps_json.strip().replace("\n", ",")) |
|
|
| try: |
| p_port = "11434" |
| for i in ps: |
| if "ollama/ollama" in i["Image"]: |
| if len(i["Publishers"]) == 0: break |
| p_port = i["Publishers"][0]["PublishedPort"] |
| except: |
| p_port = "11434" |
|
|
| self.set_ollama_local_url(p_port) |
|
|
| url = self.ollama_local_url + uri |
| param = {"model": "{}:{}".format(get.model_name, get.model_version)} |
|
|
| import requests |
| response = requests.post(url, data=json.dumps(param), timeout=10) |
|
|
| return public.returnResult(True, data=response.json()) |
|
|
| |
| def list_online_models(self): |
| ''' |
| @name 获取在线的所有models |
| ''' |
| if not os.path.exists(self.ollama_online_models_file): |
| public.downloadFile(public.get_url() + '/src/dk_app/apps/ollama_model.json', self.ollama_online_models_file) |
|
|
| try: |
| models = json.loads(public.readFile(self.ollama_online_models_file)) |
|
|
| res = [] |
| for i in models: |
| res.append({ |
| "name": i["name"], |
| "description": i["zh_cn_msg"], |
| "version": i["parameters"], |
| "size": i["size"], |
| "can_down": True, |
| }) |
|
|
| return res |
| except: |
| return [] |
|
|
| |
| def get_models_list(self, get): |
| ''' |
| @name 获取模型列表 |
| ''' |
| get.search = get.get("search", "") |
| get.p = get.get("p/d", 1) |
| get.row = get.get("limit/d", 20) |
| get.service_name = get.get("service_name", None) |
| if get.service_name is None: |
| return public.returnResult(False, "service_name参数不能为空") |
| get.status = get.get("status", "all") |
| self.set_service_name(get.service_name) |
|
|
| local_models = self.list_local_models() |
| public.print_log(local_models) |
| online_models = self.list_online_models() |
| res = [] |
| can_down = True |
| if os.path.exists("/tmp/nocandown.pl"): |
| can_down = False |
|
|
| |
| for i in online_models: |
| i["can_down"] = can_down |
|
|
| i["status"] = "uninstall" |
| for j in local_models: |
| if i["name"] == j["l_name"]: |
| i["status"] = "installed" if i["version"] == j["version"] else "uninstall" |
|
|
| if os.path.exists("/tmp/{model_name}:{model_version}.failed".format( |
| model_name=i["name"], |
| model_version=i["version"], |
| )): |
| i["status"] = "failed" |
|
|
| if os.path.exists("/tmp/{model_name}:{model_version}.pl".format( |
| model_name=i["name"], |
| model_version=i["version"], |
| )): |
| i["status"] = "downloading" |
|
|
| if i["status"] in ("installed", "failed", "downloading"): |
| break |
|
|
| if get.status != "all": |
| if get.status != i["status"]: continue |
| if get.search != "": |
| if get.search not in i["name"] and get.search not in i["description"]: continue |
|
|
| res.append(i) |
|
|
| page_data = self.get_page(res, get) |
| return self.pageResult(True, data=page_data["data"], page=page_data["page"]) |
|
|
| |
| def down_models(self, get): |
| ''' |
| @name 给指定应用安装指定模型 |
| @param service_name 服务名称 |
| @param model_name 模型名称 |
| @param model_version 模型版本 |
| ''' |
| get.service_name = get.get("service_name", None) |
| if get.service_name is None: |
| return public.returnResult(False, "service_name参数不能为空") |
| get.model_name = get.get("model_name", None) |
| if get.model_name is None: |
| return public.returnResult(False, "model_name参数不能为空") |
| get.model_version = get.get("model_version", None) |
| if get.model_version is None: |
| return public.returnResult(False, "model_version参数不能为空") |
|
|
| self.set_service_name(get.service_name) |
|
|
| |
| ps_json, stderr = public.ExecShell("docker-compose -p {service_name} ps --format json | {grep_v}".format( |
| service_name=self.service_name.lower(), |
| grep_v=self.grep_version, |
| )) |
| if "Segmentation fault" in ps_json: |
| return public.returnResult(False, "获取容器信息失败,docker-compose执行异常!") |
|
|
| if not ps_json.startswith("["): |
| ps = json.loads("[" + ps_json.strip().replace("\n", ",") + "]") |
| else: |
| ps = json.loads(ps_json.strip().replace("\n", ",")) |
|
|
| try: |
| p_port = "11434" |
| for i in ps: |
| if "ollama/ollama" in i["Image"]: |
| if len(i["Publishers"]) == 0: break |
| p_port = i["Publishers"][0]["PublishedPort"] |
| except: |
| p_port = "11434" |
|
|
| self.set_ollama_local_url(p_port) |
| |
| |
| self.set_cmd_log() |
| public.ExecShell("echo > {}".format(self.app_cmd_log)) |
| |
| |
| from mod.project.docker.app.sub_app.downModel import download_model |
| import threading |
| |
| |
| download_thread = threading.Thread( |
| target=download_model, |
| args=( |
| get.service_name, |
| get.model_name, |
| get.model_version, |
| self.ollama_local_url, |
| self.app_cmd_log |
| ) |
| ) |
| download_thread.daemon = True |
| download_thread.start() |
|
|
| return public.returnResult(True, "正在下载模型,请稍后查看日志") |
|
|
| |
| def del_models(self, get): |
| ''' |
| @name 删除指定应用的指定模型 |
| ''' |
| get.service_name = get.get("service_name", None) |
| if get.service_name is None: |
| return public.returnResult(False, "service_name参数不能为空") |
| get.model_name = get.get("model_name", None) |
| if get.model_name is None: |
| return public.returnResult(False, "model_name参数不能为空") |
| get.model_version = get.get("model_version", None) |
| if get.model_version is None: |
| return public.returnResult(False, "model_version参数不能为空") |
|
|
| self.set_service_name(get.service_name) |
|
|
| ps_json, stderr = public.ExecShell("docker-compose -p {service_name} ps --format json | {grep_v}".format( |
| service_name=self.service_name.lower(), |
| grep_v=self.grep_version, |
| )) |
| if "Segmentation fault" in ps_json: |
| return public.returnResult(True, "删除模型失败,docker-compose执行异常!") |
|
|
| if not ps_json.startswith("["): |
| ps = json.loads("[" + ps_json.strip().replace("\n", ",") + "]") |
| else: |
| ps = json.loads(ps_json.strip().replace("\n", ",")) |
|
|
| serviceName = get.service_name |
| if len(ps) == 2: |
| serviceName = "ollama" |
|
|
| cmd = ("docker-compose -p {service_name} exec -it {serviceName} ollama rm {model_name}:{model_version}".format( |
| service_name=get.service_name.lower(), |
| serviceName=serviceName, |
| model_name=get.model_name, |
| model_version=get.model_version, |
| )) |
| public.ExecShell(cmd) |
| return public.returnResult(True, "删除模型成功!") |
|
|