Instructions to use Privoid-ai/Privoid-Action-1B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use Privoid-ai/Privoid-Action-1B with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("ibm-granite/granite-4.0-1b") model = PeftModel.from_pretrained(base_model, "Privoid-ai/Privoid-Action-1B") - Notebooks
- Google Colab
- Kaggle
Download docs/API.md from Privoid-ai/Privoid-Action-1B: direct link, hf CLI and curl.
- Browser
- Download file 7.13 kB
-
https://huggingface.co/Privoid-ai/Privoid-Action-1B/resolve/main/docs/API.md
- Command line
-
hf download hf://Privoid-ai/Privoid-Action-1B/docs/API.md
-
curl -L -o API.md https://huggingface.co/Privoid-ai/Privoid-Action-1B/resolve/main/docs/API.md
Privoid Action — local inference API
A minimal FastAPI service (privoid_action_api/) that serves the Action adapter on the original Granite base, or a
validated merged model, from local files only.
Run
cd Privoid-Action-1B
copy api\config.example.json api\config.json # then set adapter_path to this repository's root folder
python -m privoid_action_api --config api\config.json --check-config
python -m privoid_action_api --config api\config.json
- Binds to
127.0.0.1:8095by default. Any non-loopback host is refused unlessallow_non_loopback: trueis set. - Startup sets
HF_HUB_OFFLINE=1/TRANSFORMERS_OFFLINE=1before any Hugging Face import and loads withlocal_files_only=True. It never downloads, trains or prepares data. If artifacts are missing or invalid, the server still starts,/healthreportsmodel_state: "unavailable", and/extractreturns 503. - The loader refuses adapters whose base is not Granite 4.0 1B.
- The model loads at startup (
load_on_startup: true). One generation runs at a time (max_concurrent: 1, sized for a 12 GB GPU), with up tomax_queuerequests waiting.
Endpoints
GET /health
Process health. Never loads or downloads anything.
{"status": "ok", "model_state": "ready", "request_id": "3f1c0a9e5b7d2c41"}
model_state is one of not_loaded, loading, ready, unavailable.
GET /model-info
Model identity (base ID and revision, adapter folder name and a short weight hash), schema version, and limits
(max_prompt_tokens, max_new_tokens, max_body_bytes, timeout, concurrency, contract limits). Filesystem paths are
not exposed.
POST /extract
Body: one transcript segment in the input schema (docs/SCHEMA.md §1). Example requests are in examples/:
curl.exe -s -X POST http://127.0.0.1:8095/extract -H "content-type: application/json" `
--data-binary "@examples/request_accepted_request.json"
Response 200 (abridged; the full illustrative response is in examples/response_accepted_request.json. It was produced
by the deterministic finalizer from a hand-written output, not by the model):
{
"request_id": "…", "schema_version": "1.0",
"result": {
"schema_version": "1.0", "meeting_id": "meeting-001",
"actions": [{
"id": "A1", "task": "Send the revised proposal.", "owner_speaker_ids": ["S2"], "owner_text": "Omar",
"assignment_status": "accepted", "deadline_text": "Friday", "conditions": [], "status": "active",
"evidence": [{"turn_id": "T1", "quote": "Omar, can you send the revised proposal by Friday?"},
{"turn_id": "T2", "quote": "Yes, I will send it by Friday."}],
"needs_review": false, "review_reasons": [], "pipeline_flags": ["deadline_not_normalized"],
"owner_names": ["Omar"], "deadline_normalized": null,
"deadline_normalization": {"rule": null, "reason": "bare_weekday_ambiguous"}}],
"decisions": [], "unresolved_requests": [], "rejected_records": []},
"validation": {"raw_output_fully_valid": true, "rejected_record_count": 0, "grounded_record_count": 0},
"usage": {"prompt_tokens": 882, "seconds": 1.9},
"model": {"backend": "transformers", "base_model_id": "ibm-granite/granite-4.0-1b", "…": "…"},
"notice": "Records are extracted from the transcript for human review. They do not create tasks, …"
}
(The seconds value above is a placeholder, not a measurement.)
POST /extract-meeting (experimental, disabled by default)
Enable with enable_meeting_endpoint: true. The endpoint cuts the meeting into whole-turn segments
(max_segment_tokens, segment_overlap_turns), extracts each segment, and reconciles the results with the documented
rules (docs/SCHEMA.md §5). The response is marked "experimental": true and includes segments,
reconciliation_log, limitations, segment_failures and complete. Its quality is measured separately (notebook
§10.5). Cross-segment cancellations are flagged, not applied.
Errors
All errors are JSON: {"error": code, "message": text, "request_id": id, …}. They never contain stack traces or
filesystem paths.
| Status | error |
When |
|---|---|---|
| 400 | invalid_json |
Body is not JSON |
| 413 | input_too_large |
Body > max_body_bytes, a contract size limit, or prompt tokens > max_prompt_tokens. Nothing is truncated; split the transcript. |
| 422 | invalid_input |
Schema problems (unknown speaker, duplicate turn ID, invalid date or timezone, control sequences …), listed in problems |
| 429 | busy |
All slots busy and the wait queue is full |
| 502 | model_output_invalid |
The model output was not one schema-valid JSON object. No records are returned and none are invented. |
| 503 | model_unavailable |
Model not loaded (see the server log) |
| 504 | timeout |
Generation exceeded request_timeout_s. Generation is also bounded by max_new_tokens and a matching max_time, and the slot stays occupied until the worker thread really finishes. |
| 500 | internal_error |
Unexpected failure (details only in the server log, keyed by request ID) |
A record that fails validation (quote not found, unknown speaker, inconsistent status) is returned in
result.rejected_records with its errors, and validation.raw_output_fully_valid is false. Valid records are still
returned.
With ground_evidence: true (the default), quotes that the model tidied (fillers or repeated words dropped) or
attached to a neighbouring turn are first re-anchored to the transcript's verbatim words; see docs/SCHEMA.md §2.5.
Every record changed this way carries a pipeline flag, and validation.grounded_record_count counts them. Set
ground_evidence: false to reject such records instead.
Privacy behaviour
- Transcript bodies are never logged and never written to disk. Log lines carry the request ID, path, status, latency, turn count, prompt-token count and validation counts only. Uvicorn's access log is disabled.
- No cloud fallback exists. The only network listener is the configured local address.
- Validation, and any constrained decoding a client might add, ensures the output is well-formed. It is not proof of semantic correctness: owners, statuses and deadlines must still be reviewed by a human before anyone acts on them.
- Extracted records never send messages, create tasks in external systems, or commit participants to anything.
Privacy of a deployment also depends on the surrounding application, its logs and storage, the host OS and its telemetry, and the network configuration. Those are outside this API.
Tests
python -m unittest discover -s tests -t . runs the API tests against a mocked backend. They cover every route,
error code, oversize rejection, invalid-output rejection, record-level rejection, timeouts, the concurrency bound, a full
queue (429), hidden internal errors, the loopback-only default, no transcript text in logs, and a check that importing
the API does not import torch/transformers/peft/trl. Real-model checks are in notebook §12 (ALLOW_API_CHECKS).