vlm-guard 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mohamed Fakhry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,257 @@
1
+ Metadata-Version: 2.4
2
+ Name: vlm-guard
3
+ Version: 0.1.0
4
+ Summary: Medical Verification Layer for Multimodal LLMs — composable, auditable guardrails for structured LLM outputs
5
+ Author-email: Mohamed Fakhry <mohamed.fakhry@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/MohamedFakhry2007/vlm-guard
8
+ Project-URL: Source, https://github.com/MohamedFakhry2007/vlm-guard
9
+ Project-URL: Tracker, https://github.com/MohamedFakhry2007/vlm-guard/issues
10
+ Keywords: llm,multimodal,guardrails,medical-ai,verification,safety,hallucination-prevention
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Requires-Dist: Pillow>=10.0.0
26
+ Provides-Extra: image
27
+ Requires-Dist: torch>=2.0.0; extra == "image"
28
+ Requires-Dist: transformers>=4.40.0; extra == "image"
29
+ Requires-Dist: bitsandbytes>=0.41.0; extra == "image"
30
+ Provides-Extra: all
31
+ Requires-Dist: vlm-guard[image]; extra == "all"
32
+ Requires-Dist: fpdf>=1.7.2; extra == "all"
33
+ Requires-Dist: accelerate>=0.25.0; extra == "all"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # VLM-Guard
39
+
40
+ **Medical Verification Layer for Multimodal LLMs.**
41
+
42
+ VLM-Guard is a framework for building rule-based verification layers that catch physically impossible, biologically inconsistent, or logically contradictory outputs from multimodal LLMs — *before* they reach the end user.
43
+
44
+ ```python
45
+ from vlm_guard import GuardrailEngine, BaseRule, RuleResult
46
+
47
+ # 1. Define a rule
48
+ class NoMalariaInTissueRule(BaseRule):
49
+ name = "sample_type_check"
50
+ description = "Malaria requires blood smear, not tissue biopsy"
51
+
52
+ def condition(self, analysis, context):
53
+ return (
54
+ analysis.label == "Malaria"
55
+ and "tissue" in context.get("sample_type", "").lower()
56
+ )
57
+
58
+ def action(self, analysis, context):
59
+ analysis.label = "Unclear"
60
+ analysis.confidence = "Low"
61
+ return analysis, RuleResult(
62
+ action_taken=True, action_type="block",
63
+ message="Malaria cannot be diagnosed on tissue biopsy"
64
+ )
65
+
66
+ # 2. Register and run
67
+ engine = GuardrailEngine()
68
+ engine.register(NoMalariaInTissueRule())
69
+
70
+ final = engine.apply(analysis, context={"sample_type": "Tissue Biopsy"})
71
+ ```
72
+
73
+ ## Why
74
+
75
+ Multimodal LLMs hallucinate confidently. In medical AI, a "hallucination" isn't a funny caption — it's a biologically impossible diagnosis that could lead to real-world harm.
76
+
77
+ VLM-Guard gives you a **composable, auditable rule engine** to:
78
+
79
+ - ✅ **Block** impossible outputs (malaria in a tissue biopsy)
80
+ - ✅ **Correct** misclassifications (flagellate in blood → trypanosomiasis)
81
+ - ✅ **Promote** clear patterns when the LLM is uncertain
82
+ - ✅ **Flag** ambiguous findings for human review
83
+ - ✅ **Audit** every modification with before/after snapshots
84
+
85
+ ## Installation
86
+
87
+ ```bash
88
+ pip install vlm-guard
89
+ ```
90
+
91
+ For image processing extras:
92
+ ```bash
93
+ pip install vlm-guard[image]
94
+ ```
95
+
96
+ ## Quick Start
97
+
98
+ ### 1. Define your analysis schema
99
+
100
+ ```python
101
+ from vlm_guard import Analysis
102
+
103
+ result = Analysis(
104
+ label="Malaria",
105
+ confidence="High",
106
+ evidence="Ring forms observed inside RBCs",
107
+ findings="Multiple ring-stage parasites in thin blood smear",
108
+ recommendation="Confirm species with PCR",
109
+ metadata={"severity": "Moderate (++)", "species": "P. falciparum"}
110
+ )
111
+ ```
112
+
113
+ ### 2. Build rules
114
+
115
+ Rules have two methods:
116
+ - **`condition(analysis, context)`** — should this rule fire?
117
+ - **`action(analysis, context)`** — what to do when it fires
118
+
119
+ ```python
120
+ from vlm_guard import BaseRule, RuleResult
121
+
122
+ class SizeCheckRule(BaseRule):
123
+ name = "size_check"
124
+ description = "Rejects morphometrically impossible descriptions"
125
+
126
+ def condition(self, analysis, context):
127
+ text = (analysis.findings + " " + analysis.evidence).lower()
128
+ return "7 μm" in text and "macrophage" in text
129
+
130
+ def action(self, analysis, context):
131
+ analysis.label = "Unclear"
132
+ analysis.confidence = "Low"
133
+ return analysis, RuleResult(
134
+ action_taken=True, action_type="block",
135
+ message="RBC-sized structures in macrophage cannot be amastigotes (2-4 μm)"
136
+ )
137
+ ```
138
+
139
+ ### 3. Run the guardrail engine
140
+
141
+ ```python
142
+ from vlm_guard import GuardrailEngine
143
+
144
+ engine = GuardrailEngine()
145
+ engine.register(SizeCheckRule())
146
+
147
+ final, audit = engine.apply_with_audit(result, context={"sample_type": "Bone Marrow"})
148
+ print(audit.summary())
149
+ # [{"rule": "size_check", "action": "block", "message": "...", "modified": ...}]
150
+ ```
151
+
152
+ ### 4. End-to-end pipeline
153
+
154
+ ```python
155
+ from vlm_guard import VLMGuardPipeline
156
+ from vlm_guard.llm.parsing import parse_to_analysis
157
+ from vlm_guard.image.enhance import ImageEnhancer, EnhancementStrategy
158
+
159
+ pipeline = VLMGuardPipeline(
160
+ model_fn=my_llm_inference_fn, # any Callable[[Image, str], str]
161
+ parser_fn=parse_to_analysis, # built-in JSON parser
162
+ guardrail_engine=engine,
163
+ enhancer_fn=ImageEnhancer(EnhancementStrategy.HIGH_CONTRAST),
164
+ )
165
+
166
+ result = pipeline.run(image, prompt, context={"sample_type": "Blood Smear"})
167
+ print(result.analysis.label) # final label after guardrails
168
+ print(result.audit.summary()) # everything that changed
169
+ ```
170
+
171
+ ## Architecture
172
+
173
+ ```
174
+ +-----------+
175
+ | Image |
176
+ +-----+-----+
177
+ |
178
+ v
179
+ +----------+----------+
180
+ | Enhancement (opt) |
181
+ +----------+----------+
182
+ |
183
+ v
184
+ +----------+----------+
185
+ | Multimodal LLM |
186
+ +----------+----------+
187
+ |
188
+ v
189
+ +----------+----------+
190
+ | JSON Parser |
191
+ +----------+----------+
192
+ |
193
+ v
194
+ +----------+----------+
195
+ | Guardrail Engine |
196
+ | +-- Rule 1 (block) |
197
+ | +-- Rule 2 (flag) |
198
+ | +-- Rule 3 (correct)|
199
+ | +-- Audit Trail |
200
+ +----------+----------+
201
+ |
202
+ v
203
+ +----------+----------+
204
+ | Final Analysis |
205
+ +---------------------+
206
+ ```
207
+
208
+ ## Plugin System
209
+
210
+ Domain-specific rule packs can be distributed as plugins:
211
+
212
+ ```python
213
+ from vlm_guard import GuardrailEngine
214
+ from my_plugin import register_my_rules
215
+
216
+ engine = GuardrailEngine()
217
+ register_my_rules(engine)
218
+ ```
219
+
220
+ Check the `plugins/` directory for built-in examples:
221
+
222
+ - **`ntd_microscopy`** — 12 rule classes for Neglected Tropical Disease microscopy (migrated from [NTD-Assist](https://github.com/MohamedFakhry2007/ntd-assist))
223
+
224
+ ## Rules
225
+
226
+ VLM-Guard supports four rule types:
227
+
228
+ | Type | Use Case | Example |
229
+ |------|----------|---------|
230
+ | **Block** | Prevent impossible outputs | Malaria on tissue biopsy → Unclear |
231
+ | **Correct** | Fix misidentifications | Flagellate in macrophage → Leishmaniasis |
232
+ | **Promote** | Upgrade confidence when strong signal | Amastigote + tissue → Leishmaniasis |
233
+ | **Flag** | Lower confidence / append to recommendation | "Ambiguous morphology, manual review suggested" |
234
+
235
+ ## Extending
236
+
237
+ VLM-Guard is model-agnostic. The pipeline accepts any `Callable[[Image, str], str]`:
238
+
239
+ - HuggingFace `transformers` models
240
+ - OpenAI / Anthropic API clients
241
+ - Local GGUF inference
242
+ - Mock models for testing
243
+
244
+ ## License
245
+
246
+ MIT
247
+
248
+ ## Citation
249
+
250
+ ```bibtex
251
+ @software{vlmguard2026,
252
+ title = {VLM-Guard: Verification Layer for Multimodal LLMs},
253
+ author = {Fakhry, Mohamed},
254
+ year = {2026},
255
+ url = {https://github.com/MohamedFakhry2007/vlm-guard}
256
+ }
257
+ ```
@@ -0,0 +1,220 @@
1
+ # VLM-Guard
2
+
3
+ **Medical Verification Layer for Multimodal LLMs.**
4
+
5
+ VLM-Guard is a framework for building rule-based verification layers that catch physically impossible, biologically inconsistent, or logically contradictory outputs from multimodal LLMs — *before* they reach the end user.
6
+
7
+ ```python
8
+ from vlm_guard import GuardrailEngine, BaseRule, RuleResult
9
+
10
+ # 1. Define a rule
11
+ class NoMalariaInTissueRule(BaseRule):
12
+ name = "sample_type_check"
13
+ description = "Malaria requires blood smear, not tissue biopsy"
14
+
15
+ def condition(self, analysis, context):
16
+ return (
17
+ analysis.label == "Malaria"
18
+ and "tissue" in context.get("sample_type", "").lower()
19
+ )
20
+
21
+ def action(self, analysis, context):
22
+ analysis.label = "Unclear"
23
+ analysis.confidence = "Low"
24
+ return analysis, RuleResult(
25
+ action_taken=True, action_type="block",
26
+ message="Malaria cannot be diagnosed on tissue biopsy"
27
+ )
28
+
29
+ # 2. Register and run
30
+ engine = GuardrailEngine()
31
+ engine.register(NoMalariaInTissueRule())
32
+
33
+ final = engine.apply(analysis, context={"sample_type": "Tissue Biopsy"})
34
+ ```
35
+
36
+ ## Why
37
+
38
+ Multimodal LLMs hallucinate confidently. In medical AI, a "hallucination" isn't a funny caption — it's a biologically impossible diagnosis that could lead to real-world harm.
39
+
40
+ VLM-Guard gives you a **composable, auditable rule engine** to:
41
+
42
+ - ✅ **Block** impossible outputs (malaria in a tissue biopsy)
43
+ - ✅ **Correct** misclassifications (flagellate in blood → trypanosomiasis)
44
+ - ✅ **Promote** clear patterns when the LLM is uncertain
45
+ - ✅ **Flag** ambiguous findings for human review
46
+ - ✅ **Audit** every modification with before/after snapshots
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ pip install vlm-guard
52
+ ```
53
+
54
+ For image processing extras:
55
+ ```bash
56
+ pip install vlm-guard[image]
57
+ ```
58
+
59
+ ## Quick Start
60
+
61
+ ### 1. Define your analysis schema
62
+
63
+ ```python
64
+ from vlm_guard import Analysis
65
+
66
+ result = Analysis(
67
+ label="Malaria",
68
+ confidence="High",
69
+ evidence="Ring forms observed inside RBCs",
70
+ findings="Multiple ring-stage parasites in thin blood smear",
71
+ recommendation="Confirm species with PCR",
72
+ metadata={"severity": "Moderate (++)", "species": "P. falciparum"}
73
+ )
74
+ ```
75
+
76
+ ### 2. Build rules
77
+
78
+ Rules have two methods:
79
+ - **`condition(analysis, context)`** — should this rule fire?
80
+ - **`action(analysis, context)`** — what to do when it fires
81
+
82
+ ```python
83
+ from vlm_guard import BaseRule, RuleResult
84
+
85
+ class SizeCheckRule(BaseRule):
86
+ name = "size_check"
87
+ description = "Rejects morphometrically impossible descriptions"
88
+
89
+ def condition(self, analysis, context):
90
+ text = (analysis.findings + " " + analysis.evidence).lower()
91
+ return "7 μm" in text and "macrophage" in text
92
+
93
+ def action(self, analysis, context):
94
+ analysis.label = "Unclear"
95
+ analysis.confidence = "Low"
96
+ return analysis, RuleResult(
97
+ action_taken=True, action_type="block",
98
+ message="RBC-sized structures in macrophage cannot be amastigotes (2-4 μm)"
99
+ )
100
+ ```
101
+
102
+ ### 3. Run the guardrail engine
103
+
104
+ ```python
105
+ from vlm_guard import GuardrailEngine
106
+
107
+ engine = GuardrailEngine()
108
+ engine.register(SizeCheckRule())
109
+
110
+ final, audit = engine.apply_with_audit(result, context={"sample_type": "Bone Marrow"})
111
+ print(audit.summary())
112
+ # [{"rule": "size_check", "action": "block", "message": "...", "modified": ...}]
113
+ ```
114
+
115
+ ### 4. End-to-end pipeline
116
+
117
+ ```python
118
+ from vlm_guard import VLMGuardPipeline
119
+ from vlm_guard.llm.parsing import parse_to_analysis
120
+ from vlm_guard.image.enhance import ImageEnhancer, EnhancementStrategy
121
+
122
+ pipeline = VLMGuardPipeline(
123
+ model_fn=my_llm_inference_fn, # any Callable[[Image, str], str]
124
+ parser_fn=parse_to_analysis, # built-in JSON parser
125
+ guardrail_engine=engine,
126
+ enhancer_fn=ImageEnhancer(EnhancementStrategy.HIGH_CONTRAST),
127
+ )
128
+
129
+ result = pipeline.run(image, prompt, context={"sample_type": "Blood Smear"})
130
+ print(result.analysis.label) # final label after guardrails
131
+ print(result.audit.summary()) # everything that changed
132
+ ```
133
+
134
+ ## Architecture
135
+
136
+ ```
137
+ +-----------+
138
+ | Image |
139
+ +-----+-----+
140
+ |
141
+ v
142
+ +----------+----------+
143
+ | Enhancement (opt) |
144
+ +----------+----------+
145
+ |
146
+ v
147
+ +----------+----------+
148
+ | Multimodal LLM |
149
+ +----------+----------+
150
+ |
151
+ v
152
+ +----------+----------+
153
+ | JSON Parser |
154
+ +----------+----------+
155
+ |
156
+ v
157
+ +----------+----------+
158
+ | Guardrail Engine |
159
+ | +-- Rule 1 (block) |
160
+ | +-- Rule 2 (flag) |
161
+ | +-- Rule 3 (correct)|
162
+ | +-- Audit Trail |
163
+ +----------+----------+
164
+ |
165
+ v
166
+ +----------+----------+
167
+ | Final Analysis |
168
+ +---------------------+
169
+ ```
170
+
171
+ ## Plugin System
172
+
173
+ Domain-specific rule packs can be distributed as plugins:
174
+
175
+ ```python
176
+ from vlm_guard import GuardrailEngine
177
+ from my_plugin import register_my_rules
178
+
179
+ engine = GuardrailEngine()
180
+ register_my_rules(engine)
181
+ ```
182
+
183
+ Check the `plugins/` directory for built-in examples:
184
+
185
+ - **`ntd_microscopy`** — 12 rule classes for Neglected Tropical Disease microscopy (migrated from [NTD-Assist](https://github.com/MohamedFakhry2007/ntd-assist))
186
+
187
+ ## Rules
188
+
189
+ VLM-Guard supports four rule types:
190
+
191
+ | Type | Use Case | Example |
192
+ |------|----------|---------|
193
+ | **Block** | Prevent impossible outputs | Malaria on tissue biopsy → Unclear |
194
+ | **Correct** | Fix misidentifications | Flagellate in macrophage → Leishmaniasis |
195
+ | **Promote** | Upgrade confidence when strong signal | Amastigote + tissue → Leishmaniasis |
196
+ | **Flag** | Lower confidence / append to recommendation | "Ambiguous morphology, manual review suggested" |
197
+
198
+ ## Extending
199
+
200
+ VLM-Guard is model-agnostic. The pipeline accepts any `Callable[[Image, str], str]`:
201
+
202
+ - HuggingFace `transformers` models
203
+ - OpenAI / Anthropic API clients
204
+ - Local GGUF inference
205
+ - Mock models for testing
206
+
207
+ ## License
208
+
209
+ MIT
210
+
211
+ ## Citation
212
+
213
+ ```bibtex
214
+ @software{vlmguard2026,
215
+ title = {VLM-Guard: Verification Layer for Multimodal LLMs},
216
+ author = {Fakhry, Mohamed},
217
+ year = {2026},
218
+ url = {https://github.com/MohamedFakhry2007/vlm-guard}
219
+ }
220
+ ```
@@ -0,0 +1,61 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vlm-guard"
7
+ version = "0.1.0"
8
+ description = "Medical Verification Layer for Multimodal LLMs — composable, auditable guardrails for structured LLM outputs"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [
12
+ {name = "Mohamed Fakhry", email = "mohamed.fakhry@example.com"},
13
+ ]
14
+ keywords = [
15
+ "llm", "multimodal", "guardrails", "medical-ai",
16
+ "verification", "safety", "hallucination-prevention",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Intended Audience :: Developers",
21
+ "Intended Audience :: Science/Research",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
28
+ "Topic :: Scientific/Engineering :: Medical Science Apps.",
29
+ ]
30
+ requires-python = ">=3.10"
31
+ dependencies = [
32
+ "pydantic>=2.0.0",
33
+ "Pillow>=10.0.0",
34
+ ]
35
+
36
+ [project.optional-dependencies]
37
+ image = [
38
+ "torch>=2.0.0",
39
+ "transformers>=4.40.0",
40
+ "bitsandbytes>=0.41.0",
41
+ ]
42
+ all = [
43
+ "vlm-guard[image]",
44
+ "fpdf>=1.7.2",
45
+ "accelerate>=0.25.0",
46
+ ]
47
+ dev = [
48
+ "pytest>=7.0.0",
49
+ ]
50
+
51
+ [project.urls]
52
+ Homepage = "https://github.com/MohamedFakhry2007/vlm-guard"
53
+ Source = "https://github.com/MohamedFakhry2007/vlm-guard"
54
+ Tracker = "https://github.com/MohamedFakhry2007/vlm-guard/issues"
55
+
56
+ [tool.setuptools.packages.find]
57
+ include = ["vlm_guard*"]
58
+
59
+ [tool.pytest.ini_options]
60
+ testpaths = ["tests"]
61
+ python_files = ["test_*.py"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,29 @@
1
+ from vlm_guard.core.analysis import Analysis
2
+
3
+
4
+ def test_analysis_defaults():
5
+ a = Analysis(label="Test", confidence="High")
6
+ assert a.label == "Test"
7
+ assert a.confidence == "High"
8
+ assert a.evidence == ""
9
+ assert a.findings == ""
10
+ assert a.recommendation == ""
11
+ assert a.metadata == {}
12
+
13
+
14
+ def test_analysis_metadata():
15
+ a = Analysis(label="Test", confidence="Medium", metadata={"species": "P. falciparum"})
16
+ assert a.metadata["species"] == "P. falciparum"
17
+
18
+
19
+ def test_analysis_forbids_extra_fields():
20
+ import pytest
21
+ with pytest.raises(ValueError):
22
+ Analysis(label="Test", confidence="High", nonexistent_field="should fail")
23
+
24
+
25
+ def test_analysis_dump():
26
+ a = Analysis(label="X", confidence="Low", evidence="proof", findings="desc", recommendation="action")
27
+ d = a.model_dump()
28
+ assert d["label"] == "X"
29
+ assert d["confidence"] == "Low"