UNPKG

claudes-office

Version:

CLI tool to initialize Claude's office in your project

279 lines 11 kB
"use strict"; /** * 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