mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-20 09:24:08 +00:00
feat: support DeepSeek R1 and V3 models
This commit is contained in:
parent
89a3b669c5
commit
4e149c54de
13 changed files with 300 additions and 64 deletions
|
|
@ -1,12 +1,12 @@
|
|||
package ee.carlrobert.codegpt;
|
||||
|
||||
import static java.io.File.separator;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
|
@ -26,18 +26,18 @@ public final class CodeGPTPlugin {
|
|||
}
|
||||
|
||||
public static @NotNull String getPluginOptionsPath() {
|
||||
return PathManager.getOptionsPath() + File.separator + "CodeGPT";
|
||||
return PathManager.getOptionsPath() + separator + "CodeGPT";
|
||||
}
|
||||
|
||||
public static @NotNull String getIndexStorePath() {
|
||||
return getPluginOptionsPath() + File.separator + "indexes";
|
||||
return getPluginOptionsPath() + separator + "indexes";
|
||||
}
|
||||
|
||||
public static @NotNull String getLlamaSourcePath() {
|
||||
return getPluginBasePath() + File.separator + "llama.cpp";
|
||||
return getPluginBasePath() + separator + "llama.cpp";
|
||||
}
|
||||
|
||||
public static @NotNull String getProjectIndexStorePath(@NotNull Project project) {
|
||||
return getIndexStorePath() + File.separator + project.getName();
|
||||
return getIndexStorePath() + separator + project.getName();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,17 @@ public enum HuggingFaceModel {
|
|||
DEEPSEEK_CODER_33B_Q5(33, 5, "deepseek-coder-33b-instruct-GGUF",
|
||||
"deepseek-coder-33b-instruct.Q5_K_M.gguf", 23.5),
|
||||
|
||||
DEEPSEEK_R1_1_5B_Q6(1, 6, "DeepSeek-R1-Distill-Qwen-1.5B-GGUF",
|
||||
"DeepSeek-R1-Distill-Qwen-1.5B-Q6_K.gguf", "bartowski", 1.89),
|
||||
DEEPSEEK_R1_7B_Q4(7, 4, "DeepSeek-R1-Distill-Qwen-7B-GGUF",
|
||||
"DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf", "bartowski", 4.68),
|
||||
DEEPSEEK_R1_7B_Q6(7, 6, "DeepSeek-R1-Distill-Qwen-7B-GGUF",
|
||||
"DeepSeek-R1-Distill-Qwen-7B-Q6_K.gguf", "bartowski", 6.25),
|
||||
DEEPSEEK_R1_14B_Q4(14, 4, "DeepSeek-R1-Distill-Qwen-14B-GGUF",
|
||||
"DeepSeek-R1-Distill-Qwen-14B-Q4_K_M.gguf", "bartowski", 8.99),
|
||||
DEEPSEEK_R1_14B_Q6(14, 6, "DeepSeek-R1-Distill-Qwen-14B-GGUF",
|
||||
"DeepSeek-R1-Distill-Qwen-14B-Q6_K.gguf", "bartowski", 12.12),
|
||||
|
||||
PHIND_CODE_LLAMA_34B_Q3(34, 3, "Phind-CodeLlama-34B-v2-GGUF",
|
||||
"phind-codellama-34b-v2.Q3_K_M.gguf"),
|
||||
PHIND_CODE_LLAMA_34B_Q4(34, 4, "Phind-CodeLlama-34B-v2-GGUF",
|
||||
|
|
|
|||
|
|
@ -64,6 +64,20 @@ public enum LlamaModel {
|
|||
HuggingFaceModel.DEEPSEEK_CODER_33B_Q3,
|
||||
HuggingFaceModel.DEEPSEEK_CODER_33B_Q4,
|
||||
HuggingFaceModel.DEEPSEEK_CODER_33B_Q5)),
|
||||
DEEPSEEK_R1(
|
||||
"Deepseek R1",
|
||||
"DeepSeek-R1-Zero, a model trained via large-scale reinforcement learning (RL) "
|
||||
+ "without supervised fine-tuning (SFT) as a preliminary step, demonstrated remarkable "
|
||||
+ "performance on reasoning. DeepSeek-R1 achieves performance comparable to OpenAI-o1 "
|
||||
+ "across math, code, and reasoning tasks.",
|
||||
PromptTemplate.DEEPSEEK_R1,
|
||||
InfillPromptTemplate.DEEPSEEK_CODER,
|
||||
List.of(
|
||||
HuggingFaceModel.DEEPSEEK_R1_1_5B_Q6,
|
||||
HuggingFaceModel.DEEPSEEK_R1_7B_Q4,
|
||||
HuggingFaceModel.DEEPSEEK_R1_7B_Q6,
|
||||
HuggingFaceModel.DEEPSEEK_R1_14B_Q4,
|
||||
HuggingFaceModel.DEEPSEEK_R1_14B_Q6)),
|
||||
PHIND_CODE_LLAMA(
|
||||
"Phind Code Llama",
|
||||
"This model is fine-tuned from Phind-CodeLlama-34B-v1 on an additional 1.5B tokens "
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ public final class LlamaServerAgent implements Disposable {
|
|||
|
||||
private static final Logger LOG = Logger.getInstance(LlamaServerAgent.class);
|
||||
|
||||
private @Nullable OSProcessHandler makeProcessHandler;
|
||||
private @Nullable OSProcessHandler makeSetupProcessHandler;
|
||||
private @Nullable OSProcessHandler makeBuildProcessHandler;
|
||||
private @Nullable OSProcessHandler startServerProcessHandler;
|
||||
private ServerProgressPanel activeServerProgressPanel;
|
||||
private boolean stoppedByUser;
|
||||
|
|
@ -49,11 +50,44 @@ public final class LlamaServerAgent implements Disposable {
|
|||
stoppedByUser = false;
|
||||
serverProgressPanel.displayText(
|
||||
CodeGPTBundle.get("llamaServerAgent.buildingProject.description"));
|
||||
makeProcessHandler = new OSProcessHandler(
|
||||
getMakeCommandLine(params));
|
||||
makeProcessHandler.addProcessListener(
|
||||
getMakeProcessListener(params, onSuccess, onServerStopped));
|
||||
makeProcessHandler.startNotify();
|
||||
|
||||
makeSetupProcessHandler = new OSProcessHandler(getCMakeSetupCommandLine(params));
|
||||
makeSetupProcessHandler.addProcessListener(new ProcessAdapter() {
|
||||
private final List<String> errorLines = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
|
||||
if (ProcessOutputType.isStderr(outputType)) {
|
||||
errorLines.add(event.getText());
|
||||
return;
|
||||
}
|
||||
LOG.info(event.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processTerminated(@NotNull ProcessEvent event) {
|
||||
int exitCode = event.getExitCode();
|
||||
LOG.info(format("CMake setup exited with code %d", exitCode));
|
||||
if (stoppedByUser) {
|
||||
onServerStopped.accept(activeServerProgressPanel);
|
||||
return;
|
||||
}
|
||||
if (exitCode != 0) {
|
||||
showServerError(String.join(",", errorLines), onServerStopped);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
makeBuildProcessHandler = new OSProcessHandler(getCMakeBuildCommandLine(params));
|
||||
makeBuildProcessHandler.addProcessListener(
|
||||
getMakeProcessListener(params, onSuccess, onServerStopped));
|
||||
makeBuildProcessHandler.startNotify();
|
||||
} catch (ExecutionException e) {
|
||||
showServerError(e.getMessage(), onServerStopped);
|
||||
}
|
||||
}
|
||||
});
|
||||
makeSetupProcessHandler.startNotify();
|
||||
} catch (ExecutionException e) {
|
||||
showServerError(e.getMessage(), onServerStopped);
|
||||
}
|
||||
|
|
@ -62,8 +96,8 @@ public final class LlamaServerAgent implements Disposable {
|
|||
|
||||
public void stopAgent() {
|
||||
stoppedByUser = true;
|
||||
if (makeProcessHandler != null) {
|
||||
makeProcessHandler.destroyProcess();
|
||||
if (makeSetupProcessHandler != null) {
|
||||
makeSetupProcessHandler.destroyProcess();
|
||||
}
|
||||
if (startServerProcessHandler != null) {
|
||||
startServerProcessHandler.destroyProcess();
|
||||
|
|
@ -71,9 +105,9 @@ public final class LlamaServerAgent implements Disposable {
|
|||
}
|
||||
|
||||
public boolean isServerRunning() {
|
||||
return (makeProcessHandler != null
|
||||
&& makeProcessHandler.isStartNotified()
|
||||
&& !makeProcessHandler.isProcessTerminated())
|
||||
return (makeSetupProcessHandler != null
|
||||
&& makeSetupProcessHandler.isStartNotified()
|
||||
&& !makeSetupProcessHandler.isProcessTerminated())
|
||||
|| (startServerProcessHandler != null
|
||||
&& startServerProcessHandler.isStartNotified()
|
||||
&& !startServerProcessHandler.isProcessTerminated());
|
||||
|
|
@ -147,25 +181,14 @@ public final class LlamaServerAgent implements Disposable {
|
|||
|
||||
@Override
|
||||
public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
|
||||
if (ProcessOutputType.isStderr(outputType)) {
|
||||
errorLines.add(event.getText());
|
||||
}
|
||||
LOG.info(event.getText());
|
||||
|
||||
if (ProcessOutputType.isStdout(outputType)) {
|
||||
LOG.info(event.getText());
|
||||
// TODO: Use proper successful boot up validation
|
||||
if (event.getText().contains("server is listening")) {
|
||||
LOG.info("Server up and running!");
|
||||
|
||||
try {
|
||||
var serverMessage = objectMapper.readValue(event.getText(), LlamaServerMessage.class);
|
||||
// hack
|
||||
if ("HTTP server listening".equals(serverMessage.msg())) {
|
||||
LOG.info("Server up and running!");
|
||||
|
||||
LlamaSettings.getCurrentState().setServerPort(port);
|
||||
onSuccess.run();
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
// ignore
|
||||
}
|
||||
LlamaSettings.getCurrentState().setServerPort(port);
|
||||
onSuccess.run();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -177,20 +200,32 @@ public final class LlamaServerAgent implements Disposable {
|
|||
OverlayUtil.showClosableBalloon(errorText, MessageType.ERROR, activeServerProgressPanel);
|
||||
}
|
||||
|
||||
private static GeneralCommandLine getMakeCommandLine(LlamaServerStartupParams params) {
|
||||
GeneralCommandLine commandLine = new GeneralCommandLine().withCharset(StandardCharsets.UTF_8);
|
||||
commandLine.setExePath("make");
|
||||
commandLine.withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath());
|
||||
commandLine.addParameters("-j");
|
||||
commandLine.addParameters(params.additionalBuildParameters());
|
||||
commandLine.withEnvironment(params.additionalEnvironmentVariables());
|
||||
commandLine.setRedirectErrorStream(false);
|
||||
return commandLine;
|
||||
private static GeneralCommandLine getCMakeSetupCommandLine(LlamaServerStartupParams params) {
|
||||
GeneralCommandLine cmakeSetupCommand = new GeneralCommandLine().withCharset(
|
||||
StandardCharsets.UTF_8);
|
||||
cmakeSetupCommand.setExePath("cmake");
|
||||
cmakeSetupCommand.withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath());
|
||||
cmakeSetupCommand.addParameters("-B", "build");
|
||||
cmakeSetupCommand.withEnvironment(params.additionalEnvironmentVariables());
|
||||
cmakeSetupCommand.setRedirectErrorStream(false);
|
||||
return cmakeSetupCommand;
|
||||
}
|
||||
|
||||
private static GeneralCommandLine getCMakeBuildCommandLine(LlamaServerStartupParams params) {
|
||||
GeneralCommandLine cmakeBuildCommand = new GeneralCommandLine().withCharset(
|
||||
StandardCharsets.UTF_8);
|
||||
cmakeBuildCommand.setExePath("cmake");
|
||||
cmakeBuildCommand.withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath());
|
||||
cmakeBuildCommand.addParameters("--build", "build", "--config", "Release", "-t", "llama-server",
|
||||
"-j", "4");
|
||||
cmakeBuildCommand.withEnvironment(params.additionalEnvironmentVariables());
|
||||
cmakeBuildCommand.setRedirectErrorStream(false);
|
||||
return cmakeBuildCommand;
|
||||
}
|
||||
|
||||
private GeneralCommandLine getServerCommandLine(LlamaServerStartupParams params) {
|
||||
GeneralCommandLine commandLine = new GeneralCommandLine().withCharset(StandardCharsets.UTF_8);
|
||||
commandLine.setExePath("./server");
|
||||
commandLine.setExePath("./build/bin/llama-server");
|
||||
commandLine.withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath());
|
||||
commandLine.addParameters(
|
||||
"-m", params.modelPath(),
|
||||
|
|
@ -210,8 +245,8 @@ public final class LlamaServerAgent implements Disposable {
|
|||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (makeProcessHandler != null && !makeProcessHandler.isProcessTerminated()) {
|
||||
makeProcessHandler.destroyProcess();
|
||||
if (makeSetupProcessHandler != null && !makeSetupProcessHandler.isProcessTerminated()) {
|
||||
makeSetupProcessHandler.destroyProcess();
|
||||
}
|
||||
if (startServerProcessHandler != null && !startServerProcessHandler.isProcessTerminated()) {
|
||||
startServerProcessHandler.destroyProcess();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import static java.util.Collections.emptyList;
|
|||
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum PromptTemplate {
|
||||
|
||||
|
|
@ -237,6 +238,23 @@ public enum PromptTemplate {
|
|||
.toString();
|
||||
}
|
||||
},
|
||||
DEEPSEEK_R1("DeepSeek R1") {
|
||||
@Override
|
||||
public String buildPrompt(String systemPrompt, String userPrompt, List<Message> history) {
|
||||
var historyString = history.stream()
|
||||
.map(it -> {
|
||||
String response = it.getResponse();
|
||||
if (response.startsWith("<think>")) {
|
||||
response = response.replaceAll("(?s)<think>.*?</think>", "").trim();
|
||||
}
|
||||
return String.format("User:\n%s\n\nAssistant:\n%s", it.getPrompt(), response);
|
||||
})
|
||||
.collect(Collectors.joining("\n\n"));
|
||||
|
||||
return "<|begin▁of▁sentence|>%s<|User|>History:\n%s\n\nUser:\n%s<|Assistant|>"
|
||||
.formatted(systemPrompt, historyString, userPrompt);
|
||||
}
|
||||
},
|
||||
DEEPSEEK_CODER("DeepSeek Coder") {
|
||||
@Override
|
||||
public String buildPrompt(String systemPrompt, String userPrompt, List<Message> history) {
|
||||
|
|
|
|||
|
|
@ -225,7 +225,6 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
panel.addCopyAction(() -> CopyAction.copyToClipboard(message.getResponse()));
|
||||
panel.addContent(new ChatMessageResponseBody(
|
||||
project,
|
||||
true,
|
||||
false,
|
||||
message.isWebSearchIncluded(),
|
||||
fileContextIncluded || message.getDocumentationDetails() != null,
|
||||
|
|
|
|||
|
|
@ -37,17 +37,18 @@ import ee.carlrobert.codegpt.events.WebSearchEventDetails;
|
|||
import ee.carlrobert.codegpt.settings.GeneralSettingsConfigurable;
|
||||
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.StreamParser;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ThinkingOutputParser;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.editor.ResponseEditorPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.editor.actions.CopyAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.ui.ResponseBodyProgressPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.ui.WebpageList;
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil;
|
||||
import ee.carlrobert.codegpt.ui.ThoughtProcessPanel;
|
||||
import ee.carlrobert.codegpt.ui.UIUtil;
|
||||
import ee.carlrobert.codegpt.util.EditorUtil;
|
||||
import ee.carlrobert.codegpt.util.MarkdownUtil;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JEditorPane;
|
||||
|
|
@ -62,6 +63,7 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
private final Project project;
|
||||
private final Disposable parentDisposable;
|
||||
private final StreamParser streamParser;
|
||||
private final ThinkingOutputParser thinkingOutputParser;
|
||||
private final boolean readOnly;
|
||||
private final DefaultListModel<WebSearchEventDetails> webpageListModel = new DefaultListModel<>();
|
||||
private final WebpageList webpageList = new WebpageList(webpageListModel);
|
||||
|
|
@ -71,12 +73,11 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
private JPanel webpageListPanel;
|
||||
|
||||
public ChatMessageResponseBody(Project project, Disposable parentDisposable) {
|
||||
this(project, false, false, false, false, parentDisposable);
|
||||
this(project, false, false, false, parentDisposable);
|
||||
}
|
||||
|
||||
public ChatMessageResponseBody(
|
||||
Project project,
|
||||
boolean withGhostText,
|
||||
boolean readOnly,
|
||||
boolean webSearchIncluded,
|
||||
boolean withProgress,
|
||||
|
|
@ -84,6 +85,7 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
this.project = project;
|
||||
this.parentDisposable = parentDisposable;
|
||||
this.streamParser = new StreamParser();
|
||||
this.thinkingOutputParser = new ThinkingOutputParser();
|
||||
this.readOnly = readOnly;
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
setOpaque(false);
|
||||
|
|
@ -96,12 +98,6 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
webpageListPanel = createWebpageListPanel(webpageList);
|
||||
add(webpageListPanel);
|
||||
}
|
||||
|
||||
if (withGhostText) {
|
||||
prepareProcessingText(!readOnly);
|
||||
currentlyProcessedTextPane.setText(
|
||||
"<html><p style=\"margin-top: 4px; margin-bottom: 8px;\">‍</p></html>");
|
||||
}
|
||||
}
|
||||
|
||||
public ChatMessageResponseBody withResponse(@NotNull String response) {
|
||||
|
|
@ -119,6 +115,29 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
}
|
||||
|
||||
public void updateMessage(String partialMessage) {
|
||||
thinkingOutputParser.processChunk(partialMessage);
|
||||
|
||||
var thoughtProcessPanel = (ThoughtProcessPanel) Stream.of(getComponents())
|
||||
.filter(it -> it instanceof ThoughtProcessPanel)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (thinkingOutputParser.isThinking()) {
|
||||
progressPanel.setVisible(false);
|
||||
|
||||
if (thoughtProcessPanel == null) {
|
||||
thoughtProcessPanel = new ThoughtProcessPanel();
|
||||
add(thoughtProcessPanel);
|
||||
} else {
|
||||
thoughtProcessPanel.updateText(thinkingOutputParser.getThoughtProcess());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (thoughtProcessPanel != null && !thoughtProcessPanel.getFinished()) {
|
||||
thoughtProcessPanel.setFinished();
|
||||
}
|
||||
|
||||
for (var item : streamParser.parse(partialMessage)) {
|
||||
processResponse(item.response(), CODE.equals(item.type()), true);
|
||||
}
|
||||
|
|
@ -240,6 +259,19 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
}
|
||||
}
|
||||
|
||||
private void processThinkingOutput(String thoughtProcess) {
|
||||
Stream.of(getComponents())
|
||||
.filter(it -> it instanceof ThoughtProcessPanel)
|
||||
.findFirst()
|
||||
.ifPresentOrElse(thoughtProcessPanel -> {
|
||||
((ThoughtProcessPanel) thoughtProcessPanel).updateText(thoughtProcess);
|
||||
}, () -> {
|
||||
add(new ThoughtProcessPanel());
|
||||
revalidate();
|
||||
repaint();
|
||||
});
|
||||
}
|
||||
|
||||
private void processCode(String markdownCode) {
|
||||
var document = Parser.builder().build().parse(markdownCode);
|
||||
var child = document.getChildOfType(FencedCodeBlock.class);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue