Skip to content

Commit

Permalink
example: free replacement of limitless.ai & rewind.ai by screenpipe
Browse files Browse the repository at this point in the history
  • Loading branch information
louis030195 committed Jul 20, 2024
1 parent 1fb2c28 commit 3dcba94
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 0 deletions.
7 changes: 7 additions & 0 deletions examples/ts/meeting-summaries-in-obsidian/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@





need help? [i'll install this with you in less than 10 minutes](https://cal.com/louis030195/screenpipe)

7 changes: 7 additions & 0 deletions examples/ts/meeting-summaries-in-obsidian/conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const conf = () => {
const secrets = process.env.HOME + '/secrets.json'
console.log("fetching secrets.json from", secrets)
return require(secrets);
}
module.exports = conf;
// ~/secrets.json: {"OPENAI_API_KEY": "sk-..."}
101 changes: 101 additions & 0 deletions examples/ts/meeting-summaries-in-obsidian/screenpipeMeeting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
const OPENAI_API_URL = 'https://api.openai.com/v1/chat/completions';
const OPENAI_MODEL = 'gpt-4o';
// to use ollama just comment out the above and uncomment below:
// const OPENAI_API_URL = 'http://localhost:11434/api/chat';
// const OPENAI_MODEL = 'phi3:medium-128k';
// make sure to run "ollama run phi3:medium-128k"
const SCREENPIPE_API_URL = 'http://localhost:3030/search';

const generateMeetingSummary = async (openAIKey, meetingDuration, startTimestamp, endTimestamp) => {
// Step 5: Query Screenpipe API for audio transcripts
const startTime = encodeURIComponent(startTimestamp);
const screenpipeUrl = `${SCREENPIPE_API_URL}?limit=1000&offset=0&content_type=audio&start_time=${startTime}`;
console.log("going to fetch", screenpipeUrl);

const response = await fetch(screenpipeUrl);
const screenpipeResults = await response.json();
console.log("got", screenpipeResults.data.length, "results from screenpipe");

const transcriptText = JSON.stringify(screenpipeResults);

// Step 6: Generate meeting summary using ChatGPT
const summaryResponse = await fetch(OPENAI_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${openAIKey}`,
},
body: JSON.stringify({
'messages': [
{
'role': 'system',
'content': 'You are an AI assistant that summarizes meetings and extracts action items. Make sure to ignore noise from bad transcripts.'
},
{
'role': 'user',
'content': `Please summarize the following meeting transcript and provide a list of action items at the top:
${transcriptText}`
}
],
'model': OPENAI_MODEL,
'stream': false
})
})
.catch(err => console.error(err))
.then(res => res.json());
console.log("answer from AI", summaryResponse);

const summary = summaryResponse.choices?.[0]?.message?.content || summaryResponse?.message?.content.trim()

const noteTitle = `Meeting Summary - ${startTimestamp.split('T')[0]}`;
const noteContent = `# ${noteTitle}
${summary}
Meeting Duration: ${meetingDuration} minutes
Start Time: ${startTimestamp}
End Time: ${endTimestamp}
`;

return { noteTitle, noteContent };
};

const screenpipe = async (conf, meetingDuration) => {
const openAIKey = conf.openai;

// Step 1: Ask for meeting duration
if (!meetingDuration) return "Meeting duration not provided.";

// Step 2 & 3: Start recording and store start timestamp
const startTimestamp = new Date().toISOString();
new Notice(`Recording started. Meeting will end in ${meetingDuration} minutes.`);

// Step 4: Wait for the meeting duration and store end timestamp
await new Promise(resolve => setTimeout(resolve, meetingDuration * 60 * 1000));
const endTimestamp = new Date().toISOString();
new Notice("Recording stopped. Processing meeting data...");

new Notice("Generating meeting summary...");

const { noteTitle, noteContent } = await generateMeetingSummary(openAIKey, meetingDuration, startTimestamp, endTimestamp);

new Notice("Creating meeting summary note...");

// Create the new note using Obsidian API
await app.vault.create(noteTitle + '.md', noteContent);

new Notice("Meeting summary created successfully!");

return `Meeting summary created: [[${noteTitle}]]`;
};

module.exports = screenpipe;

// testing
// generateMeetingSummary(process.env.OPENAI_API_KEY, 10,
// // 1h ago
// new Date(Date.now() - 90 * 60 * 1000).toISOString(),
// // 10m ago
// new Date(Date.now() - 10 * 60 * 1000).toISOString(),
// ).then(console.log);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<% tp.user.screenpipeMeeting(tp.user.conf(), await tp.system.prompt("How long is the meeting (in minutes)?")) %>

0 comments on commit 3dcba94

Please sign in to comment.