Sebastien Rousseau

Àkàndé: GPT-Powered Voice Assistant for Executives

Arhitectura unui asistent vocal Python open-source: Whisper, GPT-4, cache SQLite și fpdf2

6 min de citit
Banner for: Àkàndé: GPT-Powered Voice Assistant for Executives

Rezumat executiv / Concluzii cheie

  • Àkàndé ⧉ este un asistent vocal Python cu sursă deschisă care înlănțuie OpenAI Whisper pentru conversia vorbirii în text, GPT-4 chat completions, un cache de răspunsuri SQLite local și exportul PDF fpdf2 într-un singur flux de lucru bazat pe voce, fără stocare în cloud și fără ponderi locale ale modelului AI.
  • Cache-ul SQLite stochează hashuri SHA-256 ale șirurilor de interogare normalizate asociate cu textul brut al răspunsurilor API; accesările cache-ului costă zero tokeni și revin în mai puțin de 10 ms, făcând interogările repetate (cum ar fi revizuirea unei decizii de mai devreme din ședință) practic gratuite.
  • Conversația multi-tur este menținută prin construirea listei messages în memorie și transmiterea ei la fiecare apel Chat Completions API — modelul primește istoricul complet al sesiunii pentru a se putea referi la schimburile anterioare, cu costul utilizării incrementale a tokenilor pe tur.
  • Generarea rezumatului PDF serializează lista messages a sesiunii într-un document fpdf2 formatat: tururile utilizatorului și ale asistentului sunt etichetate, marcajele de timp sunt inserate, iar paginarea automată gestionează sesiuni de orice lungime; fișierul este scris în sistemul de fișiere local, nu încărcat.
  • Limita de confidențialitate: doar interogarea live (și istoricul sesiunii până la limita ferestrei de context) părăsește dispozitivul — nicio înregistrare audio, niciun transcript și niciun răspuns din cache nu sunt trimise către niciun serviciu la distanță altul decât API-ul OpenAI.

Àkàndé ⧉ este un asistent vocal Python cu sursă deschisă, construit în jurul a trei componente compozabile: OpenAI Whisper pentru recunoașterea vorbirii, API-ul GPT-4 Chat Completions pentru înțelegerea și generarea limbajului, și o bază de date SQLite locală pentru memorarea în cache a răspunsurilor și persistența sesiunii. Rezultatul este un flux de lucru bazat pe voce care poate fi rulat pe un laptop fără ponderi locale ale modelului, infrastructură de stocare offline sau un stack de containere.

Acest articol descrie arhitectura tehnică a fiecărei componente, deciziile de proiectare privind memorarea în cache și contextul multi-tur, precum și pipeline-ul de export PDF.

Prezentare generală a pipeline-ului #

O singură interacțiune Àkàndé urmează această secvență:

  1. Capturarea audio — utilizatorul vorbește; aplicația înregistrează audio într-un fișier WAV temporar folosind sounddevice sau o bibliotecă audio compatibilă.
  2. Conversia vorbirii în text — fișierul WAV este trimis la openai.audio.transcriptions.create() (Whisper API); transcriptul este returnat ca un șir simplu.
  3. Căutarea în cache — transcriptul este normalizat (litere mici, spații comprimate) și hașat cu SHA-256; hashul este căutat în tabelul local SQLite response_cache.
  4. Apel API sau accesare cache — la un miss, transcriptul este adăugat la lista messages a sesiunii și trimis la openai.chat.completions.create(); textul răspunsului este stocat în cache.
  5. Conversia textului în vorbire — textul răspunsului este convertit în audio folosind endpoint-ul openai.audio.speech.create() (TTS) sau o bibliotecă TTS locală, și redat.
  6. Exportul PDF (la cerere) — lista completă messages este serializată într-un document fpdf2 formatat și scrisă pe disc.

Integrarea cu OpenAI: Chat Completions și Whisper #

Àkàndé folosește Python SDK openai atât pentru recunoașterea vorbirii, cât și pentru generarea textului. Apelul de transcriere Whisper:

with open(audio_file_path, "rb") as f:
    transcript = openai.audio.transcriptions.create(
        model="whisper-1",
        file=f,
        language=None  # auto-detect
    )
user_text = transcript.text

Apelul Chat Completions menține o listă messages cu domeniu de sesiune:

messages.append({"role": "user", "content": user_text})

response = openai.chat.completions.create(
    model="gpt-4-turbo-preview",
    messages=messages,
    temperature=0.2,
    max_tokens=1024
)

assistant_text = response.choices[0].message.content
messages.append({"role": "assistant", "content": assistant_text})

Promptul de sistem este adăugat o singură dată la începutul sesiunii și controlează persona Àkàndé, formatul de ieșire și orice constrângeri specifice domeniului:

messages = [
    {
        "role": "system",
        "content": (
            "You are Àkàndé, a concise executive assistant. "
            "Respond in plain prose. Do not use markdown. "
            "If asked to summarise, produce three bullet points maximum."
        )
    }
]

Setarea temperature=0.2 sacrifică variația creativă în favoarea determinismului — important pentru interogări factuale, cum ar fi reamintirea unei decizii de mai devreme în sesiune.

Cache-ul de răspunsuri SQLite #

Schema cache-ului este minimală:

CREATE TABLE IF NOT EXISTS response_cache (
    query_hash  TEXT PRIMARY KEY,
    response    TEXT NOT NULL,
    created_at  INTEGER NOT NULL  -- Unix timestamp
);

Calea de căutare și scriere:

import hashlib, sqlite3, time

def _normalise(text: str) -> str:
    return " ".join(text.lower().split())

def cache_get(conn: sqlite3.Connection, query: str) -> str | None:
    h = hashlib.sha256(_normalise(query).encode()).hexdigest()
    row = conn.execute(
        "SELECT response FROM response_cache WHERE query_hash = ?", (h,)
    ).fetchone()
    return row[0] if row else None

def cache_set(conn: sqlite3.Connection, query: str, response: str) -> None:
    h = hashlib.sha256(_normalise(query).encode()).hexdigest()
    conn.execute(
        "INSERT OR REPLACE INTO response_cache VALUES (?, ?, ?)",
        (h, response, int(time.time()))
    )
    conn.commit()

INSERT OR REPLACE asigură că un răspuns memorat în cache este actualizat dacă aceeași interogare este trimisă după o actualizare a modelului. O interogare de evacuare bazată pe TTL (DELETE WHERE created_at < ?) poate fi programată la pornire pentru a limita dimensiunea cache-ului.

Performanța accesării cache-ului: o căutare SQLite pe un SSD local revine în mai puțin de 1 ms pentru tabele cu până la ~100.000 de rânduri. Latența tur-retur pentru un apel live GPT-4 API este de obicei 600–900 ms pentru răspunsuri scurte. Pentru un briefing zilnic cu câteva interogări repetate, cache-ul elimină majoritatea apelurilor API după prima sesiune.

Generarea rezumatului PDF #

Exportul PDF folosește fpdf2, o bibliotecă Python PDF menținută fără dependențe binare:

from fpdf import FPDF
from datetime import datetime

def export_session_pdf(messages: list[dict], output_path: str) -> None:
    pdf = FPDF()
    pdf.add_page()
    pdf.set_font("Helvetica", size=11)
    pdf.set_margins(20, 20, 20)

    pdf.set_font("Helvetica", "B", 14)
    pdf.cell(0, 10, f"Àkàndé Session — {datetime.now():%Y-%m-%d %H:%M}", ln=True)
    pdf.ln(4)

    for msg in messages:
        if msg["role"] == "system":
            continue
        label = "You" if msg["role"] == "user" else "Àkàndé"
        pdf.set_font("Helvetica", "B", 10)
        pdf.cell(0, 6, label, ln=True)
        pdf.set_font("Helvetica", size=10)
        pdf.multi_cell(0, 5, msg["content"])
        pdf.ln(3)

    pdf.output(output_path)

multi_cell() gestionează împărțirea pe rânduri și întreruperile automate de pagină, astfel că sesiunile de orice lungime produc un document bine formatat fără logică manuală de paginare. Ieșirea este un fișier compatibil cu PDF/A fără fonturi încorporate în afara metricelor standard Helvetica.

Modelul de confidențialitate #

Limita de confidențialitate în Àkàndé este definită de trei fapte:

  1. Audioul este trimis la Whisper API prin HTTPS și nu este reținut de OpenAI după apelul API (conform politicii de utilizare a datelor API OpenAI din februarie 2024).
  2. Apelurile Chat Completions API transmit lista messages a sesiunii — care poate conține istoricul complet al conversației pentru sesiunile multi-tur.
  3. Baza de date SQLite și fișierele PDF trăiesc în întregime în sistemul de fișiere local; nu apare nicio sincronizare în fundal cu niciun serviciu cloud.

Pentru cazurile de utilizare executivă implicând subiecte sensibile — discuții M&A, probleme de personal, strategie de reglementare — istoricul sesiunii transmis la API ar trebui revizuit față de politica de utilizare AI a organizației înainte de implementare. Limita max_tokens din promptul de sistem poate fi folosită pentru a preveni transmiterea inadvertentă a contextului care depășește domeniul de divulgare intenționat.

Întrebări frecvente #

Păstrează Àkàndé istoricul conversațiilor după terminarea sesiunii? Lista messages din memorie este eliminată când procesul se încheie. Istoricul conversațiilor este reținut doar dacă utilizatorul declanșează un export PDF sau dacă este adăugat un strat de persistență personalizat. Cache-ul SQLite stochează hashurile interogărilor și textul răspunsurilor, nu contextul complet al conversației.

Cum gestionează cache-ul interogările similare, dar nu identice? Cache-ul folosește hashing cu potrivire exactă pe șirul de interogare normalizat. Două interogări care diferă cu un singur cuvânt vor produce hashuri diferite și vor rezulta în apeluri API separate. Memorarea semantică în cache (folosind similitudinea vectorilor de embedding pentru a potrivi interogări aproape duplicate) ar necesita un pas suplimentar de căutare vectorială și nu face parte din implementarea de bază.

Ce model GPT folosește Àkàndé în mod implicit? Implicit este gpt-4-turbo-preview din februarie 2024. Numele modelului este un parametru de configurare, deci orice model de completare chat OpenAI poate fi substituit. Trecerea la gpt-3.5-turbo reduce costul API cu aproximativ 20× pe token, dar reduce calitatea raționamentului pentru interogări complexe cu mai mulți pași.

Poate fi personalizat formatul de export PDF? Da. Funcția de export fpdf2 acceptă lista messages ca singura intrare necesară, astfel că fontul, marginile, dimensiunea paginii, conținutul antetului și etichetarea pot fi toate modificate prin editarea funcției de export. fpdf2 suportă, de asemenea, adăugarea de imagini, tabele și fonturi Unicode, permițând aspecte de document mai bogate pentru organizațiile cu cerințe specifice de branding.

Referințe #

  1. OpenAI. Audio Transcriptions — Whisper API. OpenAI Platform Documentation, 2024. https://platform.openai.com/docs/api-reference/audio/createTranscription
  2. OpenAI. Chat Completions API. OpenAI Platform Documentation, 2024. https://platform.openai.com/docs/api-reference/chat/create
  3. Voss, J. et al. fpdf2: Modern PDF generation for Python. GitHub, 2024. https://github.com/py-pdf/fpdf2
  4. SQLite Consortium. SQLite Documentation. sqlite.org, 2024. https://www.sqlite.org/docs.html

Ultima revizuire .

Ultima revizuire .