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

عملکرد AvalAI

در AvalAI، ما به شفافیت کامل و ارائه عملکردی در سطح سازمانی به کاربران خود متعهدیم. هدف ما ارائه یک API قدرتمند و یکپارچه است که نه‌تنها دسترسی به طیف گسترده‌ای از مدل‌های هوش مصنوعی را ساده می‌کند، بلکه عملکردی رقابتی و در بسیاری از موارد برتر نیز ارائه می‌دهد. این تعهد شامل مدل قیمت‌گذاری ما نیز می‌شود—ما ۱۰۰٪ با نرخ‌های پایه ارائه‌دهندگان همسو هستیم و هیچ سودی از خدمات اصلی آن‌ها کسب نمی‌کنیم.

پس از سه ماه بهینه‌سازی فشرده در تمام لایه‌های زیرساخت خود، مفتخریم که به یک نقطه عطف مهم دست یافته‌ایم: AvalAI اکنون تاخیر کمتری نسبت به دسترسی مستقیم به OpenAI برای مدل gpt-4o-mini ارائه می‌دهد، درحالی‌که به تعهد خود مبنی بر قیمت‌گذاری ۱۰۰٪ منطبق و پایداری خدمات در سطح سازمانی پایبند است. این صفحه نگاهی دقیق و شفاف به عملکرد API ما به همراه بنچمارک‌های جامع برای مقایسه سرویس ما با دسترسی مستقیم به ارائه‌دهندگان ارائه می‌دهد.

تاثیر حفاظ‌های امنیتی (Guardrails)

برای اطمینان از یک مقایسه منصفانه و عادلانه، تمامی تست‌های بنچمارک در این صفحه با ویژگی حفاظ امنیتی (Guardrail) غیرفعال انجام شده است.

حفاظ امنیتی AvalAI یک ویژگی امنیتی قدرتمند است که به‌طور خودکار داده‌های حساس (مانند کلیدهای API و رمزهای عبور) را در درخواست‌های شما شناسایی و حذف می‌کند. اگرچه ما اکیدا توصیه می‌کنیم این ویژگی را برای اکثر برنامه‌ها فعال نگه‌دارید، اما این لایه امنیتی تاخیر جزئی در حدود ۲۰۰ تا ۳۰۰ میلی‌ثانیه به همراه دارد. با غیرفعال کردن آن برای این تست‌ها، می‌توانیم اندازه‌گیری خالص‌تری از عملکرد زیرساخت اصلی خود ارائه دهیم.

کاربران می‌توانند بر اساس نیازهای برنامه خود بین حداکثر سرعت یا امنیت پیشرفته یکی را انتخاب کنند.

چگونه به این بهبودها دست یافتیم

بین خرداد و مهر ماه ۱۴۰۴، یک ابتکار جامع بهینه‌سازی را در تمام لایه‌های پلتفرم خود انجام دادیم. بهبودهای ما هم از مزایای معماری و هم از بهینه‌سازی‌های هدفمند ناشی می‌شود:

مزایای معماری

اتصالات پایدار به ارائه‌دهندگان: به‌عنوان یک پلتفرم API یکپارچه با ترافیک بالا، AvalAI اتصالات ثابت و همیشه-باز به OpenAI و سایر ارائه‌دهندگان هوش مصنوعی را حفظ می‌کند. وقتی شما API ما را فراخوانی می‌کنید، از این اتصالات از پیش برقرارشده استفاده می‌کنیم و سربار TLS handshake و برقراری اتصال را که کاربران هنگام فراخوانی مستقیم API با آن مواجه می‌شوند، حذف می‌کنیم.

مدیریت اتصال در مقیاس: زیرساخت ما استخرهای اتصال بهینه‌شده را به تمام ارائه‌دهندگان مدیریت می‌کند. توسعه‌دهندگانی که فراخوانی‌های مستقیم انجام می‌دهند باید یا اتصالات جدید را برای هر درخواست برقرار کنند (که سربار قابل‌توجهی دارد) یا منطق استخر اتصال خود را پیاده‌سازی و نگهداری کنند. رویکرد متمرکز ما این مزایا را به‌طور خودکار برای تمام کاربران فراهم می‌کند.

بهینه‌سازی‌های اخیر

طی سه ماه گذشته، ما بهبودهای هدفمندی را پیاده‌سازی کرده‌ایم:

  • بهینه‌سازی سرویس API اصلی: منطق پردازش و مسیریابی درخواست‌ها را ساده‌تر کردیم
  • کاهش سربار زیرساخت: تاخیر را در هر نقطه از زیرساخت خود به حداقل رساندیم
  • بهبودهای لایه شبکه: پیکربندی‌های شبکه و مسیریابی را بهینه کردیم
  • بهینه‌سازی فراخوانی‌های تکراری: بهینه‌سازی‌های ویژه‌ای که به‌طور قابل‌توجهی سربار را برای برنامه‌هایی که فراخوانی‌های تکراری API انجام می‌دهند کاهش می‌دهد—یک الگوی رایج در بارهای کاری تولیدی

این مزایای معماری همراه با تلاش‌های بهینه‌سازی مداوم ما، اکنون منجر به تاخیر کمتر از دسترسی مستقیم به ارائه‌دهندگان می‌شود که به‌ویژه برای برنامه‌های تولیدی با الگوهای استفاده پایدار API سودمند است.

چک‌لیست تاخیر برای توسعه‌دهندگان

بنچمارک‌های زیر زیرساخت AvalAI را اندازه‌گیری می‌کنند، اما latency برنامه همچنان به طراحی درخواست شما وابسته است. پیش از tuning زیرساخت، این چک‌لیست را بررسی کنید:

  • سطح مدل درست را انتخاب کنید: با کوچک‌ترین مدلی شروع کنید که evalهای شما را پاس می‌کند و مدل‌های reasoning بزرگ‌تر را برای تصمیم‌های سخت نگه دارید.
  • توکن‌های تولیدی را محدود کنید: بودجه کلمه/بخش را صریح تعیین کنید و برای /v1/responses از max_output_tokens یا برای /v1/chat/completions از max_completion_tokens استفاده کنید.
  • پرامپت را cache-friendly نگه دارید: instructions ثابت، policy text، schema ابزارها و مثال‌های قابل reuse را اول قرار دهید؛ context مخصوص کاربر و snippetهای بازیابی‌شده را انتها بگذارید.
  • تعداد درخواست‌ها را کم کنید: مراحل نزدیک به هم را در صورت امکان در یک structured response ترکیب کنید.
  • ایمن موازی‌سازی کنید: retrieval، classification، moderation یا enrichment مستقل را هم‌زمان اجرا کنید و RPM/TPM را زیر نظر بگیرید.
  • خروجی کاربرمحور را stream کنید: streaming همیشه زمان کل generation را کم نمی‌کند، اما time-to-first-token را کاهش می‌دهد و پیشرفت را قابل مشاهده می‌کند.
  • فراخوانی غیرضروری LLM را حذف کنید: confirmationهای محدود را hard-code کنید، نتایج lookup رایج را cache کنید و metricها یا search resultها را وقتی generation ارزشی اضافه نمی‌کند با UI نمایش دهید.

برای ردیابی production، TTFB، latency کل، مدل، endpoint، input tokens، output tokens، cached tokens، request ID و وضعیت نهایی را log کنید تا بتوانید مسیریابی AvalAI، latency ارائه‌دهنده و کار سمت برنامه را از هم جدا کنید.

اگر اولویت شما هزینه است نه latency، این صفحه را کنار بهینه‌سازی هزینه بخوانید.

پیکربندی تست

مهم: تمام تست‌های عملکرد در این صفحه با استفاده از دامنه اصلی ما (api.avalai.ir) انجام شده است که بر روی CDN Cloudflare اجرا می‌شود و عملکرد بهینه را ارائه می‌دهد. ما همچنین یک دامنه ثانویه (api.avalapis.ir) به‌طور خاص برای کاربرانی که به‌دلیل محدودیت‌های شبکه با مشکلات اتصال مواجه هستند ارائه می‌دهیم؛ با این حال، این دامنه ثانویه تاخیر بالاتری دارد و برای این تست‌های بنچمارک استفاده نمی‌شود.

بررسی دقیق تاخیر منطقه‌ای

تاخیر یک عدد ثابت نیست؛ بلکه به شدت تحت‌تاثیر موقعیت جغرافیایی کاربر و مرکز داده قرار دارد. برای ارائه تصویری واضح، تست‌هایی را از دو منطقه متمایز که کاربران ما در آنجا متمرکز هستند، انجام داده‌ایم.


آخرین عملکرد - ۲۰-۰۷-۱۴۰۴

عملکرد مرکز داده اروپا (EU) - ۲۰-۰۷-۱۴۰۴

این تست از یک ماشین مجازی در یک مرکز داده Azure در اتحادیه اروپا انجام شد و عملکرد AvalAI را با فراخوانی مستقیم API OpenAI از همان مکان مقایسه می‌کند.

محیط تست:

  • مدل: gpt-4o-mini
  • ارائه دهنده ابری: Microsoft Azure
  • سخت‌افزار: 4GB RAM، 2 vCPUs
  • مکان: اروپا

نتایج عملکرد اروپا

معیارAvalAI (gpt-4o-mini)OpenAI (gpt-4o-mini)
میانگین TTFB (ثانیه)0.4350.717
میانه TTFB (ثانیه)0.3930.685
صدک ۹۵ TTFB (ثانیه)0.6051.032
میانگین توکن در ثانیه24.513.8
نرخ موفقیت100.00%100.00%

مقایسه عملکرد API در اروپا

تحلیل

نتایج خودگویاست: AvalAI اکنون ۳۹٪ سریع‌تر از دسترسی مستقیم به OpenAI از مرکز داده اروپایی ما است. میانه TTFB ما ۰.۳۹۳ ثانیه در مقایسه با ۰.۶۸۵ ثانیه OpenAI، به همراه توان عملیاتی توکن ۷۷٪ بالاتر (۲۴.۵ در مقابل ۱۳.۸ توکن/ثانیه)، نشان می‌دهد که یک پلتفرم API یکپارچه با معماری خوب می‌تواند از دسترسی مستقیم به ارائه‌دهنده بهتر عمل کند.

این مزیت عملکردی از اتصالات پایدار ما به زیرساخت OpenAI و مدیریت بهینه‌شده درخواست‌های ما ناشی می‌شود. درحالی‌که کاربران فردی باید اتصالات را برقرار کرده و سربار را با هر درخواست مدیریت کنند، سیستم با ترافیک بالای ما اتصالات گرم و مسیرهای بهینه‌شده به تمام ارائه‌دهندگان را حفظ می‌کند. بهینه‌سازی‌های اخیر زیرساخت ما هر سربار داخلی را بیشتر کاهش داده است که منجر به عملکرد برتری شده که در این بنچمارک‌ها نشان داده شده است.


عملکرد مرکز داده خاورمیانه (ME) - ۲۰-۰۷-۱۴۰۴

این تست از یک ماشین مجازی در یک مرکز داده Arvancloud در خاورمیانه انجام شد و عملکرد AvalAI را با فراخوانی مستقیم API OpenAI از همان مکان مقایسه می‌کند.

محیط تست:

  • مدل: gpt-4o-mini
  • ارائه دهنده ابری: Arvancloud
  • سخت‌افزار: 4GB RAM، 2 vCPUs
  • مکان: خاورمیانه

نتایج عملکرد خاورمیانه

معیارAvalAI (gpt-4o-mini)OpenAI (gpt-4o-mini)
میانگین TTFB (ثانیه)0.7031.246
میانه TTFB (ثانیه)0.6681.048
صدک ۹۵ TTFB (ثانیه)0.9472.309
میانگین توکن در ثانیه14.98.4
نرخ موفقیت100.00%100.00%

مقایسه عملکرد API در خاورمیانه

تحلیل

مزیت عملکردی حتی برای کاربران خاورمیانه نیز برجسته‌تر است: AvalAI ۴۴٪ زمان پاسخ سریع‌تر با میانه TTFB ۰.۶۶۸ ثانیه در مقایسه با ۱.۰۴۸ ثانیه OpenAI ارائه می‌دهد. توان عملیاتی توکن ۷۷٪ بالاتر است (۱۴.۹ در مقابل ۸.۴ توکن/ثانیه) که تجربه بسیار بهتری برای استقرارهای منطقه‌ای فراهم می‌کند.

موقعیت استراتژیک زیرساخت ما و مسیرهای مسیریابی بهینه‌شده، به همراه اتصالات پایدار به ارائه‌دهندگان و بهینه‌سازی‌های اخیر، عملکرد استثنایی را برای کاربران در این منطقه ارائه می‌دهد. فاصله عملکردی در مقایسه با دسترسی مستقیم به OpenAI از زمان بنچمارک‌های خردادماه به‌طور قابل‌توجهی افزایش یافته است که تاثیر تلاش‌های بهینه‌سازی ما را نشان می‌دهد.


عملکرد تاریخی - خرداد ۱۴۰۴

برای شفافیت و نمایش بهبود مستمر ما، نتایج بنچمارک قبلی خود را از خرداد ۱۴۰۴ حفظ می‌کنیم. این نتایج تاریخی نقطه شروع قبل از ابتکار بهینه‌سازی اخیر ما را نشان می‌دهند.

عملکرد مرکز داده اروپا (EU) - تاریخ ۲۲-۰۳-۱۴۰۴

محیط تست:

  • مدل: gpt-4o-mini
  • ارائه دهنده ابری: Microsoft Azure
  • مکان: اروپا

نتایج عملکرد اروپا (تاریخی)

معیارAvalAI (gpt-4o-mini)OpenAI (gpt-4o-mini)
میانگین TTFB (ثانیه)0.7280.531
میانه TTFB (ثانیه)0.6830.510
صدک ۹۵ TTFB (ثانیه)1.0560.740
میانگین توکن در ثانیه15.918.9
نرخ موفقیت100.00%100.00%

مقایسه عملکرد API در اروپا - خرداد ۱۴۰۴

تحلیل تاریخی

در خرداد ۱۴۰۴، AvalAI سربار تاخیر جزئی در حدود ۲۰۰ میلی‌ثانیه نسبت به فراخوانی مستقیم OpenAI از مراکز داده Azure نشان داد. این امر با توجه به میزبانی اصلی OpenAI بر روی زیرساخت Azure قابل انتظار بود. خدمات ارزش‌افزوده‌ای که ما ارائه می‌دادیم—مسیریابی API یکپارچه، لایه‌های امنیتی قوی و پشتیبانی از چند ارائه‌دهنده—با این سربار جزئی همراه بود.

عملکرد مرکز داده خاورمیانه (ME) - تاریخ ۲۲-۰۳-۱۴۰۴

محیط تست:

  • مدل: gpt-4o-mini
  • ارائه دهنده ابری: Arvancloud
  • مکان: خاورمیانه

نتایج عملکرد خاورمیانه (تاریخی)

معیارAvalAI (gpt-4o-mini)OpenAI (gpt-4o-mini)
میانگین TTFB (ثانیه)0.9931.095
میانه TTFB (ثانیه)0.9290.951
صدک ۹۵ TTFB (ثانیه)1.4791.386
میانگین توکن در ثانیه11.49.6
نرخ موفقیت100.00%100.00%

مقایسه عملکرد API در خاورمیانه - خرداد ۱۴۰۴

تحلیل تاریخی

حتی در خرداد ۱۴۰۴، AvalAI عملکرد رقابتی را برای کاربران خاورمیانه با تاخیر کمتر و توان عملیاتی بالاتر نسبت به دسترسی مستقیم به OpenAI ارائه می‌داد. نتایج مهرماه ما بهبودهای قابل‌توجه بیشتری را از تلاش‌های بهینه‌سازی ما نشان می‌دهد.


نتایج ما را بازتولید کنید

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

توجه: درحالی‌که این بنچمارک‌ها با استفاده از مدل gpt-4o-mini انجام شده‌اند، بهبودهای عملکردی برای تمام مدل‌های موجود در پلتفرم ما اعمال می‌شود. شما می‌توانید هر مدلی از انتخاب خود را با استفاده از این اسکریپت تست کنید تا ببینید AvalAI برای مورد استفاده خاص شما چگونه عمل می‌کند.

لطفا اطمینان حاصل کنید که کتابخانه‌های لازم (requests، numpy، matplotlib، seaborn، tabulate، tqdm) را نصب کرده‌اید.

python
import os
import requests
import time
import numpy as np
import matplotlib.pyplot as plt
import json
from tabulate import tabulate
from tqdm import tqdm
from datetime import datetime
import seaborn as sns


def test_api_performance(
    api_name, api_url, api_key, model, num_requests=10, prompt="Say hi"
):
    """Test API performance and collect comprehensive metrics"""
    headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
    data = {"model": model, "messages": [{"role": "user", "content": prompt}]}

    ttfb_times = []
    total_times = []
    token_counts = []
    tokens_per_second = []
    errors = 0

    print(f"Testing {api_name} API with {num_requests} requests...")
    for _ in tqdm(range(num_requests)):
        try:
            start_time = time.time()
            response = requests.post(
                api_url, headers=headers, json=data, timeout=(10, 30)
            )
            response_time = time.time()

            # Process the response
            response_json = response.json()
            end_time = time.time()

            # Calculate metrics
            ttfb = response_time - start_time
            total_time = end_time - start_time

            # Try to get token count if available
            try:
                usage = response_json.get("usage", {})
                total_tokens = usage.get("total_tokens", 0)
                completion_tokens = usage.get("completion_tokens", 0)
                token_counts.append(total_tokens)

                # Calculate tokens per second (using completion tokens)
                if completion_tokens > 0 and total_time > 0:
                    tokens_per_second.append(completion_tokens / total_time)
                else:
                    tokens_per_second.append(0)
            except Exception as e:
                token_counts.append(0)
                tokens_per_second.append(0)

            ttfb_times.append(ttfb)
            total_times.append(total_time)

            # Add a small delay to avoid rate limiting
            time.sleep(0.5)

        except Exception as e:
            print(f"Error on request: {e}")
            errors += 1

    return {
        "name": api_name,
        "url": api_url,
        "model": model,
        "average_ttfb": np.mean(ttfb_times) if ttfb_times else None,
        "median_ttfb": np.median(ttfb_times) if ttfb_times else None,
        "p95_ttfb": np.percentile(ttfb_times, 95) if ttfb_times else None,
        "average_total": np.mean(total_times) if total_times else None,
        "median_total": np.median(total_times) if total_times else None,
        "p95_total": np.percentile(total_times, 95) if total_times else None,
        "ttfb_times": ttfb_times,
        "total_times": total_times,
        "token_counts": token_counts,
        "avg_tokens": (
            np.mean(token_counts) if token_counts and any(token_counts) else None
        ),
        "tokens_per_second": tokens_per_second,
        "avg_tokens_per_second": (
            np.mean([t for t in tokens_per_second if t > 0])
            if tokens_per_second and any(tokens_per_second)
            else None
        ),
        "median_tokens_per_second": (
            np.median([t for t in tokens_per_second if t > 0])
            if tokens_per_second and any(tokens_per_second)
            else None
        ),
        "success_rate": (
            len(ttfb_times) / (len(ttfb_times) + errors)
            if (len(ttfb_times) + errors) > 0
            else 0
        ),
        "error_count": errors,
    }


def print_comparison_table(results_avalai, results_openai):
    """Print comparison table between two APIs"""
    headers = [
        "Metric",
        f"AvalAI ({results_avalai['model']})",
        f"OpenAI ({results_openai['model']})",
    ]

    data = [
        [
            "Average TTFB (s)",
            f"{results_avalai['average_ttfb']:.3f}",
            f"{results_openai['average_ttfb']:.3f}",
        ],
        [
            "Median TTFB (s)",
            f"{results_avalai['median_ttfb']:.3f}",
            f"{results_openai['median_ttfb']:.3f}",
        ],
        [
            "95th Percentile TTFB (s)",
            f"{results_avalai['p95_ttfb']:.3f}",
            f"{results_openai['p95_ttfb']:.3f}",
        ],
        [
            "Average Total Time (s)",
            f"{results_avalai['average_total']:.3f}",
            f"{results_openai['average_total']:.3f}",
        ],
        [
            "Median Total Time (s)",
            f"{results_avalai['median_total']:.3f}",
            f"{results_openai['median_total']:.3f}",
        ],
        [
            "95th Percentile Total (s)",
            f"{results_avalai['p95_total']:.3f}",
            f"{results_openai['p95_total']:.3f}",
        ],
        [
            "Success Rate",
            f"{results_avalai['success_rate']:.2%}",
            f"{results_openai['success_rate']:.2%}",
        ],
    ]

    # Add token metrics if available
    if (
        results_avalai["avg_tokens"] is not None
        and results_openai["avg_tokens"] is not None
    ):
        data.append(
            [
                "Avg Tokens per Response",
                f"{results_avalai['avg_tokens']:.1f}",
                f"{results_openai['avg_tokens']:.1f}",
            ]
        )

    # Add tokens per second metrics if available
    if (
        results_avalai["avg_tokens_per_second"] is not None
        and results_openai["avg_tokens_per_second"] is not None
    ):
        data.append(
            [
                "Avg Tokens per Second",
                f"{results_avalai['avg_tokens_per_second']:.1f}",
                f"{results_openai['avg_tokens_per_second']:.1f}",
            ]
        )
        data.append(
            [
                "Median Tokens per Second",
                f"{results_avalai['median_tokens_per_second']:.1f}",
                f"{results_openai['median_tokens_per_second']:.1f}",
            ]
        )

    print("\nAPI Performance Comparison:")
    print(tabulate(data, headers=headers, tablefmt="grid"))


def plot_comparison(results_avalai, results_openai, output_file=None):
    """Create improved visualization plots for API comparison"""
    # Set the style
    sns.set(style="whitegrid")

    # Create figure with subplots - adding a third subplot for tokens per second
    fig, axes = plt.subplots(3, 1, figsize=(12, 15))

    # Define metrics to plot
    metrics = [
        ("ttfb_times", "Time to First Byte (s)"),
        ("total_times", "Total Request Time (s)"),
        ("tokens_per_second", "Tokens per Second"),
    ]

    # Define colors for each API
    colors = {"AvalAI": "#3498db", "OpenAI": "#2ecc71"}

    for i, (metric, title) in enumerate(metrics):
        # Create violin plots with individual points
        ax = axes[i]

        # Prepare data for plotting
        data_to_plot = []
        labels = []

        for result, label in [(results_avalai, "AvalAI"), (results_openai, "OpenAI")]:
            # Filter out zeros for tokens per second
            if metric == "tokens_per_second":
                data_to_plot.append([t for t in result[metric] if t > 0])
            else:
                data_to_plot.append(result[metric])
            labels.append(f"{label}\n({result['model']})")

        # Create violin plot
        parts = ax.violinplot(data_to_plot, showmeans=True, showmedians=True)

        # Customize violin plots
        for pc, color_key in zip(parts["bodies"], colors.keys()):
            pc.set_facecolor(colors[color_key])
            pc.set_alpha(0.7)

        # Add boxplot inside violin
        bp = ax.boxplot(
            data_to_plot,
            positions=range(1, len(data_to_plot) + 1),
            widths=0.15,
            patch_artist=True,
            showfliers=False,
        )

        # Customize boxplots
        for box, color_key in zip(bp["boxes"], colors.keys()):
            box.set(color="black", linewidth=1.5)
            box.set(facecolor="white")

        # Add scatter points with jitter
        for j, data in enumerate(
            [
                (
                    results_avalai[metric]
                    if metric != "tokens_per_second"
                    else [t for t in results_avalai[metric] if t > 0]
                ),
                (
                    results_openai[metric]
                    if metric != "tokens_per_second"
                    else [t for t in results_openai[metric] if t > 0]
                ),
            ]
        ):
            # Add jitter to x position
            x = np.random.normal(j + 1, 0.05, size=len(data))
            ax.scatter(
                x,
                data,
                alpha=0.4,
                s=20,
                color=list(colors.values())[j],
                edgecolor="white",
                linewidth=0.5,
            )

        # Set labels and title
        ax.set_title(title, fontsize=14, fontweight="bold")
        if metric == "tokens_per_second":
            ax.set_ylabel("Tokens/second", fontsize=12)
        else:
            ax.set_ylabel("Time (seconds)", fontsize=12)
        ax.set_xticks(range(1, len(labels) + 1))
        ax.set_xticklabels(labels, fontsize=12)

        # Add horizontal grid lines
        ax.yaxis.grid(True, linestyle="--", alpha=0.7)

        # Add stats as text
        for j, (result, label) in enumerate(
            [(results_avalai, "AvalAI"), (results_openai, "OpenAI")]
        ):
            if metric == "tokens_per_second":
                if result["avg_tokens_per_second"] is not None:
                    stats = (
                        f"Mean: {result['avg_tokens_per_second']:.1f}\n"
                        f"Median: {result['median_tokens_per_second']:.1f}"
                    )
                    max_val = (
                        max([t for t in result[metric] if t > 0])
                        if any(t > 0 for t in result[metric])
                        else 0
                    )
                    ax.annotate(
                        stats,
                        xy=(j + 1, max_val * 1.05),
                        ha="center",
                        va="bottom",
                        fontsize=10,
                        bbox=dict(boxstyle="round,pad=0.5", fc="white", alpha=0.7),
                    )
            else:
                stats = (
                    f"Mean: {result[f'average_{metric.split("_")[0]}']:.3f}s\n"
                    f"Median: {result[f'median_{metric.split("_")[0]}']:.3f}s\n"
                    f"95th: {result[f'p95_{metric.split("_")[0]}']:.3f}s"
                )
                ax.annotate(
                    stats,
                    xy=(j + 1, result[f'p95_{metric.split("_")[0]}'] * 1.05),
                    ha="center",
                    va="bottom",
                    fontsize=10,
                    bbox=dict(boxstyle="round,pad=0.5", fc="white", alpha=0.7),
                )

    # Add title and timestamp
    plt.suptitle(
        f"API Performance Comparison: AvalAI vs OpenAI", fontsize=16, fontweight="bold"
    )
    plt.figtext(
        0.5,
        0.01,
        f'Generated on {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}',
        ha="center",
        fontsize=10,
    )

    plt.tight_layout(rect=[0, 0.03, 1, 0.97])

    if output_file:
        plt.savefig(output_file, dpi=300, bbox_inches="tight")
        print(f"Plot saved to {output_file}")
    else:
        plt.show()


def save_results(results_avalai, results_openai, filename):
    """Save results to JSON file"""
    # Convert numpy arrays to lists for JSON serialization
    results_avalai_copy = results_avalai.copy()
    results_openai_copy = results_openai.copy()

    for key in ["ttfb_times", "total_times", "token_counts"]:
        if key in results_avalai_copy:
            results_avalai_copy[key] = [float(x) for x in results_avalai_copy[key]]
        if key in results_openai_copy:
            results_openai_copy[key] = [float(x) for x in results_openai_copy[key]]

    data = {
        "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
        "results": {"avalai": results_avalai_copy, "openai": results_openai_copy},
    }

    with open(filename, "w") as f:
        json.dump(data, f, indent=2)

    print(f"Results saved to {filename}")


def main():
    # API configuration
    model_name = "gpt-4o-mini"

    url_avalai = "https://api.avalai.ir/v1/chat/completions"
    api_key_avalai = os.getenv("AVALAI_API_KEY")  # Replace with actual key

    url_openai = "https://api.openai.com/v1/chat/completions"
    api_key_openai = os.getenv("OPENAI_API_KEY")  # Replace with actual key

    # Number of requests to make for each API
    num_requests = 60

    # Test prompt
    prompt = "Say hi"

    # Run the tests
    results_avalai = test_api_performance(
        "AvalAI", url_avalai, api_key_avalai, model_name, num_requests, prompt
    )
    results_openai = test_api_performance(
        "OpenAI", url_openai, api_key_openai, model_name, num_requests, prompt
    )

    # Print comparison table
    print_comparison_table(results_avalai, results_openai)

    # Generate visualization
    plot_comparison(results_avalai, results_openai, "api_performance_comparison.png")

    # Save results
    save_results(results_avalai, results_openai, "api_performance_results.json")


if __name__ == "__main__":
    main()

منابع مرتبط