Standalone PHP 8.2 SDK for the Ingestão Vetorial API — Guzzle-based, Laravel-compatible.

Maintainers

Package info

github.com/ezequiel88/sdk-php-ingestao-vetorial

pkg:composer/ingestao-vetorial/sdk-php

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.2 2026-04-19 23:09 UTC

This package is auto-updated.

Last update: 2026-05-19 23:42:30 UTC


README

SDK PHP oficial para a API do Ingestão Vetorial — sistema de ingestão e busca vetorial com suporte a RAG (Retrieval-Augmented Generation).

Este repositório é a casa dedicada do SDK PHP extraído do monorepo sdk-ingestao-vetorial.

Requer PHP 8.2+ e Guzzle 7. Totalmente compatível com Laravel, Symfony e PHP puro.

Os endpoints paginados da API respondem com items e meta, mas o SDK continua retornando arrays de DTOs ou strings nos métodos de lista, desempacotando items internamente para manter compatibilidade.

Índice

Requisitos

  • PHP ≥ 8.2
  • guzzlehttp/guzzle: ^7.0

Instalação

composer require ingestao-vetorial/sdk-php

Atualização no Packagist

O repositório notifica o Packagist automaticamente a cada push para main e também em tags v*.*.*, usando o workflow Sync Packagist metadata.

Para isso funcionar no GitHub Actions, configure o environment packagist com estes secrets:

  • PACKAGIST_USERNAME
  • PACKAGIST_API_TOKEN

No Packagist, o pacote deve estar cadastrado apontando para https://github.com/ezequiel88/sdk-php-ingestao-vetorial.

Releases automáticos e tags

As tags de release do SDK PHP agora devem ser geradas automaticamente pelo workflow PHP SDK Release Orchestrator.

Como este repositório foi extraído do monorepo original, a primeira tag automática continua a linhagem anterior a partir da baseline 0.1.1.

Como funciona:

  • Todo PR com mudança relevante em src/, tests/, composer.json, phpunit.xml ou phpstan.neon deve incluir um arquivo em .changeset/.
  • O changeset usa a chave php com um bump semver: patch, minor ou major.
  • Ao entrar na main, o workflow valida o SDK, consome os changesets pendentes, cria um commit automático e publica a tag vX.Y.Z.
  • A tag vX.Y.Z dispara o workflow de release do Packagist.

Exemplo de changeset:

---
php: patch
---

Corrige a serializacao de payload no upload e ajusta a documentacao.

Início rápido

<?php

use IngestaoVetorial\Client;
use IngestaoVetorial\DTO\UploadOptions;

$client = new Client(
    baseUrl: 'http://localhost:8000',
    apiKey:  'sua_api_key',   // enviado como X-API-Key em toda requisição
    timeout: 30.0,
);

// Criar uma coleção
$col = $client->createCollection([
    'name'            => 'Documentos Jurídicos',
    'embedding_model' => 'text-embedding-3-small',
    'dimension'       => 1536,
    'description'     => 'Contratos e pareceres',
]);
echo $col->id . PHP_EOL;

// Upload de arquivo
$options = new UploadOptions(
    collectionId:  $col->id,
    documentType:  'contract',
    tags:          ['jurídico', '2024'],
    overwriteExisting: true,
);
$resp = $client->upload('/caminho/para/contrato.pdf', $options);
echo $resp->document_id . PHP_EOL;

// Busca semântica
$results = $client->search(
    query:        'cláusula de rescisão contratual',
    collectionId: $col->id,
    limit:        5,
    minScore:     0.75,
);
foreach ($results as $r) {
    echo sprintf("[%.3f] %s\n", $r->score, $r->document_name);
    echo substr($r->content, 0, 200) . PHP_EOL;
}

Integração com Laravel

Registre o cliente como singleton no AppServiceProvider:

// app/Providers/AppServiceProvider.php
use IngestaoVetorial\Client;

public function register(): void
{
    $this->app->singleton(Client::class, fn () => new Client(
        baseUrl: config('services.ingestao.url'),
        apiKey:  config('services.ingestao.api_key'),
    ));
}

Configure em config/services.php:

'ingestao' => [
    'url'     => env('INGESTAO_URL', 'http://localhost:8000'),
    'api_key' => env('INGESTAO_API_KEY'),
],

Use com injeção de dependência:

use IngestaoVetorial\Client;

class DocumentController extends Controller
{
    public function __construct(private readonly Client $ingestao) {}

    public function search(Request $request): JsonResponse
    {
        $results = $this->ingestao->search(
            query:        $request->string('q'),
            collectionId: $request->string('collection_id'),
            limit:        10,
        );
        return response()->json($results);
    }
}

Tratamento de erros

Todo erro 4xx/5xx lança ApiException:

use IngestaoVetorial\Exceptions\ApiException;

try {
    $doc = $client->document('id-inexistente');
} catch (ApiException $e) {
    echo $e->statusCode();    // 404
    echo $e->responseBody();  // '{"detail":"Not found"}'
    echo $e->getMessage();    // "API error 404: ..."
}

DTOs e tipos retornados

O SDK retorna DTOs imutáveis com tipagem completa via readonly properties. Todos os DTOs possuem um método estático fromArray(array $data) e são encontrados em IngestaoVetorial\DTO\*:

DTO Retornado por
Collection collections(), createCollection(), getCollection(), updateCollection()
Document documents(), collectionDocuments()
DocumentDetail document(), setVersionActive()
DocumentChunk documentChunks()
SearchResult search()
Tag createTag()
UploadResponse upload(), reprocessDocument()
DashboardStats dashboardStats()
RecentActivity recentActivity()
TopCollection topCollections()
UploadsPerDay uploadsPerDay()
VectorsPerWeek vectorsPerWeek()
JobProgress activeJobs(), jobProgress()
LogList logs()
LogFacets logFacets()
LogSummary logSummary()
EmbeddingModelOption embeddingModels()

Enums disponíveis em IngestaoVetorial\Enums\*:

use IngestaoVetorial\Enums\JobStatus;
use IngestaoVetorial\Enums\LogExportFormat;
use IngestaoVetorial\Enums\ReprocessMode;

$mode   = ReprocessMode::Replace;  // 'replace'
$format = LogExportFormat::Csv;    // 'csv'

Referência completa

Coleções

embeddingModels(): EmbeddingModelOption[]

$models = $client->embeddingModels();
foreach ($models as $m) {
    echo "$m->id ($m->provider) — dims: " . implode(', ', $m->dimensions) . PHP_EOL;
}

collections(array $params = []): Collection[]

$cols = $client->collections(['query' => 'jurídico', 'limit' => 10]);
foreach ($cols as $col) {
    echo "$col->name$col->document_count docs\n";
}

createCollection(array $params): Collection

$col = $client->createCollection([
    'name'            => 'Base RAG',
    'embedding_model' => 'text-embedding-3-small',
    'dimension'       => 1536,
    'chunk_size'      => 1400,
    'chunk_overlap'   => 250,
    'is_public'       => false,
]);

getCollection(string $collectionId): Collection

$col = $client->getCollection('uuid');
echo $col->embedding_model;

updateCollection(string $collectionId, array $params): Collection

$col = $client->updateCollection('uuid', ['name' => 'Novo Nome', 'is_public' => true]);

deleteCollection(string $collectionId): void

$client->deleteCollection('uuid');

collectionDocuments(string $collectionId, int $skip = 0, int $limit = 100): Document[]

$docs = $client->collectionDocuments('uuid', limit: 25);

Documentos

documents(int $skip = 0, int $limit = 100, ?string $collectionId = null): Document[]

$docs = $client->documents(collectionId: 'uuid', limit: 20);

document(string $documentId): DocumentDetail

$doc = $client->document('uuid');
echo $doc->checksum;
echo $doc->metadata->document_type;
foreach ($doc->versions as $v) {
    echo "v{$v->version} — ativo: " . ($v->is_active ? 'sim' : 'não') . PHP_EOL;
}

documentChunks(string $documentId, ?int $version = null, ?string $q = null): DocumentChunk[]

Quando $q é informado, o filtro é aplicado no servidor sobre o conteúdo dos chunks. O SDK pagina internamente até devolver todos os resultados.

$chunks = $client->documentChunks('uuid', version: 1);
$filtered = $client->documentChunks('uuid', version: 1, q: 'cláusula penal');
foreach ($chunks as $c) {
    echo substr($c->content, 0, 80) . " — tokens: {$c->tokens}\n";
    echo "embedding dim: " . count($c->embedding) . PHP_EOL;
}

Esse comportamento vale também para embeddingModels(), collections(), collectionDocuments(), documents(), search(), tags(), searchTags(), recentActivity(), topCollections(), uploadsPerDay(), vectorsPerWeek() e activeJobs().

documentMarkdown(string $documentId, ?int $version = null): string

Retorna bytes brutos (string PHP).

$md = $client->documentMarkdown('uuid', 1);
file_put_contents('extraido.md', $md);

deleteDocument(string $documentId): void

$client->deleteDocument('uuid');

reprocessDocument(string $documentId, ReprocessMode $mode = ReprocessMode::Replace, ?int $sourceVersion = null, ?string $extractionTool = null): UploadResponse

use IngestaoVetorial\Enums\ReprocessMode;

$resp = $client->reprocessDocument('uuid', ReprocessMode::Replace, sourceVersion: 1);
echo "Nova versão: {$resp->version}\n";

deleteDocumentVersion(string $documentId, int $version): void

$client->deleteDocumentVersion('uuid', 2);

setVersionActive(string $documentId, int $version, bool $isActive): DocumentDetail

$doc = $client->setVersionActive('uuid', 2, isActive: true);

Upload

upload(string|\SplFileInfo $file, UploadOptions $options): UploadResponse

metadata é um objeto UploadOptions tipado — o SDK serializa internamente para JSON string.

use IngestaoVetorial\DTO\UploadOptions;

$options = new UploadOptions(
    collectionId:      'uuid-da-colecao',
    documentType:      'report',
    description:       'Relatório anual 2024',
    tags:              ['finanças', '2024'],
    customFields:      [['key' => 'departamento', 'value' => 'RH']],
    overwriteExisting: true,
    embeddingModel:    'text-embedding-3-small',
    dimension:         1536,
);

$resp = $client->upload('/caminho/relatorio.pdf', $options);
echo $resp->document_id . "\n";

// Também aceita SplFileInfo
$resp = $client->upload(new \SplFileInfo('/path/to/file.pdf'), $options);

Campos de UploadResponse:

$resp->success       // bool
$resp->document_id   // string  (UUID)
$resp->vector_count  // int     (0 até ingestão concluir)
$resp->version       // int
$resp->message       // string|null

Busca semântica

search(string $query, ?string $collectionId = null, int $limit = 10, int $offset = 0, float $minScore = 0.0): SearchResult[]

$results = $client->search(
    query:        'rescisão contratual',
    collectionId: 'uuid',
    limit:        5,
    minScore:     0.75,
);

foreach ($results as $r) {
    printf("[%.3f] %s — chunk %d\n", $r->score, $r->document_name, $r->chunk_index ?? 0);
    echo substr($r->content, 0, 200) . "\n";
}

Tags

tags(int $skip = 0, int $limit = 100): string[]

$all = $client->tags();

searchTags(string $q): string[]

$found = $client->searchTags('fin');

createTag(string $name): Tag

$tag = $client->createTag('compliance');
echo $tag->id . '' . $tag->name;

Estatísticas

$stats    = $client->dashboardStats();
// $stats->total_collections, $stats->total_vectors, $stats->total_size_mb

$activity = $client->recentActivity(limit: 10);
$top      = $client->topCollections(limit: 3);
$uploads  = $client->uploadsPerDay(days: 30);
$vecs     = $client->vectorsPerWeek(weeks: 12);

Progresso de ingestão

activeJobs(): JobProgress[]

$jobs = $client->activeJobs();
foreach ($jobs as $j) {
    printf("%s — %s (%.0f%%)\n", $j->document_name, $j->status, $j->percent);
}

jobProgress(string $documentId, int $version): JobProgress

// Polling simples
do {
    sleep(2);
    $p = $client->jobProgress('uuid', 1);
    echo "{$p->status} {$p->percent}%\n";
} while (!in_array($p->status, ['completed', 'error', 'cancelled']));

Status: extractingchunkingupsertingcompleted | error | cancelled

cancelIngestion(string $documentId, int $version): array

$result = $client->cancelIngestion('uuid', 1);
// ['ok' => true]

Logs

logs(array $params = []): LogList

from_ts / to_ts aceitam string ISO-8601 ou \DateTimeInterface.

$page = $client->logs([
    'from_ts'   => new \DateTime('-1 day'),
    'nivel'     => 'ERROR',
    'page'      => 1,
    'page_size' => 20,
]);
echo $page->meta->total . " erros\n";
foreach ($page->items as $entry) {
    echo $entry->timestamp . ' ' . $entry->acao . PHP_EOL;
}

logFacets(): LogFacets

$f = $client->logFacets();
print_r($f->apps);
print_r($f->endpoints);

logSummary(\DateTimeInterface|string|null $fromTs = null, ...$toTs): LogSummary

$s = $client->logSummary(fromTs: new \DateTime('-7 days'));
echo $s->total;
print_r($s->byLevel);

exportLogs(LogExportFormat $format = LogExportFormat::Json, int $limit = 10000, array $params = []): string

use IngestaoVetorial\Enums\LogExportFormat;

// CSV
$csv = $client->exportLogs(LogExportFormat::Csv, limit: 500, params: ['nivel' => 'ERROR']);
file_put_contents('erros.csv', $csv);

// JSON
$json = $client->exportLogs(LogExportFormat::Json);
$registros = json_decode($json, true);

Executar testes

cd sdk/php
composer install

# Todos os testes
./vendor/bin/phpunit --testdox

# Análise estática (PHPStan nível 8)
./vendor/bin/phpstan analyse src/ --level=8

Licença

MIT