NsfwAiApi/الدليل
واجهة برمجة تطبيقات LLM NSFW في Python: البث المتدفق، JSON والأدوات
لاستخدام واجهة برمجة تطبيقات LLM NSFW بنمط Python، تحتاج فقط إلى الحزمة القياسية openai وتغييرين: عنوان URL الأساسي والمفتاح. يوضح هذا الدليل أول طلب، البث المتدفق، وضع JSON، استدعاء الأدوات ومعالجة حدود المعدل بشكل نظيف.

الإعداد: التثبيت وإجراء أول استدعاء
تحتاج إلى Python 3 الحالي، حزمة openai (pip install openai) ومفتاح API. يمكن للحسابات الجديدة المطالبة برصيد تجريبي مجاني بقيمة $0.50 على صفحة مفتاح API بنقرة واحدة بعد تسجيل حساب؛ لا يتطلب تفاصيل الدفع. احفظ المفتاح في متغير بيئة، وليس في كود المصدر.
الخدمة تتوافق مع بروتوكول إكمال الدردشة الخاص بـ OpenAI: POST /v1/chat/completions للتوليد وGET /v1/models لقائمة النماذج. المصادقة تكون عبر رمز Bearer، ومعرف النموذج هو 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)
إذا كنت تفضل اختبار الاتصال من سطر الأوامر أولاً، فإن نفس الطلب يعمل مع 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."}]}'
النموذج مُعدّ للإجابة بدون رفض المحتوى للاستخدام القانوني للبالغين. يؤثر ذلك على نبرة ما يكتبه، وليس على شكل واجهة برمجة التطبيقات، لذا يبدو باقي كودك كأي تكامل آخر مع OpenAI. احتفظ بالموجّهات للخيال، ودردشة الشخصيات والمشاريع القانونية الأخرى للبالغين، وتأكد من أن كل شخصية بالغة.
تساعدك بعض العادات منذ اليوم الأول. ضع التعليمات التي لا تتغير في رسالة النظام، واحتفظ برسالة المستخدم للجزء الذي يتغير في كل دور. اختر درجة حرارة واحدة للمهمة واتركها أثناء مقارنة الموجّهات، لأن تغيير شيئين في وقت واحد لا يعلمك شيئاً. سجّل معرف الطلب وأعداد الرموز من resp.usage بجانب كل استدعاء، بحيث يكون لديك سجل للرجوع إليه عندما تفاجئك الفاتورة أو مخرجاتك.
ردود البث المتدفق مع SSE
اضبط stream=True ويرسل الخادم الرموز كـ أحداث مُرسَلة من الخادم. لتطبيقات الدردشة، هذا مهم جداً، لأن القارئ يرى الكلمات الأولى بسرعة بدلاً من انتظار الرد الكامل. تصل إجماليات الاستخدام في نهاية البث، لذا يمكن طلب البث أن يُفوتر ويُسجل بدقة.
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 فارغة، ولهذا تتحقق الحلقة منها قبل الفهرسة. ثانياً، يحمل طلب البث موضع التوازي حتى ينتهي البث، لذا إذا تركت الكود الخاص بك البث دون إغلاقه، يظل هذا الموضع مشغولاً. استخدم 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 ميجابايت. نوعان من أخطاء الحد يعودان كخطأ HTTP 429: الكود rate_limited يعني طلبات كثيرة جداً في الدقيقة، وconcurrency يعني طلبات كثيرة جداً في وقت واحد. يؤدي الحمل الزائد المؤقت أيضاً إلى إرجاع 429، مع رأس Retry-After: 5.
مجموعة تطوير البرمجيات OpenAI SDK تعيد المحاولة لبعض الأخطاء بشكل افتراضي. للتحكم، قم بإيقاف ذلك واكتب حلقة صغيرة تحترم 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 بأي الحدود تنطبق على مفتاحك. لتشغيل العديد من المهام في وقت واحد، حدّ التوازي في كودك الخاص باستخدام قفل عدّاد (semaphore) بحجم مفتاحك، 8 للمفتاح الكامل و2 لمفتاح التجربة، بحيث نادراً ما ترى خطأ 429 على الإطلاق.
تشغيل العديد من الطلبات بالتوازي
المهام الدفعية، مثل توليد وسوم لبضع مئات من مقاطع القصة، هي حيث يهم حدود التوازي. يقبل المفتاح الكامل 8 طلبات في وقت واحد، لذا شغل العمل عبر عميل غير متزامن وإشارة (semaphore) بنفس الحجم. إذا كنت تستخدم مفتاح تجربة، استخدم 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)
الإشارة (semaphore) هي الحيلة بأكملها. بدونها، يطلق قائمة من 200 مقطع 200 طلب معاً، وتعود معظمها كأخطاء 429 مع الكود concurrency. معها، يتدفق العمل بسرعة يسمح بها مفتاحك ولا يُهدر شيء. إذا كنت تشغل أيضاً ميزانية لكل دقيقة، فإن 300 طلب في الدقيقة على مفتاح كامل يعني خمسة طلبات في الثانية، لذا يمكن أن تصل الطلبات القصيرة جداً حدّ الدقيقة قبل حدّ التوازي.
المشاكل الشائعة وحلولها
- 401 أو أخطاء المصادقة. المفتاح مفقود أو مقطوع أو مُرسَل إلى المضيف الخاطئ. اطبع
client.base_urlوتحقق من متغير البيئة. يجب أن يقرأ الرأسAuthorization: Bearerمتبوعاً بمفتاحك. - النموذج غير موجود. معرف النموذج الوحيد هو
uncensored. مثال منسوخ يقول اسماً آخر سيفشل، لذا استدعِGET /v1/modelsإذا كنت غير متأكد. - ردود فارغة أو قصيرة في حلقة القصة. تحقق من أنك تضيف رد المساعد إلى قائمة الرسائل قبل الدورة التالية. بدونه، يرى النموذج فقط رسالتك الأخيرة.
- ردود تتكرر فيها نفسها. ارفع
frequency_penaltyقليلاً، على سبيل المثال إلى 0.3، أو اخفضtemperatureإذا انحرف النص. يتم تمرير جميع العقوبات،top_p،stopوseed. - مخرجات مختلفة في كل تشغيل. اضبط
seedودرجة حرارة منخفضةtemperatureعندما تحتاج إلى نتائج قابلة للتكرار قدر الإمكان أثناء تصحيح الأخطاء. - طلب كبير جداً. حدّ حجم نص الطلب هو 8 ميجابايت، ويجب أن يتسع الموجّه والإكمال في 100,000 رمز. قم بتقليص أو تلخيص السياق القديم قبل أن يصل إلى أي من الحدين.
عندما يبدو أن شيئاً ما خطأ من جانب الخادم، احفظ رأس X-Request-Id من الرد وأرسله إلى صفحة الدعم للتواصل مع وصف قصير. يتيح ذلك للمشغلين العثور على طلبك الدقيق.
التكلفة وما لا يمكنه القيام به
التسعير هو $0.15 لكل مليون رمز إدخال و $0.50 لكل مليون رمز إخراج، من رصيد مسبق الدفع بدون اشتراك. الطلبات الفاشلة أو المرفوضة لا يتم تحصيل رسوم عنها، والرصيد لا ينتهي. كمثال عملي، سكريبت يرسل 3,000 رمز ويستقبل 800 يدفع $0.00045 للإدخال بالإضافة إلى $0.0004 للإخراج، وهو $0.00085 لكل استدعاء، لذا فإن 1,000 استدعاء تكلف $0.85. يتم شحن الرصيد من $20 إلى $500، مع مكافآت +5% من $50، +10% من $100 و +15% من $200. هذا الموقع يقبل العملات المشفرة فقط، في USDT على TRC20 أو USDC على Base. انظر صفحة التسعير للحصول على الجدول الكامل، و التوثيق لمرجع نقطة النهاية.
الحدود واضحة. إنه نموذج مفتوح الأوزان واحد، يشغله مزود مستقل، وليس API الرسمي لأي بائع نماذج. نافذة السياق هي 100,000 رمز للموجّه والإكمال. لا يولد صوراً أو صوتاً أو فيديو، ولا يوفر تضمينات ولا يدعم الضبط الدقيق. استخدمه للاستخدام القانوني للبالغين فقط، ولاحظ الحد الصارم: لا محتوى جنسي يتضمن القاصرين. لا تُستخدم الموجّهات للتدريب.
المزيد من الأدلة
أسئلة وأجوبة
هل أحتاج إلى SDK خاص لاستدعاء هذا API من Python؟
لا. حزمة openai الرسمية تعمل. اضبط base_url إلى https://api.nsfwaiapi.com/v1 ومرر مفتاحك واستخدم معرف النموذج uncensored.
هل يعمل البث المتدفق بنفس الطريقة كما مع OpenAI؟
نعم. مرر stream=True واقرأ أحداث SSE قطعة تلو الأخرى. يتم الإبلاغ عن الاستخدام في نهاية البث.
ماذا أفعل عندما أحصل على خطأ 429؟
انتظر وأعد المحاولة. إذا كان الرد يحتوي على رأس Retry-After، التزم به. رمز الخطأ rate_limited يعني طلبات كثيرة جداً في الدقيقة، وconcurrency يعني طلبات كثيرة جداً في آن واحد.
هل يمكنني اختباره دون دفع؟
نعم. بعد تسجيل الدخول يمكنك المطالبة بـ $0.50 من رصيد تجريبي في صفحة مفتاح API. لا يتطلب تفاصيل الدفع، وهو صالح لمدة 7 أيام وهو واحد لكل شخص.
مفتاحك على بُعد نموذج واحد
أنشئ حساباً، وانسخ المفتاح، ثم غيّر عنوان URL الأساسي. هذا هو الإعداد الكامل.
احصل على مفتاح APINsfwAiApiAPI LLM بدون رقابة لتوليد النص NSFW