# Project export: Stylo

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: Stylo turns your messy and dumb request for AI into a platform-tuned prompt with memory adapting to what you like with the output you dreamed about
- Devpost: https://devpost.com/software/stylo-bni68x
- GitHub: https://github.com/lolil9874/Stylo.git
- Video: https://www.youtube.com/embed/ABDIJEN68rk?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — vivi0275 (9 commits)

## Devpost submission (written by the team)

No Devpost description available.

## README (from the GitHub repository)

# Stylo

An Electron application with a transparent floating interface for macOS, featuring AI-powered text enhancement capabilities.

## Features

- **Floating Interface**: Transparent window that stays above other applications
- **Liquid Glass Effect**: Transparency and background blur for a modern look
- **Smooth Animations**: Seamless transitions between button states
- **4 Action Buttons**:
  - Text Rephrasing
  - Text Translation
  - **Prompt Enhancement** (AI-powered with GPT-4o-mini)
  - Voice Input

## 🚀 New: AI Prompt Enhancement

The **Prompt Enhancer** button (star icon) can now:
- Detect text in any input field, textarea, or contenteditable element
- Send text to Supabase Edge Function for AI processing
- Enhance prompts using GPT-4o-mini via OpenAI API
- Replace original text with AI-enhanced version
- Work across all web applications and websites

## Installation

1. Install dependencies:
```bash
npm install
```

2. Launch the application:
```bash
npm start
```

3. For development mode:
```bash
npm run dev
```

## Usage

### Basic Interface
- **Clicking buttons**: Changes the active state and triggers the action
- **Keyboard Shortcuts**:
  - `1`: Rephrase text
  - `2`: Translate text
  - `3`: **Enhance prompt with AI** (star button)
  - `4`: Activate voice input

### AI Prompt Enhancement
1. **Type text** in any input field, textarea, or contenteditable element on any website
2. **Click the star button** (Prompt Enhancer) in the floating interface
3. **Watch** as your text gets enhanced by GPT-4o-mini
4. **The enhanced text** automatically replaces your original text

### Supported Input Types
- `<input type="text">`
- `<input type="search">`
- `<input type="email">`
- `<textarea>`
- `[contenteditable="true"]` elements

## Design

- **Active buttons**: Black 100% opacity with scale animation
- **Inactive buttons**: Black 30% opacity (gray/transparent)
- **Hover state**: Black 60% opacity
- **Animations**: Cubic-bezier transitions for smooth effects
- **Glass effect**: Backdrop-filter with transparency
- **Minimalistic Apple vibe**: Clean, transparent design

## Setup for AI Features

### 1. Supabase Configuration
```bash
# Install Supabase CLI
npm install -g supabase

# Initialize and link your project
supabase init
supabase link --project-ref YOUR_PROJECT_REF

# Deploy the Edge Function
supabase functions deploy enhance-prompt
```

### 2. Environment Variables
Create `.env.local` in `supabase-functions/enhance-prompt/`:
```env
OPENAI_API_KEY=your_openai_api_key_here
```

### 3. Update Configuration
Edit `script.js` and replace:
- `YOUR_PROJECT_REF` with your Supabase project reference
- `YOUR_ANON_KEY` with your Supabase anonymous key

## Testing

Open `test-page.html` in your browser to test the AI enhancement feature with various input types.

## Project Structure

```
├── main.js                    # Main Electron process
├── index.html                 # User interface
├── styles.css                 # Styles and animations
├── script.js                  # Interaction logic + AI features
├── config.js                  # Configuration file
├── test-page.html             # Test page for AI features
├── icone/                     # SVG icons directory
├── supabase-functions/        # Supabase Edge Functions
│   ├── enhance-prompt/        # AI enhancement function
│   ├── rephrase-text/         # Text rephrasing function
│   ├── translate-text/        # Text translation function
│   ├── voice-processing/      # Voice processing function
│   └── functions-config.json  # Functions configuration
├── supabase/                  # Supabase configuration
│   └── config.toml           # Supabase config
├── env.example               # Environment variables template
└── package.json              # Project configuration
```


## Detected evidence (automated analysis)

Indexed codebase: 72 recognized source files, 533 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Supabase (technology) — detected in the code
- Swift (language) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (86 of 86)

```
.DS_Store
.env
.env.example
.gitignore
ADD_OPENAI_KEY_HERE.md
AUTO_TEST_GUIDE.md
AX_TEST_GUIDE.md
bin/StyloAXHelper
bin/StyloBridge
bin/StyloHelper
config.js
CONFIGURATION_GUIDE.md
DEBUG_VOICE.md
debug-stylo.html
deploy-functions.sh
DEPLOYMENT.md
error-popup.html
FILTRES_INTEGRATION.md
FINAL_COMPLETE_IMPLEMENTATION.md
FINAL_FIX_FOCUS.md
FINAL_IMPLEMENTATION.md
FINAL_TEST_GUIDE.md
FINAL_TEST.md
FOCUS_TEST_GUIDE.md
GLASSMORPHISM_REFONTE.md
HOW_TO_USE.md
HUGGINGFACE_SETUP.md
icone/.DS_Store
IMPLEMENTATION_SUMMARY.md
index.html
INDEX.md
main-broken.js
main-fixed.js
main.js
native-bridge/build.sh
native-bridge/StyloAXHelper.swift
native-bridge/StyloBridge.swift
native-bridge/StyloHelper.swift
NOUVELLE_APPROCHE.md
package.json
PERMISSIONS_GUIDE.md
permissions.json
preload.js
QUICK_FIX_TEST.md
QUICK_START_NO_ONBOARDING.md
QUICK_START.md
QUICK_TEST.md
README_BOUTON_STAR.md
README_FIRST.md
README.md
script.js
server.js
SETUP_OPENAI_KEY.md
SIMPLE_TEST.md
START_HERE.txt
START.md
STATUS.md
styles.css
SUCCESS.md
SUPABASE_CONFIG.md
SUPABASE_SETUP.md
supabase-functions/enhance-prompt-openrouter/index.ts
supabase-functions/functions-config.json
supabase-functions/package.json
supabase-functions/rephrase-text-openrouter/index.ts
supabase-functions/translate-text-openrouter/index.ts
supabase-functions/voice-processing/index.ts
supabase/config.toml
TEST_DEBUG_GUIDE.md
TEST_FOCUS_FIX.md
TEST_GUIDE.md
test-api.html
test-ax-bridge.js
test-buttons.html
test-deepgram-simple.html
test-function.sh
test-panel.html
test-stylo.js
test-voice-debug.html
test-voice-deepgram-real.html
test-voice-deepgram.html
test-voice-simple.html
test-voice-workflow.html
UTILISATION_GUIDE.md
VOICE_INTEGRATION_GUIDE.md
WHAT_WAS_DONE.md
```

### Dependencies

- package.json: @composio/core@^0.2.0, @composio/openai-agents@^0.2.0, @openai/agents@^0.2.1, dotenv@^17.2.3, electron@^27.3.11
- supabase-functions/package.json: supabase@^1.0.0

### Recent commits (newest first)

- fix: Improve menu auto-close detection
- feat: Per-action provider selection and menu options implementation
- fix: Add voice options support and fix menu hover behavior
- feat: Add debug logs for provider selection per action
- feat: Add per-action provider selection in menu
- fix: Enable drag for window movement and reduce panel size
- refactor: Reduce floating panel size for easier window selection
- feat: Add LettA AI provider integration
- Merge pull request #3 from lolil9874/Victor
- feat: Refonte majeure de l'interface et intégration des filtres
- Merge pull request #2 from lolil9874/main
- fix: Réinstallation des dépendances avec --legacy-peer-deps pour corriger l'erreur ENOENT d'Electron
- Merge pull request #1 from lolil9874/Victor
- Merge branch 'main' into Victor
- Refonte glassmorphism: filtres redesignés avec scroll invisible
- 🚀 Major improvements: Dock persistence + Enhanced Deepgram STT
- ✨ Refonte complète UI avec glassmorphism et optimisations
- Complete English translation and implement interactive filter system
- 🎯 Fix app name: Change from 'Electron' to 'Stylo' in menu bar
- 🎯 Simplify provider system with single choice

## Key source files (fetched from GitHub, selected and truncated for size)

### README_BOUTON_STAR.md

```markdown
# ⭐ Bouton Star - Mode d'emploi

## 🚀 Lancer Stylo

```bash
cd /Users/mrh/Desktop/Stylo
npm start
```

## 📝 Utiliser le bouton Star

**3 étapes simples :**

1. **Sélectionne du texte** n'importe où (Chrome, Notes, Slack, etc.)
2. **Click sur ⭐** dans l'interface Stylo
3. **Le texte amélioré est collé automatiquement !** ✨

## ✅ Fonctionne partout

- Gmail
- ChatGPT  
- Google Docs
- Slack
- Notes (macOS)
- N'importe quelle application !

## 🎯 Exemple

**Tu tapes :** `Write a story about a cat`

**Tu cliques sur ⭐**

**Résultat automatique :**
```
Write a compelling short story about a curious and adventurous cat.
Include vivid descriptions of the cat's personality, its environment,
and the challenges it faces. Use engaging narrative elements and
sensory details to bring the story to life.
```

**C'est tout !** 🎉

---

**Plus d'infos :** Voir `HOW_TO_USE.md` ou `FINAL_TEST.md`


```

### START.md

```markdown
# 🎯 STYLO - DÉMARRAGE RAPIDE

## ⚡ Lancer l'application

```bash
cd /Users/mrh/Desktop/Stylo
npm start
```

L'interface flottante apparaît en haut de l'écran ! ✨

## ⭐ Utiliser le bouton STAR

### Fonctionne sur N'IMPORTE QUELLE PAGE WEB !

**3 étapes :**

1. 📝 **Sélectionne du texte** (n'importe où : Chrome, Safari, Notes, Slack...)
2. ⭐ **Click sur l'étoile**
3. ✨ **Le texte est amélioré et collé automatiquement !**

### Exemple rapide :

1. Ouvre ChatGPT ou Gmail
2. Tape : `Write a story about a cat`
3. Sélectionne ce texte avec ta souris
4. Click sur ⭐
5. BOOM ! Texte amélioré ! 🎉

## 🔧 Mode développement (avec logs)

```bash
npm run dev
```

## 📚 Documentation

- **`README_BOUTON_STAR.md`** - Mode d'emploi simple
- **`HOW_TO_USE.md`** - Guide complet
- **`FINAL_TEST.md`** - Explications techniques

## 🧪 Tester l'API Supabase

```bash
open test-api.html
```

---

**C'est tout !** Lance `npm start` et teste le bouton ⭐ ! 🚀


```

### package.json

```
{
  "name": "stylo",
  "productName": "Stylo",
  "version": "1.0.0",
  "description": "Stylo - Interface flottante macOS avec IA pour l'amélioration de texte",
  "main": "main.js",
  "author": {
    "name": "Stylo",
    "email": "stylo@example.com"
  },
  "scripts": {
    "start": "ELECTRON_APP_NAME=Stylo electron .",
    "dev": "ELECTRON_APP_NAME=Stylo electron . --dev"
  },
  "keywords": [
    "electron",
    "macos",
    "floating",
    "interface",
    "ai",
    "text-enhancement",
    "stylo"
  ],
  "license": "MIT",
  "dependencies": {
    "@composio/core": "^0.2.0",
    "@composio/openai-agents": "^0.2.0",
    "@openai/agents": "^0.2.1",
    "dotenv": "^17.2.3",
    "electron": "^27.3.11"
  }
}

```

### supabase-functions/package.json

```
{
  "name": "stylo-supabase-functions",
  "version": "1.0.0",
  "description": "Supabase Edge Functions for Stylo - AI-powered text enhancement",
  "scripts": {
    "deploy": "supabase functions deploy",
    "serve": "supabase functions serve",
    "test": "supabase functions test"
  },
  "dependencies": {
    "supabase": "^1.0.0"
  },
  "devDependencies": {}
}

```

### server.js

```javascript
const express = require('express');
const path = require('path');

const app = express();
const PORT = 3000;

// Servir les fichiers statiques
app.use(express.static(__dirname));

// Route principale
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, 'index.html'));
});

// Démarrer le serveur
app.listen(PORT, () => {
  console.log(`🚀 Stylo web version running at: http://localhost:${PORT}`);
  console.log(`📂 Open your browser and visit: http://localhost:${PORT}`);
});

```

### main.js

```javascript
const { app, BrowserWindow, screen, clipboard, globalShortcut, ipcMain, shell, Menu, Tray, nativeImage } = require('electron');
const path = require('path');
const { exec } = require('child_process');
const fs = require('fs');

// Set the app name to "Stylo" - MUST be called before app.whenReady()
app.setName('Stylo');

// Also set the process title for macOS menu bar
process.title = 'Stylo';

// GPU acceleration enabled for better performance

let mainWindow;
let tray = null;
let onboardingWindow = null;
let errorPopupWindow = null;
let frontmostAppBundleId = null;
let permissionConfig = null;
let dragStart = null;
let isDragging = false;

function createWindow() {
  const { width, height } = screen.getPrimaryDisplay().workAreaSize;
  
  // Create the floating window - MACOS DOCK PERSISTENT CONFIGURATION
  mainWindow = new BrowserWindow({
    width: 200,
    height: 50,
    x: Math.round((width - 200) / 2), // Center horizontally
    y: 50, // Position at the top
    frame: false, // No title bar
    transparent: false, // Disable transparency to prevent GPU errors and dock disappearing
    alwaysOnTop: false, // Disable alwaysOnTop to maintain dock presence
    skipTaskbar: false, // Show in dock
    resizable: false,
    focusable: true, // Allow focus to maintain dock presence
    show: false, // Don't show until ready
    minimizable: true, // Allow minimizing to dock
    closable: true, // Allow closing
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js')
    }
  });

  // Load the interface
  mainWindow.loadFile('index.html');

  // Show window when ready to maintain dock presence
  mainWindow.once('ready-to-show', () => {
    mainWindow.show();
    // Ensure app stays in dock
    app.focus();
    // Set alwaysOnTop AFTER showing to maintain dock presence
    setTimeout(() => {
      mainWindow.setAlwaysOnTop(true, 'screen-saver');
    }, 100);
  });

  // Allow focus and interaction
  mainWindow.setFocusable(true);
  mainWindow.setIgnoreMouseEvents(false);
  
  // Ensure window is draggable
  mainWindow.setMovable(true);
  
  // Force enable dragging - DÉSACTIVÉ pour permettre la sélection de texte
  /* mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.webContents.executeJavaScript(`
      // Ensure drag regions are properly set
      const draggableArea = document.querySelector('.draggable-area');
      if (draggableArea) {
        draggableArea.style.webkitAppRegion = 'drag';
        console.log('✅ Drag region enabled');
      }
    `);
  }); */

  // Create tray icon for easy access
  createTray();
  mainWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
  
  // Open DevTools in development mode
  if (process.argv.includes('--dev')) {
    mainWindow.webContents.openDevTools();
  }

  // Use CSS-based drag regions only; no programmatic dragging
}

// MARK: - Helper function to get provider for action
function getProviderForAction(action) {
  const configPath = path.join(__dirname, 'config.js');
  const config = fs.readFileSync(configPath, 'utf8');
  
  // Map des noms d'actions vers les noms de config
  const actionMap = {
    'rephrase': 'rephrase',
    'translate': 'translate',
    'enhance': 'enhance',
    'voice': 'voice'
  };
  
  const configKey = actionMap[action] || 'default';
  const regex = new RegExp(`${configKey}:\\s*'(\\w+)'`);
  const match = config.match(regex);
  return match ? match[1] : 'letta';
}

// MARK: - Menu Configuration
function createMenu() {
  const template = [
    {
      label: 'Stylo',
      submenu: [
        {
          label: 'About Stylo',
          role: 'about'
        },
        { type: 'separator' },
        {
          label: 'Quit Stylo',
          accelerator: 'CmdOrCtrl+Q',
          click: () => app.quit()
        }
      ]
    },
    {
      label: 'Provider',
      submenu: [
        {
          label: 'Rephrase',
          submenu: [
            {
              label: 'LettA AI',
              type: 'radio',
              checked: getProviderForAction('rephrase') === 'letta',
              click: () => updateProvider('rephrase', 'letta')
            },
            {
              label: 'OpenRouter (Llama 3.3)',
              type: 'radio',
              checked: getProviderForAction('rephrase') === 'openrouter',
              click: () => updateProvider('rephrase', 'openrouter')
            },
            {
              label: 'OpenAI (GPT-4o-mini)',
              type: 'radio',
              checked: getProviderForAction('rephrase') === 'openai',
              click: () => updateProvider('rephrase', 'openai')
            }
          ]
        },
        {
          label: 'Translate',
          submenu: [
            {
              label: 'LettA AI',
              type: 'radio',
              checked: getProviderForAction('translate') === 'letta',
              click: () => updateProvider('translate', 'letta')
            },
            {
              label: 'OpenRouter (Llama 3.3)',
              type: 'radio',
              checked: getProviderForAction('translate') === 'openrouter',
              click: () => updateProvider('translate', 'openrouter')
            },
            {
              label: 'OpenAI (GPT-4o-mini)',
              type: 'radio',
              checked: getProviderForAction('translate') === 'openai',
              click: () => updateProvider('translate', 'openai')
            }
          ]
        },
        {
          label: 'Enhance',
          submenu: [
            {
              label: 'LettA AI',
              type: 'radio',
              checked: getProviderForAction('enhance') === 'letta',
              click: () => updateProvider('enhance', 'letta')
            },
            {
              label: 'OpenRouter (Llama 3.3)',
              type: 'radio',
              checked: getProviderForAction('enhance') === 'openrouter',
              click: () => updateProvider('enhance', 
[truncated — 11648 more characters]
```

### supabase-functions/enhance-prompt-openrouter/index.ts

```typescript
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}

serve(async (req) => {
  // Handle CORS preflight requests
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }

  try {
    // Récupérer le texte et les options depuis la requête
    const { text, options = {} } = await req.json()
    
    if (!text || typeof text !== 'string') {
      return new Response(
        JSON.stringify({ error: 'Text is required' }),
        { 
          status: 400, 
          headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
        }
      )
    }

    // Extraire les paramètres des options (frontend envoie: goal, audience, detail, format)
    const goal = options.goal || 'informative'
    const audience = options.audience || 'general'
    const detail = options.detail || 'balanced'
    const format = options.format || 'paragraph'

    // Configuration OpenAI
    const openaiApiKey = Deno.env.get('OPENAI_API_KEY')
    if (!openaiApiKey) {
      throw new Error('OpenAI API key not found')
    }

    // Build dynamic system prompt based on options
    const goalPrompts = {
      informative: 'make this prompt more informative and comprehensive',
      creative: 'make this prompt more creative and engaging',
      analytical: 'make this prompt more analytical and detailed',
      technical: 'make this prompt more technical and precise'
    }
    
    const audiencePrompts = {
      general: 'suitable for a general audience',
      expert: 'suitable for expert-level audience',
      beginner: 'suitable for beginners',
      technical: 'suitable for technical users'
    }
    
    const detailPrompts = {
      concise: 'more concise and direct',
      balanced: 'balanced level of detail',
      detailed: 'more detailed and comprehensive'
    }
    
    const formatPrompts = {
      paragraph: 'in paragraph format',
      bullet: 'in bullet point format',
      numbered: 'in numbered list format'
    }

    const systemPrompt = `${goalPrompts[goal] || goalPrompts.informative}, 
${audiencePrompts[audience] || audiencePrompts.general}, 
${detailPrompts[detail] || detailPrompts.balanced}, 
${formatPrompts[format] || formatPrompts.paragraph}.
Make it more clear, specific, and effective. Return only the enhanced prompt, no explanations.`

    // Appel à l'API OpenAI
    const openaiResponse = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${openaiApiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: 'gpt-4o-mini',
        messages: [
          {
            role: 'system',
            content: 'You are a prompt enhancement expert.'
          },
          {
            role: 'user',
            content: `${systemPrompt}\n\nOriginal prompt:\n${text}`
          }
        ],
        max_tokens: 1000,
        temperature: 0.7,
      }),
    })

    if (!openaiResponse.ok) {
      const errorData = await openaiResponse.json()
      console.error('OpenAI API error:', errorData)
      throw new Error(`OpenAI API error: ${openaiResponse.status}`)
    }

    const openaiData = await openaiResponse.json()
    const enhancedText = openaiData.choices[0]?.message?.content

    if (!enhancedText) {
      throw new Error('No enhanced text received from OpenAI')
    }

    // Retourner la réponse
    return new Response(
      JSON.stringify({ 
        enhanced_text: enhancedText,
        original_text: text,
        options_used: { goal, audience, detail, format },
        model_used: 'gpt-4o-mini'
      }),
      { 
        status: 200, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    )

  } catch (error) {
    console.error('Error in enhance-prompt function:', error)
    
    return new Response(
      JSON.stringify({ 
        error: 'Internal server error',
        details: error.message 
      }),
      { 
        status: 500, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    )
  }
})

```

### supabase-functions/rephrase-text-openrouter/index.ts

```typescript
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}

serve(async (req) => {
  // Handle CORS preflight requests
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }

  try {
    // Récupérer le texte et les options depuis la requête
    const { text, options = {} } = await req.json()
    
    if (!text || typeof text !== 'string') {
      return new Response(
        JSON.stringify({ error: 'Text is required' }),
        { 
          status: 400, 
          headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
        }
      )
    }

    // Extraire les paramètres des options (frontend envoie: type, tone, length, corrections)
    const type = options.type || 'professional'
    const tone = options.tone || 'neutral'
    const length = options.length || 'same'
    const corrections = options.corrections || 'all'

    // Configuration OpenAI
    const openaiApiKey = Deno.env.get('OPENAI_API_KEY')
    if (!openaiApiKey) {
      throw new Error('OpenAI API key not found')
    }

    // Build dynamic system prompt based on options
    const typePrompts = {
      professional: 'professional and formal tone',
      casual: 'casual and friendly tone',
      formal: 'highly formal and academic tone',
      simple: 'simple and straightforward tone'
    }
    
    const tonePrompts = {
      neutral: 'balanced and neutral tone',
      friendly: 'warm and friendly tone',
      assertive: 'confident and assertive tone',
      persuasive: 'persuasive and compelling tone'
    }
    
    const lengthPrompts = {
      shorter: 'Make it shorter and more concise',
      same: 'Keep approximately the same length',
      longer: 'Expand with more detail'
    }
    
    const correctionPrompt = corrections === 'all' ? 'Correct all grammar and spelling errors'
                           : corrections === 'grammar' ? 'Focus on grammar corrections'
                           : corrections === 'spelling' ? 'Focus on spelling corrections'
                           : 'Minimal corrections, maintain original style'

    const systemPrompt = `You are a text rephrasing expert. Rephrase the following text with:
- Style: ${typePrompts[type] || typePrompts.professional}
- Tone: ${tonePrompts[tone] || tonePrompts.neutral}
- Length: ${lengthPrompts[length] || lengthPrompts.same}
- Corrections: ${correctionPrompt}

Maintain the original meaning and intent. Return only the rephrased text, no explanations.`

    // Appel à l'API OpenAI
    const openaiResponse = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${openaiApiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: 'gpt-4o-mini',
        messages: [
          {
            role: 'system',
            content: 'You are a professional text rephrasing assistant.'
          },
          {
            role: 'user',
            content: `${systemPrompt}\n\nOriginal text:\n${text}`
          }
        ],
        max_tokens: 1000,
        temperature: 0.7,
      }),
    })

    if (!openaiResponse.ok) {
      const errorData = await openaiResponse.json()
      console.error('OpenAI API error:', errorData)
      throw new Error(`OpenAI API error: ${openaiResponse.status}`)
    }

    const openaiData = await openaiResponse.json()
    const rephrasedText = openaiData.choices[0]?.message?.content

    if (!rephrasedText) {
      throw new Error('No rephrased text received from OpenAI')
    }

    // Retourner la réponse
    return new Response(
      JSON.stringify({ 
        rephrased_text: rephrasedText,
        original_text: text,
        options_used: { type, tone, length, corrections },
        model_used: 'gpt-4o-mini'
      }),
      { 
        status: 200, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    )

  } catch (error) {
    console.error('Error in rephrase-text function:', error)
    
    return new Response(
      JSON.stringify({ 
        error: 'Internal server error',
        details: error.message 
      }),
      { 
        status: 500, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    )
  }
})

```

### supabase-functions/voice-processing/index.ts

```typescript
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}

serve(async (req) => {
  // Handle CORS preflight requests
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }

  try {
    // Récupérer les données audio et les paramètres depuis la requête
    const { audio_data, action = 'transcribe', language = 'auto' } = await req.json()
    
    if (!audio_data) {
      return new Response(
        JSON.stringify({ error: 'Audio data is required' }),
        { 
          status: 400, 
          headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
        }
      )
    }

    // Configuration OpenAI
    const openaiApiKey = Deno.env.get('OPENAI_API_KEY')
    if (!openaiApiKey) {
      throw new Error('OpenAI API key not found')
    }

    let result;

    if (action === 'transcribe') {
      // Transcription audio en texte
      const transcriptionResponse = await fetch('https://api.openai.com/v1/audio/transcriptions', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${openaiApiKey}`,
        },
        body: createFormData(audio_data, 'audio.m4a', language)
      })

      if (!transcriptionResponse.ok) {
        const errorData = await transcriptionResponse.json()
        throw new Error(`Transcription error: ${transcriptionResponse.status} - ${errorData.error?.message}`)
      }

      const transcriptionData = await transcriptionResponse.json()
      result = {
        type: 'transcription',
        text: transcriptionData.text,
        language: language
      }

    } else if (action === 'analyze') {
      // Analyse du contenu vocal avec IA
      const analysisResponse = await fetch('https://api.openai.com/v1/chat/completions', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${openaiApiKey}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          model: 'gpt-4o-mini',
          messages: [
            {
              role: 'system',
              content: `You are a voice content analyzer. Analyze the transcribed voice content and provide insights about:
              - Main topics discussed
              - Key points and action items
              - Sentiment and tone
              - Suggestions for improvement
              - Summary of the content
              
              Provide a structured analysis in JSON format.`
            },
            {
              role: 'user',
              content: `Analyze this voice content: ${audio_data}`
            }
          ],
          max_tokens: 1000,
          temperature: 0.7,
        }),
      })

      if (!analysisResponse.ok) {
        const errorData = await analysisResponse.json()
        throw new Error(`Analysis error: ${analysisResponse.status}`)
      }

      const analysisData = await analysisResponse.json()
      result = {
        type: 'analysis',
        analysis: analysisData.choices[0]?.message?.content,
        language: language
      }

    } else {
      throw new Error('Invalid action. Supported actions: transcribe, analyze')
    }

    // Retourner la réponse
    return new Response(
      JSON.stringify({ 
        ...result,
        action_performed: action,
        model_used: 'gpt-4o-mini',
        timestamp: new Date().toISOString()
      }),
      { 
        status: 200, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    )

  } catch (error) {
    console.error('Error in voice-processing function:', error)
    
    return new Response(
      JSON.stringify({ 
        error: 'Internal server error',
        details: error.message 
      }),
      { 
        status: 500, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    )
  }
})

// Helper function to create FormData for audio upload
function createFormData(audioData: string, filename: string, language: string): FormData {
  const formData = new FormData()
  
  // Convert base64 audio data to blob
  const audioBlob = new Blob([Uint8Array.from(atob(audioData), c => c.charCodeAt(0))], {
    type: 'audio/m4a'
  })
  
  formData.append('file', audioBlob, filename)
  formData.append('model', 'whisper-1')
  formData.append('language', language === 'auto' ? '' : language)
  formData.append('response_format', 'json')
  
  return formData
}

```

### supabase-functions/translate-text-openrouter/index.ts

```typescript
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}

serve(async (req) => {
  // Handle CORS preflight requests
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }

  try {
    // Récupérer le texte et les options depuis la requête
    const { text, options = {} } = await req.json()
    
    if (!text || typeof text !== 'string') {
      return new Response(
        JSON.stringify({ error: 'Text is required' }),
        { 
          status: 400, 
          headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
        }
      )
    }

    // Extraire les paramètres des options (frontend envoie: target, style, context)
    const target = options.target || 'en'
    const style = options.style || 'standard'
    const context = options.context || 'general'
    
    // Map de langue code -> langue complète
    const languageMap: Record<string, string> = {
      en: 'English',
      es: 'Spanish', 
      de: 'German',
      fr: 'French',
      zh: 'Chinese',
      it: 'Italian',
      pt: 'Portuguese',
      ja: 'Japanese',
      ko: 'Korean',
      ru: 'Russian',
      ar: 'Arabic'
    }
    
    const target_language = languageMap[target] || 'English'
    const source_language = 'auto' // Auto-detect
    
    // Configuration OpenAI
    const openaiApiKey = Deno.env.get('OPENAI_API_KEY')
    if (!openaiApiKey) {
      throw new Error('OpenAI API key not found')
    }

    // Build context-based system prompt
    const contextPrompt = context === 'business' ? 'business and professional context' 
                       : context === 'technical' ? 'technical and specialized context'
                       : 'general context'
    
    const stylePrompt = style === 'formal' ? 'formal and professional tone'
                      : style === 'casual' ? 'casual and friendly tone'
                      : 'natural and standard tone'

    // Appel à l'API OpenAI
    const openaiResponse = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${openaiApiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: 'gpt-4o-mini',
        messages: [
          {
            role: 'system',
            content: `You are a professional translator. Translate the given text to ${target_language}, maintaining the original tone and style. Adapt to ${contextPrompt} and use a ${stylePrompt}. Return only the translated text, no explanations.
            
Guidelines:
- Provide accurate and natural translation
- Maintain the original tone and style
- Preserve formatting and structure when possible
- If the source language is 'auto', detect it automatically
- Return only the translated text, no explanations
- If the text is already in the target language, return it as is`
          },
          {
            role: 'user',
            content: `Translate this text to ${target_language}:\n\n${text}`
          }
        ],
        max_tokens: 1000,
        temperature: 0.3, // Lower temperature for more consistent translations
      }),
    })

    if (!openaiResponse.ok) {
      const errorData = await openaiResponse.json()
      console.error('OpenAI API error:', errorData)
      throw new Error(`OpenAI API error: ${openaiResponse.status}`)
    }

    const openaiData = await openaiResponse.json()
    const translatedText = openaiData.choices[0]?.message?.content

    if (!translatedText) {
      throw new Error('No translated text received from OpenAI')
    }

    // Retourner la réponse
    return new Response(
      JSON.stringify({ 
        translated_text: translatedText,
        original_text: text,
        source_language: source_language,
        target_language: target_language,
        target: target,
        style: style,
        context: context,
        model_used: 'gpt-4o-mini'
      }),
      { 
        status: 200, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    )

  } catch (error) {
    console.error('Error in translate-text function:', error)
    
    return new Response(
      JSON.stringify({ 
        error: 'Internal server error',
        details: error.message 
      }),
      { 
        status: 500, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    )
  }
})

```

[62 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]