diff --git a/gpt4all-backend/deps/llama.cpp-mainline b/gpt4all-backend/deps/llama.cpp-mainline index 58a55efc..b06658d3 160000 --- a/gpt4all-backend/deps/llama.cpp-mainline +++ b/gpt4all-backend/deps/llama.cpp-mainline @@ -1 +1 @@ -Subproject commit 58a55efc4ae5dd3bc12887d47981faa7136027af +Subproject commit b06658d366abe3cea92f4e868db72165531a74da diff --git a/gpt4all-chat/CHANGELOG.md b/gpt4all-chat/CHANGELOG.md index 451495d3..1b909d64 100644 --- a/gpt4all-chat/CHANGELOG.md +++ b/gpt4all-chat/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Added +- Support DeepSeek-R1 Qwen models ([#3431](https://github.com/nomic-ai/gpt4all/pull/3431)) + ### Fixed - Fix regression while using localdocs with server API ([#3410](https://github.com/nomic-ai/gpt4all/pull/3410)) - Don't show system messages in server chat view ([#3411](https://github.com/nomic-ai/gpt4all/pull/3411)) diff --git a/gpt4all-chat/src/chatllm.cpp b/gpt4all-chat/src/chatllm.cpp index 5fe5f41c..17bdec77 100644 --- a/gpt4all-chat/src/chatllm.cpp +++ b/gpt4all-chat/src/chatllm.cpp @@ -64,6 +64,14 @@ namespace ranges = std::ranges; //#define DEBUG //#define DEBUG_MODEL_LOADING +static std::string jinjaGetStringArg(const jinja2::ValuesMap &args, const std::string &name) +{ + auto arg = args.find(name); + if (arg == args.end() || !arg->second.isString()) + throw std::runtime_error(fmt::format("'{}' argument to raise_exception() must be a string", name)); + return arg->second.asString(); +} + // NOTE: not threadsafe static jinja2::TemplateEnv *jinjaEnv() { @@ -75,27 +83,34 @@ static jinja2::TemplateEnv *jinjaEnv() settings.lstripBlocks = true; env.AddGlobal("raise_exception", jinja2::UserCallable( /*callable*/ [](auto ¶ms) -> jinja2::Value { - auto messageArg = params.args.find("message"); - if (messageArg == params.args.end() || !messageArg->second.isString()) - throw std::runtime_error("'message' argument to raise_exception() must be a string"); - throw std::runtime_error(fmt::format("Jinja template error: {}", messageArg->second.asString())); + auto message = jinjaGetStringArg(params.args, "message"); + throw std::runtime_error(fmt::format("Jinja template error: {}", message)); }, /*argsInfo*/ { jinja2::ArgInfo("message", /*isMandatory*/ true) } )); env.AddGlobal("strftime_now", jinja2::UserCallable( /*callable*/ [](auto ¶ms) -> jinja2::Value { using Clock = std::chrono::system_clock; - auto formatArg = params.args.find("format"); - if (formatArg == params.args.end() || !formatArg->second.isString()) - throw std::runtime_error("'format' argument to strftime_now() must be a string"); + auto format = jinjaGetStringArg(params.args, "format"); time_t nowUnix = Clock::to_time_t(Clock::now()); auto localDate = *std::localtime(&nowUnix); std::ostringstream ss; - ss << std::put_time(&localDate, formatArg->second.asString().c_str()); + ss << std::put_time(&localDate, format.c_str()); return ss.str(); }, /*argsInfo*/ { jinja2::ArgInfo("format", /*isMandatory*/ true) } )); + env.AddGlobal("regex_replace", jinja2::UserCallable( + /*callable*/ [](auto ¶ms) -> jinja2::Value { + auto str = jinjaGetStringArg(params.args, "str" ); + auto pattern = jinjaGetStringArg(params.args, "pattern"); + auto repl = jinjaGetStringArg(params.args, "repl" ); + return std::regex_replace(str, std::regex(pattern), repl); + }, + /*argsInfo*/ { jinja2::ArgInfo("str", /*isMandatory*/ true), + jinja2::ArgInfo("pattern", /*isMandatory*/ true), + jinja2::ArgInfo("repl", /*isMandatory*/ true) } + )); } return &*environment; } diff --git a/gpt4all-chat/src/jinja_replacements.cpp b/gpt4all-chat/src/jinja_replacements.cpp index c80a2521..f86d28a9 100644 --- a/gpt4all-chat/src/jinja_replacements.cpp +++ b/gpt4all-chat/src/jinja_replacements.cpp @@ -52,6 +52,30 @@ const std::unordered_map CHAT_TEMPLATE_SUBST {{- '<|assistant|>\n' }} {%- else %} {{- eos_token }} +{%- endif %})TEMPLATE", + }, + // DeepSeek-R1-Distill-Qwen-7B-Q4_0.gguf + { + // original + R"TEMPLATE({% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='') %}{%- for message in messages %}{%- if message['role'] == 'system' %}{% set ns.system_prompt = message['content'] %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\n' + '```json' + '\n' + tool['function']['arguments'] + '\n' + '```' + '<|tool▁call▁end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\n' + '```json' + '\n' + tool['function']['arguments'] + '\n' + '```' + '<|tool▁call▁end|>'}}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{% set content = message['content'] %}{% if '' in content %}{% set content = content.split('')[-1] %}{% endif %}{{'<|Assistant|>' + content + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\n<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|>'}}{% endif %})TEMPLATE", + // replacement + R"TEMPLATE({%- if not add_generation_prompt is defined %} + {%- set add_generation_prompt = false %} +{%- endif %} +{%- if messages[0]['role'] == 'system' %} + {{- messages[0]['content'] }} +{%- endif %} +{%- for message in messages %} + {%- if message['role'] == 'user' %} + {{- '<|User|>' + message['content'] }} + {%- endif %} + {%- if message['role'] == 'assistant' %} + {%- set content = message['content'] | regex_replace('^[\\s\\S]*', '') %} + {{- '<|Assistant|>' + content + '<|end▁of▁sentence|>' }} + {%- endif %} +{%- endfor -%} +{%- if add_generation_prompt %} + {{- '<|Assistant|>' }} {%- endif %})TEMPLATE", }, // gemma-2-9b-it-Q4_0.gguf (nomic-ai/gpt4all#3282)