IT ▾
Ottieni la chiave API

NsfwAiApiGuida

API LLM NSFW in Python: streaming, JSON e funzioni

Per utilizzare un'API LLM NSFW in stile Python, ti servono solo il pacchetto openai standard e due modifiche: l'URL base e la chiave. Questa guida mostra una prima richiesta, lo streaming, la modalità JSON, la chiamata di funzioni e la gestione pulita dei limiti di richieste.

Aggiornato

Finestra del terminale che emette uno stream di token luminosi avvolti da un nastro di luce attorcigliato

Configurazione: installazione e prima chiamata

Ti servono Python 3 corrente, il pacchetto openai (pip install openai) e una chiave API. I nuovi account possono richiedere un credito di prova da $0,50 nella pagina della chiave API con un clic dopo l'accesso; non richiedono dati di pagamento. Memorizza la chiave in una variabile d'ambiente, non nel codice sorgente.

Il servizio utilizza il protocollo di completamento chat di OpenAI: POST /v1/chat/completions per la generazione e GET /v1/models per l'elenco dei modelli. L'autenticazione è un token bearer e l'ID del modello è uncensored. Questo è lo script minimo funzionante:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "You are a fiction co-writer for adult readers. Write vivid, non-explicit scenes."},
        {"role": "user", "content": "Open a noir story in a rainy harbor town, three sentences."},
    ],
    temperature=0.8,
)

print(resp.choices[0].message.content)
print(resp.usage)

Se preferisci verificare la connessione da un terminale, la stessa richiesta funziona con curl:

curl https://api.nsfwaiapi.com/v1/chat/completions \
  -H "Authorization: Bearer $NSFWAIAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "uncensored", "messages": [{"role": "user", "content": "Say hello in five words."}]}'

Il modello è ottimizzato per rispondere senza rifiuti di contenuto per uso adulto legale. Questo influisce sul tono di ciò che scriverà, non sulla forma dell'API, quindi il resto del tuo codice sembra un'integrazione OpenAI standard. Mantieni i prompt per finzione, chat di personaggi e altri progetti adulti legali, e assicurati che ogni personaggio sia adulto.

Alcune abitudini aiutano fin dal primo giorno. Inserisci le istruzioni che non cambiano nel messaggio di sistema e mantieni il messaggio utente per la parte che cambia a ogni turno. Scegli un valore di temperature per un'attività e lascialo invariato mentre confronti i prompt, perché modificare due cose contemporaneamente non ti insegna nulla. Registra l'ID della richiesta e i conteggi dei token da resp.usage accanto a ogni chiamata, così quando la tua fattura o il tuo output ti sorprendono, c'è una registrazione da verificare.

Risposte in streaming con SSE

Imposta stream=True e il server invia i token come eventi inviati dal server. Per le app di chat questo è molto importante, perché il lettore vede le prime parole rapidamente invece di aspettare la risposta completa. I totali di utilizzo arrivano alla fine dello streaming, quindi una richiesta in streaming può ancora essere fatturata e registrata con precisione.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Write a short scene: two rival smugglers share a lantern during a storm."}],
    stream=True,
)

text = ""
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        piece = chunk.choices[0].delta.content
        text += piece
        print(piece, end="", flush=True)
    usage = getattr(chunk, "usage", None)
    if usage:
        print("\n[usage]", usage)

Due dettagli risparmiano tempo di debug. Innanzitutto, l'ultimo chunk può avere un elenco choices vuoto, motivo per cui il loop lo controlla prima dell'accesso per indice. In secondo luogo, una richiesta in streaming mantiene la sua slot di concorrenza fino alla fine dello streaming, quindi se il tuo codice abbandona uno streaming senza chiuderlo, quella slot rimane occupata. Usa with client.chat.completions.create(..., stream=True) as stream: o chiama stream.close() quando smetti di leggere anticipatamente.

Modalità JSON per output strutturato

Quando il tuo programma ha bisogno di dati e non di prosa, come una scheda personaggio, un elenco di fasi della scena o tag per una storia, usa la modalità JSON con response_format={"type": "json_object"}. Dì anche "JSON" nel prompt e descrivi le chiavi che vuoi. L'impostazione richiede un oggetto JSON, ma non può promettere che le tue chiavi siano presenti, quindi verificale.

import json
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)

resp = client.chat.completions.create(
    model="uncensored",
    response_format={"type": "json_object"},
    messages=[
        {"role": "system", "content": "Reply with a JSON object with keys: name, age, goal, secret. All characters are adults."},
        {"role": "user", "content": "Create a ship's cook for a pirate adventure."},
    ],
    temperature=0.7,
)

sheet = json.loads(resp.choices[0].message.content)
missing = [k for k in ("name", "age", "goal", "secret") if k not in sheet]
if missing:
    raise ValueError(f"model skipped keys: {missing}")
print(sheet["name"], "-", sheet["goal"])

Se una risposta lunga viene interrotta da max_tokens, il JSON sarà incompleto e json.loads fallirà. Lascia max_tokens non impostato, poiché è opzionale e il completamento può utilizzare il resto della finestra di contesto, oppure impostalo generosamente.

Chiamata di funzioni

La chiamata di funzioni permette al modello di chiedere al tuo codice di fare qualcosa, come lanciare dadi, cercare una nota su un personaggio o recuperare un prezzo. Passi tools e, se vuoi, tool_choice. La risposta contiene tool_calls; li esegui e invii i risultati indietro come messaggi con role: "tool". Le risposte in streaming contengono tool_calls anche nei delta.

import json
import os
import random
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)

tools = [{
    "type": "function",
    "function": {
        "name": "roll_die",
        "description": "Roll one die with the given number of sides",
        "parameters": {
            "type": "object",
            "properties": {"sides": {"type": "integer", "minimum": 2}},
            "required": ["sides"],
        },
    },
}]

messages = [
    {"role": "system", "content": "You run a tabletop fiction game. Use roll_die for any chance-based outcome."},
    {"role": "user", "content": "I try to pick the lock on the captain's cabin. Roll a d20."},
]

first = client.chat.completions.create(
    model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = first.choices[0].message

if msg.tool_calls:
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = random.randint(1, args["sides"])
        messages.append({"role": "tool", "tool_call_id": call.id, "content": str(result)})
    final = client.chat.completions.create(
        model="uncensored", messages=messages, tools=tools
    )
    print(final.choices[0].message.content)
else:
    print(msg.content)

Tratta gli argomenti come input non attendibile. Validali prima di agire su di essi, esattamente come faresti per un modulo web. I modelli a volte inviano un campo mancante o di tipo errato e una piccola protezione intorno a json.loads impedisce a una chiamata difettosa di terminare la tua sessione.

Limiti di richiesta, ritentativi e tuo saldo

I limiti proteggono il servizio e ti danno un comportamento prevedibile. Una chiave completa consente 8 richieste concorrenti e 300 richieste al minuto. Una chiave di prova ne consente 2 e 60. Il corpo massimo è 8 MB. Due tipi di errore di limite tornano come HTTP 429: il codice rate_limited indica troppe richieste al minuto, e concurrency indica troppe simultanee. Un sovraccarico temporaneo restituisce anche 429, con un'intestazione Retry-After: 5.

L'SDK di OpenAI riprova alcuni errori per impostazione predefinita. Per il controllo, disattivalo e scrivi un piccolo loop che rispetti Retry-After:

import os
import time
from openai import OpenAI, RateLimitError

client = OpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
    max_retries=0,
)

def ask(messages, tries=5):
    for attempt in range(tries):
        try:
            raw = client.chat.completions.with_raw_response.create(
                model="uncensored", messages=messages
            )
            print("balance:", raw.headers.get("X-Balance-USD"), "request id:", raw.headers.get("X-Request-Id"))
            return raw.parse()
        except RateLimitError as err:
            wait = float(err.response.headers.get("Retry-After", 2 ** attempt))
            time.sleep(wait)
    raise RuntimeError("still rate limited after retries")

reply = ask([{"role": "user", "content": "Describe a market at dawn in two sentences."}])
print(reply.choices[0].message.content)

Ogni risposta include X-Request-Id, che devi citare se contatti il supporto, e X-Balance-USD, che mostra il tuo credito residuo. Le intestazioni X-RateLimit-Limit-Requests e X-RateLimit-Limit-Concurrency indicano quali limiti si applicano alla tua chiave. Per eseguire molti job in parallelo, limita la concorrenza nel tuo codice usando un semaforo dimensionato alla tua chiave: 8 per una chiave completa e 2 per una chiave di prova, così raramente vedrai un 429.

Esecuzione di molte richieste in parallelo

I lavori batch, come la generazione di tag per alcune centinaia di frammenti di storia, sono dove i limiti di concorrenza contano. Una chiave completa accetta 8 richieste alla volta, quindi esegui il lavoro attraverso un client asincrono e un semaforo di quella dimensione. Se sei su una chiave di prova, usa 2.

import asyncio
import os
from openai import AsyncOpenAI

client = AsyncOpenAI(
    base_url="https://api.nsfwaiapi.com/v1",
    api_key=os.environ["NSFWAIAPI_KEY"],
)
gate = asyncio.Semaphore(8)

async def summarize(fragment):
    async with gate:
        resp = await client.chat.completions.create(
            model="uncensored",
            messages=[
                {"role": "system", "content": "Summarize the passage in one sentence."},
                {"role": "user", "content": fragment},
            ],
            temperature=0.3,
        )
    return resp.choices[0].message.content

async def main(fragments):
    return await asyncio.gather(*(summarize(f) for f in fragments))

results = asyncio.run(main(["The tide came in early.", "Marta hid the ledger under the floor."]))
print(results)

Il semaforo è la chiave di tutto. Senza di esso, un elenco di 200 frammenti invia 200 richieste insieme, e la maggior parte di esse torna come errori 429 con il codice concurrency. Con esso, il lavoro scorre alla velocità consentita dalla tua chiave e nulla viene sprecato. Se esegui anche un budget per minuto, 300 richieste al minuto su una chiave completa equivalgono a cinque al secondo, quindi le richieste molto brevi possono raggiungere il limite per minuto prima del limite di concorrenza.

Problemi comuni e soluzioni

  • 401 o errori di autenticazione. La chiave è mancante, troncata o inviata all'host sbagliato. Stampa client.base_url e controlla la variabile d'ambiente. L'intestazione deve leggere Authorization: Bearer seguita dalla tua chiave.
  • Modello non trovato. L'unico ID del modello è uncensored. Un esempio copiato che dice un altro nome fallirà, quindi chiama GET /v1/models se non sei sicuro.
  • Risposte vuote o brevi in un loop di storia. Verifica di aggiungere la risposta dell'assistente all'elenco dei messaggi prima del turno successivo. Senza di essa, il modello vede solo il tuo ultimo messaggio.
  • Risposte che si ripetono. Aumenta leggermente frequency_penalty, ad esempio a 0,3, o abbassa temperature se il testo devia. Le penalità, top_p, stop e seed sono tutte trasmesse.
  • Output diversi ad ogni esecuzione. Imposta seed e un temperature basso quando hai bisogno di risultati il più possibile ripetibili mentre esegui il debug.
  • Richiesta troppo grande. Il limite del corpo è 8 MB e prompt più completamento devono adattarsi in 100.000 token. Taglia o riassume il contesto vecchio prima che raggiunga uno di questi limiti.

Quando qualcosa sembra sbagliato lato server, salva l'intestazione X-Request-Id dalla risposta e inviala al contatto nella pagina di supporto insieme a una breve descrizione. Questo permette agli operatori di trovare la tua richiesta esatta.

Quanto costa e cosa non può fare

La tariffazione è $0,15 per 1M token di input e $0,50 per 1M token di output, da credito prepagato senza abbonamento. Le richieste fallite o rifiutate non vengono addebitate e il credito non scade mai. Come esempio pratico, uno script che invia 3.000 token e ne riceve 800 paga $0,00045 per l'input più $0,0004 per l'output, che è $0,00085 per chiamata, quindi 1.000 chiamate costano $0,85. I ricarichi vanno da $20 a $500, con bonus del +5% da $50, +10% da $100 e +15% da $200. Questo sito accetta solo cripto, in USDT su TRC20 o USDC su Base. Vedi la pagina dei prezzi per la tabella completa e la documentazione per il riferimento all'endpoint.

I confini sono chiari. È un singolo modello a pesi aperti, gestito da un provider indipendente, e non l'API ufficiale di alcun fornitore di modelli. La finestra di contesto è di 100.000 token per prompt più completamento. Non genera immagini, audio o video, non fornisce embeddings e non supporta il fine-tuning. Usalo solo per uso adulto legale e nota il limite rigido: nessun contenuto sessuale che coinvolga minorenni. I prompt non vengono utilizzati per l'addestramento.

Domande e risposte

Ho bisogno di un SDK speciale per chiamare questa API da Python?

No. Il pacchetto openai ufficiale funziona. Imposta base_url su https://api.nsfwaiapi.com/v1, passa la tua chiave e usa l'ID del modello uncensored.

Lo streaming funziona allo stesso modo di OpenAI?

Sì. Imposta stream=True e leggi gli eventi inviati dal server chunk per chunk. L'utilizzo viene segnalato alla fine dello streaming.

Cosa devo fare quando ricevo un errore 429?

Attendi e riprova. Se la risposta include l'intestazione Retry-After, onoralo. Il codice di errore rate_limited indica troppe richieste al minuto, mentre concurrency indica troppe richieste simultanee.

Posso provarlo senza pagare?

Sì. Dopo l'accesso puoi richiedere $0,50 di credito di prova nella pagina della chiave API. Non richiede dati di pagamento, è valido per 7 giorni ed è limitato a una persona.

La tua chiave è a un modulo di distanza

Crea un account, copia la chiave, modifica l'URL di base. È tutta la configurazione.

Ottieni la chiave API

NsfwAiApiAPI LLM senza censura per la generazione di testo NSFW