TH ▾
รับคีย์ API

NsfwAiApiคู่มือ

API LLM NSFW ใน Python: การสตรีมมิง, JSON และเครื่องมือ สตรีมมิง, JSON และเครื่องมือ

เพื่อใช้ NSFW LLM API จาก Python คุณต้องการเพียงแพ็กเกจ openai มาตรฐานและการเปลี่ยนแปลงสองอย่าง: base URL และคีย์ คู่มือนี้แสดงคำขอแรก การสตรีมมิง โหมด JSON การเรียกใช้เครื่องมือ และการจัดการขีดจำกัดอัตราอย่างเรียบร้อย

อัปเดต

หน้าต่างเทอร์มินัลปล่อยสตรีมของโทเกนที่เรืองแสงซึ่งห่อหุ้มด้วยริบบิ้นแสงที่พันกัน

การติดตั้ง: ติดตั้งและทำการเรียกครั้งแรก

คุณต้องการ Python 3 ปัจจุบัน แพ็คเกจ openai (pip install openai) และคีย์ API บัญชีใหม่สามารถรับเครดิตทดลอง $0.50 บน หน้าคีย์ API ได้ด้วยการคลิกหนึ่งครั้งหลังการเข้าสู่ระบบ มันไม่ต้องการรายละเอียดการชำระเงิน เก็บคีย์ในตัวแปรสภาพแวดล้อม ไม่ใช่ในซอร์สโค้ด

บริการนี้ใช้โปรโตคอล chat completions ของ OpenAI: POST /v1/chat/completions สำหรับการสร้าง และ GET /v1/models สำหรับรายการโมเดล การตรวจสอบสิทธิ์คือ Bearer token และ model ID คือ uncensored นี่คือสคริปต์ที่ทำงานได้เล็กที่สุด:

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)

หากคุณต้องการตรวจสอบการเชื่อมต่อจาก shell ก่อน คำขอนี้สามารถใช้กับ 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."}]}'

โมเดลได้รับการปรับแต่งให้ตอบโดยไม่มีข้อจำกัดเนื้อหาสำหรับการใช้งานผู้ใหญ่ที่ถูกต้องตามกฎหมาย สิ่งนี้ส่งผลต่อน้ำเสียงของข้อความที่โมเดลจะสร้าง ไม่ใช่รูปแบบของ API ดังนั้นโค้ดของคุณส่วนอื่นจึงดูเหมือนการผสานรวมกับ OpenAI ทั่วไป เก็บพรอมต์สำหรับนิยาย การแชทตัวละคร และโปรเจกต์ผู้ใหญ่ที่ถูกต้องกฎหมายอื่นๆ ไว้ และรักษาให้ตัวละครทุกตัวเป็นผู้ใหญ่

นิสัยบางอย่างช่วยได้ตั้งแต่แรกวัน ใส่คำแนะนำที่ไม่เปลี่ยนแปลงในข้อความระบบ และเก็บข้อความผู้ใช้สำหรับส่วนที่เปลี่ยนแปลงในแต่ละรอบ เลือกค่า temperature หนึ่งค่าสำหรับงานหนึ่งๆ และคงไว้ขณะเปรียบเทียบพรอมต์ เพราะการเปลี่ยนสองอย่างพร้อมกันไม่ได้สอนอะไรคุณ บันทึก ID ของคำขอและจำนวนโทเคนจาก resp.usage ไว้ถัดจากแต่ละการเรียกใช้ เพื่อให้เมื่อบิลหรือผลลัพธ์ของคุณทำให้คุณประหลาดใจ จะมีบันทึกให้ตรวจสอบ

การตอบแบบสตรีมมิงด้วย SSE

ตั้งค่า stream=True และเซิร์ฟเวอร์จะส่งโทเคนเป็นเหตุการณ์ที่ส่งจากเซิร์ฟเวอร์ (SSE) สำหรับแอปแชท สิ่งนี้สำคัญมาก เพราะผู้อ่านจะเห็นคำแรกๆ ทันทีแทนที่จะรอการตอบกลับทั้งหมด ยอดการใช้งานจะมาถึงที่ท้ายสตรีม ดังนั้นคำขอแบบสตรีมมิงจึงยังคงสามารถเรียกเก็บเงินและบันทึกได้แม่นยำ

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)

รายละเอียดสองอย่างนี้ช่วยประหยัดเวลาในการดีบัก ประการแรก ชิ้นสุดท้ายอาจมีรายการ choices ว่างเปล่า นั่นคือเหตุผลที่ลูปตรวจสอบรายการนี้ก่อนการเข้าถึงดัชนี ประการที่สอง คำขอแบบสตรีมมิงจะครอบครองช่องการทำงานพร้อมกัน (concurrency slot)จนกว่าสตรีมจะสิ้นสุด ดังนั้นหากโค้ดของคุณทิ้งสตรีมโดยไม่ปิดช่องนั้น ช่องนี้จะยังคงใช้งานอยู่ ใช้ with client.chat.completions.create(..., stream=True) as stream: หรือเรียกใช้ stream.close() เมื่อคุณหยุดอ่านก่อน

โหมด JSON สำหรับผลลัพธ์ที่มีโครงสร้าง

เมื่อโปรแกรมของคุณต้องการข้อมูลไม่ใช่ข้อความบรรยาย เช่น ใบตัวละคร รายการจังหวะของฉาก หรือแท็กสำหรับเรื่องราว ให้ใช้โหมด JSON ด้วย response_format={"type": "json_object"} นอกจากนี้ให้ระบุ "JSON" ในพรอมต์และอธิบายคีย์ที่คุณต้องการ การตั้งค่านี้ขอออบเจกต์ JSON แต่ไม่สามารถรับประกันได้ว่าคีย์ของคุณจะปรากฏอยู่ ดังนั้นจึงควรตรวจสอบคีย์เหล่านั้น

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"])

หากคำตอบที่ยาวถูกตัดโดย max_tokens JSON จะไม่สมบูรณ์และ json.loads จะล้มเหลว ให้ละเว้นการตั้งค่า max_tokens เนื่องจากเป็นค่าที่ไม่บังคับและการสร้างข้อความสามารถใช้พื้นที่ที่เหลือของหน้าต่างบริบทได้ หรือตั้งค่าไว้สูงๆ

การเรียกใช้เครื่องมือ

การเรียกใช้เครื่องมือช่วยให้โมเดลขอให้โค้ดของคุณทำงานบางอย่าง เช่น ทอยลูกเต๋า ดูบันทึกตัวละคร หรือดึงราคา คุณส่ง tools และหากต้องการ tool_choice การตอบกลับมี tool_calls; คุณดำเนินการตามนั้นและส่งผลลัพธ์กลับเป็นข้อความด้วย role: "tool" การตอบกลับแบบสตรีมมิงมี tool_calls ในเดลต้าด้วย

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)

ปฏิบัติต่ออาร์กิวเมนต์ว่าเป็นข้อมูลที่ไม่ไว้วางใจ ตรวจสอบความถูกต้องก่อนดำเนินการตามนั้น เหมือนกับที่คุณทำกับฟอร์มเว็บ โมเดลบางครั้งส่งฟิลด์ที่ขาดหายหรือประเภทที่ผิด และการป้องกันเล็กน้อยรอบ json.loads จะป้องกันไม่ให้การเรียกใช้ที่ผิดพลาดหนึ่งครั้งทำให้เซสชันของคุณสิ้นสุดลง

ขีดจำกัดอัตรา การทำซ้ำ และยอดเงินของคุณ

ขีดจำกัดปกป้องบริการและให้คุณมีพฤติกรรมที่คาดการณ์ได้ คีย์แบบเต็มอนุญาตให้ทำคำขอพร้อมกัน 8 คำขอและ 300 คำขอต่อนาที คีย์แบบทดลองอนุญาตให้ทำ 2 และ 60 ขนาดสูงสุดของบอดีคือ 8 MB ข้อผิดพลาดขีดจำกัดสองประเภทจะส่งกลับเป็น HTTP 429: รหัส rate_limited หมายถึงคำขอมากเกินไปต่อนาที และ concurrency หมายถึงคำขอพร้อมกันมากเกินไป การโอเวอร์โหลดชั่วคราวยังส่งกลับ 429 พร้อมหัว Retry-After: 5

SDK ของ OpenAI จะลองใหม่สำหรับข้อผิดพลาดบางรายการโดยค่าเริ่มต้น สำหรับการควบคุม ให้ปิดการทำงานนั้นและเขียนลูปเล็กๆ ที่เคารพ 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)

ทุกการตอบกลับมี X-Request-Id ซึ่งคือค่าที่คุณระบุเมื่อติดต่อฝ่ายสนับสนุน และ X-Balance-USD ซึ่งแสดงเครดิตคงเหลือของคุณ หัวข้อ X-RateLimit-Limit-Requests และ X-RateLimit-Limit-Concurrency บอกคุณว่าขีดจำกัดใดใช้กับคีย์ของคุณ เพื่อทำงานจำนวนมากพร้อมกัน ให้จำกัดความขนานในโค้ดของคุณเองด้วยเซมาโฟร์ที่มีขนาดตามคีย์ของคุณ คือ 8 สำหรับคีย์แบบเต็มและ 2 สำหรับคีย์แบบทดลอง เพื่อให้คุณแทบไม่เห็นข้อผิดพลาด 429 เลย

การรันคำขอหลายคำขอแบบขนาน

งานแบบแบตช์ เช่น การสร้างแท็กสำหรับส่วนเรื่องราวหลายร้อยส่วน เป็นจุดที่ขีดจำกัดการทำงานพร้อมกันมีความสำคัญ คีย์แบบเต็มรองรับคำขอ 8 คำขอพร้อมกัน ดังนั้นให้ทำงานผ่านไคลเอนต์แบบอะซิงโครนัสและเซมาโฟร์ที่มีขนาดนั้น หากคุณใช้คีย์แบบทดลอง ให้ใช้ 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)

เซมาโฟร์คือเคล็ดลับทั้งหมด โดยไม่มีมัน รายการส่วน 200 ส่วนจะยิงคำขอ 200 คำขอพร้อมกัน และส่วนใหญ่จะส่งกลับเป็นข้อผิดพลาด 429 พร้อมรหัส concurrency ด้วยมัน งานจะไหลด้วยความเร็วที่คีย์ของคุณอนุญาตและไม่มีอะไรสูญเปล่า หากคุณยังกำหนดงบประมาณต่อนาทีอีกด้วย 300 คำขอต่อนาทีบนคีย์แบบเต็มเท่ากับห้าคำขอต่อวินาที ดังนั้นคำขอที่สั้นมากอาจชนกับขีดจำกัดต่อนาทีก่อนขีดจำกัดการทำงานพร้อมกัน

ปัญหาที่พบบ่อยและการแก้ไข

  • 401 หรือข้อผิดพลาดการตรวจสอบสิทธิ์ คีย์หายไป ตัดทอนหรือส่งไปยังโฮสต์ที่ผิด พิมพ์ client.base_url และตรวจสอบตัวแปรสภาพแวดล้อม หัวต้องอ่านว่า Authorization: Bearer ตามด้วยคีย์ของคุณ
  • ไม่พบโมเดล ID ของโมเดลมีเพียง uncensored ตัวอย่างที่คัดลอกมาซึ่งระบุชื่ออื่นจะล้มเหลว ดังนั้นให้เรียกใช้ GET /v1/models หากคุณไม่แน่ใจ
  • การตอบกลับว่างเปล่าหรือสั้นในลูปเรื่องราว ตรวจสอบว่าคุณเพิ่มการตอบกลับของผู้ช่วยลงในรายการข้อความก่อนเทิร์นถัดไป โดยไม่มีสิ่งนี้ โมเดลจะเห็นเพียงข้อความล่าสุดของคุณ
  • การตอบกลับที่ซ้ำกัน เพิ่ม frequency_penalty เล็กน้อย เช่น เป็น 0.3 หรือลด temperature หากข้อความเบี่ยงเบน ค่าปรับ top_p, stop และ seed ถูกส่งผ่านทั้งหมด
  • ผลลัพธ์ที่แตกต่างกันในทุกการรัน ตั้งค่า seed และ temperature ต่ำเมื่อคุณต้องการผลลัพธ์ที่ซ้ำได้มากที่สุดเท่าที่จะเป็นไปได้ขณะดีบัก
  • คำขอมีขนาดใหญ่เกินไป ขีดจำกัดบอดีคือ 8 MB และพรอมต์รวมกับการสร้างข้อความต้องพอดีกับ 100,000 โทเคน ตัดหรือสรุปบริบทเก่าก่อนที่มันจะถึงขีดจำกัดใดขีดจำกัดหนึ่ง

เมื่อมีบางอย่างดูผิดปกติจากฝั่งเซิร์ฟเวอร์ ให้บันทึกหัว X-Request-Id จากการตอบกลับและส่งไปยังที่ติดต่อ หน้าสนับสนุน พร้อมคำอธิบายสั้นๆ มันช่วยให้ผู้ดำเนินการพบคำขอที่แน่นอนของคุณ

ต้นทุนและสิ่งที่ทำไม่ได้

ราคาอยู่ที่ $0.15 ต่อ 1M input tokens และ $0.50 ต่อ 1M output tokens โดยหักจาก prepaid credit โดยไม่มี subscription คำขอที่ล้มเหลวหรือถูกปฏิเสธจะไม่ถูกเรียกเก็บเงิน และ credit จะไม่หมดอายุ ตัวอย่างการคำนวณ: สคริปต์ที่ส่ง 3,000 tokens และรับ 800 tokens จะเสีย $0.00045 สำหรับ input และ $0.0004 สำหรับ output ซึ่งรวมเป็น $0.00085 ต่อการเรียกใช้ ดังนั้น 1,000 การเรียกใช้จะมีค่าใช้จ่าย $0.85 การเติมเงินเริ่มต้นที่ $20 ถึง $500 พร้อมโบนัส +5% เมื่อเติม $50, +10% เมื่อเติม $100 และ +15% เมื่อเติม $200 เว็บไซต์นี้รับเฉพาะ crypto คือ USDT บน TRC20 หรือ USDC บน Base ดู หน้าราคาสำหรับตารางเต็ม และ เอกสารประกอบสำหรับ reference ของ endpoint

ขอบเขตนั้นชัดเจน เป็น open-weight model เดียวที่ให้บริการโดยผู้ให้บริการอิสระ ไม่ใช่ official API ของผู้ขายโมเดลใด ๆ context window มีขนาด 100,000 tokens สำหรับ prompt รวมกับ completion ไม่สร้างภาพ เสียง หรือวิดีโอ ไม่รองรับ embeddings และไม่รองรับ fine-tuning ใช้สำหรับการใช้งานผู้ใหญ่ที่ถูกต้องตามกฎหมายเท่านั้น และโปรดทราบข้อจำกัดที่ชัดเจน: ไม่มีเนื้อหาทางเพศที่เกี่ยวข้องกับผู้เยาว์ prompts ไม่ถูกนำไปใช้ในการฝึกโมเดล

ถาม-ตอบ

ฉันจำเป็นต้องใช้ SDK พิเศษเพื่อเรียก API นี้จาก Python หรือไม่?

ไม่ แพ็คเกจ openai ทางการใช้งานได้ ตั้งค่า base_url เป็น https://api.nsfwaiapi.com/v1, ส่งคีย์ของคุณ และใช้ model ID uncensored

streaming ทำงานเหมือนกับ OpenAI หรือไม่?

ใช่ ส่ง stream=True และอ่าน server-sent events ทีละ chunk การใช้งานจะถูกรายงานที่ท้าย stream

ฉันควรทำอย่างไรเมื่อได้รับข้อผิดพลาด 429?

รอแล้วลองใหม่ หาก response มี header Retry-After ให้ปฏิบัติตาม รหัส error rate_limited หมายถึงคำขอมากเกินไปต่อนาที และ concurrency หมายถึงคำขอมากเกินไปในเวลาเดียวกัน

ฉันสามารถทดสอบโดยไม่เสียเงินได้หรือไม่?

ใช่ หลังจาก sign-up คุณสามารถรับ trial credit มูลค่า $0.50 ได้ที่หน้า API key ไม่จำเป็นต้องใส่ข้อมูลการชำระเงิน มีอายุการใช้งาน 7 วัน และจำกัดหนึ่งต่อหนึ่งบุคคล

คีย์ของคุณอยู่ห่างแค่แบบฟอร์มเดียว

สร้างบัญชี คัดลอกคีย์ และเปลี่ยน base URL นั่นคือการตั้งค่าทั้งหมด

รับคีย์ API

NsfwAiApiAPI LLM แบบไม่เซ็นเซอร์สำหรับการสร้างข้อความ NSFW