پرش به محتوا
هوشی

راهنماها

نمونه‌ها و یکپارچه‌سازی‌ها

دستورپخت‌های آمادهٔ کپی برای رایج‌ترین سناریوها. همهٔ نمونه‌ها با API یکپارچه نوشته شده‌اند؛ پس با تغییر یک رشته می‌توانی مدل را از GPT به Claude یا Gemini عوض کنی.

رابط چت استریمی (Next.js)

کلید روی سرور می‌ماند: یک Route Handler درخواست را به هوشی می‌فرستد و متن را تکه‌تکه به مرورگر استریم می‌کند. سمت کلاینت فقط fetch و ReadableStream لازم است.

// app/api/chat/route.ts — کلید فقط روی سرور
import OpenAI from "openai";

const hooshi = new OpenAI({ baseURL: "https://api.hooshi.ai/v1", apiKey: process.env.HOOSHI_API_KEY });

export async function POST(req: Request) {
  // TODO: کاربر خودت را احراز کن و سقف مصرفش را چک کن
  const { messages, model = "anthropic/claude-sonnet-5-5" } = await req.json();

  const stream = await hooshi.chat.completions.create({ model, messages, stream: true });

  const encoder = new TextEncoder();
  const body = new ReadableStream({
    async start(controller) {
      try {
        for await (const chunk of stream) {
          const text = chunk.choices[0]?.delta?.content;
          if (text) controller.enqueue(encoder.encode(text));
        }
      } catch (e) {
        controller.enqueue(encoder.encode("\n[خطا در دریافت پاسخ]"));
      } finally {
        controller.close();
      }
    },
  });
  return new Response(body, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
}

ساده‌ترش کن

اگر از Vercel AI SDK استفاده می‌کنی، نمونهٔ Vercel AI SDK پایین همین را با useChat و چند خط انجام می‌دهد.

ایجنت با Function Calling

حلقهٔ کلاسیک ایجنت: مدل ابزار صدا می‌زند، تو اجرا می‌کنی و نتیجه را برمی‌گردانی تا مدل پاسخ نهایی بدهد. چون هوشی Tool Calling را برای Claude هم به قالب OpenAI ترجمه می‌کند، این کد بدون تغییر با GPT، Claude، Gemini و Grok کار می‌کند.

agent.py
import json
from openai import OpenAI

client = OpenAI(base_url="https://api.hooshi.ai/v1", api_key="hk-...")
MODEL = "anthropic/claude-opus-5-5"   # یا openai/gpt-5.5 — بدون تغییر کد

def search_products(query: str, max_price: int | None = None):
    return [{"name": "هدفون بی‌سیم", "price": 2_400_000}, {"name": "اسپیکر", "price": 1_900_000}]

def get_order_status(order_id: str):
    return {"order_id": order_id, "status": "ارسال‌شده", "eta": "۲ روز"}

TOOLS = {"search_products": search_products, "get_order_status": get_order_status}
SCHEMAS = [
    {"type": "function", "function": {
        "name": "search_products",
        "description": "جستجوی محصولات فروشگاه",
        "parameters": {"type": "object", "properties": {
            "query": {"type": "string"}, "max_price": {"type": "integer", "description": "تومان"}},
            "required": ["query"]}}},
    {"type": "function", "function": {
        "name": "get_order_status",
        "description": "وضعیت سفارش با شماره سفارش",
        "parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}}},
]

def run_agent(user_msg: str, max_steps: int = 8) -> str:
    messages = [
        {"role": "system", "content": "تو پشتیبان فروشگاه هستی. برای اطلاعات واقعی حتماً از ابزارها استفاده کن."},
        {"role": "user", "content": user_msg},
    ]
    for _ in range(max_steps):
        resp = client.chat.completions.create(model=MODEL, messages=messages, tools=SCHEMAS)
        msg = resp.choices[0].message
        if not msg.tool_calls:
            return msg.content
        messages.append(msg.model_dump(exclude_none=True))
        for call in msg.tool_calls:
            fn = TOOLS[call.function.name]
            result = fn(**json.loads(call.function.arguments or "{}"))
            messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result, ensure_ascii=False)})
    return "به سقف مراحل رسیدیم."

print(run_agent("سفارش 12345 کجاست؟ یه هدفون زیر ۳ میلیون هم پیشنهاد بده."))

RAG با Embedding

اسناد را با /v1/embeddings به بردار تبدیل کن، نزدیک‌ترین‌ها را با شباهت کسینوسی پیدا کن و به‌عنوان زمینه به مدل گفتگو بده. برای production به‌جای numpy از یک پایگاه برداری (pgvector، Qdrant، Weaviate) استفاده کن.

rag.py
import numpy as np
from openai import OpenAI

client = OpenAI(base_url="https://api.hooshi.ai/v1", api_key="hk-...")
EMBED = "openai/text-embedding-3-small"

docs = [
    "هوشی کیف پول API جداگانه دارد و پرداخت آن تومانی است.",
    "محدودیت نرخ پیش‌فرض هر کلید ۶۰ درخواست در دقیقه است.",
    "برای Claude از base_url برابر https://api.hooshi.ai/anthropic استفاده کنید.",
]

# ۱) ایندکس: همهٔ اسناد در یک درخواست
doc_vecs = np.array([d.embedding for d in client.embeddings.create(model=EMBED, input=docs).data])
doc_vecs /= np.linalg.norm(doc_vecs, axis=1, keepdims=True)

def retrieve(q: str, k: int = 2):
    v = np.array(client.embeddings.create(model=EMBED, input=q).data[0].embedding)
    scores = doc_vecs @ (v / np.linalg.norm(v))
    return [docs[i] for i in scores.argsort()[::-1][:k]]

def answer(q: str) -> str:
    context = "\n".join(f"- {c}" for c in retrieve(q))
    r = client.chat.completions.create(
        model="openai/gpt-6-luna",
        messages=[
            {"role": "system", "content": "فقط بر اساس متن زمینه پاسخ بده. اگر جواب در زمینه نیست، بگو نمی‌دانم."},
            {"role": "user", "content": f"زمینه:\n{context}\n\nسؤال: {q}"},
        ],
    )
    return r.choices[0].message.content

print(answer("سقف درخواست در دقیقه چقدره؟"))

تعویض پویای مدل و fallback

چون همهٔ مدل‌ها پشت یک API هستند، می‌توانی بر اساس نوع کار مدل را انتخاب کنی یا اگر یک پروایدر موقتاً مشکل داشت، خودکار به پروایدر دیگری بروی.

import openai
from openai import OpenAI

client = OpenAI(base_url="https://api.hooshi.ai/v1", api_key="hk-...", max_retries=1)

CHAIN = ["anthropic/claude-sonnet-5-5", "openai/gpt-5.5", "gemini/gemini-3.1-pro-preview"]

def chat(messages, chain=CHAIN):
    last = None
    for model in chain:
        try:
            r = client.chat.completions.create(model=model, messages=messages, timeout=90)
            return model, r.choices[0].message.content
        except (openai.RateLimitError, openai.InternalServerError, openai.APIConnectionError, openai.APITimeoutError) as e:
            last = e          # 429/5xx/شبکه → مدل بعدی
        except openai.APIStatusError as e:
            if e.status_code in (402, 401, 403):
                raise          # مشکل حساب/کلید؛ سوییچ مدل کمکی نمی‌کند
            last = e
    raise last

# انتخاب پویا بر اساس نوع کار
def pick_model(task: str) -> str:
    return {"code": "anthropic/claude-opus-5-5", "cheap": "openai/gpt-6-luna", "long_doc": "gemini/gemini-3.1-pro-preview"}.get(task, "openai/gpt-5.5")

فریم‌ورک‌ها: LangChain، LlamaIndex و Vercel AI SDK

هر فریم‌ورکی که «OpenAI-compatible base URL» را می‌پذیرد، با هوشی کار می‌کند.

LangChain

# pip install langchain-openai
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

llm = ChatOpenAI(
    model="anthropic/claude-sonnet-5-5",
    base_url="https://api.hooshi.ai/v1",
    api_key="hk-...",
    temperature=0.3,
)
print(llm.invoke("سه نکته برای نوشتن پرامپت خوب").content)

emb = OpenAIEmbeddings(model="openai/text-embedding-3-small", base_url="https://api.hooshi.ai/v1", api_key="hk-...",
                       check_embedding_ctx_length=False)

LlamaIndex

Python
# pip install llama-index-llms-openai-like llama-index-embeddings-openai
from llama_index.llms.openai_like import OpenAILike
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core import Settings

Settings.llm = OpenAILike(
    model="gemini/gemini-3.1-pro-preview",
    api_base="https://api.hooshi.ai/v1",
    api_key="hk-...",
    is_chat_model=True,
    is_function_calling_model=True,
    context_window=1_000_000,
)
Settings.embed_model = OpenAIEmbedding(
    model_name="openai/text-embedding-3-small",
    api_base="https://api.hooshi.ai/v1",
    api_key="hk-...",
)

Vercel AI SDK

// npm i ai @ai-sdk/openai-compatible
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { streamText, convertToModelMessages, type UIMessage } from "ai";

const hooshi = createOpenAICompatible({
  name: "hooshi",
  baseURL: "https://api.hooshi.ai/v1",
  apiKey: process.env.HOOSHI_API_KEY,
  includeUsage: true,
});

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json();
  const result = streamText({
    model: hooshi("anthropic/claude-sonnet-5-5"),
    messages: convertToModelMessages(messages),
  });
  return result.toUIMessageStreamResponse();
}

Claude Code، Cursor و ابزارهای برنامه‌نویسی

Claude Code

Claude Code از API بومی Anthropic استفاده می‌کند. کافی است Base URL را به هوشی تغییر دهی؛ کلید را با ANTHROPIC_AUTH_TOKEN (هدر Bearer) یا ANTHROPIC_API_KEY (هدر x-api-key) بده. هر دو پذیرفته می‌شوند.

export ANTHROPIC_BASE_URL="https://api.hooshi.ai/anthropic"
export ANTHROPIC_AUTH_TOKEN="hk-..."
# اختیاری: انتخاب مدل‌ها
export ANTHROPIC_MODEL="claude-opus-5-5"
export ANTHROPIC_SMALL_FAST_MODEL="claude-haiku-5-5"

claude

یک کلید جدا برای ابزارها

برای Claude Code یک کلید اختصاصی با سقف هزینهٔ ماهانه بساز و تزریق هویت را برای آن خاموش کن تا سیستم‌پرامپت خود ابزار دست‌نخورده بماند.

Cursor، Continue، Cline و ابزارهای سازگار با OpenAI

ابزارتنظیم
CursorSettings → Models → OpenAI API Key: کلید hk-...؛ گزینهٔ Override OpenAI Base URL: https://api.hooshi.ai/v1؛ سپس مدل سفارشی مثل anthropic/claude-sonnet-5-5 اضافه کن.
Continue / Cline / RooProvider: «OpenAI Compatible»، Base URL: https://api.hooshi.ai/v1، Model: هر شناسهٔ provider/model. یا Provider «Anthropic» با Base URL https://api.hooshi.ai/anthropic.
Codex CLI و ابزارهای OpenAIمتغیرهای OPENAI_BASE_URL=https://api.hooshi.ai/openai/v1 و OPENAI_API_KEY=hk-... (Responses API بومی پشتیبانی می‌شود).
Aideraider --openai-api-base https://api.hooshi.ai/v1 --model openai/anthropic/claude-sonnet-5-5
.env (اکثر ابزارهای مبتنی بر SDK OpenAI)
OPENAI_BASE_URL=https://api.hooshi.ai/v1
OPENAI_API_KEY=hk-...

سؤالی داری یا نمونه‌ای کم است؟ از پشتیبانی بپرس یا مقالهٔ راهنمای API هوش مصنوعی برای برنامه‌نویسان را بخوان.