Download source/api.py from sriharithebest/nayara-v1: direct link, hf CLI and curl.
- Browser
- Download file 5.74 kB
-
https://huggingface.co/sriharithebest/nayara-v1/resolve/main/source/api.py
- Command line
-
hf download hf://sriharithebest/nayara-v1/source/api.py
-
curl -L -o api.py https://huggingface.co/sriharithebest/nayara-v1/resolve/main/source/api.py
5.74 kB
| from __future__ import annotations | |
| import json | |
| import os | |
| import secrets | |
| import threading | |
| import time | |
| import uuid | |
| from contextlib import asynccontextmanager | |
| from typing import Any, Literal | |
| from fastapi import Depends, FastAPI, Header, HTTPException | |
| from fastapi.concurrency import run_in_threadpool | |
| from fastapi.responses import StreamingResponse | |
| from pydantic import BaseModel, Field | |
| from tokenizers import Tokenizer | |
| from nayara.artifacts import materialize_checkpoint | |
| from nayara.generate import load_model, stream_generate | |
| class CompletionRequest(BaseModel): | |
| model: str = "nayara-v1" | |
| prompt: str | |
| max_tokens: int = Field(192, ge=1, le=512) | |
| temperature: float = Field(0.2, ge=0, le=2) | |
| top_k: int = Field(40, ge=1, le=32000) | |
| stream: bool = False | |
| class ChatMessage(BaseModel): | |
| role: Literal["system", "user", "assistant"] | |
| content: str | |
| class ChatRequest(BaseModel): | |
| model: str = "nayara-v1" | |
| messages: list[ChatMessage] | |
| max_tokens: int = Field(192, ge=1, le=512) | |
| temperature: float = Field(0.2, ge=0, le=2) | |
| top_k: int = Field(40, ge=1, le=32000) | |
| stream: bool = False | |
| runtime: dict[str, Any] = {"ready": False} | |
| generation_lock = threading.Lock() | |
| MODEL_ID = os.environ.get("NAYARA_MODEL_ID", "nayara-v1") | |
| def _authorize(authorization: str | None = Header(default=None)) -> None: | |
| expected = os.environ.get("NAYARA_API_KEY") | |
| if not expected: | |
| return | |
| supplied = authorization.removeprefix("Bearer ") if authorization else "" | |
| if not secrets.compare_digest(supplied, expected): | |
| raise HTTPException(status_code=401, detail="invalid bearer token") | |
| def _chat_prompt(messages: list[ChatMessage]) -> str: | |
| if not messages or not any(message.role == "user" for message in messages): | |
| raise HTTPException(status_code=422, detail="messages must contain at least one user message") | |
| parts: list[str] = [] | |
| for message in messages: | |
| if message.role == "system": | |
| parts.append(f"<|user|>\nSystem guidance: {message.content.strip()}") | |
| else: | |
| parts.append(f"<|{message.role}|>\n{message.content.strip()}") | |
| parts.append("<|assistant|>\n") | |
| return "\n".join(parts) | |
| def _generate(prompt: str, request: CompletionRequest | ChatRequest): | |
| return stream_generate( | |
| runtime["model"], runtime["tokenizer"], prompt, | |
| max_new_tokens=request.max_tokens, temperature=request.temperature, top_k=request.top_k, | |
| ) | |
| def _complete(prompt: str, request: CompletionRequest | ChatRequest) -> str: | |
| final = "" | |
| with generation_lock: | |
| for final in _generate(prompt, request): | |
| pass | |
| return final | |
| def _sse(prompt: str, request: CompletionRequest | ChatRequest, chat: bool): | |
| request_id = f"nayara-{uuid.uuid4().hex}" | |
| previous = "" | |
| with generation_lock: | |
| for partial in _generate(prompt, request): | |
| delta, previous = partial[len(previous) :], partial | |
| if chat: | |
| payload = {"id": request_id, "object": "chat.completion.chunk", "model": MODEL_ID, "choices": [{"index": 0, "delta": {"content": delta}, "finish_reason": None}]} | |
| else: | |
| payload = {"id": request_id, "object": "text_completion", "model": MODEL_ID, "choices": [{"index": 0, "text": delta, "finish_reason": None}]} | |
| yield f"data: {json.dumps(payload)}\n\n" | |
| yield "data: [DONE]\n\n" | |
| async def lifespan(_: FastAPI): | |
| if os.environ.get("NAYARA_REQUIRE_API_KEY") == "1" and not os.environ.get("NAYARA_API_KEY"): | |
| raise RuntimeError("NAYARA_REQUIRE_API_KEY=1 but NAYARA_API_KEY is unset") | |
| checkpoint = await run_in_threadpool(materialize_checkpoint) | |
| threads = int(os.environ.get("NAYARA_THREADS", max(1, (os.cpu_count() or 4) // 2))) | |
| runtime["tokenizer"] = Tokenizer.from_file(str(checkpoint / "tokenizer.json")) | |
| runtime["model"] = await run_in_threadpool(load_model, checkpoint, True, threads) | |
| runtime.update({"ready": True, "checkpoint": str(checkpoint), "loaded_at": time.time()}) | |
| yield | |
| runtime.clear() | |
| runtime["ready"] = False | |
| app = FastAPI(title="NAYARA API", version="1.0.0", lifespan=lifespan) | |
| def health() -> dict[str, str]: | |
| return {"status": "ok"} | |
| def ready() -> dict[str, Any]: | |
| if not runtime.get("ready"): | |
| raise HTTPException(status_code=503, detail="model is not loaded") | |
| return {"status": "ready", "model": MODEL_ID, "loaded_at": runtime["loaded_at"]} | |
| def models() -> dict[str, Any]: | |
| return {"object": "list", "data": [{"id": MODEL_ID, "object": "model", "owned_by": "nayara"}]} | |
| async def completions(request: CompletionRequest): | |
| prompt = request.prompt | |
| if request.stream: | |
| return StreamingResponse(_sse(prompt, request, False), media_type="text/event-stream") | |
| text = await run_in_threadpool(_complete, prompt, request) | |
| return {"id": f"nayara-{uuid.uuid4().hex}", "object": "text_completion", "model": MODEL_ID, "choices": [{"index": 0, "text": text, "finish_reason": "stop"}]} | |
| async def chat_completions(request: ChatRequest): | |
| prompt = _chat_prompt(request.messages) | |
| if request.stream: | |
| return StreamingResponse(_sse(prompt, request, True), media_type="text/event-stream") | |
| text = await run_in_threadpool(_complete, prompt, request) | |
| return {"id": f"nayara-{uuid.uuid4().hex}", "object": "chat.completion", "model": MODEL_ID, "choices": [{"index": 0, "message": {"role": "assistant", "content": text}, "finish_reason": "stop"}]} | |