mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-12 22:31:24 +00:00
anymous telemetry based on redhat (#212)
* initial telemetry * fixed segment bugs * Move telemetry impl to submodule, add more actions * Replace privacy policy link, minor refactoring --------- Co-authored-by: Carl-Robert Linnupuu <carlrobertoh@gmail.com>
This commit is contained in:
parent
05c7560ec9
commit
8f9980fbf1
56 changed files with 5348 additions and 32 deletions
|
|
@ -1,9 +1,7 @@
|
|||
package ee.carlrobert.codegpt;
|
||||
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import java.util.Objects;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
public final class Icons {
|
||||
|
||||
|
|
@ -13,9 +11,4 @@ public final class Icons {
|
|||
public static final Icon OpenAIIcon = IconLoader.getIcon("/icons/openai.svg", Icons.class);
|
||||
public static final Icon AzureIcon = IconLoader.getIcon("/icons/azure.svg", Icons.class);
|
||||
public static final Icon YouIcon = IconLoader.getIcon("/icons/you.svg", Icons.class);
|
||||
public static final ImageIcon DefaultImageIcon = getImageIcon("/icons/chatgpt.png");
|
||||
|
||||
private static ImageIcon getImageIcon(String path) {
|
||||
return new ImageIcon(Objects.requireNonNull(Icons.class.getResource(path)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
16
src/main/java/ee/carlrobert/codegpt/TelemetryService.java
Normal file
16
src/main/java/ee/carlrobert/codegpt/TelemetryService.java
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package ee.carlrobert.codegpt;
|
||||
|
||||
import ee.carlrobert.codegpt.telemetry.core.service.TelemetryMessageBuilder;
|
||||
import ee.carlrobert.codegpt.telemetry.core.util.Lazy;
|
||||
|
||||
public class TelemetryService {
|
||||
|
||||
private static final TelemetryService INSTANCE = new TelemetryService();
|
||||
|
||||
private final Lazy<TelemetryMessageBuilder> builder = new Lazy<>(() -> new TelemetryMessageBuilder(TelemetryService.class.getClassLoader()));
|
||||
|
||||
public static TelemetryMessageBuilder instance() {
|
||||
return INSTANCE.builder.get();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
package ee.carlrobert.codegpt.actions.toolwindow;
|
||||
|
||||
import static ee.carlrobert.codegpt.Icons.DefaultImageIcon;
|
||||
import static ee.carlrobert.codegpt.Icons.DefaultIcon;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import ee.carlrobert.codegpt.actions.editor.EditorActionsUtil;
|
||||
import ee.carlrobert.codegpt.completions.TelemetryAction;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
|
@ -32,12 +33,21 @@ public class DeleteAllConversationsAction extends AnAction {
|
|||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent event) {
|
||||
int answer = Messages.showYesNoDialog("Are you sure you want to delete all conversations?", "Clear History", DefaultImageIcon);
|
||||
int answer = Messages.showYesNoDialog(
|
||||
"Are you sure you want to delete all conversations?",
|
||||
"Clear History",
|
||||
DefaultIcon);
|
||||
if (answer == Messages.YES) {
|
||||
var project = event.getProject();
|
||||
if (project != null) {
|
||||
ConversationService.getInstance().clearAll();
|
||||
StandardChatToolWindowContentManager.getInstance(project).resetActiveTab();
|
||||
try {
|
||||
ConversationService.getInstance().clearAll();
|
||||
StandardChatToolWindowContentManager.getInstance(project).resetActiveTab();
|
||||
} finally {
|
||||
TelemetryAction.createActionMessage(TelemetryAction.IDE_ACTION)
|
||||
.property("action", "DELETE_ALL_CONVERSATIONS")
|
||||
.send();
|
||||
}
|
||||
}
|
||||
this.onRefresh.run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.intellij.openapi.actionSystem.AnAction;
|
|||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import ee.carlrobert.codegpt.actions.editor.EditorActionsUtil;
|
||||
import ee.carlrobert.codegpt.completions.TelemetryAction;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.util.OverlayUtils;
|
||||
|
|
@ -30,6 +31,10 @@ public class DeleteConversationAction extends AnAction {
|
|||
if (OverlayUtils.showDeleteConversationDialog() == Messages.YES) {
|
||||
var project = event.getProject();
|
||||
if (project != null) {
|
||||
TelemetryAction.createActionMessage(TelemetryAction.IDE_ACTION)
|
||||
.property("action", "DELETE_CONVERSATION")
|
||||
.send();
|
||||
|
||||
ConversationService.getInstance().deleteSelectedConversation();
|
||||
onDelete.run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager;
|
|||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import ee.carlrobert.codegpt.TelemetryService;
|
||||
import ee.carlrobert.codegpt.actions.editor.EditorActionsUtil;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import ee.carlrobert.codegpt.TelemetryService;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.state.AzureSettingsState;
|
||||
|
|
@ -122,16 +123,21 @@ public class CompletionRequestHandler {
|
|||
}
|
||||
|
||||
protected Void doInBackground() {
|
||||
var settings = SettingsState.getInstance();
|
||||
try {
|
||||
eventSource = startCall(
|
||||
conversation,
|
||||
message,
|
||||
isRetry,
|
||||
SettingsState.getInstance().isUseYouService() ? getYouCompletionEventListener() : getCompletionEventListener());
|
||||
settings.isUseYouService() ?
|
||||
getYouCompletionEventListener() :
|
||||
getCompletionEventListener());
|
||||
} catch (TotalUsageExceededException e) {
|
||||
if (tokensExceededListener != null) {
|
||||
tokensExceededListener.run();
|
||||
}
|
||||
} finally {
|
||||
sendInfo(settings);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -162,8 +168,12 @@ public class CompletionRequestHandler {
|
|||
|
||||
@Override
|
||||
public void onError(ErrorDetails error, Throwable ex) {
|
||||
if (errorListener != null) {
|
||||
errorListener.accept(error, ex);
|
||||
try {
|
||||
if (errorListener != null) {
|
||||
errorListener.accept(error, ex);
|
||||
}
|
||||
} finally {
|
||||
sendError(error, ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -186,8 +196,12 @@ public class CompletionRequestHandler {
|
|||
|
||||
@Override
|
||||
public void onError(ErrorDetails error, Throwable ex) {
|
||||
if (errorListener != null) {
|
||||
errorListener.accept(error, ex);
|
||||
try {
|
||||
if (errorListener != null) {
|
||||
errorListener.accept(error, ex);
|
||||
}
|
||||
} finally {
|
||||
sendError(error, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,5 +213,27 @@ public class CompletionRequestHandler {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void sendInfo(SettingsState settings) {
|
||||
var service = "openai";
|
||||
if (settings.isUseAzureService()) {
|
||||
service = "azure";
|
||||
}
|
||||
if (settings.isUseYouService()) {
|
||||
service = "you";
|
||||
}
|
||||
TelemetryAction.createActionMessage(TelemetryAction.COMPLETION)
|
||||
.property("conversationId", conversation.getId().toString())
|
||||
.property("model", conversation.getModel())
|
||||
.property("service", service)
|
||||
.send();
|
||||
}
|
||||
|
||||
private void sendError(ErrorDetails error, Throwable ex) {
|
||||
TelemetryAction.createActionMessage(TelemetryAction.COMPLETION)
|
||||
.property("conversationId", conversation.getId().toString())
|
||||
.error(new RuntimeException("Received an error during completion.\n" + error, ex))
|
||||
.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import ee.carlrobert.codegpt.TelemetryService;
|
||||
import ee.carlrobert.codegpt.telemetry.core.service.TelemetryMessageBuilder.ActionMessage;
|
||||
|
||||
public enum TelemetryAction {
|
||||
|
||||
COMPLETION("CodeGPT-Completion"),
|
||||
IDE_ACTION("CodeGPT-Action");
|
||||
|
||||
private final String code;
|
||||
|
||||
TelemetryAction(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static ActionMessage createActionMessage(TelemetryAction action) {
|
||||
return TelemetryService.instance().action(action.getCode());
|
||||
}
|
||||
}
|
||||
|
|
@ -11,8 +11,10 @@ import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
|
|||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.TelemetryService;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestHandler;
|
||||
import ee.carlrobert.codegpt.completions.SerpResult;
|
||||
import ee.carlrobert.codegpt.completions.TelemetryAction;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
|
|
@ -111,7 +113,11 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
}
|
||||
|
||||
var messageWrapper = createNewMessageWrapper(message.getId());
|
||||
messageWrapper.add(new UserMessagePanel(project, message, message.getUserMessage() != null, this));
|
||||
messageWrapper.add(new UserMessagePanel(
|
||||
project,
|
||||
message,
|
||||
message.getUserMessage() != null,
|
||||
this));
|
||||
var responsePanel = new ResponsePanel()
|
||||
.withReloadAction(() -> reloadMessage(message, conversation))
|
||||
.withDeleteAction(() -> deleteMessage(message.getId(), messageWrapper, conversation))
|
||||
|
|
@ -134,7 +140,11 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
return OpenAICredentialsManager.getInstance().isApiKeySet();
|
||||
}
|
||||
|
||||
private void call(Conversation conversation, Message message, ResponsePanel responsePanel, boolean isRetry) {
|
||||
private void call(
|
||||
Conversation conversation,
|
||||
Message message,
|
||||
ResponsePanel responsePanel,
|
||||
boolean isRetry) {
|
||||
ChatMessageResponseBody responseContainer = (ChatMessageResponseBody) responsePanel.getContent();
|
||||
|
||||
if (!isCredentialSet()) {
|
||||
|
|
@ -167,13 +177,22 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
|
||||
if (containsResults) {
|
||||
message.setSerpResults(serpResults.stream()
|
||||
.map(result -> new SerpResult(result.getUrl(), result.getName(), result.getSnippet(), result.getSnippetSource()))
|
||||
.map(result -> new SerpResult(
|
||||
result.getUrl(),
|
||||
result.getName(),
|
||||
result.getSnippet(),
|
||||
result.getSnippetSource()))
|
||||
.collect(toList()));
|
||||
}
|
||||
});
|
||||
requestHandler.addTokensExceededListener(() -> SwingUtilities.invokeLater(() -> {
|
||||
var answer = OverlayUtils.showTokenLimitExceededDialog();
|
||||
if (answer == OK) {
|
||||
TelemetryService.instance().action(TelemetryAction.IDE_ACTION.getCode())
|
||||
.property("action", "DISCARD_TOKEN_LIMIT")
|
||||
.property("model", conversation.getModel())
|
||||
.send();
|
||||
|
||||
conversationService.discardTokenLimits(conversation);
|
||||
requestHandler.call(conversation, message, true);
|
||||
} else {
|
||||
|
|
@ -185,9 +204,14 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
responseContainer.displayError(error.getMessage());
|
||||
stopStreaming(responseContainer);
|
||||
});
|
||||
requestHandler.addSerpResultsListener(serpResults -> serpResultsMapping.put(message.getId(), serpResults.stream()
|
||||
.map(result -> new SerpResult(result.getUrl(), result.getName(), result.getSnippet(), result.getSnippetSource()))
|
||||
.collect(toList())));
|
||||
requestHandler.addSerpResultsListener(
|
||||
serpResults -> serpResultsMapping.put(message.getId(), serpResults.stream()
|
||||
.map(result -> new SerpResult(
|
||||
result.getUrl(),
|
||||
result.getName(),
|
||||
result.getSnippet(),
|
||||
result.getSnippetSource()))
|
||||
.collect(toList())));
|
||||
userPromptTextArea.setRequestHandler(requestHandler);
|
||||
userPromptTextArea.setSubmitEnabled(false);
|
||||
requestHandler.call(conversation, message, isRetry);
|
||||
|
|
@ -196,7 +220,8 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
protected void reloadMessage(Message message, Conversation conversation) {
|
||||
ResponsePanel responsePanel = null;
|
||||
try {
|
||||
responsePanel = (ResponsePanel) Arrays.stream(visibleMessagePanels.get(message.getId()).getComponents())
|
||||
responsePanel = (ResponsePanel) Arrays.stream(
|
||||
visibleMessagePanels.get(message.getId()).getComponents())
|
||||
.filter(component -> component instanceof ResponsePanel)
|
||||
.findFirst().orElseThrow();
|
||||
((ChatMessageResponseBody) responsePanel.getContent()).clear();
|
||||
|
|
@ -259,7 +284,8 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
var selectionModel = editor.getSelectionModel();
|
||||
var selectedText = selectionModel.getSelectedText();
|
||||
if (selectedText != null && !selectedText.isEmpty()) {
|
||||
var fileExtension = FileUtils.getFileExtension(((EditorImpl) editor).getVirtualFile().getName());
|
||||
var fileExtension = FileUtils.getFileExtension(
|
||||
((EditorImpl) editor).getVirtualFile().getName());
|
||||
message = new Message(text + format("\n```%s\n%s\n```", fileExtension, selectedText));
|
||||
message.setUserMessage(text);
|
||||
selectionModel.removeSelection();
|
||||
|
|
@ -293,7 +319,6 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridy = 1;
|
||||
|
||||
|
||||
var model = getModel();
|
||||
var modelIconWrapper = JBUI.Panels.simplePanel(
|
||||
new ModelIconLabel(getClientCode(), model)).withBorder(JBUI.Borders.empty(0, 0, 8, 4));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package ee.carlrobert.codegpt.util;
|
|||
|
||||
import static com.intellij.openapi.ui.Messages.CANCEL;
|
||||
import static com.intellij.openapi.ui.Messages.OK;
|
||||
import static ee.carlrobert.codegpt.Icons.DefaultImageIcon;
|
||||
import static ee.carlrobert.codegpt.Icons.DefaultIcon;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.notification.Notification;
|
||||
|
|
@ -56,7 +56,7 @@ public class OverlayUtils {
|
|||
return Messages.showYesNoDialog(
|
||||
CodeGPTBundle.get("dialog.deleteConversation.description"),
|
||||
CodeGPTBundle.get("dialog.deleteConversation.title"),
|
||||
DefaultImageIcon);
|
||||
DefaultIcon);
|
||||
}
|
||||
|
||||
public static int showTokenLimitExceededDialog() {
|
||||
|
|
@ -65,7 +65,7 @@ public class OverlayUtils {
|
|||
CodeGPTBundle.get("dialog.tokenLimitExceeded.description"))
|
||||
.yesText(CodeGPTBundle.get("dialog.tokenLimitExceeded.continue"))
|
||||
.noText(CodeGPTBundle.get("dialog.tokenLimitExceeded.cancel"))
|
||||
.icon(DefaultImageIcon)
|
||||
.icon(DefaultIcon)
|
||||
.doNotAsk(new DoNotAskOption.Adapter() {
|
||||
@Override
|
||||
public void rememberChoice(boolean isSelected, int exitCode) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue