API Reference¶
Reference for the unbias_plus package: pipeline, model, schema, FastAPI server, CLI, prompt, parser, and formatters. All public classes and functions are listed below.
Package¶
unbias_plus
¶
unbias-plus: Bias detection and debiasing using a single LLM.
UnBiasPlus
¶
Main pipeline for bias detection and debiasing.
Loads a fine-tuned LLM and exposes a simple interface for analyzing text for bias. Combines prompt building, inference, JSON parsing, offset computation, and formatting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name_or_path
|
str | Path
|
HuggingFace model ID or local path to the fine-tuned model. Defaults to 'vector-institute/Qwen3-4B-UnBias-Plus-SFT'. |
DEFAULT_MODEL
|
device
|
str | None
|
Device to run on ('cuda' or 'cpu'). Auto-detected if None. |
None
|
load_in_4bit
|
bool
|
Load model in 4-bit quantization. Default is False. |
False
|
max_new_tokens
|
int
|
Maximum tokens to generate. Default is 4096. |
4096
|
Examples:
>>> from unbias_plus import UnBiasPlus
>>> pipe = UnBiasPlus()
>>> result = pipe.analyze("Women are too emotional to lead.")
>>> print(result.binary_label)
biased
Source code in src/unbias_plus/pipeline.py
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | |
analyze
¶
Analyze input text for bias.
Runs the full pipeline: builds chat messages, runs inference, parses JSON output, computes character offsets for each segment, and attaches the original text to the result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
BiasResult
|
Structured bias result with start/end offsets on each segment and original_text populated. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the LLM output cannot be parsed into a valid BiasResult. |
Examples:
Source code in src/unbias_plus/pipeline.py
analyze_to_cli
¶
Analyze text and return a formatted CLI string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Human-readable colored string for terminal display. |
Source code in src/unbias_plus/pipeline.py
analyze_to_dict
¶
Analyze text and return result as a plain dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Plain dictionary representation of the result. |
Source code in src/unbias_plus/pipeline.py
analyze_to_json
¶
Analyze text and return result as a JSON string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Pretty-printed JSON string of the result. |
Source code in src/unbias_plus/pipeline.py
BiasedSegment
¶
Bases: BaseModel
A single biased segment detected in the text.
Attributes:
| Name | Type | Description |
|---|---|---|
original |
str
|
The original biased phrase from the input text. |
replacement |
str
|
The suggested neutral replacement. Defaults to empty string if the model omits it (e.g. under 4-bit quantization). |
severity |
str
|
Severity level: 'low', 'medium', or 'high'. Defaults to 'medium' if omitted by the model. |
bias_type |
str
|
Type of bias (e.g. 'loaded language', 'framing bias'). |
reasoning |
str
|
Explanation of why this segment is considered biased. |
start |
int | None
|
Character offset start in the original text. Computed by the pipeline after parsing. |
end |
int | None
|
Character offset end in the original text. Computed by the pipeline after parsing. |
Examples:
>>> seg = BiasedSegment(
... original="Sharia-obsessed fanatics",
... replacement="extremist groups",
... severity="high",
... bias_type="dehumanizing framing",
... reasoning="Uses inflammatory religious language.",
... )
>>> seg.severity
'high'
Source code in src/unbias_plus/schema.py
validate_severity
classmethod
¶
Validate and normalise segment severity to low/medium/high.
Source code in src/unbias_plus/schema.py
BiasResult
¶
Bases: BaseModel
Full bias analysis result for an input text.
Attributes:
| Name | Type | Description |
|---|---|---|
binary_label |
str
|
Overall label: 'biased' or 'unbiased'. |
severity |
int
|
Overall severity score: 0 = neutral / no bias 2 = recurring biased framing 3 = strong persuasive tone 4 = inflammatory rhetoric If the model returns a string ('low', 'medium', 'high'), it is coerced to the nearest integer value. |
bias_found |
bool
|
Whether any bias was detected in the text. |
biased_segments |
list[BiasedSegment]
|
List of biased segments found in the text, each with character-level start/end offsets. |
unbiased_text |
str
|
Full neutral rewrite of the input text. |
original_text |
str | None
|
The original input text. Set by the pipeline. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="A neutral version of the text.",
... )
>>> result.binary_label
'biased'
Source code in src/unbias_plus/schema.py
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
validate_binary_label
classmethod
¶
Validate binary_label is 'biased' or 'unbiased'.
Source code in src/unbias_plus/schema.py
validate_severity
classmethod
¶
Coerce and validate global severity.
Accepts: - int 0, 2, 3, 4 (correct model output) - str 'low', 'medium', 'high', 'none' (model confused scales) - any other int (clamped to nearest valid value)
Source code in src/unbias_plus/schema.py
serve
¶
serve(
model_name_or_path=DEFAULT_MODEL,
host="0.0.0.0",
port=8000,
load_in_4bit=False,
reload=False,
)
Start the unbias-plus API server with the demo UI.
Loads the model and starts a uvicorn server. The demo UI is served at http://localhost:{port}/ and the API is at http://localhost:{port}/analyze.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name_or_path
|
str | Path
|
HuggingFace model ID or local path to the model. |
DEFAULT_MODEL
|
host
|
str
|
Host address to bind to. Default is '0.0.0.0'. |
'0.0.0.0'
|
port
|
int
|
Port to listen on. Default is 8000. |
8000
|
load_in_4bit
|
bool
|
Load model in 4-bit quantization. Default is False. |
False
|
reload
|
bool
|
Enable auto-reload on code changes. Default is False. |
False
|
Examples:
Source code in src/unbias_plus/api.py
api
¶
FastAPI server for unbias-plus.
AnalyzeRequest
¶
Bases: BaseModel
Request body for the analyze endpoint.
Attributes:
| Name | Type | Description |
|---|---|---|
text |
str
|
The input text to analyze for bias. |
Source code in src/unbias_plus/api.py
HealthResponse
¶
Bases: BaseModel
Response body for the health endpoint.
Attributes:
| Name | Type | Description |
|---|---|---|
status |
str
|
Server status string. |
model |
str
|
Currently loaded model name or path. |
Source code in src/unbias_plus/api.py
lifespan
async
¶
Load the model on startup and release on shutdown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
app
|
FastAPI
|
The FastAPI application instance. |
required |
Yields:
| Type | Description |
|---|---|
None
|
|
Source code in src/unbias_plus/api.py
index
¶
Serve the demo UI.
Returns:
| Type | Description |
|---|---|
str
|
HTML content of the demo page. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
404 if the demo directory is not found. |
Source code in src/unbias_plus/api.py
health
¶
Check if the server and model are ready.
Returns:
| Type | Description |
|---|---|
HealthResponse
|
Server status and loaded model name. |
Source code in src/unbias_plus/api.py
analyze
¶
Analyze input text for bias.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
FastAPI request (for app state). |
required |
body
|
AnalyzeRequest
|
Request body containing the text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
BiasResult
|
Structured bias analysis result with character offsets. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
500 if the model is not loaded or inference fails. |
HTTPException
|
422 if the model output cannot be parsed. |
Source code in src/unbias_plus/api.py
serve
¶
serve(
model_name_or_path=DEFAULT_MODEL,
host="0.0.0.0",
port=8000,
load_in_4bit=False,
reload=False,
)
Start the unbias-plus API server with the demo UI.
Loads the model and starts a uvicorn server. The demo UI is served at http://localhost:{port}/ and the API is at http://localhost:{port}/analyze.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name_or_path
|
str | Path
|
HuggingFace model ID or local path to the model. |
DEFAULT_MODEL
|
host
|
str
|
Host address to bind to. Default is '0.0.0.0'. |
'0.0.0.0'
|
port
|
int
|
Port to listen on. Default is 8000. |
8000
|
load_in_4bit
|
bool
|
Load model in 4-bit quantization. Default is False. |
False
|
reload
|
bool
|
Enable auto-reload on code changes. Default is False. |
False
|
Examples:
Source code in src/unbias_plus/api.py
cli
¶
CLI entry point for unbias-plus.
parse_args
¶
Parse CLI arguments.
Returns:
| Type | Description |
|---|---|
Namespace
|
Parsed arguments. |
Source code in src/unbias_plus/cli.py
main
¶
Run the unbias-plus CLI.
Examples:
$ unbias-plus --text "Women are too emotional to lead." $ unbias-plus --file article.txt --json $ unbias-plus --serve --model path/to/model --port 8000 $ unbias-plus --serve --load-in-4bit
Source code in src/unbias_plus/cli.py
formatter
¶
Formatters for displaying BiasResult output.
format_cli
¶
Format a BiasResult for CLI terminal display.
Produces a human-readable, colored terminal output showing the bias label, severity, each biased segment with its replacement and reasoning, and the full unbiased rewrite.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
BiasResult
|
The bias analysis result to format. |
required |
Returns:
| Type | Description |
|---|---|
str
|
A human-readable colored string for terminal output. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="Neutral.",
... )
>>> output = format_cli(result)
>>> isinstance(output, str)
True
Source code in src/unbias_plus/formatter.py
format_dict
¶
Convert a BiasResult to a plain Python dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
BiasResult
|
The bias analysis result to convert. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Plain dictionary representation of the result. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="Neutral.",
... )
>>> d = format_dict(result)
>>> isinstance(d, dict)
True
Source code in src/unbias_plus/formatter.py
format_json
¶
Convert a BiasResult to a formatted JSON string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
BiasResult
|
The bias analysis result to convert. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Pretty-printed JSON string representation of the result. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="Neutral.",
... )
>>> json_str = format_json(result)
>>> isinstance(json_str, str)
True
Source code in src/unbias_plus/formatter.py
model
¶
LLM model loader and inference for unbias-plus.
UnBiasModel
¶
Loads and runs the fine-tuned bias detection LLM.
Wraps a HuggingFace causal LM with a simple generate() interface. Compatible with any HuggingFace causal LM — thinking mode is opt-in for Qwen3 models only.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name_or_path
|
str | Path
|
HuggingFace model ID or local path to the model. Defaults to 'vector-institute/Qwen3-8B-UnBias-Plus-SFT'. |
DEFAULT_MODEL
|
device
|
str | None
|
Device to run on ('cuda' or 'cpu'). Auto-detects if not provided. |
None
|
load_in_4bit
|
bool
|
Load model in 4-bit quantization via bitsandbytes. Reduces VRAM to ~3GB (4B) or ~5GB (8B). Default is False. |
False
|
max_new_tokens
|
int
|
Maximum number of new tokens to generate. Default 2048. |
2048
|
enable_thinking
|
bool
|
Enable Qwen3 chain-of-thought thinking mode. Only supported by Qwen3 models — do not set for other models. Default is False. |
False
|
thinking_budget
|
int
|
Maximum tokens allocated to the thinking block when enable_thinking=True. Default is 512. |
512
|
Examples:
>>> model = UnBiasModel()
>>> raw = model.generate([{"role": "user", "content": "..."}])
>>> isinstance(raw, str)
True
Source code in src/unbias_plus/model.py
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | |
generate
¶
Run inference on a list of chat messages and return the raw output.
Uses greedy decoding (do_sample=False) for deterministic, consistent JSON output across runs. Works with any HuggingFace causal LM.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[dict]
|
List of {"role": ..., "content": ...} dicts. Should include system prompt and user message. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Raw string output from the model with the input prompt stripped. Special tokens are removed for clean downstream parsing. |
Examples:
>>> model = UnBiasModel()
>>> msgs = [{"role": "user", "content": "..."}]
>>> output = model.generate(msgs)
>>> isinstance(output, str)
True
Source code in src/unbias_plus/model.py
parser
¶
Parser for LLM JSON output into BiasResult objects.
parse_llm_output
¶
Parse raw LLM output string into a BiasResult object.
Handles Qwen3 thinking blocks (
Strategies (in order): 1. Extract JSON by brace counting — stops at closing } so any hallucinated text after the JSON block is ignored entirely. 2. Strip thinking block from extracted text if present. 3. Direct JSON parse of extracted block. 4. Fix truncated strings (LLM cut off mid-output). 5. Fix missing commas between JSON items. 6. Aggressive key-by-key extraction as last resort.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_output
|
str
|
Raw string returned by the LLM, may include a thinking block, extra text, markdown code fences, or be truncated/malformed. |
required |
Returns:
| Type | Description |
|---|---|
BiasResult
|
Validated and structured bias analysis result. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the output cannot be parsed as valid JSON or does not match the expected BiasResult schema after all repair attempts. |
Examples:
>>> raw = '''
... {
... "binary_label": "biased",
... "severity": 3,
... "bias_found": true,
... "biased_segments": [],
... "unbiased_text": "A neutral version."
... }
... '''
>>> result = parse_llm_output(raw)
>>> result.binary_label
'biased'
Source code in src/unbias_plus/parser.py
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 | |
pipeline
¶
Main pipeline for unbias-plus.
UnBiasPlus
¶
Main pipeline for bias detection and debiasing.
Loads a fine-tuned LLM and exposes a simple interface for analyzing text for bias. Combines prompt building, inference, JSON parsing, offset computation, and formatting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name_or_path
|
str | Path
|
HuggingFace model ID or local path to the fine-tuned model. Defaults to 'vector-institute/Qwen3-4B-UnBias-Plus-SFT'. |
DEFAULT_MODEL
|
device
|
str | None
|
Device to run on ('cuda' or 'cpu'). Auto-detected if None. |
None
|
load_in_4bit
|
bool
|
Load model in 4-bit quantization. Default is False. |
False
|
max_new_tokens
|
int
|
Maximum tokens to generate. Default is 4096. |
4096
|
Examples:
>>> from unbias_plus import UnBiasPlus
>>> pipe = UnBiasPlus()
>>> result = pipe.analyze("Women are too emotional to lead.")
>>> print(result.binary_label)
biased
Source code in src/unbias_plus/pipeline.py
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | |
analyze
¶
Analyze input text for bias.
Runs the full pipeline: builds chat messages, runs inference, parses JSON output, computes character offsets for each segment, and attaches the original text to the result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
BiasResult
|
Structured bias result with start/end offsets on each segment and original_text populated. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the LLM output cannot be parsed into a valid BiasResult. |
Examples:
Source code in src/unbias_plus/pipeline.py
analyze_to_cli
¶
Analyze text and return a formatted CLI string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Human-readable colored string for terminal display. |
Source code in src/unbias_plus/pipeline.py
analyze_to_dict
¶
Analyze text and return result as a plain dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Plain dictionary representation of the result. |
Source code in src/unbias_plus/pipeline.py
analyze_to_json
¶
Analyze text and return result as a JSON string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Pretty-printed JSON string of the result. |
Source code in src/unbias_plus/pipeline.py
prompt
¶
Prompt templates for the unbias-plus LLM.
build_messages
¶
Build the chat messages list for the LLM given input text.
Formats the system prompt and user text into the messages format required by the model's chat template.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze for bias. |
required |
Returns:
| Type | Description |
|---|---|
list[dict]
|
List of {"role": ..., "content": ...} dicts ready for tokenizer.apply_chat_template(). |
Examples:
>>> messages = build_messages("Women are too emotional to lead.")
>>> messages[0]["role"]
'system'
>>> messages[1]["role"]
'user'
>>> "Women are too emotional to lead." in messages[1]["content"]
True
Source code in src/unbias_plus/prompt.py
schema
¶
Data schemas for unbias-plus output.
BiasedSegment
¶
Bases: BaseModel
A single biased segment detected in the text.
Attributes:
| Name | Type | Description |
|---|---|---|
original |
str
|
The original biased phrase from the input text. |
replacement |
str
|
The suggested neutral replacement. Defaults to empty string if the model omits it (e.g. under 4-bit quantization). |
severity |
str
|
Severity level: 'low', 'medium', or 'high'. Defaults to 'medium' if omitted by the model. |
bias_type |
str
|
Type of bias (e.g. 'loaded language', 'framing bias'). |
reasoning |
str
|
Explanation of why this segment is considered biased. |
start |
int | None
|
Character offset start in the original text. Computed by the pipeline after parsing. |
end |
int | None
|
Character offset end in the original text. Computed by the pipeline after parsing. |
Examples:
>>> seg = BiasedSegment(
... original="Sharia-obsessed fanatics",
... replacement="extremist groups",
... severity="high",
... bias_type="dehumanizing framing",
... reasoning="Uses inflammatory religious language.",
... )
>>> seg.severity
'high'
Source code in src/unbias_plus/schema.py
validate_severity
classmethod
¶
Validate and normalise segment severity to low/medium/high.
Source code in src/unbias_plus/schema.py
BiasResult
¶
Bases: BaseModel
Full bias analysis result for an input text.
Attributes:
| Name | Type | Description |
|---|---|---|
binary_label |
str
|
Overall label: 'biased' or 'unbiased'. |
severity |
int
|
Overall severity score: 0 = neutral / no bias 2 = recurring biased framing 3 = strong persuasive tone 4 = inflammatory rhetoric If the model returns a string ('low', 'medium', 'high'), it is coerced to the nearest integer value. |
bias_found |
bool
|
Whether any bias was detected in the text. |
biased_segments |
list[BiasedSegment]
|
List of biased segments found in the text, each with character-level start/end offsets. |
unbiased_text |
str
|
Full neutral rewrite of the input text. |
original_text |
str | None
|
The original input text. Set by the pipeline. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="A neutral version of the text.",
... )
>>> result.binary_label
'biased'
Source code in src/unbias_plus/schema.py
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
validate_binary_label
classmethod
¶
Validate binary_label is 'biased' or 'unbiased'.
Source code in src/unbias_plus/schema.py
validate_severity
classmethod
¶
Coerce and validate global severity.
Accepts: - int 0, 2, 3, 4 (correct model output) - str 'low', 'medium', 'high', 'none' (model confused scales) - any other int (clamped to nearest valid value)
Source code in src/unbias_plus/schema.py
compute_offsets
¶
Compute character start/end offsets for each biased segment.
Walks the original text with a cursor so that duplicate phrases are matched in order of appearance, not just the first occurrence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
original_text
|
str
|
The original input text. |
required |
segments
|
list[BiasedSegment]
|
Parsed segments from the LLM (without offsets). |
required |
Returns:
| Type | Description |
|---|---|
list[BiasedSegment]
|
Segments with start/end fields populated, sorted by start offset. |
Source code in src/unbias_plus/schema.py
Pipeline¶
unbias_plus.pipeline
¶
Main pipeline for unbias-plus.
UnBiasPlus
¶
Main pipeline for bias detection and debiasing.
Loads a fine-tuned LLM and exposes a simple interface for analyzing text for bias. Combines prompt building, inference, JSON parsing, offset computation, and formatting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name_or_path
|
str | Path
|
HuggingFace model ID or local path to the fine-tuned model. Defaults to 'vector-institute/Qwen3-4B-UnBias-Plus-SFT'. |
DEFAULT_MODEL
|
device
|
str | None
|
Device to run on ('cuda' or 'cpu'). Auto-detected if None. |
None
|
load_in_4bit
|
bool
|
Load model in 4-bit quantization. Default is False. |
False
|
max_new_tokens
|
int
|
Maximum tokens to generate. Default is 4096. |
4096
|
Examples:
>>> from unbias_plus import UnBiasPlus
>>> pipe = UnBiasPlus()
>>> result = pipe.analyze("Women are too emotional to lead.")
>>> print(result.binary_label)
biased
Source code in src/unbias_plus/pipeline.py
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | |
analyze
¶
Analyze input text for bias.
Runs the full pipeline: builds chat messages, runs inference, parses JSON output, computes character offsets for each segment, and attaches the original text to the result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
BiasResult
|
Structured bias result with start/end offsets on each segment and original_text populated. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the LLM output cannot be parsed into a valid BiasResult. |
Examples:
Source code in src/unbias_plus/pipeline.py
analyze_to_cli
¶
Analyze text and return a formatted CLI string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Human-readable colored string for terminal display. |
Source code in src/unbias_plus/pipeline.py
analyze_to_dict
¶
Analyze text and return result as a plain dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Plain dictionary representation of the result. |
Source code in src/unbias_plus/pipeline.py
analyze_to_json
¶
Analyze text and return result as a JSON string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Pretty-printed JSON string of the result. |
Source code in src/unbias_plus/pipeline.py
Model¶
unbias_plus.model
¶
LLM model loader and inference for unbias-plus.
UnBiasModel
¶
Loads and runs the fine-tuned bias detection LLM.
Wraps a HuggingFace causal LM with a simple generate() interface. Compatible with any HuggingFace causal LM — thinking mode is opt-in for Qwen3 models only.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name_or_path
|
str | Path
|
HuggingFace model ID or local path to the model. Defaults to 'vector-institute/Qwen3-8B-UnBias-Plus-SFT'. |
DEFAULT_MODEL
|
device
|
str | None
|
Device to run on ('cuda' or 'cpu'). Auto-detects if not provided. |
None
|
load_in_4bit
|
bool
|
Load model in 4-bit quantization via bitsandbytes. Reduces VRAM to ~3GB (4B) or ~5GB (8B). Default is False. |
False
|
max_new_tokens
|
int
|
Maximum number of new tokens to generate. Default 2048. |
2048
|
enable_thinking
|
bool
|
Enable Qwen3 chain-of-thought thinking mode. Only supported by Qwen3 models — do not set for other models. Default is False. |
False
|
thinking_budget
|
int
|
Maximum tokens allocated to the thinking block when enable_thinking=True. Default is 512. |
512
|
Examples:
>>> model = UnBiasModel()
>>> raw = model.generate([{"role": "user", "content": "..."}])
>>> isinstance(raw, str)
True
Source code in src/unbias_plus/model.py
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | |
generate
¶
Run inference on a list of chat messages and return the raw output.
Uses greedy decoding (do_sample=False) for deterministic, consistent JSON output across runs. Works with any HuggingFace causal LM.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[dict]
|
List of {"role": ..., "content": ...} dicts. Should include system prompt and user message. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Raw string output from the model with the input prompt stripped. Special tokens are removed for clean downstream parsing. |
Examples:
>>> model = UnBiasModel()
>>> msgs = [{"role": "user", "content": "..."}]
>>> output = model.generate(msgs)
>>> isinstance(output, str)
True
Source code in src/unbias_plus/model.py
Schema¶
unbias_plus.schema
¶
Data schemas for unbias-plus output.
BiasedSegment
¶
Bases: BaseModel
A single biased segment detected in the text.
Attributes:
| Name | Type | Description |
|---|---|---|
original |
str
|
The original biased phrase from the input text. |
replacement |
str
|
The suggested neutral replacement. Defaults to empty string if the model omits it (e.g. under 4-bit quantization). |
severity |
str
|
Severity level: 'low', 'medium', or 'high'. Defaults to 'medium' if omitted by the model. |
bias_type |
str
|
Type of bias (e.g. 'loaded language', 'framing bias'). |
reasoning |
str
|
Explanation of why this segment is considered biased. |
start |
int | None
|
Character offset start in the original text. Computed by the pipeline after parsing. |
end |
int | None
|
Character offset end in the original text. Computed by the pipeline after parsing. |
Examples:
>>> seg = BiasedSegment(
... original="Sharia-obsessed fanatics",
... replacement="extremist groups",
... severity="high",
... bias_type="dehumanizing framing",
... reasoning="Uses inflammatory religious language.",
... )
>>> seg.severity
'high'
Source code in src/unbias_plus/schema.py
validate_severity
classmethod
¶
Validate and normalise segment severity to low/medium/high.
Source code in src/unbias_plus/schema.py
BiasResult
¶
Bases: BaseModel
Full bias analysis result for an input text.
Attributes:
| Name | Type | Description |
|---|---|---|
binary_label |
str
|
Overall label: 'biased' or 'unbiased'. |
severity |
int
|
Overall severity score: 0 = neutral / no bias 2 = recurring biased framing 3 = strong persuasive tone 4 = inflammatory rhetoric If the model returns a string ('low', 'medium', 'high'), it is coerced to the nearest integer value. |
bias_found |
bool
|
Whether any bias was detected in the text. |
biased_segments |
list[BiasedSegment]
|
List of biased segments found in the text, each with character-level start/end offsets. |
unbiased_text |
str
|
Full neutral rewrite of the input text. |
original_text |
str | None
|
The original input text. Set by the pipeline. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="A neutral version of the text.",
... )
>>> result.binary_label
'biased'
Source code in src/unbias_plus/schema.py
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
validate_binary_label
classmethod
¶
Validate binary_label is 'biased' or 'unbiased'.
Source code in src/unbias_plus/schema.py
validate_severity
classmethod
¶
Coerce and validate global severity.
Accepts: - int 0, 2, 3, 4 (correct model output) - str 'low', 'medium', 'high', 'none' (model confused scales) - any other int (clamped to nearest valid value)
Source code in src/unbias_plus/schema.py
compute_offsets
¶
Compute character start/end offsets for each biased segment.
Walks the original text with a cursor so that duplicate phrases are matched in order of appearance, not just the first occurrence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
original_text
|
str
|
The original input text. |
required |
segments
|
list[BiasedSegment]
|
Parsed segments from the LLM (without offsets). |
required |
Returns:
| Type | Description |
|---|---|
list[BiasedSegment]
|
Segments with start/end fields populated, sorted by start offset. |
Source code in src/unbias_plus/schema.py
API (FastAPI server)¶
unbias_plus.api
¶
FastAPI server for unbias-plus.
AnalyzeRequest
¶
Bases: BaseModel
Request body for the analyze endpoint.
Attributes:
| Name | Type | Description |
|---|---|---|
text |
str
|
The input text to analyze for bias. |
Source code in src/unbias_plus/api.py
HealthResponse
¶
Bases: BaseModel
Response body for the health endpoint.
Attributes:
| Name | Type | Description |
|---|---|---|
status |
str
|
Server status string. |
model |
str
|
Currently loaded model name or path. |
Source code in src/unbias_plus/api.py
lifespan
async
¶
Load the model on startup and release on shutdown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
app
|
FastAPI
|
The FastAPI application instance. |
required |
Yields:
| Type | Description |
|---|---|
None
|
|
Source code in src/unbias_plus/api.py
index
¶
Serve the demo UI.
Returns:
| Type | Description |
|---|---|
str
|
HTML content of the demo page. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
404 if the demo directory is not found. |
Source code in src/unbias_plus/api.py
health
¶
Check if the server and model are ready.
Returns:
| Type | Description |
|---|---|
HealthResponse
|
Server status and loaded model name. |
Source code in src/unbias_plus/api.py
analyze
¶
Analyze input text for bias.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
FastAPI request (for app state). |
required |
body
|
AnalyzeRequest
|
Request body containing the text to analyze. |
required |
Returns:
| Type | Description |
|---|---|
BiasResult
|
Structured bias analysis result with character offsets. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
500 if the model is not loaded or inference fails. |
HTTPException
|
422 if the model output cannot be parsed. |
Source code in src/unbias_plus/api.py
serve
¶
serve(
model_name_or_path=DEFAULT_MODEL,
host="0.0.0.0",
port=8000,
load_in_4bit=False,
reload=False,
)
Start the unbias-plus API server with the demo UI.
Loads the model and starts a uvicorn server. The demo UI is served at http://localhost:{port}/ and the API is at http://localhost:{port}/analyze.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name_or_path
|
str | Path
|
HuggingFace model ID or local path to the model. |
DEFAULT_MODEL
|
host
|
str
|
Host address to bind to. Default is '0.0.0.0'. |
'0.0.0.0'
|
port
|
int
|
Port to listen on. Default is 8000. |
8000
|
load_in_4bit
|
bool
|
Load model in 4-bit quantization. Default is False. |
False
|
reload
|
bool
|
Enable auto-reload on code changes. Default is False. |
False
|
Examples:
Source code in src/unbias_plus/api.py
CLI¶
unbias_plus.cli
¶
CLI entry point for unbias-plus.
parse_args
¶
Parse CLI arguments.
Returns:
| Type | Description |
|---|---|
Namespace
|
Parsed arguments. |
Source code in src/unbias_plus/cli.py
main
¶
Run the unbias-plus CLI.
Examples:
$ unbias-plus --text "Women are too emotional to lead." $ unbias-plus --file article.txt --json $ unbias-plus --serve --model path/to/model --port 8000 $ unbias-plus --serve --load-in-4bit
Source code in src/unbias_plus/cli.py
Prompt¶
unbias_plus.prompt
¶
Prompt templates for the unbias-plus LLM.
build_messages
¶
Build the chat messages list for the LLM given input text.
Formats the system prompt and user text into the messages format required by the model's chat template.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The input text to analyze for bias. |
required |
Returns:
| Type | Description |
|---|---|
list[dict]
|
List of {"role": ..., "content": ...} dicts ready for tokenizer.apply_chat_template(). |
Examples:
>>> messages = build_messages("Women are too emotional to lead.")
>>> messages[0]["role"]
'system'
>>> messages[1]["role"]
'user'
>>> "Women are too emotional to lead." in messages[1]["content"]
True
Source code in src/unbias_plus/prompt.py
Parser¶
unbias_plus.parser
¶
Parser for LLM JSON output into BiasResult objects.
parse_llm_output
¶
Parse raw LLM output string into a BiasResult object.
Handles Qwen3 thinking blocks (
Strategies (in order): 1. Extract JSON by brace counting — stops at closing } so any hallucinated text after the JSON block is ignored entirely. 2. Strip thinking block from extracted text if present. 3. Direct JSON parse of extracted block. 4. Fix truncated strings (LLM cut off mid-output). 5. Fix missing commas between JSON items. 6. Aggressive key-by-key extraction as last resort.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_output
|
str
|
Raw string returned by the LLM, may include a thinking block, extra text, markdown code fences, or be truncated/malformed. |
required |
Returns:
| Type | Description |
|---|---|
BiasResult
|
Validated and structured bias analysis result. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the output cannot be parsed as valid JSON or does not match the expected BiasResult schema after all repair attempts. |
Examples:
>>> raw = '''
... {
... "binary_label": "biased",
... "severity": 3,
... "bias_found": true,
... "biased_segments": [],
... "unbiased_text": "A neutral version."
... }
... '''
>>> result = parse_llm_output(raw)
>>> result.binary_label
'biased'
Source code in src/unbias_plus/parser.py
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 | |
Formatter¶
unbias_plus.formatter
¶
Formatters for displaying BiasResult output.
format_cli
¶
Format a BiasResult for CLI terminal display.
Produces a human-readable, colored terminal output showing the bias label, severity, each biased segment with its replacement and reasoning, and the full unbiased rewrite.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
BiasResult
|
The bias analysis result to format. |
required |
Returns:
| Type | Description |
|---|---|
str
|
A human-readable colored string for terminal output. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="Neutral.",
... )
>>> output = format_cli(result)
>>> isinstance(output, str)
True
Source code in src/unbias_plus/formatter.py
format_dict
¶
Convert a BiasResult to a plain Python dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
BiasResult
|
The bias analysis result to convert. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Plain dictionary representation of the result. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="Neutral.",
... )
>>> d = format_dict(result)
>>> isinstance(d, dict)
True
Source code in src/unbias_plus/formatter.py
format_json
¶
Convert a BiasResult to a formatted JSON string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
BiasResult
|
The bias analysis result to convert. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Pretty-printed JSON string representation of the result. |
Examples:
>>> result = BiasResult(
... binary_label="biased",
... severity=3,
... bias_found=True,
... biased_segments=[],
... unbiased_text="Neutral.",
... )
>>> json_str = format_json(result)
>>> isinstance(json_str, str)
True