Image-Text-to-Text
Transformers
Safetensors
qwen3_5
qwen3.5
video
video-captioning
data-engine
conversational
Instructions to use nvidia/Flora-Captioner with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use nvidia/Flora-Captioner with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="nvidia/Flora-Captioner") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("nvidia/Flora-Captioner") model = AutoModelForMultimodalLM.from_pretrained("nvidia/Flora-Captioner", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use nvidia/Flora-Captioner with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "nvidia/Flora-Captioner" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "nvidia/Flora-Captioner", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/nvidia/Flora-Captioner
- SGLang
How to use nvidia/Flora-Captioner with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "nvidia/Flora-Captioner" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "nvidia/Flora-Captioner", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "nvidia/Flora-Captioner" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "nvidia/Flora-Captioner", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use nvidia/Flora-Captioner with Docker Model Runner:
docker model run hf.co/nvidia/Flora-Captioner
Download batch_utils/cli.py from nvidia/Flora-Captioner: direct link, hf CLI and curl.
- Browser
- Download file 4.76 kB
-
https://huggingface.co/nvidia/Flora-Captioner/resolve/refs%2Fpr%2F1/batch_utils/cli.py
- Command line
-
hf download hf://nvidia/Flora-Captioner@refs/pr/1/batch_utils/cli.py
-
curl -L -o cli.py https://huggingface.co/nvidia/Flora-Captioner/resolve/refs%2Fpr%2F1/batch_utils/cli.py
4.76 kB
| from pathlib import Path | |
| import argparse | |
| import json | |
| import re | |
| import sys | |
| from .api import DataEnginePipeline | |
| def parser(): | |
| p = argparse.ArgumentParser(description='FLORA: TempSeg -> Captioner with native video preprocessing.') | |
| source = p.add_mutually_exclusive_group(required=True) | |
| source.add_argument('--video', type=Path, help='Main/egocentric local video.') | |
| source.add_argument('--input-jsonl', type=Path, help='One video job per line; paths relative to this JSONL.') | |
| p.add_argument('--profile', choices=['human', 'yam', 'dex', 'tianji'], default='human') | |
| p.add_argument('--left-wrist', type=Path) | |
| p.add_argument('--right-wrist', type=Path) | |
| p.add_argument('--yam32', action='store_true', help='Use the native 32-second three-view YAM temporal profile.') | |
| p.add_argument('--instruction', default='', help='Optional episode instruction; blank by default.') | |
| p.add_argument('--output', type=Path, help='Single-video result; default annotations.json.') | |
| p.add_argument('--output-dir', type=Path, help='Required with --input-jsonl for inference.') | |
| p.add_argument('--validate-only', action='store_true', help='Check media/timestamps on CPU; no weight downloads or generation.') | |
| p.add_argument('--include-audit', action='store_true', help='Include temporal/model-input audit records in the result.') | |
| p.add_argument('--overwrite', action='store_true', help='Explicitly allow replacing existing output files.') | |
| return p | |
| def jobs(args, p): | |
| if args.video: | |
| if args.output_dir: | |
| p.error('--output-dir is for JSONL jobs; use --output for a single video') | |
| return [(dict(video=args.video, profile=args.profile, left_wrist=args.left_wrist, right_wrist=args.right_wrist, yam32=args.yam32, instruction=args.instruction), args.output or Path('annotations.json'))] | |
| if args.output or args.left_wrist or args.right_wrist or args.yam32 or args.instruction or (args.profile != 'human'): | |
| p.error('Put per-video profile/cameras/instruction in JSONL rows.') | |
| if not args.output_dir and (not args.validate_only): | |
| p.error('--output-dir is required with --input-jsonl') | |
| source = args.input_jsonl.expanduser().resolve(strict=True) | |
| items, ids = ([], set()) | |
| allowed = {'id', 'video', 'profile', 'left_wrist', 'right_wrist', 'yam32', 'instruction'} | |
| for line_number, line in enumerate(source.read_text().splitlines(), 1): | |
| if not line.strip(): | |
| continue | |
| row = json.loads(line) | |
| if not isinstance(row, dict) or set(row) - allowed or 'video' not in row: | |
| raise ValueError(f'Invalid JSONL job on line {line_number}.') | |
| name = row.pop('id', f'video_{line_number:06d}') | |
| if not isinstance(name, str) or not re.fullmatch('[A-Za-z0-9][A-Za-z0-9_.-]{0,95}', name) or name in ids: | |
| raise ValueError(f'Invalid or duplicate job id on line {line_number}.') | |
| ids.add(name) | |
| for key in ['video', 'left_wrist', 'right_wrist']: | |
| if row.get(key) is not None: | |
| if not isinstance(row[key], str) or not row[key].strip(): | |
| raise ValueError(f'Invalid camera path on JSONL line {line_number}.') | |
| value = Path(row[key]).expanduser() | |
| row[key] = value if value.is_absolute() else source.parent / value | |
| items.append((row, (args.output_dir or Path('.')) / (name + '.json'))) | |
| if not items: | |
| raise ValueError('The JSONL contains no video jobs.') | |
| return items | |
| def main(argv=None): | |
| p = parser() | |
| args = p.parse_args(argv) | |
| try: | |
| items = jobs(args, p) | |
| if not args.validate_only and (not args.overwrite): | |
| for _, output in items: | |
| if output.exists(): | |
| raise FileExistsError(f'Output already exists: {output}. Use --overwrite to replace it.') | |
| engine = DataEnginePipeline() | |
| for kwargs, output in items: | |
| if args.validate_only: | |
| print(json.dumps(engine.inspect_inputs(**kwargs), allow_nan=False)) | |
| continue | |
| result = engine.annotate(**kwargs, include_audit=args.include_audit, progress=lambda fraction, desc='': print(f'{fraction:.0%} {desc}', file=sys.stderr, flush=True)) | |
| payload = json.dumps(result, ensure_ascii=False, indent=2, allow_nan=False) + '\n' | |
| output.parent.mkdir(parents=True, exist_ok=True) | |
| with output.open('w' if args.overwrite else 'x') as f: | |
| f.write(payload) | |
| print(json.dumps({'output': str(output), 'segments': len(result['segments'])})) | |
| return 0 | |
| except (OSError, ValueError, RuntimeError) as error: | |
| print(f'FLORA inference failed: {error}', file=sys.stderr) | |
| return 1 | |