claudes-office
Version:
CLI tool to initialize Claude's office in your project
279 lines • 11 kB
JavaScript
;
/**
* Meeting generation functionality for claudes-office
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateMeeting = generateMeeting;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const commands_1 = require("../types/commands");
const prompts_1 = require("./prompts");
const axios_1 = __importDefault(require("axios"));
/**
* Generate a meeting using the specified options
* @param options - Meeting generation options
* @returns Result of the meeting generation
*/
async function generateMeeting(options) {
// Get LLM configuration from environment
const config = getLLMConfigFromEnvironment();
// Load agenda file if specified as path
let agendaContent = '';
let agendaItems = [];
if (options.agenda) {
if (typeof options.agenda === 'string') {
try {
// Check if the agenda is a file path
if (await fs.pathExists(options.agenda)) {
agendaContent = await fs.readFile(options.agenda, 'utf8');
agendaItems = agendaContent.split('\n').map(line => line.trim()).filter(Boolean);
}
else {
// It's a single agenda item
agendaItems = [options.agenda];
}
}
catch (error) {
// If there's an error reading the file, treat it as a direct agenda item
agendaItems = [options.agenda];
}
}
else if (Array.isArray(options.agenda)) {
// It's already an array of agenda items
agendaItems = options.agenda;
}
}
// Prepare meeting options
const meetingOptions = {
title: options.title || `${options.type || commands_1.MeetingType.PLANNING} Meeting`,
type: options.type || commands_1.MeetingType.PLANNING,
participants: Array.isArray(options.participants) ? options.participants :
(options.participants ? [options.participants] : []),
agenda: agendaItems,
duration: options.duration || 60,
date: new Date().toISOString(),
};
// Get the prompt for this meeting type
const prompt = await (0, prompts_1.getMeetingPrompt)(meetingOptions);
// Call the LLM with the prompt
const llmResponse = await callLLM(config, prompt);
// Parse the response
const result = parseResponse(llmResponse);
// Determine output paths
const outputDir = options.output || 'claudes-office/meetings';
const dateStr = new Date().toISOString().split('T')[0];
const titleSlug = meetingOptions.title.toLowerCase().replace(/\s+/g, '-');
const filePrefix = `${dateStr}-${titleSlug}`;
// Create output directories
await fs.ensureDir(path.join(outputDir, 'transcripts'));
await fs.ensureDir(path.join(outputDir, 'minutes'));
// Write files
const transcriptPath = path.join(outputDir, 'transcripts', `${filePrefix}.md`);
const minutesPath = path.join(outputDir, 'minutes', `${filePrefix}.md`);
await fs.writeFile(transcriptPath, result.transcript);
await fs.writeFile(minutesPath, result.minutes);
return {
transcriptPath,
minutesPath,
summary: result.summary,
};
}
/**
* Get LLM configuration from environment variables
* @returns LLM configuration
*/
function getLLMConfigFromEnvironment() {
// Check for SMART_MODEL environment variable
const modelEnv = process.env.SMART_MODEL || '';
// Default to Anthropic Claude if not specified
if (!modelEnv) {
return {
model: 'claude-3-opus-20240229',
endpoint: 'https://api.anthropic.com/v1/messages',
apiKey: process.env.ANTHROPIC_API_KEY || '',
};
}
// Parse environment variable
// Expected format: provider:model (e.g., "anthropic:claude-3-opus")
const [provider, model] = modelEnv.split(':');
switch (provider.toLowerCase()) {
case 'anthropic':
return {
model: model || 'claude-3-opus-20240229',
endpoint: 'https://api.anthropic.com/v1/messages',
apiKey: process.env.ANTHROPIC_API_KEY || '',
};
case 'openai':
return {
model: model || 'gpt-4',
endpoint: 'https://api.openai.com/v1/chat/completions',
apiKey: process.env.OPENAI_API_KEY || '',
organizationId: process.env.OPENAI_ORG_ID,
};
case 'local':
// For local LLM server (e.g., Ollama)
return {
model: model || 'mistral',
endpoint: process.env.LOCAL_LLM_ENDPOINT || 'http://localhost:11434/api/generate',
apiKey: '',
};
default:
throw new Error(`Unsupported model provider: ${provider}`);
}
}
/**
* Call the LLM API with a prompt
* @param config - LLM configuration
* @param prompt - Prompt to send to the LLM
* @returns LLM response
*/
async function callLLM(config, prompt) {
// Determine which API to call based on the configuration
if (config.endpoint.includes('anthropic')) {
return callAnthropic(config, prompt);
}
else if (config.endpoint.includes('openai')) {
return callOpenAI(config, prompt);
}
else {
return callLocalLLM(config, prompt);
}
}
/**
* Call the Anthropic API
* @param config - LLM configuration
* @param prompt - Prompt to send to the LLM
* @returns LLM response
*/
async function callAnthropic(config, prompt) {
var _a;
try {
const response = await axios_1.default.post(config.endpoint, {
model: config.model,
messages: [{ role: 'user', content: prompt }],
max_tokens: 4000,
}, {
headers: {
'Content-Type': 'application/json',
'X-API-Key': config.apiKey,
'anthropic-version': '2023-06-01',
},
});
return response.data.content[0].text;
}
catch (error) {
console.error('Error calling Anthropic API:', ((_a = error.response) === null || _a === void 0 ? void 0 : _a.data) || error.message);
throw new Error(`Failed to generate meeting with Anthropic: ${error.message}`);
}
}
/**
* Call the OpenAI API
* @param config - LLM configuration
* @param prompt - Prompt to send to the LLM
* @returns LLM response
*/
async function callOpenAI(config, prompt) {
var _a;
try {
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${config.apiKey}`,
};
if (config.organizationId) {
headers['OpenAI-Organization'] = config.organizationId;
}
const response = await axios_1.default.post(config.endpoint, {
model: config.model,
messages: [{ role: 'user', content: prompt }],
max_tokens: 4000,
}, { headers });
return response.data.choices[0].message.content;
}
catch (error) {
console.error('Error calling OpenAI API:', ((_a = error.response) === null || _a === void 0 ? void 0 : _a.data) || error.message);
throw new Error(`Failed to generate meeting with OpenAI: ${error.message}`);
}
}
/**
* Call a local LLM API
* @param config - LLM configuration
* @param prompt - Prompt to send to the LLM
* @returns LLM response
*/
async function callLocalLLM(config, prompt) {
var _a;
try {
const response = await axios_1.default.post(config.endpoint, {
model: config.model,
prompt: prompt,
stream: false,
});
return response.data.response || response.data.output || response.data.generated_text;
}
catch (error) {
console.error('Error calling local LLM API:', ((_a = error.response) === null || _a === void 0 ? void 0 : _a.data) || error.message);
throw new Error(`Failed to generate meeting with local LLM: ${error.message}`);
}
}
/**
* Parse the LLM response into transcript, minutes, and summary
* @param response - Raw LLM response
* @returns Parsed meeting result
*/
function parseResponse(response) {
var _a, _b, _c;
// Look for transcript and minutes sections in the response
const transcriptMatch = response.match(/## Transcript\s+([\s\S]+?)(?=## Minutes|$)/i);
const minutesMatch = response.match(/## Minutes\s+([\s\S]+?)(?=## Summary|$)/i);
const summaryMatch = response.match(/## Summary\s+([\s\S]+?)$/i);
// Extract transcript, minutes, and summary
const transcript = ((_a = transcriptMatch === null || transcriptMatch === void 0 ? void 0 : transcriptMatch[1]) === null || _a === void 0 ? void 0 : _a.trim()) || response;
const minutes = ((_b = minutesMatch === null || minutesMatch === void 0 ? void 0 : minutesMatch[1]) === null || _b === void 0 ? void 0 : _b.trim()) || 'No minutes available';
const summary = ((_c = summaryMatch === null || summaryMatch === void 0 ? void 0 : summaryMatch[1]) === null || _c === void 0 ? void 0 : _c.trim()) || 'No summary available';
// Format transcript
const formattedTranscript = `# Meeting Transcript\n\n${transcript}`;
// Format minutes
const formattedMinutes = `# Meeting Minutes\n\n${minutes}\n\n## Summary\n\n${summary}`;
return {
transcript: formattedTranscript,
minutes: formattedMinutes,
summary,
};
}
//# sourceMappingURL=generator.js.map