From 67068a9dbb0d1d50dc1f744fa9d30077e93f52cd Mon Sep 17 00:00:00 2001 From: wailovet Date: Wed, 5 Jun 2024 02:44:41 +0800 Subject: [PATCH] 'update' --- __init__.py | 31 +++- half_json.py | 349 +++++++++++++++++++++++++++++++++++++++++ mz_gen_translate.py | 1 + mz_llama_core_nodes.py | 151 ++++++++++++++++-- mz_llama_cpp.py | 43 ++++- mz_prompt_utils.py | 105 +++++++++---- mz_prompts.py | 20 +++ 7 files changed, 657 insertions(+), 43 deletions(-) create mode 100644 half_json.py diff --git a/__init__.py b/__init__.py index 1c19d5e..c6dd6d0 100644 --- a/__init__.py +++ b/__init__.py @@ -60,9 +60,12 @@ class MZ_LLamaCPPModelConfig_ManualSelect: @classmethod def INPUT_TYPES(s): gguf_files = Utils.get_gguf_files() + + chat_format = mz_llama_cpp.get_llama_cpp_chat_handlers() return { "required": { "llama_cpp_model": (gguf_files,), + "chat_format": (["auto"] + chat_format, {"default": "auto"}), }, "optional": { }, @@ -82,9 +85,13 @@ class MZ_LLamaCPPModelConfig_ManualSelect: llama_cpp_model = os.path.join( Utils.get_gguf_models_path(), llama_cpp_model) + chat_format = kwargs.get("chat_format", "auto") + if chat_format == "auto": + chat_format = None return ({ "type": "ManualSelect", "model_path": llama_cpp_model, + "chat_format": chat_format, },) @@ -100,9 +107,11 @@ class MZ_LLamaCPPModelConfig_DownloaderSelect: model_names = [ model["model"] for model in optional_models ] + chat_format = mz_llama_cpp.get_llama_cpp_chat_handlers() return { "required": { "model_name": (model_names,), + "chat_format": (["auto"] + chat_format, {"default": "auto"}), }, "optional": { }, @@ -118,9 +127,13 @@ class MZ_LLamaCPPModelConfig_DownloaderSelect: kwargs = kwargs.copy() model_name = kwargs.get("model_name", "") + chat_format = kwargs.get("chat_format", "auto") + if chat_format == "auto": + chat_format = None return ({ "type": "DownloaderSelect", "model_name": model_name, + "chat_format": chat_format, },) @@ -211,6 +224,9 @@ class MZ_LLamaCPPOptions: opt = {} for key in kwargs: opt[key] = kwargs[key] + + # if opt.get("chat_format", None) == "auto": + # opt["chat_format"] = None return (opt,) @@ -370,6 +386,7 @@ class MZ_ImageInterrogatorCLIPTextEncode: return { "required": { "resolution": ("INT", {"default": 512, "min": 128, "max": 0xffffffffffffffff}), + "post_processing": ([False, True], {"default": True}), "keep_device": ([False, True], {"default": False}), "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), }, @@ -406,10 +423,12 @@ class MZ_ImageInterrogatorModelConfig_ManualSelect: @classmethod def INPUT_TYPES(s): gguf_files = Utils.get_gguf_files() + chat_format = mz_llama_cpp.get_llama_cpp_chat_handlers() return { "required": { "llama_cpp_model": (gguf_files,), "mmproj_model": (["auto"] + gguf_files,), + "chat_format": (["auto"] + chat_format, {"default": "auto"}), }, "optional": { }, @@ -434,10 +453,14 @@ class MZ_ImageInterrogatorModelConfig_ManualSelect: mmproj_model = os.path.join( Utils.get_gguf_models_path(), mmproj_model) + chat_format = kwargs.get("chat_format", "auto") + if chat_format == "auto": + chat_format = None return ({ "type": "ManualSelect", "model_path": llama_cpp_model, "mmproj_model": mmproj_model, + "chat_format": chat_format, },) @@ -459,10 +482,12 @@ class MZ_ImageInterrogatorModelConfig_DownloaderSelect: model["model"] for model in optional_models ] + chat_format = mz_llama_cpp.get_llama_cpp_chat_handlers() return { "required": { "model_name": (model_names,), - "mmproj_model_name": (mmproj_model_names,), + "mmproj_model_name": (["auto"] + mmproj_model_names,), + "chat_format": (["auto"] + chat_format, {"default": "auto"}), }, "optional": { }, @@ -478,10 +503,14 @@ class MZ_ImageInterrogatorModelConfig_DownloaderSelect: kwargs = kwargs.copy() model_name = kwargs.get("model_name") mmproj_model_name = kwargs.get("mmproj_model_name", "auto") + chat_format = kwargs.get("chat_format", "auto") + if chat_format == "auto": + chat_format = None return ({ "type": "DownloaderSelect", "model_name": model_name, "mmproj_model_name": mmproj_model_name, + "chat_format": chat_format, },) diff --git a/half_json.py b/half_json.py new file mode 100644 index 0000000..c02f19f --- /dev/null +++ b/half_json.py @@ -0,0 +1,349 @@ +# coding=utf8 +import json +from typing import Any, List, NamedTuple, Optional, Tuple +import json.decoder +from json.decoder import JSONDecodeError as PyJSONDecodeError, JSONDecoder, py_scanstring +from json.scanner import py_make_scanner +from typing import Any, Dict, NamedTuple, Optional, Tuple, Union + + +class FixResult(NamedTuple): + success: bool + line: str + origin: bool + + +class JSONFixer: + def __init__(self, max_try: int = 20, max_stack: int = 3, *, js_style: bool = False) -> None: + self._max_try = max_try + self._max_stack = max_stack + self._js_style = js_style + self.last_fix: Optional[bool] = None + self.fix_stack: List[str] = [] + + def fix(self, line: str, *, strict: bool = True) -> FixResult: + try: + json.loads(line, strict=strict) + return FixResult(success=True, line=line, origin=True) + except Exception: + pass + + ok, new_line = self.fixwithtry(line, strict=strict) + return FixResult(success=ok, line=new_line, origin=False) + + def fixwithtry(self, line: str, *, strict: bool = True) -> Tuple[bool, str]: + if self._max_try <= 0: + return False, line + + self.fix_stack = [] + self.last_fix = None + + ok = False + for _ in range(self._max_try): + ok, new_line = self.patch_line(line, strict=strict) + if ok: + return ok, new_line + + self.last_fix = line != new_line + if self.last_fix: + self.fix_stack.insert(0, new_line) + self.fix_stack = self.fix_stack[: self._max_stack] + + line = new_line + return ok, line + + def patch_line(self, line: str, *, strict: bool = True) -> Tuple[bool, str]: + result = decode_line(line, strict=strict) + if result.success: + return True, line + + if isinstance(result.exception, ValueError): + return self.patch_value_error(line, result.err_info) + + if isinstance(result.exception, StopIteration): + return self.patch_stop_iteration(line) + + if result.exception is None: + return self.patch_half_parse(line, result.err_info) + + return False, line + + def patch_value_error(self, line: str, err_info: Any) -> Tuple[bool, str]: + if err_info["error"] is None: + return False, line + + error = err_info["error"] + pos = err_info["pos"] + nextchar = line[pos: pos + 1] + lastchar = line[pos - 1: pos] + nextline = line[pos:] + lastline = line[:pos] + + if error == errors.StringUnterminatedString: + return False, insert_line(line, '"', len(line)) + if error == errors.ObjectExceptKey: + if nextchar == "": + return False, insert_line(line, "}", pos) + if nextchar == ":": + return False, insert_line(line, '""', pos) + if lastchar in "{," and nextchar == ",": + return False, remove_line(line, pos, pos + 1) + if lastchar == "," and nextchar == "}": + return False, remove_line(line, pos - 1, pos) + if nextchar in "[{": + return False, insert_line(line, '"":', pos) + if self._js_style: + # find 'abc' + if nextchar == "'": + nextline = remove_line(nextline, 0, 1) + idx = nextline.find(":") + if idx != -1 and idx != 0 and nextline[idx - 1] == "'": + nextline = remove_line(nextline, idx - 1, idx) + + return False, lastline + nextline + # abc:1 --> "aabc":1 + idx = nextline.find(":") + if idx != -1: + line = lastline + insert_line(nextline, '"', idx) + return False, insert_line(line, '"', pos) + # TODO process more case " + return False, insert_line(line, '"', pos) + if error == errors.ObjectExceptColon: + return False, insert_line(line, ":", pos) + if error == errors.ObjectExceptObject: + if nextchar == "": + if lastchar == "{": + return False, insert_line(line, "}", pos) + return False, insert_line(line, "null}", pos) + if nextchar == "}": + return False, insert_line(line, "null", pos) + # TODO guess more + return False, insert_line(line, '"', pos) + if error == errors.ObjectExceptComma: + if nextchar == "": + return False, insert_line(line, "}", pos) + return False, insert_line(line, ",", pos) + if error == errors.ArrayExceptObject: + if nextchar == "," and lastchar == "[": + return False, remove_line(line, pos, pos + 1) + if nextchar == ",": + return False, insert_line(line, "null", pos) + if nextchar == "]": + return False, remove_line(line, pos - 1, pos) + if nextchar == "": + if lastchar == "[": + return False, insert_line(line, "]", pos) + return False, insert_line(line, "null]", pos) + # TODO guess more? + return False, insert_line(line, "{", pos) + if error == errors.ArrayExceptComma: + if len(line) == pos: + return False, insert_line(line, "]", pos) + return False, insert_line(line, ",", pos) + # TODO unknonwn + return False, line + + def patch_stop_iteration(self, line: str) -> Tuple[bool, str]: + # TODO clean + # TODO fix + # 1. }] + # 2. ]} + # 3. constans + # 4. - + # 先 patch 完 {[]} + # TODO: process number + if line.startswith("-."): + new_line = "-0." + line[2:] + return False, new_line + # patch + left = patch_lastest_left_object_and_array(line) + if left == "": + if not self.last_fix: + left = patch_guess_left(line) + + new_line = left + line + return False, new_line + + def patch_half_parse(self, line: str, err_info: Any) -> Tuple[bool, str]: + obj, end = err_info + nextline = line[end:].strip() + nextchar = nextline[:1] + left = patch_lastest_left_object_and_array(nextline) + # ?? + if left == "": + if nextchar == ",": + left = "[" + elif nextchar == ":" and isinstance(obj, str): + left = "{" + else: + if not self.last_fix: + left = patch_guess_left(nextline) + + new_line = left + line[:end] + nextline + return False, new_line + + +# TODO better name +def patch_lastest_left_object_and_array(line: str) -> str: + # '}]{[' --> '[{}]{[' + pairs = {"}": "{", "]": "["} + breaks = "{[" + left = "" + for char in line: + if char in breaks: + break + if char in pairs: + left = pairs[char] + left + + return left + + +# TODO better name +# TODO 改成 lastest +# TODO {}}]]]] --> { not [ +def patch_guess_left(line: str) -> str: + miss_object = line.count("}") - line.count("{") + miss_array = line.count("]") - line.count("[") + if miss_object == miss_array == 0: + if line[-1:] == '"' and line.count('"') == 1: + return '"' + elif miss_object >= miss_array: + return "{" + else: + return "[" + return "" + + +def insert_line(line: str, value: str, pos: int) -> str: + return line[:pos] + value + line[pos:] + + +def remove_line(line: str, start: int, end: int) -> str: + return line[:start] + line[end:] + + +class JSONDecodeError: + def __init__(self, parser, message): + self.message = message + self.parser = parser + + def __eq__(self, err): + return err.parser == self.parser and self.message in err.message + + +class errors: + StringInvalidUXXXXEscape = JSONDecodeError( + "py_scanstring", "Invalid \\uXXXX escape") + # 2 different case + StringUnterminatedString = JSONDecodeError( + "py_scanstring", "Unterminated string starting at") + StringInvalidControlCharacter = JSONDecodeError( + "py_scanstring", "Invalid control character") + StringInvalidEscape = JSONDecodeError("py_scanstring", "Invalid \\escape") + ObjectExceptColon = JSONDecodeError( + "JSONObject", "Expecting ':' delimiter") + ObjectExceptObject = JSONDecodeError("JSONObject", "Expecting value") + # 2 different case + ObjectExceptKey = JSONDecodeError( + "JSONObject", "Expecting property name enclosed in double quotes") + ObjectExceptComma = JSONDecodeError( + "JSONObject", "Expecting ',' delimiter") + ArrayExceptObject = JSONDecodeError("JSONArray", "Expecting value") + ArrayExceptComma = JSONDecodeError("JSONArray", "Expecting ',' delimiter") + + @classmethod + def get_decode_error(cls, parser, message): + err = JSONDecodeError(parser, message) + for _, value in cls.__dict__.items(): + if isinstance(value, JSONDecodeError): + if err == value: + return value + return None + + """ + 01 先不看,不研究 + 02 badcase: " --> "" success + 03 控制符 pass + 04 unicode \\u 的 pass + 05 同上 + 06 object 后面没有跟随 " , badcase: {abc":1} --> {"abc":1} + 07 object key 后面没有 : , badcase: {"abc"1} --> {"abc":1} + 08 object 开始检测 Value 收到 StopIteration + 08.1 要么后面没有了 + 08.2 要么后面不是 "/{/[/n[ull]/t[rue]/f[alse]/number/NaN/Infinity/-Infinity 开头的东西 + -- 08.1 后面补上 null} + -- 08.2 无脑补一个 " + 09 object 解析完一个 pair 后,下一个不是}, 期待一个 ',' + badcase {"k":1"s":2} + 10 在 09 的基础上解析完{"k":1, 发现下一个不是 ", 这个后面再优化(暂时和 06 一致) + badcase {"k":1,x":2} + 11 array 开始检测 Value 收到 StopIteration + 11.1 要么后面没有了,补上] + 11.2 同 08.2,无脑补一个{ 看看 + 12 array 解析完前一个 object, 需要一个 , + 这里 nextchar 既不是 ] 也不是, 代表这个 nextchar 的 end 也已经+1 了,所以减 2 + """ + + +def errmsg_inv(e: ValueError) -> Dict[str, Any]: + assert isinstance(e, PyJSONDecodeError) + parser = e.__dict__.get("parser", "") + errmsg = e.msg + localerr = errors.get_decode_error(parser, errmsg) + return { + "parsers": e.__dict__.get("parsers", []), + "error": localerr, + "lineno": e.lineno, + "colno": e.colno, + "pos": e.pos, + } + + +def record_parser_name(parser: Any) -> Any: + def new_parser(*args: Any, **kwargs: Any) -> Any: + try: + return parser(*args, **kwargs) + except Exception as e: + if "parser" not in e.__dict__: + e.__dict__["parser"] = parser.__name__ + if "parsers" not in e.__dict__: + e.__dict__["parsers"] = [] + e.__dict__["parsers"].append(parser.__name__) + raise e + + return new_parser + + +def make_decoder(*, strict: bool = True) -> JSONDecoder: + json.decoder.scanstring = record_parser_name(py_scanstring) + + decoder = JSONDecoder(strict=strict) + decoder.parse_object = record_parser_name(decoder.parse_object) + decoder.parse_array = record_parser_name(decoder.parse_array) + decoder.parse_string = record_parser_name(py_scanstring) + decoder.parse_object = record_parser_name(decoder.parse_object) + + decoder.scan_once = py_make_scanner(decoder) + return decoder + + +decoder = make_decoder() +decoder_unstrict = make_decoder(strict=False) + + +class DecodeResult(NamedTuple): + success: bool + exception: Optional[Exception] + err_info: Optional[Union[Dict[str, Any], Tuple[Any, Any]]] + + +def decode_line(line: str, *, strict: bool = True) -> DecodeResult: + try: + obj, end = (decoder if strict else decoder_unstrict).scan_once(line, 0) + ok = end == len(line) + return DecodeResult(success=ok, exception=None, err_info=(obj, end)) + except StopIteration as e: + return DecodeResult(success=False, exception=e, err_info=None) + except ValueError as e: + err_info = errmsg_inv(e) + return DecodeResult(success=False, exception=e, err_info=err_info) diff --git a/mz_gen_translate.py b/mz_gen_translate.py index 157c265..0edc2af 100644 --- a/mz_gen_translate.py +++ b/mz_gen_translate.py @@ -35,6 +35,7 @@ ZH_Replace_Map = { "ModelConfigManualSelect": "手动模型选择器", "ModelConfigDownloaderSelect": "预设模型下载器", "captioner_config": "打标器配置", + "post_processing": "后处理", } diff --git a/mz_llama_core_nodes.py b/mz_llama_core_nodes.py index aae9c29..879e398 100644 --- a/mz_llama_core_nodes.py +++ b/mz_llama_core_nodes.py @@ -56,16 +56,23 @@ def get_style_presets(): def llama_cpp_node_encode(args_dict): importlib.reload(mz_prompts) importlib.reload(mz_llama_cpp) + # importlib.reload(mz_prompt_utils) model_config = args_dict.get("llama_cpp_model", {}) mz_prompt_utils.Utils.print_log(f"model_config: {model_config}") + chat_format = model_config.get("chat_format", None) + select_model_type = model_config.get("type", "ManualSelect") if select_model_type == "ManualSelect": model_file = model_config.get("model_path", "auto") if model_file == "auto": model_file = mz_prompt_utils.Utils.get_auto_model_fullpath( "Meta-Llama-3-8B-Instruct.Q4_K_M") + + if "llama-3" in mz_llama_cpp.get_llama_cpp_chat_handlers(): + chat_format = "llama-3" + elif select_model_type == "DownloaderSelect": model_name = model_config.get("model_name", "") model_file = mz_prompt_utils.Utils.get_auto_model_fullpath( @@ -81,6 +88,7 @@ def llama_cpp_node_encode(args_dict): keep_device = args_dict.get("keep_device", False) seed = args_dict.get("seed", -1) options["seed"] = seed + options["chat_format"] = chat_format customize_instruct = args_dict.get("customize_instruct", None) mz_prompt_utils.Utils.print_log( @@ -136,8 +144,19 @@ def llama_cpp_node_encode(args_dict): schema=schema, options=options, ) + try: + response_json = json.loads(response_text) + except Exception as e: + from . import half_json + print("json.loads failed, try fix response_text: ", response_text) + json_fixer = half_json.JSONFixer() + fix_resp = json_fixer.fix(response_text) + if fix_resp.success: + print("fix success, use fixed response_text: ", fix_resp.line) + response_json = json.loads(fix_resp.line) + else: + raise e - response_json = json.loads(response_text) mz_prompt_utils.Utils.print_log( f"response_json: {json.dumps(response_json, indent=2)}") @@ -322,6 +341,8 @@ def image_interrogator_node_encode(args_dict): "图片批量反推任务已完成 ; Image batch reverse push task completed") model_config = args_dict.get("image_interrogator_model", {}) + + chat_format = model_config.get("chat_format", None) llama_cpp_model = model_config.get("llama_cpp_model", "auto") mmproj_model = model_config.get("mmproj_model", "auto") @@ -401,13 +422,20 @@ def image_interrogator_node_encode(args_dict): seed = args_dict.get("seed", -1) options = args_dict.get("llama_cpp_options", {}) options["seed"] = seed + options["chat_format"] = chat_format image = mz_prompt_utils.Utils.resize_max(image, resolution, resolution) customize_instruct = args_dict.get("customize_instruct", None) if customize_instruct is None: - system_prompt = mz_prompts.M_ImageCaptioner_System - question = mz_prompts.M_ImageCaptioner_Prompt + # system_prompt = mz_prompts.GPT4VImageCaptioner_System + # question = mz_prompts.GPT4VImageCaptioner_Prompt + + # system_prompt = mz_prompts.M_ImageCaptioner2_System + # question = mz_prompts.M_ImageCaptioner2_Prompt + + system_prompt = "You are an assistant who perfectly describes images." + question = "Describe this image in detail please." else: system_prompt = customize_instruct.get("system", "") question = customize_instruct.get("instruct", "") @@ -421,13 +449,116 @@ def image_interrogator_node_encode(args_dict): system=system_prompt, question=question, ) - if response is not None: - response = response.strip() - if customize_instruct is None: - # 去除开头的In the image, - start_text = "In the image, " - if response.startswith(start_text): - response = response[len(start_text):] + response = response.strip() + if response is not None and response != "": + + if args_dict.get("post_processing", False): + + # 双引号换成空格 + response = response.replace("\"", " ") + # 中括号换成空格 + response = response.replace("[", " ") + response = response.replace("]", " ") + + # 括号换成空格 + response = response.replace("(", " ") + response = response.replace(")", " ") + + # 去除多余空格 + while response.find(" ") != -1: + response = response.replace(" ", " ") + + # 从第一个为英文字母的地方开始截取 + for i in range(len(response)): + if response[i].isalpha(): + response = response[i:] + break + + response = response.strip() + schema = get_schema_obj( + keys_type={ + "short_describes": get_schema_base_type("string"), + "subject_tags": get_schema_array("string"), + "action_tags": get_schema_array("string"), + "light_tags": get_schema_array("string"), + "scene_tags": get_schema_array("string"), + "mood_tags": get_schema_array("string"), + "style_tags": get_schema_array("string"), + "object_tags": get_schema_array("string"), + }, + required=[ + "short_describes", + "subject_tags", + "action_tags", + "lights_tags", + "scenes_tags", + "moods_tags", + "styles_tags", + "objects_tags", + ] + ) + response_json_str = mz_llama_cpp.llama_cpp_simple_interrogator_to_json( + model_file=llama_cpp_model, + system=mz_prompts.ImageCaptionerPostProcessing_System, + question=f"Content: {response}", + schema=schema, + options=options, + ) + + try: + response_json = json.loads(response_json_str) + except Exception as e: + from . import half_json + print("json.loads failed, try fix response_json_str: ", + response_json_str) + json_fixer = half_json.JSONFixer() + fix_resp = json_fixer.fix(response_json_str) + if fix_resp.success: + print("fix success, use fixed response_json_str: ", + fix_resp.line) + response_json = json.loads(fix_resp.line) + else: + raise e + + responses = [] + + def pure_words(text: str) -> bool: + number_of_spaces = text.count(" ") + if number_of_spaces > 2: + return False + for c in text: + if not c.isalpha() and c != "-" and c != "_" and c != " ": + return False + + return True + + for key, value in response_json.items(): + if type(value) == list: + + # 去除开头.和空格 + value = [v.strip().lstrip(".") for v in value] + # 去除空字符串 + value = [v for v in value if v != ""] + + # 去除带有空格和标点符号的字符串 + value = [ + v for v in value if pure_words(v)] + + # 空格换成下划线 + value = [v.replace(" ", "_") for v in value] + + # 首字母小写 + value = [v.lower() for v in value] + + if len(value) > 0: + responses.append(f"{', '.join(value)}") + + description = response_json.get("short_describes", "") + if description != "": + responses.append(f"{description}") + + # 对response进行去重 + response = ", ".join(responses) if keep_device is False: mz_llama_cpp.freed_gpu_memory(model_file=llama_cpp_model) diff --git a/mz_llama_cpp.py b/mz_llama_cpp.py index 327e5a9..e4d8cc9 100644 --- a/mz_llama_cpp.py +++ b/mz_llama_cpp.py @@ -1,3 +1,4 @@ +import copy import importlib import json import os @@ -109,8 +110,19 @@ def check_llama_cpp_requirements(): print("llama_cpp installed successfully. (llama_cpp安装成功)") +def get_llama_cpp_chat_handlers(): + check_llama_cpp_requirements() + from llama_cpp import llama_chat_format + chat_handlers = llama_chat_format.LlamaChatCompletionHandlerRegistry()._chat_handlers + chat_handlers = list(chat_handlers.keys()) + + return chat_handlers + + def LlamaCppOptions(): + # chat_handlers = ["auto"] + get_llama_cpp_chat_handlers() return { + # "chat_format": chat_handlers, "n_ctx": 2048, "n_batch": 2048, "n_threads": 0, @@ -170,6 +182,9 @@ def llama_cpp_messages(model_file, mmproj_file=None, messages=[], options={}): is_opts_changed = False + mz_prompt_utils.Utils.print_log( + f"llama_cpp_messages chat_format: {options.get('chat_format', None)}") + if model_and_opt is not None: for opt in init_opts: if model_and_opt.get("options").get(opt) != options.get(opt): @@ -259,6 +274,25 @@ def llama_cpp_messages(model_file, mmproj_file=None, messages=[], options={}): mirostat_mode = 1 elif options.get("mirostat_mode", "none") == "mirostat_v2": mirostat_mode = 2 + + try: + debuf_messages = copy.deepcopy(messages) + for dindex in range(len(debuf_messages)): + if debuf_messages[dindex].get("role") == "user": + debuf_messages_content = debuf_messages[dindex].get( + "content", []) + if type(debuf_messages_content) != list: + continue + for ccindex in range(len(debuf_messages_content)): + if debuf_messages_content[ccindex].get("type") == "image_url": + debuf_messages[dindex]["content"][ccindex]["image_url"] = debuf_messages[ + dindex]["content"][ccindex]["image_url"] = None + + mz_prompt_utils.Utils.print_log( + f"LLAMA_CPP messages: {json.dumps(debuf_messages, indent=4, ensure_ascii=False)}") + except Exception as e: + mz_prompt_utils.Utils.print_log( + f"LLAMA_CPP messages: {messages}") output = model.create_chat_completion( messages=messages, response_format=response_format, @@ -276,6 +310,8 @@ def llama_cpp_messages(model_file, mmproj_file=None, messages=[], options={}): mirostat_mode=mirostat_mode, mirostat_tau=options.get("mirostat_tau", 5.0), mirostat_eta=options.get("mirostat_eta", 0.1), + tools=options.get("tools", None), + tool_choice=options.get("tool_choice", None), ) mz_prompt_utils.Utils.print_log(f"LLAMA_CPP: \n{output}") choices = output.get("choices", []) @@ -330,7 +366,9 @@ def llama_cpp_simple_interrogator_to_json(model_file, use_system=True, system=No } options["response_format"] = response_format - options["chat_format"] = "chatml" + + # if options.get("chat_format", None) is None: + # options["chat_format"] = "llama-2" result = llama_cpp_messages(model_file, None, messages, options=options) result = result.replace("\n", " ") @@ -385,6 +423,9 @@ def llava_cpp_messages(model_file, mmproj_file, messages, options={}): options = options.copy() options["logits_all"] = True options["n_ctx"] = max(4096, options.get("n_ctx", 4096)) + + # if options.get("chat_format", None) is None: + # options["chat_format"] = "llama-2" return llama_cpp_messages(model_file, mmproj_file, messages, options) diff --git a/mz_prompt_utils.py b/mz_prompt_utils.py index c229f05..0e3ee8e 100644 --- a/mz_prompt_utils.py +++ b/mz_prompt_utils.py @@ -172,41 +172,81 @@ class Utils: os.makedirs(models_path, exist_ok=True) return models_path - def translate_text(text, from_code, to_code): + def get_translate_object(from_code, to_code): try: - import argostranslate - from argostranslate import translate - except ImportError: - subprocess.run([ - sys.executable, "-m", - "pip", "install", "argostranslate"], check=True) - import argostranslate - from argostranslate import translate + is_disabel_argostranslate = Utils.cache_get( + "is_disabel_argostranslate") - try: - translation = translate.get_translation_from_codes( - from_code, to_code) - if translation is None: - raise Exception("Translation not found") + if is_disabel_argostranslate is not None: + return None + try: + import argostranslate + from argostranslate import translate, package + except ImportError: + subprocess.run([ + sys.executable, "-m", + "pip", "install", "argostranslate"], check=True) + + try: + import argostranslate + from argostranslate import translate, package + except ImportError: + Utils.cache_set("is_disabel_argostranslate", True) + print( + "argostranslate not found and install failed , will disable it") + return None + + packages = package.get_installed_packages() + installed_packages = {} + for p in packages: + installed_packages[f"{p.from_code}_{p.to_code}"] = p + + argosmodel_dir = os.path.join( + Utils.get_models_path(), "argosmodel") + if not os.path.exists(argosmodel_dir): + os.makedirs(argosmodel_dir) + + model_name = None + if from_code == "zh" and to_code == "en": + model_name = "zh_en" + elif from_code == "en" and to_code == "zh": + model_name = "en_zh" + else: + return None + + if Utils.cache_get(f"argostranslate_{model_name}") is not None: + return Utils.cache_get(f"argostranslate_{model_name}") + + if installed_packages.get(model_name, None) is None: + if not os.path.exists(os.path.join(argosmodel_dir, f"translate-{model_name}-1_9.argosmodel")): + argosmodel_file = Utils.download_file( + url=f"https://www.modelscope.cn/api/v1/models/wailovet/MinusZoneAIModels/repo?Revision=master&FilePath=argosmodel%2Ftranslate-{model_name}-1_9.argosmodel", + filepath=os.path.join( + argosmodel_dir, f"translate-{model_name}-1_9.argosmodel"), + ) + else: + argosmodel_file = os.path.join( + argosmodel_dir, f"translate-{model_name}-1_9.argosmodel") + package.install_from_path(argosmodel_file) + + translate_object = translate.get_translation_from_codes( + from_code=from_code, to_code=to_code) + + Utils.cache_set(f"argostranslate_{model_name}", translate_object) + + return translate_object except Exception as e: - print(e) - argostranslate.package.update_package_index() - available_packages = argostranslate.package.get_available_packages() - package_to_install = next( - filter( - lambda x: (x.from_code == from_code and x.to_code == - to_code), available_packages, - ) - ) - download_path = package_to_install.download() - print("package_to_install.download():", download_path) - argostranslate.package.install_from_path(download_path) + Utils.cache_set("is_disabel_argostranslate", True) + print( + "argostranslate not found and install failed , will disable it") + print(f"get_translate_object error: {e}") + return None - translation = translate.get_translation_from_codes( - from_code, to_code) - if translation is None: - return text + def translate_text(text, from_code, to_code): + translation = Utils.get_translate_object(from_code, to_code) + if translation is None: + return text # Translate translatedText = translation.translate( @@ -677,6 +717,9 @@ class Utils: def to_debug_prompt(p): if p is None: return "" + zh = Utils.en2zh(p) + if p == zh: + return p zh = Utils.split_en_to_zh(p) p = p.strip() return f""" @@ -766,7 +809,7 @@ class Utils: cache_value = Utils.get_cache_by_local(cache_key) if cache_value is not None: return cache_value - + sha256 = Utils.file_hash(file_path, hashlib.sha256) Utils.set_cache_by_local(cache_key, sha256) return sha256 diff --git a/mz_prompts.py b/mz_prompts.py index c7a2328..bcb4724 100644 --- a/mz_prompts.py +++ b/mz_prompts.py @@ -47,3 +47,23 @@ Describe this image in detail please. The language of reply is English only!!! Starts with "In the image," """ + + +M_ImageCaptioner2_System = """ +You are an assistant who perfectly describes images. +""" + +M_ImageCaptioner2_Prompt = """ +Describe this image in detail please. +The language of reply is English only!!! +Starts with "In the image," +""" + + +ImageCaptionerPostProcessing_System = """ +I want you to write me a detailed list of tips for Content. +Write a very short description of the scene and put it in the 'short_describes' field +Write complete [moods, styles, lights, elements, objects] of the word array and put it in the '$_tags' field +Don't include anything that isn't in Content. +The language of reply is English only!!! +"""