داشبورد توسعه‌دهنده
پرسش از هوش مصنوعی
پرسش از هوش مصنوعی

راهنمای پیگیری هزینه نمایندگان

به عنوان نماینده فروش سرویس‌های AvalAI API، پیگیری دقیق هزینه هر فراخوانی API برای صورتحساب صحیح و مدیریت حاشیه سود ضروری است. این راهنما یک گردش کار کامل و گام به گام برای پیاده‌سازی پیگیری دقیق هزینه با استفاده از User API ارائه می‌دهد.

فهرست مطالب


چرا پیگیری دقیق هزینه مهم است

به عنوان نماینده فروش، شما نیاز دارید:

  1. صورتحساب دقیق مشتریان: هزینه دقیق بر اساس استفاده واقعی
  2. حفظ حاشیه سود: محاسبه مارک‌آپ بر اساس هزینه‌های دقیق، نه تخمینی
  3. ارائه شفافیت: گزارش‌های استفاده تفصیلی به مشتریان
  4. مدیریت جریان نقدی: درک هزینه‌های دقیق برای برنامه‌ریزی مالی
  5. رسیدگی به اختلافات: داشتن سوابق دقیق برای حل مسائل صورتحساب

چالش با estimated_cost

بسیاری از پاسخ‌های API شامل فیلد estimated_cost هستند:

json
{
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 20,
    "total_tokens": 30
  },
  "estimated_cost": {
    "unit": "0.0000066000",
    "irt": 0.76,
    "exchange_rate": 115250
  }
}

مشکلات estimated_cost:

  • تضمین وجود ندارد در تمام پاسخ‌ها
  • ممکن است صورتحساب واقعی را منعکس نکند (به خصوص با بسته‌های اعتباری، گرنت‌ها یا قیمت‌گذاری ویژه)
  • متغیرهای دیگر را در نظر نمی‌گیرد مانند توکن‌های کش شده، هزینه استریمینگ
  • نرخ ارز ممکن است با نرخ‌های صورتحساب نهایی مطابقت نداشته باشد

نتیجه: نمی‌توانید به طور قابل اعتماد بر اساس estimated_cost به مشتریان خود صورتحساب ارسال کنید.


راه‌حل: User API

نقطه پایانی /user/v1/transactions/lookup داده‌های هزینه ۱۰۰٪ دقیق برای هر فراخوانی API ارائه می‌دهد.

مزایای کلیدی:

۱۰۰٪ دقیق: دقیقا با صورتحساب واقعی شما مطابقت دارد
همیشه در دسترس: ظرف ۳۰ ثانیه پس از اتمام درخواست
جزئیات کامل: شامل گرنت‌ها، بسته‌ها و هزینه‌های واقعی
مسیر حسابرسی: تاریخچه کامل تراکنش برای انطباق
ارزهای مختلف: هزینه‌ها در UNIT (USD) و IRT (تومان)

نحوه کار:

  1. هر پاسخ API شامل هدر x-request-id (UUID v7) است
  2. این شناسه را با درخواست مشتری خود ذخیره کنید
  3. تا ۳۰ ثانیه برای پردازش هزینه صبر کنید
  4. با شناسه درخواست از /user/v1/transactions/lookup پرس‌وجو کنید
  5. داده‌های هزینه دقیق برای صورتحساب دریافت کنید

گردش کار پیاده‌سازی کامل

مرحله ۱: ضبط شناسه درخواست

هر پاسخ AvalAI API شامل هدر x-request-id است. شما باید این را ضبط کنید:

python
# انجام فراخوانی API
response = requests.post(
    "https://api.avalai.ir/v1/chat/completions",
    headers={
        "Authorization": f"Bearer {AVALAI_API_KEY}",
        "Content-Type": "application/json",
    },
    json={"model": "gpt-5.4-mini", "messages": [{"role": "user", "content": "سلام!"}]},
)

# مهم: ضبط x-request-id از هدرها
request_id = response.headers.get("x-request-id")

# فورا با context مشتری ذخیره کنید
db.insert_pending_transaction(
    {
        "request_id": request_id,
        "customer_id": customer.id,
        "timestamp": datetime.now(),
        "model": "gpt-5.4-mini",
        "response_data": response.json(),
    }
)
نسخه معادل Responses API

وقتی مدل انتخابی از /v1/responses پشتیبانی می‌کند، این نسخه را کنار مثال Chat Completions استفاده کنید. messages به input منتقل می‌شود و متن نهایی از response.output_text خوانده می‌شود.

python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AVALAI_API_KEY"],
    base_url="https://api.avalai.ir/v1",
)

response = client.responses.create(
    model="gpt-5.4-mini",
    instructions="You are a helpful assistant.",
    input="سلام!",
)

print(response.output_text)
  • messagesinput
  • پیام سیستمی → instructions یا آیتم developer
  • choices[0].message.contentresponse.output_text
  • برای ابزارها و خروجی‌های چندوجهی، response.output را بر اساس type بررسی کنید.

مرحله ۲: صبر برای پردازش هزینه

هزینه‌ها به صورت ناهمزمان پردازش می‌شوند. تا ۳۰ ثانیه صبر کنید (معمولا خیلی سریعتر):

python
import time

# گزینه الف: همزمان - فورا صبر کنید
time.sleep(5)  # معمولا در ۳-۵ ثانیه در دسترس است

# گزینه ب: ناهمزمان - بعدا پردازش کنید (توصیه می‌شود)
# request_id را برای پردازش پس‌زمینه در صف قرار دهید
cost_tracking_queue.add(
    {
        "request_id": request_id,
        "customer_id": customer.id,
        "retry_after": datetime.now() + timedelta(seconds=5),
    }
)

مرحله ۳: جستجوی هزینه دقیق

از User API برای دریافت جزئیات دقیق هزینه پرس‌وجو کنید:

python
# جستجوی هزینه تراکنش
lookup_response = requests.post(
    "https://api.avalai.ir/user/v1/transactions/lookup",
    headers={
        "Authorization": f"Bearer {AVALAI_API_KEY}",
        "Content-Type": "application/json",
    },
    json={"transaction_ids": [request_id]},
)

cost_data = lookup_response.json()

if cost_data["summary"]["found"] > 0:
    transaction = cost_data["transactions"][0]

    # استخراج هزینه‌های دقیق
    actual_cost_usd = float(transaction["cost"]["unit"])
    actual_cost_irt = float(transaction["cost"]["paid_irt"]) + float(
        transaction["cost"]["paid_grant_irt"]
    )

    # به‌روزرسانی پایگاه داده
    db.update_transaction_cost(
        request_id=request_id,
        cost_usd=actual_cost_usd,
        cost_irt=actual_cost_irt,
        cost_details=transaction["cost"],
    )

مرحله ۴: صورتحساب به مشتری

حالا هزینه‌های دقیق دارید و می‌توانید صورتحساب دقیق ارسال کنید:

python
# محاسبه قیمت‌گذاری (مثال: ۲۰٪ مارک‌آپ)
customer_cost_usd = actual_cost_usd * 1.20
customer_cost_irt = actual_cost_irt * 1.20

# ثبت هزینه
db.insert_customer_charge(
    {
        "customer_id": customer.id,
        "request_id": request_id,
        "avalai_cost_usd": actual_cost_usd,
        "customer_cost_usd": customer_cost_usd,
        "markup_percent": 20,
        "timestamp": datetime.now(),
    }
)

# به‌روزرسانی موجودی مشتری
customer.deduct_balance(customer_cost_usd)

توصیه‌های معماری

گزینه ۱: همزمان (ساده، تاخیر بیشتر)

[مشتری] → [API شما] → [AvalAI API]

         ضبط x-request-id

         صبر ۵ ثانیه

      جستجوی هزینه دقیق

      بازگشت به مشتری

مزایا: پیاده‌سازی ساده، داده فوری هزینه
معایب: ۵+ ثانیه به زمان پاسخ اضافه می‌کند

گزینه ۲: ناهمزمان (توصیه می‌شود)

[مشتری] → [API شما] → [AvalAI API]
                ↓             ↓
         ذخیره request_id     |
                ↓             |
         بازگشت فوری          |

                     [Worker پس‌زمینه]

                      جستجوی هزینه (۵ث بعد)

                      به‌روزرسانی پایگاه داده

مزایا: پاسخ سریع به مشتری، مقیاس‌پذیر
معایب: کمی پیچیده‌تر

گزینه ۳: پردازش دسته‌ای (حجم بالا)

[جمع‌آوری request_ids در طول روز]

      [کار دسته‌ای ساعتی]

   جستجوی هزینه‌ها در دسته (تا ۱۰۰۰ شناسه)

   به‌روزرسانی همه هزینه‌ها به یکباره

   تولید فاکتورهای مشتری

مزایا: کارآمد برای حجم بالا، کاهش فراخوانی‌های API
معایب: داده تاخیری هزینه


مثال‌های کد

پیاده‌سازی کامل پایتون

python
import requests
import time
from datetime import datetime, timedelta
from typing import Dict, List
import logging


class AvalAIReseller:
    def __init__(self, avalai_api_key: str):
        self.api_key = avalai_api_key
        self.base_url = "https://api.avalai.ir"

    def make_customer_request(
        self, customer_id: str, model: str, messages: List[Dict], **kwargs
    ) -> Dict:
        """
        درخواست API از طرف مشتری و پیگیری هزینه‌ها
        """
        # مرحله ۱: انجام فراخوانی API
        response = requests.post(
            f"{self.base_url}/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json",
            },
            json={"model": model, "messages": messages, **kwargs},
        )

        # مرحله ۲: ضبط x-request-id
        request_id = response.headers.get("x-request-id")
        if not request_id:
            logging.error("هیچ x-request-id در هدرهای پاسخ وجود ندارد!")
            raise ValueError("هدر x-request-id وجود ندارد")

        # مرحله ۳: ذخیره برای جستجوی هزینه
        self.store_pending_transaction(
            request_id=request_id,
            customer_id=customer_id,
            model=model,
            response_data=response.json(),
        )

        # مرحله ۴: صف برای پردازش هزینه (async)
        self.queue_cost_lookup(request_id, customer_id)

        return {"request_id": request_id, "response": response.json()}

    def lookup_transaction_cost(
        self, request_ids: List[str], max_retries: int = 3
    ) -> Dict:
        """
        جستجوی هزینه‌های دقیق برای یک یا چند تراکنش
        تلاش مجدد اگر هزینه هنوز در دسترس نباشد
        """
        for attempt in range(max_retries):
            response = requests.post(
                f"{self.base_url}/user/v1/transactions/lookup",
                headers={
                    "Authorization": f"Bearer {self.api_key}",
                    "Content-Type": "application/json",
                },
                json={"transaction_ids": request_ids},
            )

            data = response.json()

            # بررسی اینکه همه تراکنش‌ها یافت شده‌اند
            if data["summary"]["found"] == len(request_ids):
                return data

            # اگر یافت نشد، صبر کنید و دوباره تلاش کنید
            if attempt < max_retries - 1:
                wait_time = 5 * (attempt + 1)  # عقب‌نشینی نمایی
                logging.info(f"تراکنش‌ها آماده نیستند، {wait_time}ث صبر می‌کنیم...")
                time.sleep(wait_time)

        return data

    def process_transaction_cost(self, request_id: str, customer_id: str):
        """
        پردازش هزینه برای یک تراکنش و صورتحساب به مشتری
        """
        # جستجوی هزینه
        cost_data = self.lookup_transaction_cost([request_id])

        if cost_data["summary"]["found"] == 0:
            logging.error(f"تراکنش {request_id} یافت نشد!")
            return

        transaction = cost_data["transactions"][0]

        # استخراج هزینه‌ها
        avalai_cost_usd = float(transaction["cost"]["unit"])
        avalai_cost_irt = float(transaction["cost"]["paid_irt"]) + float(
            transaction["cost"]["paid_grant_irt"]
        )

        # اعمال مارک‌آپ (مثلا ۲۰٪)
        markup = 1.20
        customer_cost_usd = avalai_cost_usd * markup
        customer_cost_irt = avalai_cost_irt * markup

        # ذخیره در پایگاه داده
        self.record_customer_charge(
            customer_id=customer_id,
            request_id=request_id,
            avalai_cost_usd=avalai_cost_usd,
            customer_cost_usd=customer_cost_usd,
            avalai_cost_irt=avalai_cost_irt,
            customer_cost_irt=customer_cost_irt,
            transaction_details=transaction,
        )

        logging.info(
            f"مشتری {customer_id} صورتحساب شد: "
            f"${customer_cost_usd:.6f} "
            f"(AvalAI: ${avalai_cost_usd:.6f}, مارک‌آپ: ۲۰٪)"
        )

    def store_pending_transaction(self, request_id, customer_id, model, response_data):
        """منطق ذخیره‌سازی پایگاه داده خود را پیاده‌سازی کنید"""
        pass

    def queue_cost_lookup(self, request_id, customer_id):
        """منطق صف خود را پیاده‌سازی کنید (Redis، Celery و غیره)"""
        pass

    def record_customer_charge(self, **kwargs):
        """منطق صورتحساب خود را پیاده‌سازی کنید"""
        pass


# استفاده
reseller = AvalAIReseller(avalai_api_key="your-key")

# درخواست برای مشتری
result = reseller.make_customer_request(
    customer_id="cust_123",
    model="gpt-5.4-mini",
    messages=[{"role": "user", "content": "سلام!"}],
)

# هزینه به صورت ناهمزمان در پس‌زمینه پردازش خواهد شد
نسخه معادل Responses API

وقتی مدل انتخابی از /v1/responses پشتیبانی می‌کند، این نسخه را کنار مثال Chat Completions استفاده کنید. messages به input منتقل می‌شود و متن نهایی از response.output_text خوانده می‌شود.

python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AVALAI_API_KEY"],
    base_url="https://api.avalai.ir/v1",
)

response = client.responses.create(
    model="gpt-5.4-mini",
    instructions="You are a helpful assistant.",
    input="سلام!",
)

print(response.output_text)
  • messagesinput
  • پیام سیستمی → instructions یا آیتم developer
  • choices[0].message.contentresponse.output_text
  • برای ابزارها و خروجی‌های چندوجهی، response.output را بر اساس type بررسی کنید.

بهترین شیوه‌ها

1. همیشه x-request-id را ضبط کنید

هنگام استفاده از کتابخانه requests یا سایر HTTP clients:

python
# ✅ خوب
request_id = response.headers.get("x-request-id")
if not request_id:
    raise ValueError("x-request-id وجود ندارد - نمی‌توان هزینه را پیگیری کرد!")

# ❌ بد
# عدم ضبط x-request-id یعنی نمی‌توانید هزینه‌ها را پیگیری کنید

هنگام استفاده از OpenAI SDK (توصیه می‌شود):

python
from openai import OpenAI

client = OpenAI(
    api_key="your-avalai-api-key",
    base_url="https://api.avalai.ir/v1",
)

response = client.chat.completions.create(
    model="gpt-5.4-mini",
    messages=[{"role": "user", "content": "سلام!"}],
)

# ✅ خوب - OpenAI SDK ویژگی _request_id را فراهم می‌کند
request_id = response._request_id
if not request_id:
    raise ValueError("request_id وجود ندارد - نمی‌توان هزینه را پیگیری کرد!")

print(f"شناسه درخواست: {request_id}")
# خروجی: شناسه درخواست: 019ac4a0-a8f4-7041-845f-3ea8f15dcf1a
نسخه معادل Responses API

وقتی مدل انتخابی از /v1/responses پشتیبانی می‌کند، این نسخه را کنار مثال Chat Completions استفاده کنید. messages به input منتقل می‌شود و متن نهایی از response.output_text خوانده می‌شود.

python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AVALAI_API_KEY"],
    base_url="https://api.avalai.ir/v1",
)

response = client.responses.create(
    model="gpt-5.4-mini",
    instructions="You are a helpful assistant.",
    input="سلام!",
)

print(response.output_text)
  • messagesinput
  • پیام سیستمی → instructions یا آیتم developer
  • choices[0].message.contentresponse.output_text
  • برای ابزارها و خروجی‌های چندوجهی، response.output را بر اساس type بررسی کنید.

توجه

ویژگی _request_id به طور خودکار توسط OpenAI SDK هنگام استفاده از نقطه پایانی API AvalAI پر می‌شود. این روش توصیه شده است زیرا تجزیه هدر را به طور خودکار انجام می‌دهد.

هنگام استفاده از LangChain (که به طور مستقیم هدرهای HTTP را نمایش نمی‌دهد):

python
import httpx
from langchain_openai import ChatOpenAI
from langchain_core.callbacks import BaseCallbackHandler
from contextvars import ContextVar
import os

# ذخیره هدرها در متغیر context برای امنیت نخ
request_headers: ContextVar[dict] = ContextVar("request_headers", default={})


class HeaderCapturingClient(httpx.Client):
    def send(self, request, **kwargs):
        response = super().send(request, **kwargs)
        request_headers.set(dict(response.headers))
        return response


class HeaderAccessCallback(BaseCallbackHandler):
    def __init__(self):
        self.request_id = None

    def on_llm_end(self, response, **kwargs):
        headers = request_headers.get()
        self.request_id = headers.get("x-request-id")


# راه‌اندازی
http_client = HeaderCapturingClient()
chat_generator = ChatOpenAI(
    base_url="https://api.avalai.ir/v1",
    api_key=os.getenv("AVALAI_API_KEY"),
    model="gpt-5.4-mini",
    http_client=http_client,
)

callback = HeaderAccessCallback()
response = chat_generator.invoke("سلام!", config={"callbacks": [callback]})

# ✅ خوب - دسترسی به request_id از callback
request_id = callback.request_id
if not request_id:
    raise ValueError("request_id وجود ندارد - نمی‌توان هزینه را پیگیری کرد!")

print(f"شناسه درخواست: {request_id}")

توجه

برای استفاده غیرهمزمان از LangChain، از httpx.AsyncClient و AsyncCallbackHandler استفاده کنید. برای مثال‌های کامل غیرهمزمان به راهنمای هدرهای پاسخ مراجعه کنید.

2. منطق تلاش مجدد پیاده‌سازی کنید

هزینه‌ها ممکن است فورا در دسترس نباشند. عقب‌نشینی نمایی پیاده‌سازی کنید:

python
def lookup_with_retry(request_id, max_attempts=3):
    for attempt in range(max_attempts):
        data = lookup_cost(request_id)
        if data["summary"]["found"] > 0:
            return data
        time.sleep(5 * (attempt + 1))  # ۵ث، ۱۰ث، ۱۵ث
    raise Exception("هزینه پس از تلاش‌های مجدد در دسترس نیست")

3. پردازش دسته‌ای برای کارایی

اگر حجم بالایی دارید، درخواست‌های جستجو را دسته‌بندی کنید:

python
# پردازش ۱۰۰۰ تراکنش به یکباره
request_ids = get_pending_request_ids(limit=1000)
cost_data = lookup_transaction_cost(request_ids)

for transaction in cost_data["transactions"]:
    process_cost(transaction)

4. جزئیات کامل تراکنش را ذخیره کنید

فقط هزینه را ذخیره نکنید - همه چیز را برای حسابرسی ذخیره کنید:

python
db.store_transaction({
    "request_id": request_id,
    "customer_id": customer_id,
    "timestamp": transaction["requested_at"],
    "model": transaction["model"],
    "tokens": transaction["tokens"],
    "avalai_cost_unit": transaction["cost"]["unit"],
    "avalai_cost_irt": transaction["cost"]["paid_irt"],

markup_percent": 20
})

رفع مشکلات

مشکل: x-request-id در هدرهای پاسخ نیست

علت: استفاده از SDK قدیمی یا بررسی نادرست هدرها

راه‌حل:

python
# مطمئن شوید که به هدرهای پاسخ دسترسی دارید، نه بدنه
request_id = response.headers.get("x-request-id")  # ✅ صحیح
request_id = response.json().get("x-request-id")  # ❌ اشتباه - در بدنه نیست

مشکل: تراکنش پس از ۳۰ ثانیه یافت نمی‌شود

علت: بسیار نادر، اما ممکن است در بار بالا اتفاق بیفتد

راه‌حل:

python
# تلاش مجدد طولانی‌تر پیاده‌سازی کنید
max_wait = 60  # تا ۶۰ ثانیه صبر کنید
interval = 10
for i in range(max_wait // interval):
    data = lookup_cost(request_id)
    if data["summary"]["found"] > 0:
        return data
    time.sleep(interval)

# اگر هنوز یافت نشد، با شناسه درخواست با پشتیبانی تماس بگیرید

مشکل: هزینه‌ها با estimated_cost مطابقت ندارند

علت: این انتظار می‌رود! estimated_cost تخمینی است؛ /transactions/lookup هزینه واقعی است

راه‌حل:

  • همیشه از /transactions/lookup برای صورتحساب استفاده کنید
  • estimated_cost را برای تصمیمات مالی نادیده بگیرید
  • فقط برای تخمین‌های تقریبی UX از estimated_cost استفاده کنید

منابع مرتبط


پشتیبانی

برای پشتیبانی ویژه نمایندگان فروش یا سوالات درباره پیگیری هزینه، با تیم پشتیبانی ما با جزئیات حساب نمایندگی خود تماس بگیرید.

ایمیل: support@avalai.ir
شامل: شناسه نمایندگی شما و شناسه‌های درخواست خاص برای هر مشکلی