Skip to content

Commit

Permalink
Merge branch 'mediar-ai:main' into test-cli-ci
Browse files Browse the repository at this point in the history
  • Loading branch information
onyedikachi-david authored Sep 18, 2024
2 parents f2e1df3 + a9df45b commit 67d37a6
Show file tree
Hide file tree
Showing 25 changed files with 507 additions and 266 deletions.
2 changes: 1 addition & 1 deletion screenpipe-app-tauri/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default function Home() {
))}
</div>
</div>
) : settings.useOllama || settings.openaiApiKey ? (
) : settings.aiUrl ? (
<>
<h1 className="text-2xl font-bold mb-8 text-center mb-12">
where pixels become magic
Expand Down
54 changes: 54 additions & 0 deletions screenpipe-app-tauri/components/log-viewer-v2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useEffect, useState, useRef } from "react";
import { listen } from "@tauri-apps/api/event";
import { cn } from "@/lib/utils";
import Convert from 'ansi-to-html';

interface LogViewerProps {
className?: string;
}

const convert = new Convert({newline: true});

const LogViewer: React.FC<LogViewerProps> = ({ className }) => {
const [logs, setLogs] = useState<string[]>([]);
const logContainerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
const unlisten = listen<string>("sidecar_log", (event) => {
setLogs((prevLogs) => [...prevLogs, event.payload].slice(-100)); // Keep last 100 logs
});

return () => {
unlisten.then((f) => f()); // Cleanup listener when component unmounts
};
}, []);

useEffect(() => {
if (logContainerRef.current) {
logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
}
}, [logs]);

const htmlLogs = logs.map((log) => convert.toHtml(log));

return (
<div
ref={logContainerRef}
className={cn(
"h-64 overflow-y-auto bg-black p-2 font-mono text-sm text-white",
"whitespace-pre-wrap break-words",
className
)}
>
{htmlLogs.map((log, index) => (
<div
key={index}
dangerouslySetInnerHTML={{ __html: log }}
className="leading-5"
/>
))}
</div>
);
};

export default LogViewer;
16 changes: 5 additions & 11 deletions screenpipe-app-tauri/components/notification-handler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,14 @@ const NotificationHandler: React.FC = () => {
}

if (permission) {
const lastNotificationTime = localStorage.getItem(
"lastNotificationTime"
);
const currentTime = Date.now();
const welcomeShown = localStorage.getItem("welcomeNotificationShown");

if (
!lastNotificationTime ||
currentTime - parseInt(lastNotificationTime) > 3600000
) {
if (!welcomeShown) {
sendNotification({
title: "Welcome to Screenpipe",
body: "Thank you for using Screenpipe! We're dedicated to help you get the most out of screenpipe.",
title: "welcome to screenpipe",
body: "thank you for using screenpipe! we're dedicated to help you get the most out of screenpipe.",
});
localStorage.setItem("lastNotificationTime", currentTime.toString());
localStorage.setItem("welcomeNotificationShown", "true");
}
}

Expand Down
155 changes: 122 additions & 33 deletions screenpipe-app-tauri/components/screenpipe-status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ import { Separator } from "./ui/separator";
import { Card, CardContent, CardFooter } from "./ui/card";
import { useHealthCheck } from "@/lib/hooks/use-health-check";
import { DevSettings } from "./dev-dialog";
import { Lock, Folder } from "lucide-react";
import { Lock, Folder, FileText } from "lucide-react";
import { open } from "@tauri-apps/plugin-shell";
import { homeDir } from "@tauri-apps/api/path";
import LogViewer from "./log-viewer-v2";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";

const getDebuggingCommands = (os: string | null) => {
let cliInstructions = "";
Expand Down Expand Up @@ -218,10 +224,7 @@ const DevModeSettings = () => {
</Card>

<div className="relative">
<Badge
variant="secondary"
className="text-xs absolute -top-3 left-1/2 transform -translate-x-1/2 z-10"
>
<Badge className="text-xs absolute -top-3 left-1/2 transform -translate-x-1/2 z-10">
expert only
</Badge>
<Card className="p-4">
Expand Down Expand Up @@ -333,6 +336,8 @@ const HealthStatus = ({ className }: { className?: string }) => {
const { health } = useHealthCheck();
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [isMac, setIsMac] = useState(false);
const { settings } = useSettings();
const [isLogOpen, setIsLogOpen] = useState(false);

useEffect(() => {
setIsMac(platform() === "macos");
Expand Down Expand Up @@ -379,26 +384,82 @@ const HealthStatus = ({ className }: { className?: string }) => {
}
};

const getStatusColor = (status: string) => {
switch (status) {
case "Healthy":
return "bg-green-500";
case "Loading":
return "bg-yellow-500";
case "Unhealthy":
case "Error":
return "bg-red-500";
default:
return "bg-red-500";
const handleOpenLogFile = async () => {
try {
const homeDirPath = await homeDir();
const logPath =
platform() === "windows"
? `${homeDirPath}\\.screenpipe\\screenpipe.log`
: `${homeDirPath}/.screenpipe/screenpipe.log`;
await open(logPath);
} catch (error) {
console.error("failed to open log file:", error);
toast({
title: "error",
description: "failed to open log file.",
variant: "destructive",
duration: 3000,
});
}
};

const getStatusColor = (
status: string,
frameStatus: string,
audioStatus: string,
audioDisabled: boolean
) => {
if (status === "loading") return "bg-yellow-500";

const isVisionOk = frameStatus === "ok" || frameStatus === "disabled";
const isAudioOk =
audioStatus === "ok" || audioStatus === "disabled" || audioDisabled;

if (isVisionOk && isAudioOk) return "bg-green-500";
return "bg-red-500";
};

if (!health) return null;

const formatTimestamp = (timestamp: string | null) => {
return timestamp ? new Date(timestamp).toLocaleString() : "N/A";
return timestamp ? new Date(timestamp).toLocaleString() : "n/a";
};

const getStatusMessage = (
status: string,
frameStatus: string,
audioStatus: string,
audioDisabled: boolean
) => {
if (status === "loading")
return "the application is still initializing. please wait...";

let unhealthySystems = [];
if (frameStatus !== "ok" && frameStatus !== "disabled")
unhealthySystems.push("vision");
if (!audioDisabled && audioStatus !== "ok" && audioStatus !== "disabled")
unhealthySystems.push("audio");

if (unhealthySystems.length === 0)
return "all systems are functioning normally";
return `some systems are not functioning properly: ${unhealthySystems.join(
", "
)}`;
};

const statusColor = getStatusColor(
health.status,
health.frame_status,
health.audio_status,
settings.disableAudio
);
const statusMessage = getStatusMessage(
health.status,
health.frame_status,
health.audio_status,
settings.disableAudio
);

return (
<>
<Badge
Expand All @@ -408,12 +469,8 @@ const HealthStatus = ({ className }: { className?: string }) => {
>
status{" "}
<span
className={`ml-1 w-2 h-2 rounded-full ${getStatusColor(
health.status
)} inline-block ${
health.status === "Unhealthy" || health.status === "Error"
? "animate-pulse"
: ""
className={`ml-1 w-2 h-2 rounded-full ${statusColor} inline-block ${
statusColor === "bg-red-500" ? "animate-pulse" : ""
}`}
/>
</Badge>
Expand All @@ -423,11 +480,10 @@ const HealthStatus = ({ className }: { className?: string }) => {
aria-describedby="status-dialog-description"
>
<DialogHeader className="flex flex-row items-center justify-between">
<DialogTitle>{health.status.toLowerCase()} status</DialogTitle>
<DialogTitle>{health.status} status</DialogTitle>

<Button
variant="outline"
size="sm"
onClick={handleOpenDataDir}
className="flex-shrink-0"
>
Expand All @@ -437,22 +493,23 @@ const HealthStatus = ({ className }: { className?: string }) => {
</DialogHeader>
<div className="flex-grow overflow-auto">
<p className="text-sm mb-2">
{health.message.toLowerCase()}{" "}
{health.status === "Loading" && (
{statusMessage}
{health.status === "loading" && (
<span className="ml-1 text-xs">(up to 3m)</span>
)}
</p>
<p className="text-xs mb-1">frame: {health.frame_status}</p>
<p className="text-xs mb-1">
frame: {health.frame_status.toLowerCase()}
</p>
<p className="text-xs mb-1">
audio: {health.audio_status.toLowerCase()}
audio: {settings.disableAudio ? "disabled" : health.audio_status}
</p>
<p className="text-xs mb-1">
last frame: {formatTimestamp(health.last_frame_timestamp)}
</p>
<p className="text-xs mb-1">
last audio: {formatTimestamp(health.last_audio_timestamp)}
last audio:{" "}
{settings.disableAudio
? "n/a"
: formatTimestamp(health.last_audio_timestamp)}
</p>
<div className="text-xs mt-2 relative">
<p className="font-bold mb-1">troubleshooting instructions:</p>
Expand All @@ -470,7 +527,6 @@ const HealthStatus = ({ className }: { className?: string }) => {
<TooltipTrigger asChild>
<Button
variant="outline"
size="sm"
onClick={handleResetScreenPermissions}
className="flex-shrink-0"
>
Expand All @@ -488,6 +544,39 @@ const HealthStatus = ({ className }: { className?: string }) => {
</div>
<Separator className="my-4" />
<DevModeSettings />

<Collapsible
open={isLogOpen}
onOpenChange={setIsLogOpen}
className="w-full mt-4"
>
<div className="flex items-center justify-between w-full">
<CollapsibleTrigger className="flex items-center justify-between p-2 flex-grow border-b border-gray-200">
recorder logs
<span>{isLogOpen ? "▲" : "▼"}</span>
</CollapsibleTrigger>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="sm"
onClick={handleOpenLogFile}
className="ml-2"
>
<FileText className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>open log file</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<CollapsibleContent>
<LogViewer className="mt-2" />
</CollapsibleContent>
</Collapsible>
</div>
</DialogContent>
</Dialog>
Expand Down
17 changes: 10 additions & 7 deletions screenpipe-app-tauri/components/search-chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ ${queryParams.toString().replace(/&/g, "\\\n&")}" | jq`;
const calculateSelectedContentLength = () => {
return Array.from(selectedResults).reduce((total, index) => {
const item = results[index];
if (!item || !item.type) return total; // Add this check

const contentLength =
item.type === "OCR"
? item.content.text.length
Expand Down Expand Up @@ -276,7 +278,9 @@ ${queryParams.toString().replace(/&/g, "\\\n&")}" | jq`;
content: `You are a helpful assistant.
The user is using a product called "screenpipe" which records
his screen and mics 24/7. The user ask you questions
and you use his screenpipe recordings to answer him.
and you use his screenpipe recordings to answer him.
The user will provide you with a list of search results
and you will use them to answer his questions.
Rules:
- Current time (JavaScript Date.prototype.toString): ${new Date().toString()}. Adjust start/end times to match user intent.
Expand All @@ -288,11 +292,6 @@ ${queryParams.toString().replace(/&/g, "\\\n&")}" | jq`;
- You must reformat timestamps to a human-readable format in your response to the user.
- Never output UTC time unless explicitly asked by the user.
- Do not try to embed videos in table (would crash the app)
Based on the following selected search results:
${JSON.stringify(
results.filter((_, index) => selectedResults.has(index))
)}
`,
},
...chatMessages.map((msg) => ({
Expand All @@ -301,7 +300,11 @@ ${queryParams.toString().replace(/&/g, "\\\n&")}" | jq`;
})),
{
role: "user" as const,
content: userMessage.content,
content: `Context data: ${JSON.stringify(
results.filter((_, index) => selectedResults.has(index))
)}
User query: ${floatingInput}`,
},
];

Expand Down
11 changes: 11 additions & 0 deletions screenpipe-app-tauri/components/ui/collapsible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use client"

import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"

const Collapsible = CollapsiblePrimitive.Root

const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger

const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent

export { Collapsible, CollapsibleTrigger, CollapsibleContent }
Loading

0 comments on commit 67d37a6

Please sign in to comment.