Browse Source

Add comprehensive analytics tracking (#5271)

Co-authored-by: openhands <openhands@all-hands.dev>
Xingyao Wang 1 year ago
parent
commit
2f11634cca

+ 1 - 0
frontend/__tests__/components/browser.test.tsx

@@ -3,6 +3,7 @@ import { describe, it, expect } from "vitest";
 import { renderWithProviders } from "../../test-utils";
 import { BrowserPanel } from "#/components/features/browser/browser";
 
+
 describe("Browser", () => {
   it("renders a message if no screenshotSrc is provided", () => {
     renderWithProviders(<BrowserPanel />, {

+ 27 - 4
frontend/src/components/features/chat/chat-interface.tsx

@@ -20,10 +20,18 @@ import { ContinueButton } from "#/components/shared/buttons/continue-button";
 import { ScrollToBottomButton } from "#/components/shared/buttons/scroll-to-bottom-button";
 import { LoadingSpinner } from "#/components/shared/loading-spinner";
 
+function getEntryPoint(
+  hasRepository: boolean | null,
+  hasImportedProjectZip: boolean | null,
+): string {
+  if (hasRepository) return "github";
+  if (hasImportedProjectZip) return "zip";
+  return "direct";
+}
+
 export function ChatInterface() {
   const { send, isLoadingMessages } = useWsClient();
   const dispatch = useDispatch();
-
   const scrollRef = React.useRef<HTMLDivElement>(null);
   const { scrollDomToBottom, onChatBodyScroll, hitBottom } =
     useScrollToBottom(scrollRef);
@@ -36,11 +44,26 @@ export function ChatInterface() {
   >("positive");
   const [feedbackModalIsOpen, setFeedbackModalIsOpen] = React.useState(false);
   const [messageToSend, setMessageToSend] = React.useState<string | null>(null);
+  const { selectedRepository, importedProjectZip } = useSelector(
+    (state: RootState) => state.initalQuery,
+  );
 
   const handleSendMessage = async (content: string, files: File[]) => {
-    posthog.capture("user_message_sent", {
-      current_message_count: messages.length,
-    });
+    if (messages.length === 0) {
+      posthog.capture("initial_query_submitted", {
+        entry_point: getEntryPoint(
+          selectedRepository !== null,
+          importedProjectZip !== null,
+        ),
+        query_character_length: content.length,
+        uploaded_zip_size: importedProjectZip?.length,
+      });
+    } else {
+      posthog.capture("user_message_sent", {
+        session_message_count: messages.length,
+        current_message_length: content.length,
+      });
+    }
     const promises = files.map((file) => convertImageToBase64(file));
     const imageUrls = await Promise.all(promises);
 

+ 2 - 0
frontend/src/components/features/github/github-repo-selector.tsx

@@ -1,5 +1,6 @@
 import { Autocomplete, AutocompleteItem } from "@nextui-org/react";
 import { useDispatch } from "react-redux";
+import posthog from "posthog-js";
 import { setSelectedRepository } from "#/state/initial-query-slice";
 
 interface GitHubRepositorySelectorProps {
@@ -18,6 +19,7 @@ export function GitHubRepositorySelector({
     if (repo) {
       // set query param
       dispatch(setSelectedRepository(repo.full_name));
+      posthog.capture("repository_selected");
       onSelect();
     }
   };

+ 3 - 0
frontend/src/components/shared/task-form.tsx

@@ -65,7 +65,10 @@ export const TaskForm = React.forwardRef<HTMLFormElement>((_, ref) => {
     if (q) dispatch(setInitialQuery(q));
 
     posthog.capture("initial_query_submitted", {
+      entry_point: "task_form",
       query_character_length: q?.length,
+      has_repository: !!selectedRepository,
+      has_files: files.length > 0,
     });
 
     navigate("/app");

+ 2 - 0
frontend/src/routes/_oh._index/route.tsx

@@ -1,6 +1,7 @@
 import { useLocation, useNavigate } from "react-router";
 import React from "react";
 import { useDispatch } from "react-redux";
+import posthog from "posthog-js";
 import { setImportedProjectZip } from "#/state/initial-query-slice";
 import { convertZipToBase64 } from "#/utils/convert-zip-to-base64";
 import { useUserRepositories } from "#/hooks/query/use-user-repositories";
@@ -61,6 +62,7 @@ function Home() {
               if (event.target.files) {
                 const zip = event.target.files[0];
                 dispatch(setImportedProjectZip(await convertZipToBase64(zip)));
+                posthog.capture("zip_file_uploaded");
                 formRef.current?.requestSubmit();
               } else {
                 // TODO: handle error