Text Classification
Transformers
Safetensors
Chinese
spam-detection
advertising-detection
ad-classification
chinese
modernbert
mmbert
multi-task
four-head
Instructions to use x6nux/laya-ad with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use x6nux/laya-ad with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="x6nux/laya-ad")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("x6nux/laya-ad", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 5,567 Bytes
0cd599e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | """Bounded, best-effort usage telemetry; never part of inference success."""
import logging
import sqlite3
import threading
import time
from collections import deque
from dataclasses import dataclass
from .database import Database
logger = logging.getLogger(__name__)
@dataclass(frozen=True)
class UsageEvent:
created_at: str
source: str
key_id: int | None
model: str
input_tokens: int
output_tokens: int
duration_ms: int
class UsageWriter:
def __init__(self, db: Database, *, capacity: int = 1000, batch_size: int = 100,
flush_interval: float = 1.0, shutdown_timeout: float = 5.0):
if min(capacity, batch_size, flush_interval, shutdown_timeout) <= 0:
raise ValueError("Usage writer limits must be positive")
self.db = db
self.capacity = capacity
self.batch_size = batch_size
self.flush_interval = flush_interval
self.shutdown_timeout = shutdown_timeout
self._condition = threading.Condition()
self._pending: deque[UsageEvent] = deque()
self._thread: threading.Thread | None = None
self._accepting = False
self._deadline: float | None = None
self.dropped = 0
def start(self) -> None:
with self._condition:
if self._thread is not None and self._thread.is_alive():
raise RuntimeError("Previous usage writer is still running")
self._deadline = None
self._accepting = True
self._thread = threading.Thread(target=self._run, name="laya-usage-writer", daemon=True)
self._thread.start()
def submit(self, event: UsageEvent) -> bool:
with self._condition:
if not self._accepting or len(self._pending) >= self.capacity:
self.dropped += 1
# Avoid flooding logs when storage cannot keep up.
if self.dropped == 1 or self.dropped & (self.dropped - 1) == 0:
logger.warning("Usage queue unavailable/full; dropped events=%d", self.dropped)
return False
self._pending.append(event)
self._condition.notify()
return True
def stop(self) -> None:
with self._condition:
self._accepting = False
self._deadline = time.monotonic() + self.shutdown_timeout
self._condition.notify_all()
if self._thread is not None:
self._thread.join(self.shutdown_timeout)
if self._thread.is_alive():
logger.warning("Usage shutdown timed out; unflushed statistics may be lost")
def _next_batch(self) -> list[UsageEvent]:
with self._condition:
while not self._pending and self._accepting:
self._condition.wait()
flush_at = time.monotonic() + self.flush_interval
while self._accepting and len(self._pending) < self.batch_size:
remaining = flush_at - time.monotonic()
if remaining <= 0:
break
self._condition.wait(remaining)
if self._deadline is not None and time.monotonic() >= self._deadline:
self.dropped += len(self._pending)
self._pending.clear()
return [self._pending.popleft() for _ in range(min(self.batch_size, len(self._pending)))]
@staticmethod
def _write_batch(connection: sqlite3.Connection, batch: list[UsageEvent]) -> None:
latest: dict[int, str] = {}
for event in batch:
if event.key_id is not None:
latest[event.key_id] = max(latest.get(event.key_id, ""), event.created_at)
with connection:
connection.executemany(
"INSERT INTO usage_events (created_at,source,key_id,model,input_tokens,output_tokens,duration_ms) "
"VALUES (?,?,?,?,?,?,?)",
[(e.created_at, e.source, e.key_id, e.model, e.input_tokens, e.output_tokens, e.duration_ms)
for e in batch],
)
connection.executemany(
"UPDATE api_keys SET last_used_at=MAX(COALESCE(last_used_at,''),?) WHERE id=?",
[(created_at, key_id) for key_id, created_at in latest.items()],
)
def _run(self) -> None:
connection = None
try:
while batch := self._next_batch():
try:
if connection is None:
connection = self.db.open_connection()
self._write_batch(connection, batch)
except sqlite3.Error:
with self._condition:
self.dropped += len(batch)
logger.exception("Failed to persist %d usage events; dropping batch", len(batch))
# Do not retry an ambiguously committed batch and double-count it.
if connection is not None:
connection.close()
connection = None
finally:
with self._condition:
self._accepting = False
if self._pending:
self.dropped += len(self._pending)
logger.warning("Usage writer stopped; discarding %d pending events", len(self._pending))
self._pending.clear()
if connection is not None:
connection.close()
|