SPB Git

spb/vquant Public MIT

VibeQuant — AI-powered institutional-grade financial intelligence platform.

TypeScript 84.3% Python 11.7% JavaScript 1.6% CSS 1.5% HTML 0.7%
3.9 KB · 129 lines typescript
Raw Blame History
1/*2 * =============================================================================3 *  VibeQuant (vquant) — AI-Powered Financial Intelligence Platform4 * -----------------------------------------------------------------------------5 *  File:      server/services/slidesConverterService.ts6 *7 *  Author:    Simon-Pierre Boucher8 *  Contact:   contact@spboucher.ai9 *  Website:   https://www.spboucher.ai10 *  Demo:      https://www.vquant.ai11 *  License:   MIT (see LICENSE)12 *13 *  Copyright © 2026 Simon-Pierre Boucher. All rights reserved.14 * =============================================================================15 */1617import axios from 'axios';1819const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;20const ANTHROPIC_API_URL = 'https://api.anthropic.com/v1/messages';2122interface SlideConversionOptions {23  question: string;24  answer: string;25  author: string;26  company?: string;27}2829export interface SlideStructure {30  title: string;31  subtitle: string;32  author: string;33  company: string;34  date: string;35  slides: Array<{36    type: 'title' | 'content' | 'two-column' | 'stats' | 'conclusion';37    title?: string;38    content?: string[];39    leftColumn?: string[];40    rightColumn?: string[];41    stats?: Array<{ label: string; value: string; trend?: string }>;42    background?: string;43  }>;44}4546export async function convertToSlidesStructure(options: SlideConversionOptions): Promise<SlideStructure> {47  if (!ANTHROPIC_API_KEY) {48    throw new Error('ANTHROPIC_API_KEY not configured');49  }5051  const today = new Date().toLocaleDateString('fr-FR', {52    year: 'numeric',53    month: 'long',54    day: 'numeric'55  });5657  const systemPrompt = `You are a presentation structure expert. Analyze financial analysis content and extract a clean JSON structure for slides.5859YOUR TASK: Return ONLY a JSON object (no explanations) with this structure:60{61  "title": "Main title from question",62  "subtitle": "Brief subtitle",63  "slides": [64    {"type": "content", "title": "Slide title", "content": ["Bullet 1", "Bullet 2"]},65    {"type": "stats", "title": "Key Metrics", "stats": [{"label": "Revenue", "value": "$35.1B", "trend": "+94%"}]},66    {"type": "two-column", "title": "Comparison", "leftColumn": ["Point 1"], "rightColumn": ["Point A"]},67    {"type": "conclusion", "title": "Conclusion", "content": ["Summary point"]}68  ]69}7071RULES:72- Max 10 slides total73- Each content slide: max 5 bullets74- Extract key numbers for stats slides75- One main idea per slide76- Use type "stats" for financial metrics77- Use type "two-column" for comparisons78- Last slide must be type "conclusion"`;7980  const userPrompt = `Analyze and structure this for slides. Return ONLY JSON:8182QUESTION: ${options.question}8384ANALYSIS:85${options.answer.substring(0, 40000)}8687Extract the main points, key metrics, and insights. Structure into 6-10 slides.`;8889  try {90    console.log('[SlidesConverter] Structuring content with Claude...');9192    const response = await axios.post(93      ANTHROPIC_API_URL,94      {95        model: 'claude-opus-4-8',96        max_tokens: 8000,97        temperature: 0.1,98        messages: [{ role: 'user', content: userPrompt }],99        system: systemPrompt100      },101      {102        headers: {103          'x-api-key': ANTHROPIC_API_KEY,104          'anthropic-version': '2023-06-01',105          'content-type': 'application/json'106        },107        timeout: 60000108      }109    );110111    let jsonText = response.data.content[0].text;112    jsonText = jsonText.replace(/^```json\n?/gm, '').replace(/\n?```$/gm, '').trim();113114    const structure = JSON.parse(jsonText) as SlideStructure;115116    // Add metadata117    structure.author = options.author;118    structure.company = options.company || 'VQuant';119    structure.date = today;120121    console.log('[SlidesConverter] ✓ Structure created:', structure.slides.length, 'slides');122    return structure;123124  } catch (error) {125    console.error('[SlidesConverter] Error:', error);126    throw new Error(`Failed to structure slides: ${(error as Error).message}`);127  }128}129