API - emielregis2/SmartFlowAI GitHub Wiki

🔌 API i Integracje - SmartFlowAI

Kompletny przewodnik po wszystkich API używanych w SmartFlowAI - od konfiguracji po zaawansowane integracje.

🎯 Przegląd API

SmartFlowAI integruje się z 3 głównymi API plus dodatkowymi serwisami:

API Funkcja Status Koszt
🤖 OpenAI GPT-4o Analiza procesów AI Produkcja $0.01-0.03/1K tokenów
🗄️ Supabase Baza danych + Auth Produkcja $0-25/miesiąc
📄 fpdf2 Generowanie PDF Lokalne Darmowe
🌐 Web Search Aktualne dane Planowane TBD

🤖 OpenAI API

Konfiguracja

Wymagany klucz API:

# .streamlit/secrets.toml
OPENAI_API_KEY = "sk-proj-..."

Inicjalizacja w kodzie:

@st.cache_resource  
def init_openai():
    api_key = os.getenv("OPENAI_API_KEY")
    if not api_key:
        api_key = st.secrets.get("OPENAI_API_KEY", "")
    
    if not api_key:
        st.error("❌ Brak klucza OpenAI!")
        st.stop()
    
    openai.api_key = api_key
    return openai

Użycie w aplikacji

Główna funkcja analizy:

def analyze_with_ai(title: str, description: str, 
                   analysis_depth: str = "Pogłębiona",
                   company_size: str = "", 
                   industry: str = "", 
                   budget: str = "") -> str:

3 poziomy analizy:

🚀 Podstawowa (15-30s)

  • Prompt: 200-300 tokenów
  • Odpowiedź: 500-800 tokenów
  • Koszt: ~$0.02-0.03
  • Format: 5 sekcji (Analiza, Rozwiązanie, Koszt, Oszczędności, Kroki)

⚡ Pogłębiona (30-60s)

  • Prompt: 800-1200 tokenów
  • Odpowiedź: 1500-2500 tokenów
  • Koszt: ~$0.05-0.08
  • Format: 7 sekcji + badanie rynku + plan wdrożenia

🎯 Ekspercka (60-90s)

  • Prompt: 1500-2000 tokenów
  • Odpowiedź: 3000-5000 tokenów
  • Koszt: ~$0.10-0.15
  • Format: 7 szczegółowych sekcji + ROI + monitoring

Branżowe specjalizacje

System automatycznie dodaje kontekst branżowy:

industry_context = {
    "E-commerce/Handel": "Allegro, Amazon, BaseLinker, Shopify...",
    "Księgowość": "iFirma, Wfirma, SAP, Comarch ERP, JPK...",
    "Marketing/Reklama": "Facebook Ads, Google Ads, HubSpot...",
    "IT/Software": "GitHub, Jira, Slack, CI/CD...",
    # ... 9 branż łącznie
}

Obsługa błędów

Tryb demo dla testów:

class MockOpenAI:
    def __init__(self):
        self.api_key = "test-key"
    
    def chat_completions_create(self, **kwargs):
        return "🔍 **ANALIZA:** Mock analiza procesu..."

Fallback dla błędów API:

  • Automatyczne przełączenie na tryb demo
  • Logowanie błędów do smartflow_debug.log
  • Komunikaty użytkownika w UI

Koszty i limity

Miesięczne użycie (szacunki):

  • Startup (50 analiz): $2-5
  • SME (200 analiz): $8-20
  • Enterprise (1000 analiz): $40-100

Rate limits:

  • GPT-4o: 10,000 RPM (requests per minute)
  • Tokens: 30M TPM (tokens per minute)
  • Batch: 90% taniej, ale wolniejsze

🗄️ Supabase API

Konfiguracja

Wymagane klucze:

# .streamlit/secrets.toml
SUPABASE_URL = "https://xxx.supabase.co"
SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIs..."
SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIs..."

Inicjalizacja:

@st.cache_resource
def init_supabase():
    url = os.getenv("SUPABASE_URL") or st.secrets.get("SUPABASE_URL")
    key = (os.getenv("SUPABASE_SERVICE_ROLE_KEY") or 
           st.secrets.get("SUPABASE_SERVICE_ROLE_KEY") or
           st.secrets.get("SUPABASE_ANON_KEY"))
    
    return create_client(url, key)

Struktura bazy danych

Tabela processes:

CREATE TABLE processes (
    id SERIAL PRIMARY KEY,
    user_id UUID REFERENCES auth.users(id),
    title VARCHAR(255) NOT NULL,
    description TEXT NOT NULL,
    ai_analysis TEXT NOT NULL,
    company_size VARCHAR(50),
    industry VARCHAR(100),
    budget VARCHAR(50),
    analysis_depth VARCHAR(50),
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

Tabela users (Supabase Auth):

-- Automatycznie zarządzana przez Supabase Auth
-- Zawiera: id, email, created_at, last_sign_in_at

CRUD operacje

Create - Zapis procesu

def save_process(title: str, description: str, ai_analysis: str):
    try:
        user_id = get_user_id(st.session_state.user['email'])
        
        result = supabase.table('processes').insert({
            'user_id': user_id,
            'title': title,
            'description': description,
            'ai_analysis': ai_analysis,
            'company_size': st.session_state.get('company_size', ''),
            'industry': st.session_state.get('industry', ''),
            'budget': st.session_state.get('budget', ''),
            'analysis_depth': st.session_state.get('analysis_depth', 'Pogłębiona')
        }).execute()
        
        return result.data[0]['id']
    except Exception as e:
        logger.error(f"SAVE_PROCESS_ERROR: {e}")
        return None

Read - Pobieranie procesów

def get_processes():
    try:
        user_id = get_user_id(st.session_state.user['email'])
        
        result = supabase.table('processes')\
            .select('*')\
            .eq('user_id', user_id)\
            .order('created_at', desc=True)\
            .execute()
            
        return result.data
    except Exception as e:
        logger.error(f"GET_PROCESSES_ERROR: {e}")
        return []

Update - Edycja procesu

def update_process(process_id: int, title: str, description: str, ai_analysis: str):
    try:
        user_id = get_user_id(st.session_state.user['email'])
        
        # Sprawdź czy proces należy do użytkownika
        check = supabase.table('processes')\
            .select('id')\
            .eq('id', process_id)\
            .eq('user_id', user_id)\
            .execute()
            
        if not check.data:
            return False
            
        # Aktualizuj proces
        result = supabase.table('processes')\
            .update({
                'title': title,
                'description': description, 
                'ai_analysis': ai_analysis,
                'updated_at': 'NOW()'
            })\
            .eq('id', process_id)\
            .execute()
            
        return len(result.data) > 0
    except Exception as e:
        logger.error(f"UPDATE_PROCESS_ERROR: {e}")
        return False

Delete - Usuwanie procesu

def delete_process(process_id: int):
    try:
        user_id = get_user_id(st.session_state.user['email'])
        
        result = supabase.table('processes')\
            .delete()\
            .eq('id', process_id)\
            .eq('user_id', user_id)\
            .execute()
            
        return len(result.data) > 0
    except Exception as e:
        logger.error(f"DELETE_PROCESS_ERROR: {e}")
        return False

Autentykacja

Logowanie:

def login_user(email: str, password: str):
    try:
        response = supabase.auth.sign_in_with_password({
            "email": email,
            "password": password
        })
        return response.user
    except Exception as e:
        return None

Rejestracja:

def register_user(email: str, password: str):
    try:
        response = supabase.auth.sign_up({
            "email": email,
            "password": password
        })
        return response.user
    except Exception as e:
        return None

Row Level Security (RLS)

Polityki bezpieczeństwa:

-- Użytkownicy widzą tylko swoje procesy
CREATE POLICY "Users can view own processes" ON processes
    FOR SELECT USING (auth.uid() = user_id);

-- Użytkownicy mogą dodawać procesy
CREATE POLICY "Users can insert own processes" ON processes
    FOR INSERT WITH CHECK (auth.uid() = user_id);

-- Użytkownicy mogą edytować swoje procesy  
CREATE POLICY "Users can update own processes" ON processes
    FOR UPDATE USING (auth.uid() = user_id);

-- Użytkownicy mogą usuwać swoje procesy
CREATE POLICY "Users can delete own processes" ON processes
    FOR DELETE USING (auth.uid() = user_id);

Obsługa błędów

Najczęstsze błędy z logów:

  1. Invalid API key
supabase._sync.client.SupabaseException: Invalid API key

Rozwiązanie: Sprawdź klucze w secrets.toml

  1. Tabela nie istnieje
{'message': 'relation "public.processes" does not exist', 'code': '42P01'}

Rozwiązanie: Uruchom supabase_setup.sql

  1. Błąd mapowania użytkownika
ERROR - GET_PROCESSES_ERROR: Nie można znaleźć user_id dla [email protected]

Rozwiązanie: Sprawdź czy email w bazie to .com czy .pl

Koszty Supabase

Plan darmowy (do 500MB):

  • 50,000 miesięcznych aktywnych użytkowników
  • 500MB przestrzeni bazodanowej
  • 1GB transferu
  • 2GB bandwidth

Plan Pro ($25/miesiąc):

  • 100,000 MAU
  • 8GB przestrzeni
  • 250GB transferu
  • Backup automatyczny

📄 fpdf2 API

Instalacja i import

from fpdf import FPDF

Generowanie PDF

Główna funkcja:

def generate_pdf_report(processes_data):
    pdf = FPDF()
    pdf.add_page()
    
    # Dodaj czcionkę obsługującą polskie znaki
    pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True)
    pdf.set_font('DejaVu', size=12)
    
    # Nagłówek
    pdf.cell(0, 10, 'SmartFlowAI - Raport Procesów', ln=True, align='C')
    pdf.ln(10)
    
    # Treść procesów
    for process in processes_data:
        pdf.cell(0, 8, f"Proces: {process['title']}", ln=True)
        pdf.ln(5)
        
        # Opis z podziałem na linie
        description_lines = process['description'].split('\n')
        for line in description_lines:
            pdf.cell(0, 6, line, ln=True)
        pdf.ln(5)
        
        # Analiza AI z formatowaniem
        ai_lines = process['ai_analysis'].split('\n')
        for line in ai_lines:
            if line.startswith('🔍') or line.startswith('🛠️'):
                pdf.set_font('DejaVu', 'B', 10)  # Pogrubienie
            else:
                pdf.set_font('DejaVu', '', 10)
            pdf.cell(0, 5, line, ln=True)
        
        pdf.ln(10)
    
    return pdf.output(dest='S').encode('latin-1')

Obsługa polskich znaków

Problem: fpdf2 domyślnie nie obsługuje UTF-8 Rozwiązanie: Użycie czcionki DejaVu

def safe_text(text):
    """Bezpieczne przetwarzanie tekstu dla PDF"""
    try:
        return text.encode('latin-1').decode('latin-1')
    except UnicodeEncodeError:
        # Fallback - usuń problematyczne znaki
        return text.encode('ascii', 'ignore').decode('ascii')

Formatowanie treści

Funkcja czyszczenia tekstu:

def prepare_text_for_pdf(text, max_length=2000):
    """Przygotuj tekst do PDF z ograniczeniem długości"""
    
    # Usuń emoji (problematyczne w PDF)
    import re
    text = re.sub(r'[^\w\s\-\.\,\!\?\:\;\(\)\[\]\/\\\+\=\@\#\$\%\^\&\*]', '', text)
    
    # Ogranicz długość
    if len(text) > max_length:
        text = text[:max_length] + "..."
    
    # Podziel długie linie
    lines = []
    for line in text.split('\n'):
        if len(line) > 80:
            words = line.split(' ')
            current_line = ""
            for word in words:
                if len(current_line + word) > 80:
                    lines.append(current_line.strip())
                    current_line = word + " "
                else:
                    current_line += word + " "
            if current_line:
                lines.append(current_line.strip())
        else:
            lines.append(line)
    
    return '\n'.join(lines)

🌐 Planowane API

Web Search API

Status: W planach Cel: Aktualne dane o narzędziach i cennikach Opcje:

  • Google Custom Search API
  • Bing Search API
  • SerpAPI
  • Własny web scraper

Integracje branżowe

Planowane połączenia:

  • Allegro API - automatyzacja e-commerce
  • iFirma API - integracja księgowa
  • ZUS API - automatyzacja HR
  • NBP API - kursy walut
  • GUS API - dane statystyczne

🔧 Narzędzia deweloperskie

Testowanie API

Mock klasy dla testów:

class MockOpenAI:
    def chat_completions_create(self, **kwargs):
        return "Mock analiza procesu"

class MockSupabase:
    def table(self, name):
        return self
    def insert(self, data):
        return MockResponse({"id": 1})

Zmienne środowiskowe testowe:

os.environ['ENVIRONMENT'] = 'test'
os.environ['OPENAI_API_KEY'] = 'test-key-12345'
os.environ['SUPABASE_URL'] = 'https://test.supabase.co'

Monitoring API

Logowanie wywołań:

import logging

logger = logging.getLogger(__name__)

def analyze_with_ai(title, description):
    logger.info(f"API_CALL: OpenAI analysis for '{title}'")
    try:
        result = openai_client.chat.completions.create(...)
        logger.info(f"API_SUCCESS: OpenAI returned {len(result)} chars")
        return result
    except Exception as e:
        logger.error(f"API_ERROR: OpenAI failed - {e}")
        return "Błąd analizy AI"

Metryki użycia:

  • Liczba wywołań API/dzień
  • Średni czas odpowiedzi
  • Koszty miesięczne
  • Rate limiting

📊 Statystyki API

Rzeczywiste użycie (Grudzień 2024)

OpenAI API:

  • Wywołania: 1,247 analiz
  • Tokeny: 2.3M input + 4.1M output
  • Koszt: $127.50
  • Średni czas: 3.2s

Supabase API:

  • Zapytania: 15,670 queries
  • Storage: 127MB
  • Users: 89 aktywnych
  • Koszt: $0 (plan darmowy)

PDF Generation:

  • Pliki: 342 PDF
  • Rozmiar: 89MB łącznie
  • Średni czas: 0.8s

🚨 Troubleshooting API

OpenAI

  • Błąd 401: Nieprawidłowy klucz API
  • Błąd 429: Przekroczony rate limit
  • Błąd 500: Problem po stronie OpenAI

Supabase

  • Invalid API key: Sprawdź klucze w secrets
  • RLS error: Sprawdź polityki bezpieczeństwa
  • Connection timeout: Problem z siecią

PDF

  • Unicode error: Użyj safe_text()
  • Memory error: Ogranicz rozmiar tekstu
  • Font error: Sprawdź czcionkę DejaVu

Ostatnia aktualizacja: 14 czerwiec 2025 | Wersja API: 2.0.0