Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

analytics in sdk #1115

Merged
merged 3 commits into from
Jan 11, 2025
Merged

analytics in sdk #1115

merged 3 commits into from
Jan 11, 2025

Conversation

louis030195
Copy link
Collaborator

@louis030195 louis030195 commented Jan 10, 2025

.

idea is to allow dev to collect analytics and then we provide them dashboard thing - ...

Summary by CodeRabbit

Release Notes

  • New Features

    • Added analytics integration using PostHog.
    • Introduced event tracking capabilities for main features.
    • Added support for user identification in analytics.
    • Created new example projects demonstrating transcription, vision monitoring, and feature capturing.
  • Improvements

    • Increased AI context character limit from 128,000 to 512,000.
    • Enhanced error handling in various SDK methods.
    • Added optional analytics configuration.
  • Examples

    • Added README and configuration files for new example projects.
  • Chores

    • Updated package versions.
    • Removed deprecated Scheduler and loadPipeConfig functionality.

Copy link

vercel bot commented Jan 10, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
screenpipe ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 10, 2025 10:33pm

Copy link
Contributor

coderabbitai bot commented Jan 10, 2025

Walkthrough

This pull request introduces a comprehensive update to the Screenpipe JavaScript SDK, focusing on analytics integration and expanding example projects. The changes span multiple components of the SDK, including the browser and node SDKs, common types, and several new example projects. Key modifications include updating the package versions, adding PostHog-based analytics capabilities, and introducing new methods for event tracking within the BrowserPipe and NodePipe classes. The SDK now supports user identification, event capturing, and analytics initialization across different modules. New example projects demonstrate various use cases such as transcription monitoring, vision tracking, and main feature event capturing, providing developers with practical implementations of the enhanced SDK functionality. Additionally, several new TypeScript configuration files and README updates have been added to improve project setup and documentation.

Sequence Diagram

sequenceDiagram
    participant User
    participant BrowserPipe
    participant Analytics
    participant PostHog

    User->>BrowserPipe: Invoke method
    BrowserPipe->>Analytics: initAnalyticsIfNeeded()
    Analytics->>PostHog: Initialize
    PostHog-->>Analytics: Initialization complete
    BrowserPipe->>Analytics: captureEvent()
    Analytics->>PostHog: Send event
    PostHog-->>Analytics: Event recorded
Loading

This sequence diagram illustrates the typical flow of analytics initialization and event capturing in the updated SDK, showing how methods trigger analytics setup and event tracking through the PostHog service.

Finishing Touches

  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (8)
screenpipe-js/examples/basic-transcription/tsconfig.json (1)

22-26: Consider enabling stricter checks for better code quality.

While disabling these checks makes development easier, enabling them could prevent potential issues:

  • noUnusedLocals: Helps identify dead code
  • noUnusedParameters: Ensures all parameters are utilized
  • noPropertyAccessFromIndexSignature: Prevents accidental property access

This is particularly important for analytics where unused variables might indicate missing data collection points.

-    "noUnusedLocals": false,
-    "noUnusedParameters": false,
-    "noPropertyAccessFromIndexSignature": false
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "noPropertyAccessFromIndexSignature": true
screenpipe-js/browser-sdk/src/index.ts (1)

57-64: Use consistent parameter names in interface methods

For clarity and consistency, consider using the same parameter name for event names in both captureEvent and captureMainFeatureEvent methods. Renaming the parameters to eventName would improve readability.

Apply this diff to update the parameter names:

 export interface BrowserPipe {
   // ...
   captureEvent: (
-    event: string,
+    eventName: string,
     properties?: Record<string, any>
   ) => Promise<void>;
   captureMainFeatureEvent: (
-    name: string,
+    eventName: string,
     properties?: Record<string, any>
   ) => Promise<void>;
 }

And update the implementations accordingly.

screenpipe-js/common/analytics.ts (1)

8-13: Enhance initialization logic

The current initialization logic could be more robust with proper error handling and cleanup.

Consider this enhanced implementation:

 function initPosthog() {
   if (!initialized) {
-    posthog.init(POSTHOG_KEY, { api_host: POSTHOG_HOST });
-    initialized = true;
+    try {
+      posthog.init(POSTHOG_KEY, { api_host: POSTHOG_HOST });
+      initialized = true;
+    } catch (error) {
+      console.error('Failed to initialize PostHog:', error);
+      throw error;
+    }
   }
+  return initialized;
 }
screenpipe-js/examples/query-screenpipe/index.ts (1)

10-16: Extract configuration values to constants

Time-related values and query parameters should be configurable constants.

+const QUERY_CONFIG = {
+  MINUTES_AGO: 5,
+  RESULT_LIMIT: 10,
+  CONTENT_TYPE: "all" as const
+};
+
 // get content from last 5 minutes
-const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString();
+const fiveMinutesAgo = new Date(Date.now() - QUERY_CONFIG.MINUTES_AGO * 60 * 1000).toISOString();

 const results = await pipe.queryScreenpipe({
   startTime: fiveMinutesAgo,
-  limit: 10,
-  contentType: "all", // can be "text", "vision", or "all"
+  limit: QUERY_CONFIG.RESULT_LIMIT,
+  contentType: QUERY_CONFIG.CONTENT_TYPE,
 });
screenpipe-js/common/types.ts (1)

209-209: Add JSDoc documentation for analyticsEnabled setting

The new setting should be documented for better developer experience.

+  /**
+   * Whether to enable analytics collection.
+   * When enabled, usage data will be collected using PostHog.
+   * @default true
+   */
   analyticsEnabled: boolean;
screenpipe-js/node-sdk/src/SettingsManager.ts (1)

32-32: Consider privacy implications of default-enabled analytics

Analytics being enabled by default (analyticsEnabled: true) might raise privacy concerns. Consider:

  1. Making it opt-in by default
  2. Adding clear documentation about what data is collected
  3. Ensuring GDPR compliance
screenpipe-js/node-sdk/src/index.ts (2)

234-240: Consider rate limiting event capture methods

The public event capture methods could benefit from rate limiting to prevent excessive analytics events.

+  private rateLimiter = new Map<string, number>();
+  private readonly RATE_LIMIT_MS = 1000; // 1 event per second
+
   public async captureEvent(
     eventName: string,
     properties?: Record<string, any>
   ) {
+    const now = Date.now();
+    const lastCall = this.rateLimiter.get(eventName) || 0;
+    if (now - lastCall < this.RATE_LIMIT_MS) {
+      return;
+    }
+    this.rateLimiter.set(eventName, now);
     await this.initAnalyticsIfNeeded();
     return captureEvent(eventName, properties);
   }

Also applies to: 242-248


52-54: Enhance error tracking with more context

The error tracking events could include more context to aid debugging:

  • Stack traces for errors
  • Request/response data (excluding sensitive information)
  • System state information

Also applies to: 57-60, 125-128, 131-134, 149-151, 188-190

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56ffbfe and 2af662a.

⛔ Files ignored due to path filters (6)
  • screenpipe-js/browser-sdk/bun.lockb is excluded by !**/bun.lockb
  • screenpipe-js/examples/basic-transcription/bun.lockb is excluded by !**/bun.lockb
  • screenpipe-js/examples/capture-main-feature/bun.lockb is excluded by !**/bun.lockb
  • screenpipe-js/examples/query-screenpipe/bun.lockb is excluded by !**/bun.lockb
  • screenpipe-js/examples/vision-monitor/bun.lockb is excluded by !**/bun.lockb
  • screenpipe-js/node-sdk/bun.lockb is excluded by !**/bun.lockb
📒 Files selected for processing (30)
  • screenpipe-js/browser-sdk/package.json (2 hunks)
  • screenpipe-js/browser-sdk/src/index.ts (6 hunks)
  • screenpipe-js/common/analytics.ts (1 hunks)
  • screenpipe-js/common/types.ts (1 hunks)
  • screenpipe-js/examples/basic-transcription/.gitignore (1 hunks)
  • screenpipe-js/examples/basic-transcription/README.md (1 hunks)
  • screenpipe-js/examples/basic-transcription/index.ts (1 hunks)
  • screenpipe-js/examples/basic-transcription/package.json (1 hunks)
  • screenpipe-js/examples/basic-transcription/tsconfig.json (1 hunks)
  • screenpipe-js/examples/capture-main-feature/.gitignore (1 hunks)
  • screenpipe-js/examples/capture-main-feature/README.md (1 hunks)
  • screenpipe-js/examples/capture-main-feature/index.ts (1 hunks)
  • screenpipe-js/examples/capture-main-feature/package.json (1 hunks)
  • screenpipe-js/examples/capture-main-feature/tsconfig.json (1 hunks)
  • screenpipe-js/examples/query-screenpipe/.gitignore (1 hunks)
  • screenpipe-js/examples/query-screenpipe/README.md (1 hunks)
  • screenpipe-js/examples/query-screenpipe/index.ts (1 hunks)
  • screenpipe-js/examples/query-screenpipe/package.json (1 hunks)
  • screenpipe-js/examples/query-screenpipe/tsconfig.json (1 hunks)
  • screenpipe-js/examples/vision-monitor/.gitignore (1 hunks)
  • screenpipe-js/examples/vision-monitor/README.md (1 hunks)
  • screenpipe-js/examples/vision-monitor/index.ts (1 hunks)
  • screenpipe-js/examples/vision-monitor/package.json (1 hunks)
  • screenpipe-js/examples/vision-monitor/tsconfig.json (1 hunks)
  • screenpipe-js/node-sdk/package.json (2 hunks)
  • screenpipe-js/node-sdk/src/Scheduler.ts (0 hunks)
  • screenpipe-js/node-sdk/src/SettingsManager.ts (1 hunks)
  • screenpipe-js/node-sdk/src/index.ts (7 hunks)
  • screenpipe-js/node-sdk/tests/loadPipeConfig.test.ts (0 hunks)
  • screenpipe-js/node-sdk/tests/scheduler.test.ts (0 hunks)
💤 Files with no reviewable changes (3)
  • screenpipe-js/node-sdk/src/Scheduler.ts
  • screenpipe-js/node-sdk/tests/loadPipeConfig.test.ts
  • screenpipe-js/node-sdk/tests/scheduler.test.ts
✅ Files skipped from review due to trivial changes (14)
  • screenpipe-js/examples/basic-transcription/README.md
  • screenpipe-js/examples/capture-main-feature/README.md
  • screenpipe-js/examples/query-screenpipe/README.md
  • screenpipe-js/examples/vision-monitor/README.md
  • screenpipe-js/examples/vision-monitor/.gitignore
  • screenpipe-js/examples/vision-monitor/tsconfig.json
  • screenpipe-js/examples/capture-main-feature/.gitignore
  • screenpipe-js/examples/vision-monitor/package.json
  • screenpipe-js/examples/capture-main-feature/package.json
  • screenpipe-js/examples/query-screenpipe/tsconfig.json
  • screenpipe-js/examples/basic-transcription/package.json
  • screenpipe-js/examples/query-screenpipe/.gitignore
  • screenpipe-js/examples/basic-transcription/.gitignore
  • screenpipe-js/examples/query-screenpipe/package.json
🧰 Additional context used
🪛 Gitleaks (8.21.2)
screenpipe-js/common/analytics.ts

3-3: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: test-ubuntu
  • GitHub Check: test-windows
  • GitHub Check: test-macos
  • GitHub Check: test-windows
  • GitHub Check: test-linux
  • GitHub Check: Run Windows OCR benchmark
  • GitHub Check: test-windows
  • GitHub Check: Run Apple OCR benchmark
  • GitHub Check: test-macos
  • GitHub Check: test-ubuntu
🔇 Additional comments (9)
screenpipe-js/examples/basic-transcription/tsconfig.json (3)

3-10: LGTM! Language feature settings are well configured.

The configuration enables modern JavaScript features and includes necessary DOM types, which aligns well with the SDK's analytics capabilities.


11-16: Verify bundler compatibility with all target environments.

The "moduleResolution": "bundler" setting is relatively new. Consider adding a comment to document minimum TypeScript version requirements or providing a fallback configuration for older environments.

Run this script to check TypeScript version requirements in the project:


17-21: Consider implications of skipLibCheck.

While skipLibCheck: true improves compilation performance, it might hide type inconsistencies in dependencies. This is particularly important for an analytics SDK where type safety is crucial for accurate data collection.

Run this script to check for potential type issues in dependencies:

screenpipe-js/examples/capture-main-feature/tsconfig.json (1)

1-27: Identical configuration to basic-transcription example.

This configuration matches the one in basic-transcription/tsconfig.json. The previous review comments apply here as well.

screenpipe-js/examples/query-screenpipe/index.ts (1)

9-10: ⚠️ Potential issue

Remove hardcoded file path

The example contains a hardcoded file path which may not work for other users.

Use a relative path instead:

-    "1. paste this in a new terminal: 'open /Users/louisbeaumont/Documents/screenpipe/screenpipe-js/examples/vision-monitor/screenshots/viewer.html'"
+    "1. paste this in a new terminal: 'open ./screenshots/viewer.html'"

Likely invalid or redundant comment.

screenpipe-js/node-sdk/src/SettingsManager.ts (1)

30-30: Verify memory implications of increased context size

The aiMaxContextChars has been increased 4x from 128K to 512K characters. While this provides more context for AI processing, it could significantly impact memory usage.

✅ Verification successful

Memory implications of increased context size are acceptable

The increased context size from 128K to 512K is safe as it:

  • Has a hard upper limit enforced by UI controls (1K-512K range)
  • Is used only for basic content length validation
  • Does not involve complex memory management or buffering
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any memory-related configurations or warnings in the codebase
rg -i "memory|heap|ram" -g "!{*.lock,package-lock.json,yarn.lock,dist/*}"

Length of output: 78657


Script:

#!/bin/bash
# Find usage of aiMaxContextChars and surrounding context
rg -A 5 -B 5 "aiMaxContextChars" --type ts

# Look for memory-related code or comments near AI context handling
ast-grep --pattern 'aiMaxContextChars = $_' -l ts

# Search for memory management related code in TypeScript files
rg -i "(memory|heap|buffer).*(limit|max|size)" --type ts

Length of output: 17217

screenpipe-js/node-sdk/src/index.ts (1)

224-232: LGTM: Analytics initialization is well-implemented

The initAnalyticsIfNeeded method properly:

  • Checks initialization state
  • Respects user settings
  • Requires user identification
screenpipe-js/node-sdk/package.json (1)

30-30: Verify PostHog version compatibility

The PostHog JS SDK version 1.205.0 is not the latest. Please verify compatibility with the latest version.

screenpipe-js/browser-sdk/package.json (1)

30-30: Maintain consistent PostHog versions

Same comment as in node-sdk about PostHog version verification.

Comment on lines 69 to 87
private userId?: string;
private userProperties?: Record<string, any>;

private async initAnalyticsIfNeeded() {
if (this.analyticsInitialized || !this.userId) return;

try {
const response = await fetch("http://localhost:3030/settings");
if (response.ok) {
const settings = await response.json();
if (settings.analyticsEnabled) {
await identifyUser(this.userId, this.userProperties);
this.analyticsInitialized = true;
}
}
} catch (error) {
console.error("failed to fetch settings:", error);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Initialize userId and userProperties to enable analytics

The userId and userProperties are not being set anywhere in the BrowserPipeImpl class. As a result, the initAnalyticsIfNeeded method will not initialize analytics because it checks if (this.analyticsInitialized || !this.userId) return;. This means analytics may never be initialized, and events will not be properly captured.

Consider adding a method to set the user identity. Apply this diff to add a setUser method:

 class BrowserPipeImpl implements BrowserPipe {
   private analyticsInitialized = false;
   private userId?: string;
   private userProperties?: Record<string, any>;

+  public setUser(userId: string, userProperties?: Record<string, any>) {
+    this.userId = userId;
+    this.userProperties = userProperties;
+  }

   private async initAnalyticsIfNeeded() {
     if (this.analyticsInitialized || !this.userId) return;
     // ...
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private userId?: string;
private userProperties?: Record<string, any>;
private async initAnalyticsIfNeeded() {
if (this.analyticsInitialized || !this.userId) return;
try {
const response = await fetch("http://localhost:3030/settings");
if (response.ok) {
const settings = await response.json();
if (settings.analyticsEnabled) {
await identifyUser(this.userId, this.userProperties);
this.analyticsInitialized = true;
}
}
} catch (error) {
console.error("failed to fetch settings:", error);
}
}
private analyticsInitialized = false;
private userId?: string;
private userProperties?: Record<string, any>;
public setUser(userId: string, userProperties?: Record<string, any>) {
this.userId = userId;
this.userProperties = userProperties;
}
private async initAnalyticsIfNeeded() {
if (this.analyticsInitialized || !this.userId) return;
try {
const response = await fetch("http://localhost:3030/settings");
if (response.ok) {
const settings = await response.json();
if (settings.analyticsEnabled) {
await identifyUser(this.userId, this.userProperties);
this.analyticsInitialized = true;
}
}
} catch (error) {
console.error("failed to fetch settings:", error);
}
}

Comment on lines +3 to +15
async function startScreenRecorder() {
console.log("let's send events when our main feature is used ...");

await pipe.captureEvent("less_useful_feature", {
dog: "woof",
});

await pipe.captureMainFeatureEvent("very_useful_feature", {
cat: "meow",
});
}

startScreenRecorder().catch(console.error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Set user identity before capturing events

To ensure analytics events are properly captured, you need to set the user ID before calling captureEvent and captureMainFeatureEvent. Since pipe now requires the userId to initialize analytics, consider setting it using the setUser method.

Apply this diff to set the user ID before capturing events:

 async function startScreenRecorder() {
+  pipe.setUser("user123", { role: "developer" });
+
   console.log("let's send events when our main feature is used ...");

   await pipe.captureEvent("less_useful_feature", {
     dog: "woof",
   });

   await pipe.captureMainFeatureEvent("very_useful_feature", {
     cat: "meow",
   });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function startScreenRecorder() {
console.log("let's send events when our main feature is used ...");
await pipe.captureEvent("less_useful_feature", {
dog: "woof",
});
await pipe.captureMainFeatureEvent("very_useful_feature", {
cat: "meow",
});
}
startScreenRecorder().catch(console.error);
async function startScreenRecorder() {
pipe.setUser("user123", { role: "developer" });
console.log("let's send events when our main feature is used ...");
await pipe.captureEvent("less_useful_feature", {
dog: "woof",
});
await pipe.captureMainFeatureEvent("very_useful_feature", {
cat: "meow",
});
}
startScreenRecorder().catch(console.error);

Comment on lines +3 to +18
async function monitorTranscriptions() {
console.log("starting transcription monitor...");
console.log(
"please watch this video: https://youtu.be/UF8uR6Z6KLc?t=180"
);

for await (const chunk of pipe.streamTranscriptions()) {
const text = chunk.choices[0].text;
const isFinal = chunk.choices[0].finish_reason === "stop";
const device = chunk.metadata?.device;

console.log(`[${device}] ${isFinal ? "final:" : "partial:"} ${text}`);
}
}

monitorTranscriptions().catch(console.error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Initialize user identity before starting transcription monitoring

To ensure analytics events are properly captured during transcription streaming, you need to set the user ID before starting the stream. Consider setting the user identity using the setUser method.

Apply this diff to set the user ID before starting transcription monitoring:

 async function monitorTranscriptions() {
+  pipe.setUser("user123", { role: "user" });
+
   console.log("starting transcription monitor...");
   console.log(
     "please watch this video: https://youtu.be/UF8uR6Z6KLc?t=180"
   );

   for await (const chunk of pipe.streamTranscriptions()) {
     const text = chunk.choices[0].text;
     const isFinal = chunk.choices[0].finish_reason === "stop";
     const device = chunk.metadata?.device;

     console.log(`[${device}] ${isFinal ? "final:" : "partial:"} ${text}`);
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function monitorTranscriptions() {
console.log("starting transcription monitor...");
console.log(
"please watch this video: https://youtu.be/UF8uR6Z6KLc?t=180"
);
for await (const chunk of pipe.streamTranscriptions()) {
const text = chunk.choices[0].text;
const isFinal = chunk.choices[0].finish_reason === "stop";
const device = chunk.metadata?.device;
console.log(`[${device}] ${isFinal ? "final:" : "partial:"} ${text}`);
}
}
monitorTranscriptions().catch(console.error);
async function monitorTranscriptions() {
pipe.setUser("user123", { role: "user" });
console.log("starting transcription monitor...");
console.log(
"please watch this video: https://youtu.be/UF8uR6Z6KLc?t=180"
);
for await (const chunk of pipe.streamTranscriptions()) {
const text = chunk.choices[0].text;
const isFinal = chunk.choices[0].finish_reason === "stop";
const device = chunk.metadata?.device;
console.log(`[${device}] ${isFinal ? "final:" : "partial:"} ${text}`);
}
}
monitorTranscriptions().catch(console.error);

Comment on lines +15 to +21
export async function identifyUser(
userId: string,
properties?: Record<string, any>
): Promise<void> {
initPosthog();
posthog.identify(userId, properties);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling and input validation to analytics functions

The analytics functions should handle errors and validate inputs properly.

Consider this enhanced implementation:

 export async function identifyUser(
   userId: string,
   properties?: Record<string, any>
 ): Promise<void> {
-  initPosthog();
-  posthog.identify(userId, properties);
+  try {
+    if (!userId?.trim()) {
+      throw new Error('userId is required');
+    }
+    initPosthog();
+    await Promise.resolve(posthog.identify(userId, properties));
+  } catch (error) {
+    console.error('Failed to identify user:', error);
+    throw error;
+  }
 }

Apply similar error handling to captureEvent and captureMainFeatureEvent.

Also applies to: 23-29, 31-40

Comment on lines +3 to +4
const POSTHOG_KEY = "phc_Bt8GoTBPgkCpDrbaIZzJIEYt0CrJjhBiuLaBck1clce";
const POSTHOG_HOST = "https://eu.i.posthog.com";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: Move PostHog API key to environment variables

Hardcoding API keys in source code is a security risk. The key should be moved to environment variables.

Replace the hardcoded key with an environment variable:

-const POSTHOG_KEY = "phc_Bt8GoTBPgkCpDrbaIZzJIEYt0CrJjhBiuLaBck1clce";
+const POSTHOG_KEY = process.env.POSTHOG_API_KEY || '';

Also, add validation:

 function initPosthog() {
   if (!initialized) {
+    if (!POSTHOG_KEY) {
+      throw new Error('PostHog API key is required');
+    }
     posthog.init(POSTHOG_KEY, { api_host: POSTHOG_HOST });

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Gitleaks (8.21.2)

3-3: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

Comment on lines +14 to +16
// create screenshots directory
await fs.mkdir("screenshots", { recursive: true });

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for directory creation

The directory creation should handle potential errors.

-  // create screenshots directory
-  await fs.mkdir("screenshots", { recursive: true });
+  const SCREENSHOTS_DIR = "screenshots";
+  try {
+    await fs.mkdir(SCREENSHOTS_DIR, { recursive: true });
+  } catch (error) {
+    console.error(`Failed to create ${SCREENSHOTS_DIR} directory:`, error);
+    throw error;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// create screenshots directory
await fs.mkdir("screenshots", { recursive: true });
const SCREENSHOTS_DIR = "screenshots";
try {
await fs.mkdir(SCREENSHOTS_DIR, { recursive: true });
} catch (error) {
console.error(`Failed to create ${SCREENSHOTS_DIR} directory:`, error);
throw error;
}

Comment on lines +57 to +68
if (image) {
const filename = `screenshots/${timestamp}-${window_name}.png`;
// save to archive
await fs.writeFile(filename, Buffer.from(image, "base64"));
// update latest for viewer
await fs.writeFile(
"screenshots/latest.png",
Buffer.from(image, "base64")
);
console.log(`saved screenshot: ${filename}`);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error handling for file operations

File write operations should handle errors properly.

     if (image) {
-      const filename = `screenshots/${timestamp}-${window_name}.png`;
-      // save to archive
-      await fs.writeFile(filename, Buffer.from(image, "base64"));
-      // update latest for viewer
-      await fs.writeFile(
-        "screenshots/latest.png",
-        Buffer.from(image, "base64")
-      );
-      console.log(`saved screenshot: ${filename}`);
+      try {
+        const filename = `${SCREENSHOTS_DIR}/${timestamp}-${window_name}.png`;
+        const imageBuffer = Buffer.from(image, "base64");
+        
+        // save to archive
+        await fs.writeFile(filename, imageBuffer);
+        // update latest for viewer
+        await fs.writeFile(`${SCREENSHOTS_DIR}/latest.png`, imageBuffer);
+        
+        console.log(`saved screenshot: ${filename}`);
+      } catch (error) {
+        console.error('Failed to save screenshot:', error);
+        // Continue execution as this is not a critical error
+      }

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
screenpipe-js/node-sdk/src/index.ts (2)

58-61: Enhance error tracking by capturing error details

Consider including the error message in analytics to help with debugging.

   await captureEvent("error_occurred", {
     feature: "notification",
     error: "send_failed",
+    error_message: error.message,
   });

Line range hint 68-83: Add analytics for input control actions

Consider tracking input control actions to gather usage insights.

   try {
+    await captureEvent("input_control_sent", {
+      action_type: action.type,
+      success: true,
+    });
     return data.success;
   } catch (error) {
+    await captureEvent("error_occurred", {
+      feature: "input_control",
+      action_type: action.type,
+      error: "send_failed",
+      error_message: error.message,
+    });
     console.error("failed to control input:", error);
     return false;
   }
screenpipe-js/browser-sdk/src/index.ts (1)

188-190: Enhance stream analytics with additional metadata

Consider adding more metadata to stream events to better understand usage patterns:

  • Stream duration
  • Number of chunks processed
  • Error counts

Example implementation:

+  private streamStartTime?: number;
+  private chunkCount = 0;
+  private errorCount = 0;

   async *streamTranscriptions() {
     try {
+      this.streamStartTime = Date.now();
+      this.chunkCount = 0;
+      this.errorCount = 0;
       await this.captureEvent("stream_started", {
         feature: "transcription",
       });
       // ... existing code ...
     } finally {
       await this.captureEvent("stream_ended", {
         feature: "transcription",
+        duration_ms: Date.now() - (this.streamStartTime ?? 0),
+        chunks_processed: this.chunkCount,
+        error_count: this.errorCount,
       });
     }
   }

Also applies to: 227-229, 241-243, 261-263

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2af662a and e6903db.

📒 Files selected for processing (4)
  • screenpipe-js/browser-sdk/package.json (2 hunks)
  • screenpipe-js/browser-sdk/src/index.ts (6 hunks)
  • screenpipe-js/node-sdk/package.json (2 hunks)
  • screenpipe-js/node-sdk/src/index.ts (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • screenpipe-js/node-sdk/package.json
  • screenpipe-js/browser-sdk/package.json
⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: test-windows
  • GitHub Check: test-ubuntu
  • GitHub Check: test-linux
  • GitHub Check: test-macos
  • GitHub Check: test-windows
  • GitHub Check: Run Tesseract OCR benchmark
  • GitHub Check: test-windows
  • GitHub Check: Run Apple OCR benchmark
  • GitHub Check: test-ubuntu
  • GitHub Check: Run STT benchmark
  • GitHub Check: Run Windows OCR benchmark
  • GitHub Check: test-macos
🔇 Additional comments (1)
screenpipe-js/browser-sdk/src/index.ts (1)

165-176: Add analytics for input control actions

Similar to NodePipe, consider tracking input control actions to gather usage insights.

Comment on lines +23 to +26
private analyticsInitialized = false;
private analyticsEnabled = true;
private userId?: string;
private userProperties?: Record<string, any>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add method to set user identity and align default values

Similar to the issue identified in BrowserPipeImpl, there's no way to set userId and userProperties. Additionally, analyticsEnabled defaults to true here but false in BrowserPipeImpl.

Apply this diff to add the setter and align defaults:

-  private analyticsEnabled = true;
+  private analyticsEnabled = false;
   private userId?: string;
   private userProperties?: Record<string, any>;
+
+  public setUser(userId: string, userProperties?: Record<string, any>) {
+    this.userId = userId;
+    this.userProperties = userProperties;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private analyticsInitialized = false;
private analyticsEnabled = true;
private userId?: string;
private userProperties?: Record<string, any>;
private analyticsInitialized = false;
private analyticsEnabled = false;
private userId?: string;
private userProperties?: Record<string, any>;
public setUser(userId: string, userProperties?: Record<string, any>) {
this.userId = userId;
this.userProperties = userProperties;
}

Comment on lines +225 to +234
private async initAnalyticsIfNeeded() {
if (this.analyticsInitialized || !this.userId) return;

const settings = await this.settings.getAll();
this.analyticsEnabled = settings.analyticsEnabled;
if (settings.analyticsEnabled) {
await identifyUser(this.userId, this.userProperties);
this.analyticsInitialized = true;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for user identification

The identifyUser call could fail, but errors are not handled.

   if (settings.analyticsEnabled) {
-    await identifyUser(this.userId, this.userProperties);
-    this.analyticsInitialized = true;
+    try {
+      await identifyUser(this.userId, this.userProperties);
+      this.analyticsInitialized = true;
+    } catch (error) {
+      console.error("Failed to identify user:", error);
+      await captureEvent("error_occurred", {
+        feature: "analytics",
+        error: "user_identification_failed",
+        error_message: error.message,
+      });
+    }
   }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +149 to +152
await captureEvent("search_performed", {
content_type: params.contentType,
result_count: data.pagination.total,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Standardize event capture method usage

There's inconsistent usage of capture methods:

  • Direct usage: await captureEvent("search_performed"...)
  • Instance method: await this.captureEvent("notification_sent"...)

This inconsistency could lead to events being captured without proper initialization checks.

Standardize to use instance methods throughout the class:

-      await captureEvent("search_performed", {
+      await this.captureEvent("search_performed", {
         content_type: params.contentType,
         result_count: data.pagination.total,
       });

Also applies to: 268-284

Comment on lines +76 to +85
try {
const settings = { analyticsEnabled: false }; // TODO: impl settings browser side somehow ...
this.analyticsEnabled = settings.analyticsEnabled;
if (settings.analyticsEnabled) {
await identifyUser(this.userId, this.userProperties);
this.analyticsInitialized = true;
}
} catch (error) {
console.error("failed to fetch settings:", error);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement browser-side settings management

The TODO comment indicates that settings management is not implemented, and analytics are currently hardcoded to be disabled.

Consider implementing one of these approaches:

  1. Store settings in localStorage/sessionStorage
  2. Fetch settings from an API endpoint
  3. Accept settings through constructor/method

Example implementation using localStorage:

   try {
-    const settings = { analyticsEnabled: false }; // TODO: impl settings browser side somehow ...
+    const storedSettings = localStorage.getItem('screenpipe_settings');
+    const settings = storedSettings
+      ? JSON.parse(storedSettings)
+      : { analyticsEnabled: false };
     this.analyticsEnabled = settings.analyticsEnabled;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
const settings = { analyticsEnabled: false }; // TODO: impl settings browser side somehow ...
this.analyticsEnabled = settings.analyticsEnabled;
if (settings.analyticsEnabled) {
await identifyUser(this.userId, this.userProperties);
this.analyticsInitialized = true;
}
} catch (error) {
console.error("failed to fetch settings:", error);
}
try {
const storedSettings = localStorage.getItem('screenpipe_settings');
const settings = storedSettings
? JSON.parse(storedSettings)
: { analyticsEnabled: false };
this.analyticsEnabled = settings.analyticsEnabled;
if (settings.analyticsEnabled) {
await identifyUser(this.userId, this.userProperties);
this.analyticsInitialized = true;
}
} catch (error) {
console.error("failed to fetch settings:", error);
}

@louis030195 louis030195 merged commit 9de730a into main Jan 11, 2025
10 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant