mfcli 0.2.7__tar.gz → 0.2.9__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.
- {mfcli-0.2.7 → mfcli-0.2.9}/MCP_SETUP.md +32 -2
- {mfcli-0.2.7 → mfcli-0.2.9}/PKG-INFO +1 -1
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/constants/file_types.py +43 -2
- mfcli-0.2.9/mfcli/pipeline/extractor.py +85 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/sub_classifier.py +10 -1
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/data_cleaner.py +6 -3
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/mcp_configurator.py +4 -2
- {mfcli-0.2.7 → mfcli-0.2.9}/pyproject.toml +1 -1
- mfcli-0.2.7/mfcli/pipeline/extractor.py +0 -37
- {mfcli-0.2.7 → mfcli-0.2.9}/BUILD.md +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/CONFIGURATION.md +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/INSTALL.md +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/LICENSE +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/MANIFEST.in +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/README.md +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/install.ps1 +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/install.sh +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/.env.example +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/agents/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/agents/controller/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/agents/controller/agent.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/agents/controller/config.yaml +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/agents/controller/tools.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/agents/tools/general.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/env.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/script.py.mako +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/6ccc0c7c397c_added_fields_to_pdf_parts_model.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/769019ef4870_added_gemini_file_path_to_pdf_part_model.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/7a2e3a779fdc_added_functional_block_and_component_.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/7d5adb2a47a7_added_pdf_parts_model.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/7fcb7d6a5836_init.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/e0f2b5765c72_added_cascade_delete_for_models_that_.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/f1234567890a_make_bom_description_nullable.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic.ini +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/cli/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/cli/dependencies.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/cli/main.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/client/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/client/chroma_db.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/client/docling.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/client/gemini.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/client/vector_db.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/constants/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/constants/base_enum.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/constants/directory_names.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/constants/gemini.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/constants/openai.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/constants/pipeline_run_status.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/crud/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/crud/file.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/crud/functional_blocks.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/crud/netlist.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/crud/pipeline_run.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/crud/project.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/digikey/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/digikey/digikey.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/main.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/mcp/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/mcp/configs/cline_mcp_settings.json +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/mcp/configs/mfcli.mcp.json +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/mcp/mcp_instance.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/mcp/server.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/mcp/state_manager.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/mcp/tools/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/mcp/tools/query_knowledgebase.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/base.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/bom.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/datasheet.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/debug_setup.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/file.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/file_docket.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/file_metadata.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/functional_blocks.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/llm_response.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/mcu.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/mcu_errata.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/netlist.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/pdf_parts.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/pipeline_run.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/project.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/project_metadata.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/models/schematic_cheatsheet.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/bom_netlist_mapper.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/bom/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/bom/bom.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/debug_setup/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/debug_setup/debug_setup.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/debug_setup/instructions.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/functional_blocks/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/functional_blocks/functional_blocks.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/functional_blocks/instructions.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/functional_blocks/validator.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/generator.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/generator_base.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/mcu/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/mcu/instructions.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/mcu/mcu.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/mcu_errata/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/mcu_errata/instructions.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/mcu_errata/mcu_errata.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/schematic/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/schematic/instructions.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/schematic/schematic.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/summary/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/summary/summary.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/classifier.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/data_enricher.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/extractors/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/extractors/pdf.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parser.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/netlist/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/netlist/edif.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/netlist/kicad_legacy_net.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/netlist/kicad_spice.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/netlist/pads.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/netlist/protel.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/netlist/protel_detector.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/schematic/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/parsers/schematic/kicad_sch_detector.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/pipeline.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/preprocessors/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/preprocessors/user_guide.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/run_context.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/schema_mapper.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/__init__.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/cheatsheet_regenerator.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/cline_rules.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/config.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/configurator.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/datasheet_vectorizer.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/directory_manager.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/file_upload.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/files.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/http_requests.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/kb_lister.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/kb_remover.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/logger.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/migrations.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/orm.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/pdf_splitter.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/pre_uninstall.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/query_service.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/ssl_installer.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/system_check.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/tools.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli/utils/vectorizer.py +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/mfcli.egg-info/SOURCES.txt +0 -0
- {mfcli-0.2.7 → mfcli-0.2.9}/setup.cfg +0 -0
|
@@ -115,7 +115,8 @@ If the file doesn't exist, create it with this content:
|
|
|
115
115
|
"disabled": false,
|
|
116
116
|
"timeout": 60,
|
|
117
117
|
"type": "stdio",
|
|
118
|
-
"command": "mfcli-mcp"
|
|
118
|
+
"command": "mfcli-mcp",
|
|
119
|
+
"autoApprove": ["query_local_rag"]
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
}
|
|
@@ -133,12 +134,15 @@ If the file exists, add the `mfcli-mcp` entry to the existing `mcpServers` objec
|
|
|
133
134
|
"disabled": false,
|
|
134
135
|
"timeout": 60,
|
|
135
136
|
"type": "stdio",
|
|
136
|
-
"command": "mfcli-mcp"
|
|
137
|
+
"command": "mfcli-mcp",
|
|
138
|
+
"autoApprove": ["query_local_rag"]
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
142
|
```
|
|
141
143
|
|
|
144
|
+
**Note about `autoApprove`:** The `autoApprove` option allows the `query_local_rag` tool to run automatically without requiring explicit user approval each time. This streamlines the workflow when working with hardware documentation, as the tool is read-only and simply queries your local knowledge base.
|
|
145
|
+
|
|
142
146
|
### Step 3: Restart Your Editor
|
|
143
147
|
|
|
144
148
|
Close and reopen your AI coding assistant for the changes to take effect.
|
|
@@ -382,6 +386,32 @@ Enable verbose logging for troubleshooting:
|
|
|
382
386
|
}
|
|
383
387
|
```
|
|
384
388
|
|
|
389
|
+
### Auto-Approval for Tools
|
|
390
|
+
|
|
391
|
+
The `autoApprove` option allows specific tools to run automatically without requiring user approval each time:
|
|
392
|
+
|
|
393
|
+
```json
|
|
394
|
+
{
|
|
395
|
+
"mfcli-mcp": {
|
|
396
|
+
"autoApprove": ["query_local_rag"]
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Benefits:**
|
|
402
|
+
- ✅ Streamlined workflow - No manual approval needed for each query
|
|
403
|
+
- ✅ Faster responses - AI assistant can query documentation immediately
|
|
404
|
+
- ✅ Better UX - More natural conversation flow
|
|
405
|
+
- ✅ Safe for read-only tools - `query_local_rag` only reads local data
|
|
406
|
+
|
|
407
|
+
**Security Note:** The `query_local_rag` tool is safe to auto-approve because:
|
|
408
|
+
- It only performs read operations on your local knowledge base
|
|
409
|
+
- No data is modified or transmitted externally
|
|
410
|
+
- It operates within your local filesystem permissions
|
|
411
|
+
- All data stays on your machine
|
|
412
|
+
|
|
413
|
+
If you prefer to manually approve each tool use, simply omit the `autoApprove` field from the configuration.
|
|
414
|
+
|
|
385
415
|
## Best Practices
|
|
386
416
|
|
|
387
417
|
### Document Organization
|
|
@@ -13,6 +13,10 @@ class FileTypes(BaseEnum):
|
|
|
13
13
|
PDF = 5
|
|
14
14
|
SCH = 6
|
|
15
15
|
KICAD_SCH = 7
|
|
16
|
+
TXT = 8
|
|
17
|
+
RTF = 9
|
|
18
|
+
DOCX = 10
|
|
19
|
+
JPG = 11
|
|
16
20
|
|
|
17
21
|
|
|
18
22
|
class FileSubtypes(BaseEnum):
|
|
@@ -47,7 +51,9 @@ SchemalessFileSubtypes: set[FileSubtypes] = {
|
|
|
47
51
|
FileSubtypes.ERRATA,
|
|
48
52
|
FileSubtypes.MCU_DATASHEET,
|
|
49
53
|
FileSubtypes.USER_GUIDE,
|
|
50
|
-
FileSubtypes.REFERENCE_MANUAL
|
|
54
|
+
FileSubtypes.REFERENCE_MANUAL,
|
|
55
|
+
FileSubtypes.GENERAL_DATASHEET,
|
|
56
|
+
FileSubtypes.UNKNOWN
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
# File subtype names are for use with LLM, validating subtype response
|
|
@@ -67,7 +73,8 @@ OtherFileSubtypeNames = Literal[
|
|
|
67
73
|
'PADS_PCB_ASCII',
|
|
68
74
|
'KICAD_LEGACY_NET',
|
|
69
75
|
'KICAD_SPICE',
|
|
70
|
-
'PROTEL_ALTIUM'
|
|
76
|
+
'PROTEL_ALTIUM',
|
|
77
|
+
'UNKNOWN'
|
|
71
78
|
]
|
|
72
79
|
|
|
73
80
|
PDFMimeTypes = {
|
|
@@ -138,6 +145,40 @@ SupportedFileTypes = {
|
|
|
138
145
|
"subtypes": {
|
|
139
146
|
"SCHEMATIC"
|
|
140
147
|
}
|
|
148
|
+
},
|
|
149
|
+
"TXT": {
|
|
150
|
+
"mime_types": {
|
|
151
|
+
"text/plain"
|
|
152
|
+
},
|
|
153
|
+
"subtypes": {
|
|
154
|
+
"UNKNOWN"
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"RTF": {
|
|
158
|
+
"mime_types": {
|
|
159
|
+
"application/rtf",
|
|
160
|
+
"text/rtf"
|
|
161
|
+
},
|
|
162
|
+
"subtypes": {
|
|
163
|
+
"UNKNOWN"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
"DOCX": {
|
|
167
|
+
"mime_types": {
|
|
168
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
169
|
+
},
|
|
170
|
+
"subtypes": {
|
|
171
|
+
"UNKNOWN"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"JPG": {
|
|
175
|
+
"mime_types": {
|
|
176
|
+
"image/jpeg",
|
|
177
|
+
"image/jpg"
|
|
178
|
+
},
|
|
179
|
+
"subtypes": {
|
|
180
|
+
"UNKNOWN"
|
|
181
|
+
}
|
|
141
182
|
}
|
|
142
183
|
}
|
|
143
184
|
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from mfcli.constants.file_types import FileTypes
|
|
2
|
+
from mfcli.models.file import File
|
|
3
|
+
from mfcli.pipeline.extractors.pdf import extract_text_from_pdf
|
|
4
|
+
from mfcli.utils.files import is_text_mime_type
|
|
5
|
+
from mfcli.utils.logger import get_logger
|
|
6
|
+
|
|
7
|
+
logger = get_logger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def extract_text_from_docx(file_bytes: bytes) -> str:
|
|
11
|
+
"""Extract text from DOCX file using python-docx."""
|
|
12
|
+
try:
|
|
13
|
+
from io import BytesIO
|
|
14
|
+
import docx
|
|
15
|
+
|
|
16
|
+
doc = docx.Document(BytesIO(file_bytes))
|
|
17
|
+
text_parts = []
|
|
18
|
+
for paragraph in doc.paragraphs:
|
|
19
|
+
text_parts.append(paragraph.text)
|
|
20
|
+
return '\n'.join(text_parts)
|
|
21
|
+
except ImportError:
|
|
22
|
+
logger.warning("python-docx not installed, treating DOCX as binary")
|
|
23
|
+
return file_bytes.decode(errors='ignore')
|
|
24
|
+
except Exception as e:
|
|
25
|
+
logger.error(f"Error extracting text from DOCX: {e}")
|
|
26
|
+
return file_bytes.decode(errors='ignore')
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def extract_text_from_rtf(file_bytes: bytes) -> str:
|
|
30
|
+
"""Extract text from RTF file using striprtf."""
|
|
31
|
+
try:
|
|
32
|
+
from striprtf.striprtf import rtf_to_text
|
|
33
|
+
rtf_string = file_bytes.decode(errors='ignore')
|
|
34
|
+
return rtf_to_text(rtf_string)
|
|
35
|
+
except ImportError:
|
|
36
|
+
logger.warning("striprtf not installed, treating RTF as plain text")
|
|
37
|
+
return file_bytes.decode(errors='ignore')
|
|
38
|
+
except Exception as e:
|
|
39
|
+
logger.error(f"Error extracting text from RTF: {e}")
|
|
40
|
+
return file_bytes.decode(errors='ignore')
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def extract_document_text(file: File, file_bytes: bytes) -> str:
|
|
44
|
+
"""
|
|
45
|
+
Extract text from a file based on its MIME type.
|
|
46
|
+
|
|
47
|
+
For PDFs, uses PyMuPDF (fitz) for fast, reliable text extraction.
|
|
48
|
+
For text files, decodes the bytes directly.
|
|
49
|
+
For DOCX files, uses python-docx to extract text.
|
|
50
|
+
For RTF files, uses striprtf to extract text.
|
|
51
|
+
For image files (JPG, PNG), returns empty string (OCR not implemented).
|
|
52
|
+
KiCad schematics and other schematic files are treated as text files.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
file: File object containing metadata
|
|
56
|
+
file_bytes: Raw file content as bytes
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Extracted text content
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
ValueError: If the file type is not supported
|
|
63
|
+
"""
|
|
64
|
+
if is_text_mime_type(file.mime_type):
|
|
65
|
+
return file_bytes.decode(errors='ignore')
|
|
66
|
+
elif file.type == FileTypes.PDF:
|
|
67
|
+
return extract_text_from_pdf(file_bytes)
|
|
68
|
+
elif file.type == FileTypes.DOCX:
|
|
69
|
+
return extract_text_from_docx(file_bytes)
|
|
70
|
+
elif file.type == FileTypes.RTF:
|
|
71
|
+
return extract_text_from_rtf(file_bytes)
|
|
72
|
+
elif file.type == FileTypes.JPG:
|
|
73
|
+
# Image files don't have extractable text without OCR
|
|
74
|
+
# Return empty string for now - file will still be vectorized if it's a PDF-embedded image
|
|
75
|
+
logger.info(f"Image file detected ({file.name}), no text extraction (OCR not implemented)")
|
|
76
|
+
return ""
|
|
77
|
+
elif file.type == FileTypes.CSV:
|
|
78
|
+
# CSV files (including Excel CSV with application/vnd.ms-excel MIME type)
|
|
79
|
+
# are text-based and should be decoded directly
|
|
80
|
+
return file_bytes.decode(errors='ignore')
|
|
81
|
+
elif file.type in (FileTypes.KICAD_SCH, FileTypes.SCH, FileTypes.TXT):
|
|
82
|
+
# KiCad schematics and plain text files are S-expression text files but may have
|
|
83
|
+
# application/octet-stream MIME type
|
|
84
|
+
return file_bytes.decode(errors='ignore')
|
|
85
|
+
raise ValueError(f"Unsupported MIME type: {file.mime_type}")
|
|
@@ -85,7 +85,9 @@ class FileSubtypeAnalyzer:
|
|
|
85
85
|
subtype = await self._get_subtype_from_gemini(prompt, instructions, gemini_file, file_class)
|
|
86
86
|
logger.debug(f"Subtype discovered: {subtype}")
|
|
87
87
|
if subtype == FILE_SUBTYPE_UNKNOWN:
|
|
88
|
-
|
|
88
|
+
logger.warning(f"Could not determine the file subtype for file: {file.name}, using UNKNOWN")
|
|
89
|
+
file.sub_type = FileSubtypes.UNKNOWN.value
|
|
90
|
+
return
|
|
89
91
|
if not subtype in relevant_subtype_descriptions:
|
|
90
92
|
raise RuntimeError(f"LLM responded with invalid subtype: {subtype}")
|
|
91
93
|
file.sub_type = FileSubtypes.get(subtype)
|
|
@@ -109,6 +111,13 @@ class FileSubtypeAnalyzer:
|
|
|
109
111
|
file.sub_type = FileSubtypes.SCHEMATIC.value
|
|
110
112
|
return
|
|
111
113
|
|
|
114
|
+
# Generic document file types (TXT, RTF, DOCX, JPG) default to UNKNOWN
|
|
115
|
+
# These files will be vectorized but not analyzed for specific subtypes
|
|
116
|
+
if file.type in (FileTypes.TXT, FileTypes.RTF, FileTypes.DOCX, FileTypes.JPG):
|
|
117
|
+
file.sub_type = FileSubtypes.UNKNOWN.value
|
|
118
|
+
logger.info(f"File type {FileTypes(file.type).name} auto-assigned UNKNOWN subtype")
|
|
119
|
+
return
|
|
120
|
+
|
|
112
121
|
# Handle text MIME types for content-based detection
|
|
113
122
|
if text and is_text_mime_type(file.mime_type):
|
|
114
123
|
if file.type == FileTypes.NET:
|
|
@@ -19,7 +19,8 @@ logger = get_logger(__name__)
|
|
|
19
19
|
warning_message = dedent(
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
WARNING: This will permanently delete all mfcli data for the current project, including datasheets, cheat sheets, and project data.
|
|
22
|
+
WARNING: This will permanently delete all mfcli data for the current project, including datasheets, cheat sheets, and project data.
|
|
23
|
+
The design folder and its contents will be preserved.
|
|
23
24
|
Should we proceed? (Y/n):
|
|
24
25
|
|
|
25
26
|
"""
|
|
@@ -105,9 +106,8 @@ class DataCleaner:
|
|
|
105
106
|
logger.debug(f"Removing file docket: {app_dirs.file_docket_path}")
|
|
106
107
|
self._remove_file(app_dirs.file_docket_path)
|
|
107
108
|
|
|
108
|
-
# Remove directories
|
|
109
|
+
# Remove directories (excluding design folder)
|
|
109
110
|
for dir_path in [
|
|
110
|
-
config_dir,
|
|
111
111
|
app_dirs.data_sheets_dir,
|
|
112
112
|
app_dirs.fw_tasks_dir,
|
|
113
113
|
app_dirs.generated_files_dir,
|
|
@@ -118,6 +118,9 @@ class DataCleaner:
|
|
|
118
118
|
logger.debug(f"Removing directory: {dir_path}")
|
|
119
119
|
self._remove_dir(dir_path)
|
|
120
120
|
|
|
121
|
+
# Note: design_dir is intentionally NOT removed to preserve user input files
|
|
122
|
+
logger.info(f"Design folder preserved at: {app_dirs.design_dir}")
|
|
123
|
+
|
|
121
124
|
# Delete project (CASCADE will handle related records like pipeline_runs)
|
|
122
125
|
logger.debug(f"Deleting project from database: {project.name}")
|
|
123
126
|
self._db.delete(project)
|
|
@@ -73,7 +73,8 @@ def get_mfcli_mcp_config() -> dict:
|
|
|
73
73
|
"disabled": False,
|
|
74
74
|
"timeout": 60,
|
|
75
75
|
"type": "stdio",
|
|
76
|
-
"command": "mfcli-mcp"
|
|
76
|
+
"command": "mfcli-mcp",
|
|
77
|
+
"autoApprove": ["query_local_rag"]
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
|
|
@@ -382,7 +383,8 @@ editor's MCP configuration file.
|
|
|
382
383
|
"disabled": false,
|
|
383
384
|
"timeout": 60,
|
|
384
385
|
"type": "stdio",
|
|
385
|
-
"command": "mfcli-mcp"
|
|
386
|
+
"command": "mfcli-mcp",
|
|
387
|
+
"autoApprove": ["query_local_rag"]
|
|
386
388
|
}
|
|
387
389
|
}
|
|
388
390
|
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
from mfcli.constants.file_types import FileTypes
|
|
2
|
-
from mfcli.models.file import File
|
|
3
|
-
from mfcli.pipeline.extractors.pdf import extract_text_from_pdf
|
|
4
|
-
from mfcli.utils.files import is_text_mime_type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def extract_document_text(file: File, file_bytes: bytes) -> str:
|
|
8
|
-
"""
|
|
9
|
-
Extract text from a file based on its MIME type.
|
|
10
|
-
|
|
11
|
-
For PDFs, uses PyMuPDF (fitz) for fast, reliable text extraction.
|
|
12
|
-
For text files, decodes the bytes directly.
|
|
13
|
-
KiCad schematics and other schematic files are treated as text files.
|
|
14
|
-
|
|
15
|
-
Args:
|
|
16
|
-
file: File object containing metadata
|
|
17
|
-
file_bytes: Raw file content as bytes
|
|
18
|
-
|
|
19
|
-
Returns:
|
|
20
|
-
Extracted text content
|
|
21
|
-
|
|
22
|
-
Raises:
|
|
23
|
-
ValueError: If the file type is not supported
|
|
24
|
-
"""
|
|
25
|
-
if is_text_mime_type(file.mime_type):
|
|
26
|
-
return file_bytes.decode(errors='ignore')
|
|
27
|
-
elif file.type == FileTypes.PDF:
|
|
28
|
-
return extract_text_from_pdf(file_bytes)
|
|
29
|
-
elif file.type == FileTypes.CSV:
|
|
30
|
-
# CSV files (including Excel CSV with application/vnd.ms-excel MIME type)
|
|
31
|
-
# are text-based and should be decoded directly
|
|
32
|
-
return file_bytes.decode(errors='ignore')
|
|
33
|
-
elif file.type in (FileTypes.KICAD_SCH, FileTypes.SCH):
|
|
34
|
-
# KiCad schematics are S-expression text files but may have
|
|
35
|
-
# application/octet-stream MIME type
|
|
36
|
-
return file_bytes.decode(errors='ignore')
|
|
37
|
-
raise ValueError(f"Unsupported MIME type: {file.mime_type}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/6ccc0c7c397c_added_fields_to_pdf_parts_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mfcli-0.2.7 → mfcli-0.2.9}/mfcli/alembic/versions/f1234567890a_make_bom_description_nullable.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/functional_blocks/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/functional_blocks/instructions.py
RENAMED
|
File without changes
|
{mfcli-0.2.7 → mfcli-0.2.9}/mfcli/pipeline/analysis/generators/functional_blocks/validator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|