From 0d8402c5cb8027271ca998280245fcb5514f3c55 Mon Sep 17 00:00:00 2001 From: matthew-heartful Date: Fri, 27 Sep 2024 17:09:55 -0700 Subject: [PATCH 1/6] readme --- .../pipe-post-questions-on-reddit/README.md | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 examples/typescript/pipe-post-questions-on-reddit/README.md diff --git a/examples/typescript/pipe-post-questions-on-reddit/README.md b/examples/typescript/pipe-post-questions-on-reddit/README.md new file mode 100644 index 00000000..37c6e03a --- /dev/null +++ b/examples/typescript/pipe-post-questions-on-reddit/README.md @@ -0,0 +1,104 @@ +### pipe-post-questions-on-reddit +GPT-4o (or local model) looks at your screen 24/7 and sends you emails with questions to post on Reddit based on your activity. + +#### quick setup +1. [Get an OpenAI API key](https://platform.openai.com/account/api-keys) +2. [Create an app-specific password](https://support.google.com/accounts/answer/185833?hl=en) in your Google account that will be used to send yourself emails +3. Configure pipe in the app UI, save, enable, and restart screenpipe recording (you can configure to either receive an email daily or several every x hours) + + +#### Advanced +tech details? check `pipe.ts`. +can be used through CLI also, you can tweak the `pipe.json` to your needs, mine looks like this: + +```json +{ + "fields": [ + { + "name": "interval", + "type": "number", + "default": 60, + "description": "Interval in seconds to read your screen data and extract structured logs (will be used to summarize and send an email). Increase this value if using audio." + }, + { + "name": "summaryFrequency", + "type": "string", + "default": "daily", + "description": "Frequency of summary emails: 'daily' for once a day at emailTime, or 'hourly:X' for every X hours (e.g., 'hourly:4' for every 4 hours)", + "value": "hourly:1" + }, + { + "name": "emailTime", + "type": "time", + "default": "11:00", + "description": "Time to send daily summary email (used only if summaryFrequency is 'daily')" + }, + { + "name": "emailAddress", + "type": "string", + "default": "", + "description": "Email address to send the daily summary to", + "value": "your.email@example.com" + }, + { + "name": "emailPassword", + "type": "string", + "default": "", + "description": "App specific password for your gmail account, https://support.google.com/accounts/answer/185833?hl=en", + "value": "your-app-specific-password" + }, + { + "name": "gptApiUrl", + "type": "string", + "default": "https://api.openai.com/v1/chat/completions", + "description": "GPT API URL" + }, + { + "name": "gptModel", + "type": "string", + "default": "gpt-4", + "description": "GPT Model" + }, + { + "name": "openai_api_key", + "type": "string", + "default": "", + "description": "Your OpenAI API key", + "value": "your-openai-api-key" + }, + { + "name": "pageSize", + "type": "number", + "default": 100, + "description": "Number of records to retrieve from screenpipe per page for structured extraction, keep in mind LLMs have a context window limit. Increase this value if using audio." + }, + { + "name": "customPrompt", + "type": "string", + "default": "You are an AI assistant tasked with extracting structured information from screen data (OCR). Analyze the following screen data and extract relevant information about my daily activity.", + "description": "Custom prompt for the AI assistant that will be used to extract information from the screen data every few minutes" + }, + { + "name": "summaryPrompt", + "type": "string", + "default": "You are an AI assistant tasked with summarizing information that has previously been extracted from screen data (OCR) by another AI assistant. Analyze the following structured data extracted from my screen data and summarize my daily activity, this will be send as a mail to my email address.", + "description": "Summary prompt for the AI assistant that will be used to summarize the logs previously extracted and send a mail" + }, + { + "name": "windowName", + "type": "window", + "default": "", + "description": "Specific window name to filter the screen data, for example 'gmail', 'john', 'slack', 'myCodeFile.tsx', etc. this will filter out audio", + "value": "reddit" + }, + { + "name": "contentType", + "type": "contentType", + "default": "ocr", + "description": "Type of content to analyze: 'ocr', 'audio', or 'all'. OCR usually contains more content, so it's recommended to choose either OCR or audio rather than 'all' for better performance." + } + ], + "source": "https://github.com/mediar-ai/screenpipe/tree/main/examples/typescript/pipe-post-questions-on-reddit", + "enabled": true +} +``` From b94dd530b03382283936cecb5ca0e39478fb9b6d Mon Sep 17 00:00:00 2001 From: matthew-heartful Date: Fri, 27 Sep 2024 17:11:34 -0700 Subject: [PATCH 2/6] config --- .../pipe-post-questions-on-reddit/pipe.json | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 examples/typescript/pipe-post-questions-on-reddit/pipe.json diff --git a/examples/typescript/pipe-post-questions-on-reddit/pipe.json b/examples/typescript/pipe-post-questions-on-reddit/pipe.json new file mode 100644 index 00000000..59276dba --- /dev/null +++ b/examples/typescript/pipe-post-questions-on-reddit/pipe.json @@ -0,0 +1,82 @@ +{ + "fields": [ + { + "name": "interval", + "type": "number", + "default": 60, + "description": "Interval in seconds to read your screen data and extract structured logs (will be used to summarize and send an email). Increase this value if using audio." + }, + { + "name": "summaryFrequency", + "type": "string", + "default": "daily", + "description": "Frequency of summary emails: 'daily' for once a day at emailTime, or 'hourly:X' for every X hours (e.g., 'hourly:4' for every 4 hours)" + }, + { + "name": "emailTime", + "type": "time", + "default": "11:00", + "description": "Time to send daily summary email (used only if summaryFrequency is 'daily')" + }, + { + "name": "emailAddress", + "type": "string", + "default": "", + "description": "Email address to send the daily summary to" + }, + { + "name": "emailPassword", + "type": "string", + "default": "", + "description": "App specific password for your gmail account, https://support.google.com/accounts/answer/185833?hl=en" + }, + { + "name": "gptApiUrl", + "type": "string", + "default": "https://api.openai.com/v1/chat/completions", + "description": "GPT API URL" + }, + { + "name": "gptModel", + "type": "string", + "default": "gpt-4o", + "description": "GPT Model" + }, + { + "name": "openai_api_key", + "type": "string", + "default": "", + "description": "Your OpenAI API key" + }, + { + "name": "pageSize", + "type": "number", + "default": 100, + "description": "Number of records to retrieve from screenpipe per page for structured extraction, keep in mind LLMs have a context window limit. Increase this value if using audio." + }, + { + "name": "additional prompt for logs", + "type": "string", + "default": "", + "description": "additional prompt for the AI assistant that will be used to extract information from the screen data every specified amount of minutes" + }, + { + "name": "additional prompt for reddit questions", + "type": "string", + "default": "", + "description": "additional prompt for the AI assistant that will be used to generate a list of questions to post on reddit based on the logs previously extracted" + }, + { + "name": "windowName", + "type": "window", + "default": "", + "description": "Specific window name to filter the screen data, for example 'gmail', 'john', 'slack', 'myCodeFile.tsx', etc. this will filter out audio" + }, + { + "name": "contentType", + "type": "contentType", + "default": "all", + "description": "Type of content to analyze: 'ocr', 'audio', or 'all'. OCR usually contains more content, so it's recommended to choose either OCR or audio rather than 'all' for better performance." + } + ] +} \ No newline at end of file From e9952df121247dec91fc4524a1f832f9d643f9b5 Mon Sep 17 00:00:00 2001 From: matthew-heartful Date: Fri, 27 Sep 2024 17:16:41 -0700 Subject: [PATCH 3/6] ts configs --- .../screenpipe.d.ts | 245 ++++++++++++++++++ .../tsconfig.json | 17 ++ 2 files changed, 262 insertions(+) create mode 100644 examples/typescript/pipe-post-questions-on-reddit/screenpipe.d.ts create mode 100644 examples/typescript/pipe-post-questions-on-reddit/tsconfig.json diff --git a/examples/typescript/pipe-post-questions-on-reddit/screenpipe.d.ts b/examples/typescript/pipe-post-questions-on-reddit/screenpipe.d.ts new file mode 100644 index 00000000..820e1a2d --- /dev/null +++ b/examples/typescript/pipe-post-questions-on-reddit/screenpipe.d.ts @@ -0,0 +1,245 @@ +declare global { + const pipe: { + /** + * Reads the contents of a file. + * @param path - The path to the file to be read. + * @returns A promise that resolves with the file contents as a string. + */ + readFile: (path: string) => Promise; + + /** + * Writes content to a file. + * @param path - The path to the file to be written. + * @param contents - The content to write to the file. + * @returns A promise that resolves when the write operation is complete. + */ + writeFile: (path: string, contents: string) => Promise; + + /** + * Removes a file. + * @param path - The path to the file to be removed. + * @returns A promise that resolves when the file is removed. + */ + removeFile: (path: string) => Promise; + + /** + * Performs a GET request to the specified URL. + * @param url - The URL to send the GET request to. + * @returns A promise that resolves with the response data. + */ + get: (url: string) => Promise; + + /** + * Performs a POST request to the specified URL. + * @param url - The URL to send the POST request to. + * @param body - The body of the POST request. + * @returns A promise that resolves with the response data. + */ + post: (url: string, body: string) => Promise; + + /** + * Performs a fetch request. + * @param url - The URL to fetch. + * @param options - Optional fetch options. + * @returns A promise that resolves with the fetch response. + */ + fetch: (url: string, options?: RequestInit) => Promise; + + /** + * Sends a notification. + * @param options - The notification options. + * @returns A promise that resolves when the notification is sent. + */ + sendNotification: (options: { + title: string; + body: string; + }) => Promise; + + /** + * Loads the configuration for the pipe. + * @returns A promise that resolves with the configuration object. + */ + loadConfig: () => Promise>; + + /** + * The current configuration of the pipe. + */ + config: Record; + + /** + * Metadata about the current pipe. + */ + metadata: { + id: string; + }; + + /** + * Sends an email. + * @param options - The email options. + * @returns A promise that resolves to true if the email was sent successfully, false otherwise. + */ + sendEmail: (options: { + to: string; + from: string; + password: string; + subject: string; + body: string; + }) => Promise; + + /** + * Queries the Screenpipe database. + * @param params - The query parameters. + * @returns A promise that resolves with the query results or null if an error occurred. + */ + queryScreenpipe: ( + params: ScreenpipeQueryParams + ) => Promise; + }; + + const fs: { + /** + * Reads the contents of a file. + * @param path - The path to the file to be read. + * @returns A promise that resolves with the file contents as a string. + */ + readFile: (path: string) => Promise; + + /** + * Writes content to a file. + * @param path - The path to the file to be written. + * @param contents - The content to write to the file. + * @returns A promise that resolves when the write operation is complete. + */ + writeFile: (path: string, contents: string) => Promise; + + /** + * Reads the contents of a directory. + * @param path - The path to the directory to be read. + * @returns A promise that resolves with an array of file names in the directory. + */ + readdir: (path: string) => Promise; + + /** + * Creates a new directory. + * @param path - The path of the directory to be created. + * @returns A promise that resolves when the directory is created. + */ + mkdir: (path: string) => Promise; + }; + + const path: { + /** + * Joins multiple path segments into a single path. + * @param paths - The path segments to join. + * @returns The joined path string. + */ + join: (...paths: string[]) => string; + }; + + namespace NodeJS { + interface ProcessEnv { + SCREENPIPE_DIR: string; + SCREENPIPE_LOG_API_URL?: string; + SCREENPIPE_SERVER_URL?: string; + PIPE_DIR: string; + NOTION_DATABASE_ID: string; + NOTION_API_KEY: string; + } + } + const process: { + env: NodeJS.ProcessEnv; + }; + + /** + * Types of content that can be queried in Screenpipe. + */ + type ContentType = "ocr" | "audio" | "all"; + + /** + * Parameters for querying Screenpipe. + */ + interface ScreenpipeQueryParams { + q?: string; + content_type?: ContentType; + limit?: number; + offset?: number; + start_time?: string; + end_time?: string; + app_name?: string; + window_name?: string; + include_frames?: boolean; + min_length?: number; + max_length?: number; + } + + /** + * Structure of OCR (Optical Character Recognition) content. + */ + interface OCRContent { + frame_id: number; + text: string; + timestamp: string; + file_path: string; + offset_index: number; + app_name: string; + window_name: string; + tags: string[]; + frame?: string; + } + + /** + * Structure of audio content. + */ + interface AudioContent { + chunk_id: number; + transcription: string; + timestamp: string; + file_path: string; + offset_index: number; + tags: string[]; + device_name: string; + device_type: string; + } + + /** + * Structure of Full Text Search content. + */ + interface FTSContent { + text_id: number; + matched_text: string; + frame_id: number; + timestamp: string; + app_name: string; + window_name: string; + file_path: string; + original_frame_text?: string; + tags: string[]; + } + + /** + * Union type for different types of content items. + */ + type ContentItem = + | { type: "OCR"; content: OCRContent } + | { type: "Audio"; content: AudioContent } + | { type: "FTS"; content: FTSContent }; + + /** + * Pagination information for search results. + */ + interface PaginationInfo { + limit: number; + offset: number; + total: number; + } + + /** + * Structure of the response from a Screenpipe query. + */ + interface ScreenpipeResponse { + data: ContentItem[]; + pagination: PaginationInfo; + } +} + +export {}; diff --git a/examples/typescript/pipe-post-questions-on-reddit/tsconfig.json b/examples/typescript/pipe-post-questions-on-reddit/tsconfig.json new file mode 100644 index 00000000..c4e6dfdd --- /dev/null +++ b/examples/typescript/pipe-post-questions-on-reddit/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2018", + "module": "esnext", + "moduleResolution": "node", + "outDir": "./", + "rootDir": "./", + "strict": true, + "esModuleInterop": true + }, + "include": [ + "./**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file From 94a94f96be9bb5ea09bca53d5f64cf2b7981b17e Mon Sep 17 00:00:00 2001 From: matthew-heartful Date: Fri, 27 Sep 2024 17:17:14 -0700 Subject: [PATCH 4/6] reddit pipe to send daily reddit question to the user by email to then post them --- .../pipe-post-questions-on-reddit/pipe.ts | 368 ++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 examples/typescript/pipe-post-questions-on-reddit/pipe.ts diff --git a/examples/typescript/pipe-post-questions-on-reddit/pipe.ts b/examples/typescript/pipe-post-questions-on-reddit/pipe.ts new file mode 100644 index 00000000..e29a4309 --- /dev/null +++ b/examples/typescript/pipe-post-questions-on-reddit/pipe.ts @@ -0,0 +1,368 @@ +interface DailyLog { + activity: string; + category: string; + tags: string[]; + timestamp: string; +} + +async function generateDailyLog( + screenData: ContentItem[], + customPrompt: string, + gptModel: string, + gptApiUrl: string, + openaiApiKey: string +): Promise { + const prompt = `${customPrompt} + + Based on the following screen data, generate a concise daily log entry: + + ${JSON.stringify(screenData)} + + Return a JSON object with the following structure: + { + "activity": "Brief description of the activity", + "category": "Category of the activity like work, email, slack, etc" + "tags": ["productivity", "work", "email", "john", "salesforce", "etc"] + } + + + Rules: + - Do not add backticks to the JSON eg \`\`\`json\`\`\` is WRONG + - DO NOT RETURN ANYTHING BUT JSON. NO COMMENTS BELOW THE JSON. + + `; + + const response = await fetch(gptApiUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${openaiApiKey}`, + }, + body: JSON.stringify({ + model: gptModel, + messages: [{ role: "user", content: prompt }], + response_format: { type: "json_object" }, + }), + }); + + if (!response.ok) { + console.log("gpt response:", await response.text()); + throw new Error(`http error! status: ${response.status}`); + } + + const result = await response.json(); + + console.log("ai answer:", result); + // clean up the result + const cleanedResult = result.choices[0].message.content + .trim() + .replace(/^```(?:json)?\s*|\s*```$/g, "") // remove start and end code block markers + .replace(/\n/g, "") // remove newlines + .replace(/\\n/g, "") // remove escaped newlines + .trim(); // trim any remaining whitespace + + let content; + try { + content = JSON.parse(cleanedResult); + } catch (error) { + console.warn("failed to parse ai response:", error); + console.warn("cleaned result:", cleanedResult); + throw new Error("invalid ai response format"); + } + + return content; +} + +async function saveDailyLog(logEntry: DailyLog): Promise { + console.log("creating logs dir"); + const logsDir = `${process.env.PIPE_DIR}/logs`; + console.log("logs dir:", logsDir); + console.log("saving log entry:", logEntry); + console.log("logs dir:", logsDir); + const timestamp = new Date() + .toISOString() + .replace(/:/g, "-") + .replace(/\..+/, ""); + const filename = `${timestamp}-${logEntry.category.replace("/", "-")}.json`; + console.log("filename:", filename); + await fs.writeFile( + `${logsDir}/${filename}`, + JSON.stringify(logEntry, null, 2) + ); +} + +function generateRedditLinks(content: string): string { + const posts = content.split(/\[\d+\]/g).filter(Boolean); + let result = ''; + + posts.forEach((post, index) => { + const titleMatch = post.match(/\[TITLE\](.*?)\[\/TITLE\]/s); + const bodyMatch = post.match(/\[BODY\](.*?)\[\/BODY\]/s); + const subredditsMatch = post.match(/\[r\/.*?\]/g); + + if (titleMatch && bodyMatch && subredditsMatch) { + const title = titleMatch[1].trim(); + const body = bodyMatch[1].trim(); + const encodedTitle = encodeURIComponent(title); + const encodedBody = encodeURIComponent(`${title}\n\n${body}`); + + result += `[${index + 1}] ${title}\n\n${body}\n\n`; + + subredditsMatch.forEach(subreddit => { + const subredditName = subreddit.slice(2, -1); + const link = `https://www.reddit.com/r/${subredditName}/submit?title=${encodedTitle}&text=${encodedBody}`; + result += `${subreddit} SEND\n`; + }); + + result += '\n'; + } + }); + + return result.trim(); +} + +async function generateRedditQuestions( + screenData: ContentItem[], + customPrompt: string, + gptModel: string, + gptApiUrl: string, + openaiApiKey: string +): Promise { + const prompt = `${customPrompt} + + based on the following screen data, generate a list of questions i can ask the reddit community: + + ${JSON.stringify(screenData)} + + rules: + - be specific and concise + - return a list of posts, one level bullet list + - keep the tone casual like you are chatting to friends + - you can mention some context from the screen data 30% of the time, but don't mention very personal data + - the list should be enumerated with square brackets like [1], [2], ... + - each post starts with [TITLE] ... [/TITLE], then [BODY] ... [/BODY], + - at the end of each post add a list of subreddits to post it in enumerated as [r/...], [r/....], [r/....], ... + - at the end of each subreddit add "[SEND]" + `; + + console.log("reddit questions prompt:", prompt); + const response = await fetch(gptApiUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${openaiApiKey}`, + }, + body: JSON.stringify({ + model: gptModel, + messages: [{ role: "user", content: prompt }], + }), + }); + console.log("reddit questions gpt response:", response); + + if (!response.ok) { + console.log("gpt response:", await response.text()); + throw new Error(`http error! status: ${response.status}`); + } + + const result = await response.json(); + + console.log("ai reddit questions:", result); + + const content = result.choices[0].message.content; + return generateRedditLinks(content); +} + +async function retry( + fn: () => Promise, + maxAttempts: number = 3, + delay: number = 3000 +): Promise { + for (let attempt = 1; attempt <= maxAttempts; attempt++) { + try { + return await fn(); + } catch (error) { + if (attempt === maxAttempts) { + throw error; + } + console.log(`attempt ${attempt} failed, retrying in ${delay}ms...`); + await new Promise((resolve) => setTimeout(resolve, delay)); + } + } + throw new Error("this should never happen"); +} + +async function sendEmail( + to: string, + password: string, + subject: string, + body: string +): Promise { + const from = to; // assuming the sender is the same as the recipient + await retry(async () => { + const result = await pipe.sendEmail({ + to, + from, + password, + subject, + body, + }); + if (!result) { + throw new Error("failed to send email"); + } + console.log(`email sent to ${to} with subject: ${subject}`); + }); +} + +async function getTodayLogs(): Promise { + try { + const logsDir = `${process.env.PIPE_DIR}/logs`; + const today = new Date().toISOString().replace(/:/g, "-").split("T")[0]; // Get today's date in YYYY-MM-DD format + + console.log("reading logs dir:", logsDir); + const files = await fs.readdir(logsDir); + console.log("files:", files); + const todayFiles = files.filter((file) => file.startsWith(today)); + console.log("today's files:", todayFiles); + + const logs: DailyLog[] = []; + for (const file of todayFiles) { + const content = await fs.readFile(`${logsDir}/${file}`); + logs.push(JSON.parse(content)); + } + + return logs; + } catch (error) { + console.warn("error getting today's logs:", error); + return []; + } +} + +async function dailyLogPipeline(): Promise { + console.log("starting daily log pipeline"); + + const config = await pipe.loadConfig(); + console.log("loaded config:", JSON.stringify(config, null, 2)); + + const interval = config.interval * 1000; + const summaryFrequency = config.summaryFrequency; + const emailTime = config.emailTime; + const emailAddress = config.emailAddress; + const emailPassword = config.emailPassword; + const customPrompt = config.customPrompt!; + const summaryPrompt = config.summaryPrompt!; + const gptModel = config.gptModel; + const gptApiUrl = config.gptApiUrl; + const openaiApiKey = config.openai_api_key; + const windowName = config.windowName || ""; + const pageSize = config.pageSize; + const contentType = config.contentType || "ocr"; // Default to 'ocr' if not specified + + console.log("creating logs dir"); + const logsDir = `${process.env.PIPE_DIR}/logs`; + console.log("logs dir:", logsDir); + await fs.mkdir(logsDir).catch((error) => { + console.warn("error creating logs dir:", error); + }); + + let lastEmailSent = new Date(0); // Initialize to a past date + + // send a welcome email to announce what will happen, when it will happen, and what it will do + const welcomeEmail = ` + Welcome to the daily reddit questions pipeline! + + This pipe will send you a daily list of reddit questions based on your screen data. + ${ + summaryFrequency === "daily" + ? `It will run at ${emailTime} every day.` + : `It will run every ${summaryFrequency} hours.` + } + + `; + await sendEmail( + emailAddress, + emailPassword, + "daily reddit questions", + welcomeEmail + ); + + while (true) { + try { + const now = new Date(); + const oneMinuteAgo = new Date(now.getTime() - interval); + + const screenData = await pipe.queryScreenpipe({ + start_time: oneMinuteAgo.toISOString(), + end_time: now.toISOString(), + window_name: windowName, + limit: pageSize, + content_type: contentType, + }); + + if (screenData && screenData.data && screenData.data.length > 0) { + const logEntry = await generateDailyLog( + screenData.data, + customPrompt, + gptModel, + gptApiUrl, + openaiApiKey + ); + console.log("log entry:", logEntry); + await saveDailyLog(logEntry); + } + + let shouldSendSummary = false; + + if (summaryFrequency === "daily") { + const [emailHour, emailMinute] = emailTime.split(":").map(Number); + const emailTimeToday = new Date( + now.getFullYear(), + now.getMonth(), + now.getDate(), + emailHour, + emailMinute + ); + shouldSendSummary = + now >= emailTimeToday && + now.getTime() - lastEmailSent.getTime() > 24 * 60 * 60 * 1000; + } else if (summaryFrequency.startsWith("hourly:")) { + const hours = parseInt(summaryFrequency.split(":")[1], 10); + shouldSendSummary = + now.getTime() - lastEmailSent.getTime() >= hours * 60 * 60 * 1000; + } + + if (shouldSendSummary) { + const screenData = await pipe.queryScreenpipe({ + start_time: oneMinuteAgo.toISOString(), + end_time: now.toISOString(), + window_name: windowName, + limit: pageSize, + content_type: contentType, + }); + + if (screenData && screenData.data && screenData.data.length > 0) { + const redditQuestions = await generateRedditQuestions( + screenData.data, + customPrompt, + gptModel, + gptApiUrl, + openaiApiKey + ); + console.log("reddit questions:", redditQuestions); + await sendEmail( + emailAddress, + emailPassword, + "reddit questions", + redditQuestions + ); + lastEmailSent = now; + } + } + } catch (error) { + console.warn("error in daily log pipeline:", error); + } + console.log("sleeping for", interval, "ms"); + await new Promise((resolve) => setTimeout(resolve, interval)); + } +} + +dailyLogPipeline(); From d803452ab585bfd8b7d486d1048af6c283e9235f Mon Sep 17 00:00:00 2001 From: matthew-heartful Date: Fri, 27 Sep 2024 18:23:29 -0700 Subject: [PATCH 5/6] fixed naming --- .../typescript/pipe-post-questions-on-reddit/pipe.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/typescript/pipe-post-questions-on-reddit/pipe.json b/examples/typescript/pipe-post-questions-on-reddit/pipe.json index 59276dba..ca92f637 100644 --- a/examples/typescript/pipe-post-questions-on-reddit/pipe.json +++ b/examples/typescript/pipe-post-questions-on-reddit/pipe.json @@ -34,16 +34,16 @@ "name": "gptApiUrl", "type": "string", "default": "https://api.openai.com/v1/chat/completions", - "description": "GPT API URL" + "description": "openai-compatible API URL" }, { "name": "gptModel", "type": "string", "default": "gpt-4o", - "description": "GPT Model" + "description": "AI Model name" }, { - "name": "openai_api_key", + "name": "openaiApiKey", "type": "string", "default": "", "description": "Your OpenAI API key" @@ -55,13 +55,13 @@ "description": "Number of records to retrieve from screenpipe per page for structured extraction, keep in mind LLMs have a context window limit. Increase this value if using audio." }, { - "name": "additional prompt for logs", + "name": "dailylogPrompt", "type": "string", "default": "", "description": "additional prompt for the AI assistant that will be used to extract information from the screen data every specified amount of minutes" }, { - "name": "additional prompt for reddit questions", + "name": "customPrompt", "type": "string", "default": "", "description": "additional prompt for the AI assistant that will be used to generate a list of questions to post on reddit based on the logs previously extracted" From ec3ef2be7b8e7faf92d2b16e58fde87cbd03beca Mon Sep 17 00:00:00 2001 From: matthew-heartful Date: Fri, 27 Sep 2024 18:24:02 -0700 Subject: [PATCH 6/6] distinguish between custom prompts --- .../typescript/pipe-post-questions-on-reddit/pipe.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/typescript/pipe-post-questions-on-reddit/pipe.ts b/examples/typescript/pipe-post-questions-on-reddit/pipe.ts index e29a4309..63eb74a4 100644 --- a/examples/typescript/pipe-post-questions-on-reddit/pipe.ts +++ b/examples/typescript/pipe-post-questions-on-reddit/pipe.ts @@ -7,12 +7,12 @@ interface DailyLog { async function generateDailyLog( screenData: ContentItem[], - customPrompt: string, + dailylogPrompt: string, gptModel: string, gptApiUrl: string, openaiApiKey: string ): Promise { - const prompt = `${customPrompt} + const prompt = `${dailylogPrompt} Based on the following screen data, generate a concise daily log entry: @@ -249,10 +249,10 @@ async function dailyLogPipeline(): Promise { const emailAddress = config.emailAddress; const emailPassword = config.emailPassword; const customPrompt = config.customPrompt!; - const summaryPrompt = config.summaryPrompt!; + const dailylogPrompt = config.dailylogPrompt!; const gptModel = config.gptModel; const gptApiUrl = config.gptApiUrl; - const openaiApiKey = config.openai_api_key; + const openaiApiKey = config.openaiApiKey; const windowName = config.windowName || ""; const pageSize = config.pageSize; const contentType = config.contentType || "ocr"; // Default to 'ocr' if not specified @@ -301,7 +301,7 @@ async function dailyLogPipeline(): Promise { if (screenData && screenData.data && screenData.data.length > 0) { const logEntry = await generateDailyLog( screenData.data, - customPrompt, + dailylogPrompt, // Use dailylogPrompt here instead of customPrompt gptModel, gptApiUrl, openaiApiKey