yethee/tiktoken
PHP port of OpenAI tiktoken for fast tokenization. Get encoders by model or encoding, encode text to token IDs, with built-in vocabulary caching (configurable cache dir). Optional experimental FFI mode using tiktoken-rs for better performance on larger inputs.
composer require yethee/tiktoken
use Yethee\Tiktoken\EncoderProvider;
$provider = new EncoderProvider();
$encoder = $provider->getForModel('gpt-3.5-turbo-0301');
$tokens = $encoder->encode('Hello world!');
// Returns: [9906, 1917, 0]
$provider = new EncoderProvider();
$encoder = $provider->getForModel('gpt-4');
$tokens = $encoder->encode("Your prompt here");
$tokenCount = count($tokens);
$cost = $tokenCount * 0.00003; // Example: $0.03 per 1k tokens
use Yethee\Tiktoken\EncoderProvider;
use Closure;
class TokenLimitMiddleware
{
public function __construct(private EncoderProvider $provider) {}
public function handle($request, Closure $next)
{
$encoder = $this->provider->getForModel('gpt-4');
$tokens = $encoder->encode($request->input('prompt'));
if (count($tokens) > 8000) { // GPT-4 context limit
abort(422, 'Prompt exceeds token limit');
}
return $next($request);
}
}
// Initialize once (e.g., in a service container)
$provider = new EncoderProvider();
// Reuse encoder for the same model
$gpt4Encoder = $provider->getForModel('gpt-4');
$gpt3Encoder = $provider->getForModel('gpt-3.5-turbo');
// Encode any text
$tokens = $gpt4Encoder->encode("Your dynamic content");
// Decode back to text (if needed)
$text = $gpt4Encoder->decode($tokens);
// In a service class
class PromptService
{
public function __construct(
private EncoderProvider $provider,
private array $modelConfig
) {}
public function validatePrompt(string $prompt, string $model): void
{
$encoder = $this->provider->getForModel($model);
$tokens = $encoder->encode($prompt);
$maxTokens = $this->modelConfig[$model]['max_tokens'];
if (count($tokens) > $maxTokens) {
throw new \RuntimeException("Prompt exceeds {$maxTokens} token limit");
}
}
}
use Yethee\Tiktoken\Encoder;
class DocumentProcessor
{
public function __construct(private EncoderProvider $provider) {}
public function chunkText(string $text, int $maxTokens = 1000): array
{
$encoder = $this->provider->get('p50k_base');
$tokens = $encoder->encode($text);
$chunks = [];
foreach (array_chunk($tokens, $maxTokens) as $chunk) {
$chunks[] = $encoder->decode($chunk);
}
return $chunks;
}
}
// Configure cache directory (e.g., in config/services.php)
$provider = new EncoderProvider();
$provider->setVocabCache(storage_path('app/tiktoken-cache'));
// Or via environment variable
// TIKTOKEN_CACHE_DIR=/path/to/cache
// Cache is automatically managed; no manual invalidation needed
// (except when vocab files are updated externally)
// Initialize lib mode (requires Rust/FFI setup)
use Yethee\Tiktoken\Encoder\LibEncoder;
LibEncoder::init('/path/to/libtiktoken_php.so');
// Force lib mode for all encoders
$provider = new EncoderProvider(true);
// Or use selectively
$encoder = $provider->getForModel('gpt-4', true);
Cache Directory Permissions:
chmod -R 755 storage/app/tiktoken-cache).sys_get_temp_dir(), which may cause issues in shared hosting.Model Name Mismatches:
'gpt-3.5-turbo-0301' not 'gpt-3.5-turbo').Lib Mode Overhead:
Token Counting Quirks:
$text = mb_convert_encoding($text, 'UTF-8', 'UTF-8');
Race Conditions:
Verify Tokenization:
$encoder = $provider->getForModel('gpt-4');
$tokens = $encoder->encode("Test");
$decoded = $encoder->decode($tokens);
// Compare $decoded to original text for accuracy
Check Cache Issues:
rm -rf storage/app/tiktoken-cache/*
$provider->clearVocabCache();
Lib Mode Errors:
LibEncoder::init() not called).LD_LIBRARY_PATH)..so on macOS).try {
$encoder = $provider->getForModel('gpt-4', true);
} catch (\Yethee\Tiktoken\Exception\LibError $e) {
Log::error('Lib mode failed: ' . $e->getMessage());
}
Performance Bottlenecks:
LibEncoder is worth the setup.Custom Vocabularies:
Yethee\Tiktoken\Vocab\VocabLoader to load vocabularies from custom sources (e.g., S3, database).$loader = new CustomVocabLoader();
$vocab = $loader->load('custom://vocab.json');
$encoder = new NativeEncoder($vocab);
Token Filtering:
Yethee\Tiktoken\Encoder\NativeEncoder to filter tokens (e.g., remove stop tokens):
class FilteredEncoder implements Encoder {
public function encode(string $text): array {
$tokens = parent::encode($text);
return array_filter($tokens, fn($token) => $token !== 1234); // Example filter
}
}
Chunking Logic:
encodeInChunks() for streaming or large texts (currently experimental):
$tokens = $encoder->encodeInChunks("Very long text", 500); // 500-token chunks
Middleware Integration:
public function handle($request, Closure $next) {
$tokens = $this->provider->getForModel('gpt-4')->encode($request->prompt);
if (count($tokens) > config('ai.max_tokens')) {
abort(422, 'Token limit exceeded');
}
return $next($request);
}
Environment Variables:
TIKTOKEN_CACHE_DIR: Override cache location (e.g., /var/cache/tiktoken).TIKTOKEN_LIB_PATH: Path to FFI library (e.g., /usr/local/lib/libtiktoken_php.so).LD_LIBRARY_PATH: Fallback for lib mode (Linux/macOS).Service Container Binding:
EncoderProvider in AppServiceProvider for dependency injection:
$this->app->singleton(EncoderProvider::class, function () {
$provider = new EncoderProvider();
How can I help you explore Laravel packages today?