diff --git a/src/main/java/de/extio/lmlib/prompt/Gemma4PromptStrategy.java b/src/main/java/de/extio/lmlib/prompt/Gemma4PromptStrategy.java new file mode 100644 index 0000000..7a5398c --- /dev/null +++ b/src/main/java/de/extio/lmlib/prompt/Gemma4PromptStrategy.java @@ -0,0 +1,121 @@ +package de.extio.lmlib.prompt; + +public class Gemma4PromptStrategy implements PromptStrategy { + + private static final String TURN_END = ""; + private static final String THOUGHT_START = "<|channel>thought\n"; + private static final String THOUGHT_END = "\n"; + private static final String SYSTEM_START = "<|turn>system\n"; + private static final String USER_START = "<|turn>user\n"; + private static final String MODEL_START = "<|turn>model\n"; + + @Override + public String getPromptName() { + return "gemma4"; + } + + @Override + public StringBuilder start(final String system, final String user) { + final StringBuilder prompt = new StringBuilder(); + if (system != null && !system.isEmpty()) { + prompt.append(SYSTEM_START); + prompt.append(system); + prompt.append(TURN_END).append("\n"); + } + if (user != null && !user.isEmpty()) { + prompt.append(USER_START); + prompt.append(user); + prompt.append(TURN_END).append("\n"); + } + prompt.append(MODEL_START); + return prompt; + } + + @Override + public void next(final StringBuilder prompt, final String assistant, final String user) { + final String assistantContent = assistant == null ? "" : assistant; + if (assistantContent.startsWith(MODEL_START) && this.endsWith(prompt, MODEL_START)) { + prompt.setLength(prompt.length() - MODEL_START.length()); + } + prompt.append(assistantContent); + if (!assistantContent.endsWith(TURN_END)) { + if (!assistantContent.endsWith("\n")) { + prompt.append("\n"); + } + prompt.append(TURN_END).append("\n"); + } + else if (!assistantContent.endsWith(TURN_END + "\n")) { + prompt.append("\n"); + } + if (user != null && !user.isEmpty()) { + prompt.append(USER_START); + prompt.append(user); + prompt.append(TURN_END).append("\n"); + } + prompt.append(MODEL_START); + } + + @Override + public String removeEOT(final String prompt) { + if (prompt == null) { + return null; + } + return prompt.strip().replace(TURN_END, ""); + } + + @Override + public String getResponse(final String prompt) { + final String assistantBlock = this.assistantBlock(prompt); + if (assistantBlock == null) { + return null; + } + final int thoughtEnd = assistantBlock.indexOf(THOUGHT_END); + if (thoughtEnd != -1) { + return assistantBlock.substring(thoughtEnd + THOUGHT_END.length()).strip(); + } + return assistantBlock.strip(); + } + + @Override + public String getReasoning(final String prompt) { + final String assistantBlock = this.assistantBlock(prompt); + if (assistantBlock == null) { + return null; + } + final int thoughtStart = assistantBlock.indexOf(THOUGHT_START); + final int thoughtEnd = assistantBlock.indexOf(THOUGHT_END); + if (thoughtStart != -1 && thoughtEnd > thoughtStart) { + return assistantBlock.substring(thoughtStart + THOUGHT_START.length(), thoughtEnd).strip(); + } + return null; + } + + private String assistantBlock(final String prompt) { + if (prompt == null) { + return null; + } + String assistantBlock = prompt; + final int lastAssistantStart = prompt.lastIndexOf(MODEL_START); + if (lastAssistantStart != -1) { + assistantBlock = prompt.substring(lastAssistantStart + MODEL_START.length()); + } + final int turnEnd = assistantBlock.indexOf(TURN_END); + if (turnEnd != -1) { + assistantBlock = assistantBlock.substring(0, turnEnd); + } + return assistantBlock; + } + + private boolean endsWith(final StringBuilder value, final String suffix) { + if (value.length() < suffix.length()) { + return false; + } + for (int i = 0; i < suffix.length(); i++) { + if (value.charAt(value.length() - suffix.length() + i) != suffix.charAt(i)) { + return false; + } + } + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/de/extio/lmlib/prompt/GemmaPromptStrategy.java b/src/main/java/de/extio/lmlib/prompt/GemmaPromptStrategy.java index db414bb..cd2f24d 100755 --- a/src/main/java/de/extio/lmlib/prompt/GemmaPromptStrategy.java +++ b/src/main/java/de/extio/lmlib/prompt/GemmaPromptStrategy.java @@ -30,7 +30,7 @@ public class GemmaPromptStrategy implements PromptStrategy { @Override public String getPromptName() { - return "gemma"; + return "gemma2,3"; } } diff --git a/src/main/java/de/extio/lmlib/prompt/PromptAutoConfiguration.java b/src/main/java/de/extio/lmlib/prompt/PromptAutoConfiguration.java index 9748a56..d483778 100644 --- a/src/main/java/de/extio/lmlib/prompt/PromptAutoConfiguration.java +++ b/src/main/java/de/extio/lmlib/prompt/PromptAutoConfiguration.java @@ -35,6 +35,12 @@ public class PromptAutoConfiguration { return new GemmaPromptStrategy(); } + @Bean + @ConditionalOnMissingBean + Gemma4PromptStrategy gemma4PromptStrategy() { + return new Gemma4PromptStrategy(); + } + @Bean @ConditionalOnMissingBean GptOssPromptStrategy gptOssPromptStrategy() { @@ -89,6 +95,12 @@ public class PromptAutoConfiguration { return new Qwen3PromptStrategy(); } + @Bean + @ConditionalOnMissingBean + Qwen35PromptStrategy qwen35PromptStrategy() { + return new Qwen35PromptStrategy(); + } + @Bean @ConditionalOnMissingBean VicunaPromptStrategy vicunaPromptStrategy() { diff --git a/src/main/java/de/extio/lmlib/prompt/Qwen35PromptStrategy.java b/src/main/java/de/extio/lmlib/prompt/Qwen35PromptStrategy.java new file mode 100644 index 0000000..4703884 --- /dev/null +++ b/src/main/java/de/extio/lmlib/prompt/Qwen35PromptStrategy.java @@ -0,0 +1,130 @@ +package de.extio.lmlib.prompt; + +public class Qwen35PromptStrategy implements PromptStrategy { + + private static final String IM_END = "<|im_end|>"; + private static final String THINK_START = ""; + private static final String THINK_END = ""; + + private static final String SYSTEM_START = "<|im_start|>system\n"; + private static final String USER_START = "<|im_start|>user\n"; + private static final String ASSISTANT_START = "<|im_start|>assistant\n"; + private static final String ASSISTANT_GENERATION_START = ASSISTANT_START + THINK_START + "\n"; + + @Override + public String getPromptName() { + return "qwen3.5"; + } + + @Override + public StringBuilder start(final String system, final String user) { + final StringBuilder prompt = new StringBuilder(); + if (system != null && !system.isEmpty()) { + prompt.append(SYSTEM_START); + prompt.append(system); + prompt.append(IM_END).append("\n"); + } + if (user != null && !user.isEmpty()) { + prompt.append(USER_START); + prompt.append(user); + prompt.append(IM_END).append("\n"); + } + prompt.append(ASSISTANT_GENERATION_START); + return prompt; + } + + @Override + public void next(final StringBuilder prompt, final String assistant, final String user) { + final String assistantContent = assistant == null ? "" : assistant; + if (this.endsWith(prompt, ASSISTANT_GENERATION_START)) { + prompt.setLength(prompt.length() - ASSISTANT_GENERATION_START.length()); + } + prompt.append(ASSISTANT_START); + prompt.append(assistantContent); + if (!assistantContent.endsWith(IM_END)) { + if (!assistantContent.endsWith("\n")) { + prompt.append("\n"); + } + prompt.append(IM_END).append("\n"); + } + else if (!assistantContent.endsWith(IM_END + "\n")) { + prompt.append("\n"); + } + if (user != null && !user.isEmpty()) { + prompt.append(USER_START); + prompt.append(user); + prompt.append(IM_END).append("\n"); + } + prompt.append(ASSISTANT_GENERATION_START); + } + + @Override + public String removeEOT(final String prompt) { + if (prompt == null) { + return null; + } + return prompt.strip().replace(IM_END, ""); + } + + @Override + public String getResponse(final String prompt) { + final String assistantBlock = this.assistantBlock(prompt); + if (assistantBlock == null) { + return null; + } + final int thinkEnd = assistantBlock.indexOf(THINK_END); + if (thinkEnd != -1) { + return assistantBlock.substring(thinkEnd + THINK_END.length()).strip(); + } + if (assistantBlock.startsWith(THINK_START) || assistantBlock.startsWith("\n")) { + return ""; + } + return assistantBlock.strip(); + } + + @Override + public String getReasoning(final String prompt) { + final String assistantBlock = this.assistantBlock(prompt); + if (assistantBlock == null) { + return null; + } + final int thinkStart = assistantBlock.indexOf(THINK_START); + final int thinkEnd = assistantBlock.indexOf(THINK_END); + if (thinkEnd == -1) { + return null; + } + if (thinkStart != -1 && thinkEnd > thinkStart) { + return assistantBlock.substring(thinkStart + THINK_START.length(), thinkEnd).strip(); + } + return assistantBlock.substring(0, thinkEnd).strip(); + } + + private String assistantBlock(final String prompt) { + if (prompt == null) { + return null; + } + String assistantBlock = prompt; + final int lastAssistantStart = prompt.lastIndexOf(ASSISTANT_START); + if (lastAssistantStart != -1) { + assistantBlock = prompt.substring(lastAssistantStart + ASSISTANT_START.length()); + } + final int end = assistantBlock.indexOf(IM_END); + if (end != -1) { + assistantBlock = assistantBlock.substring(0, end); + } + return assistantBlock; + } + + private boolean endsWith(final StringBuilder value, final String suffix) { + if (value.length() < suffix.length()) { + return false; + } + for (int i = 0; i < suffix.length(); i++) { + if (value.charAt(value.length() - suffix.length() + i) != suffix.charAt(i)) { + return false; + } + } + return true; + } + +} \ No newline at end of file