Skip to content

Commit af965fc

Browse files
authored
Merge pull request #278 from helpfulengineering/materials
Materials
2 parents eb6fe1b + c1f782f commit af965fc

139 files changed

Lines changed: 8350 additions & 2320 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/setup/SKILL.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,6 @@ When the user asks a question about OHM configuration, features, or usage, find
653653
| Developer Guide | docs/development/developer-guide.md | How to set up a local dev environment and contribute |
654654
| Container Guide | docs/development/container-guide.md | Docker and docker-compose workflows; all storage env vars |
655655
| Roadmap | docs/development/roadmap.md | Planned features and development priorities |
656-
| Conference Demo Readiness | docs/development/conference-demo-readiness.md | Demo setup checklist; how to regenerate OpenAPI route counts |
657656
| Data Models Overview | docs/models/index.md | Supply trees, BOM, process requirements, and validation contexts |
658657
| Bill of Materials | docs/models/bom.md | BOM data model for nested component requirements |
659658
| Supply Trees | docs/models/supply-tree.md | Central data structure for manufacturing solutions |
@@ -664,7 +663,6 @@ When the user asks a question about OHM configuration, features, or usage, find
664663
| OKW Specification | docs/models/okw-specification.md | Full OKW specification |
665664
| Format Conversion | docs/conversion/index.md | Bi-directional OKH ↔ external format conversion (MSF Datasheet) |
666665
| MSF Datasheet | docs/conversion/msf-datasheet.md | Convert between OKH and MSF .docx datasheet format |
667-
| Matching Accuracy Baseline | docs/metrics/matching-accuracy-baseline.md | Baseline metrics for matching algorithm accuracy |
668666
| Domains Overview | docs/domains/index.md | Multi-domain system: manufacturing and cooking; domain detection and health |
669667
| Manufacturing Domain | docs/domains/manufacturing.md | Manufacturing-specific extractors, matchers, and validators |
670668
| Cooking Domain | docs/domains/cooking.md | Cooking domain components and use cases |

.gitignore

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,16 @@ synthetic_data/
192192
# credentials
193193
service-account.json
194194

195-
# Test repo clones (populated during 1.3.1 generation testing; deleted manually when done)
195+
# Test repo clones / batch reports (populated during generation testing)
196196
tests/data/okh_generation/clones/
197+
tests/data/okh_generation/clones-regen/
198+
tests/data/okh_generation/clones-azure-regen/
199+
tests/data/okh_generation/last_batch_report.json
200+
tests/data/okh_generation/last_baseline_report.json
201+
tests/data/okh_generation/last_layer_compare.json
202+
tests/data/okh_generation/materials_regen_tracker.json
203+
tests/data/okh_generation/azure_regen_replace_tracker.json
204+
tests/data/okh_generation/azure_okh_inventory.json
197205
.llm_chunk_cache/*
198206

199207

.repo-map.md

Lines changed: 405 additions & 7 deletions
Large diffs are not rendered by default.

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- **OKH-LOSH v2.4 TOML import:** `OkhLoshConverter` service (`src/core/services/okh_losh_converter.py`) converts OKH-LOSH v2.4 TOML manifests (github.com/iop-alliance/OpenKnowHow) to OHM's canonical OKH manifest, with kebab→snake field mapping and unmapped fields (full `[[image]]` array, top-level `mass`/`release`) preserved under `metadata.*`; `ohm convert from-okh-losh`; `POST /v1/api/convert/from-okh-losh`; docs at `docs/conversion/okh-losh-toml.md`; bulk-import driver at `scripts/import_okh_losh_batch.py`.
13+
1014
## [0.8.11] - 2026-07-10
1115

1216
### Added

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ The dev server proxies all `/v1` requests to the OHM API. If your API is not at
167167
168168
## Documentation
169169

170-
This README provides a quick start guide and basic project information. For full documentation, run MkDocs locally. For an active checklist aligned with the public API and CLI (conference demos, doc drift), see [docs/development/conference-demo-readiness.md](docs/development/conference-demo-readiness.md).
170+
This README provides a quick start guide and basic project information. For full documentation, run MkDocs locally.
171171

172172
### Building Documentation Locally
173173

docs/api/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# API Documentation
22

3-
The Open Hardware Manager (OHM) provides a REST API built on FastAPI with standardized request/response patterns, structured error handling, and LLM integration hooks. **Endpoint inventory:** use the interactive docs at **`/v1/docs`** and **`/v1/openapi.json`** on your running server (see [Conference demo readiness](../development/conference-demo-readiness.md#api-machine-truth-refresh-before-demo) for how to regenerate counts). Narrative pages here describe concepts and patterns; they are not a substitute for OpenAPI.
3+
The Open Hardware Manager (OHM) provides a REST API built on FastAPI with standardized request/response patterns, structured error handling, and LLM integration hooks. **Endpoint inventory:** use the interactive docs at **`/v1/docs`** and **`/v1/openapi.json`** on your running server. To dump a sorted route list locally: `uv run python scripts/dump_api_routes.py`. Narrative pages here describe concepts and patterns; they are not a substitute for OpenAPI.
44

55
## API Architecture Overview
66

docs/api/routes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Introduction
44

5-
The Open Hardware Manager (OHM) API provides programmatic access to match requirements with capabilities across multiple domains and generate valid solutions represented as Supply Trees. This document describes the **standardized API** (error handling, LLM integration patterns, and response shapes). **Do not treat the narrative sections below as an exhaustive route catalog** — paths change with releases. With the API running, use **`/v1/docs`** (Swagger UI) and **`/v1/openapi.json`** as the source of truth. A **generated** operation table lives under [Routes and Endpoints](#routes-and-endpoints); refresh it with `uv run python scripts/generate_openapi_routes_md.py`. Router wiring for `api_v1` is in `src/core/main.py`. For a machine-readable refresh checklist, see [Conference demo readiness](../development/conference-demo-readiness.md#api-machine-truth-refresh-before-demo).
5+
The Open Hardware Manager (OHM) API provides programmatic access to match requirements with capabilities across multiple domains and generate valid solutions represented as Supply Trees. This document describes the **standardized API** (error handling, LLM integration patterns, and response shapes). **Do not treat the narrative sections below as an exhaustive route catalog** — paths change with releases. With the API running, use **`/v1/docs`** (Swagger UI) and **`/v1/openapi.json`** as the source of truth. A **generated** operation table lives under [Routes and Endpoints](#routes-and-endpoints); refresh it with `uv run python scripts/generate_openapi_routes_md.py`. Router wiring for `api_v1` is in `src/core/main.py`. For a sorted route dump: `uv run python scripts/dump_api_routes.py`.
66

77
**Supported Domains:**
88
- **Manufacturing Domain**: Match OKH requirements with OKW capabilities

docs/architecture/matching.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -940,13 +940,13 @@ def _ensure_nlp_initialized(self):
940940
self._nlp_initialized = True
941941
return None
942942
943-
try:
944-
logger.info("Loading spaCy model 'en_core_web_sm' (lazy loading)")
945-
self._nlp = spacy.load("en_core_web_sm")
946-
logger.info("spaCy model 'en_core_web_sm' loaded successfully")
947-
except OSError:
948-
logger.warning("spaCy English model 'en_core_web_sm' not found. NLP matching will use fallback string similarity.")
949-
self._nlp = None
943+
# Prefer en_core_web_md (word vectors) via the shared loader
944+
self._nlp = load_spacy_english()
945+
if self._nlp is None:
946+
logger.warning(
947+
"No spaCy English model could be loaded. "
948+
"NLP matching will use fallback string similarity."
949+
)
950950
951951
self._nlp_initialized = True
952952
return self._nlp
@@ -1815,7 +1815,7 @@ manufacturing_rules = [
18151815
]
18161816

18171817
# Manufacturing-specific NLP pipeline
1818-
manufacturing_nlp = spacy.load("en_core_web_md")
1818+
manufacturing_nlp = load_spacy_english()
18191819
manufacturing_nlp.add_pipe("material_entity")
18201820
manufacturing_nlp.add_pipe("tool_entity")
18211821
manufacturing_nlp.add_pipe("process_entity")
@@ -1838,7 +1838,7 @@ cooking_rules = [
18381838
]
18391839

18401840
# Cooking-specific NLP pipeline
1841-
cooking_nlp = spacy.load("en_core_web_md")
1841+
cooking_nlp = load_spacy_english()
18421842
cooking_nlp.add_pipe("ingredient_entity")
18431843
cooking_nlp.add_pipe("utensil_entity")
18441844
cooking_nlp.add_pipe("technique_entity")

docs/conversion/index.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ OHM supports bi-directional conversion between the internal OKH (OpenKnowHow) da
77
| Format | Direction | Description |
88
|--------|-----------|-------------|
99
| **MSF Datasheet** (.docx) | OKH ↔ docx | 3D-printed product technical specification datasheet |
10+
| **OKH-LOSH v2.4** (.toml) | TOML → OKH | iop-alliance/OpenKnowHow TOML spec (import only) |
1011

1112
## Architecture
1213

@@ -25,9 +26,9 @@ All conversions pass through the `OKHManifest` dataclass, ensuring data consiste
2526

2627
The conversion utility is available through three interfaces:
2728

28-
- **CLI**: `ohm convert to-datasheet` / `ohm convert from-datasheet`
29-
- **API**: `POST /v1/api/convert/to-datasheet` / `POST /v1/api/convert/from-datasheet`
30-
- **Python**: `DatasheetConverter` class in `src.core.services.datasheet_converter`
29+
- **CLI**: `ohm convert to-datasheet` / `ohm convert from-datasheet` / `ohm convert from-okh-losh`
30+
- **API**: `POST /v1/api/convert/to-datasheet` / `POST /v1/api/convert/from-datasheet` / `POST /v1/api/convert/from-okh-losh`
31+
- **Python**: `DatasheetConverter` class in `src.core.services.datasheet_converter`, `OkhLoshConverter` class in `src.core.services.okh_losh_converter`
3132

3233
## Quick Start
3334

@@ -75,3 +76,4 @@ print(manifest.title)
7576
## Pages
7677

7778
- [MSF Datasheet Format](msf-datasheet.md) — Detailed format description and field mapping
79+
- [OKH-LOSH TOML Format](okh-losh-toml.md) — Detailed format description and field mapping

docs/conversion/okh-losh-toml.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# OKH-LOSH v2.4 TOML Conversion
2+
3+
OKH-LOSH v2.4 is the TOML-based OKH manifest format defined by
4+
[iop-alliance/OpenKnowHow](https://github.com/iop-alliance/OpenKnowHow). It
5+
uses kebab-case field names and a few shapes (a repeatable `[[image]]` table,
6+
a top-level `[outer-dimensions]` table, a top-level `mass`) that have no
7+
direct equivalent in OHM's canonical model.
8+
9+
Conversion is **one-way** (TOML → OKH). Nothing in OHM needs to export a
10+
manifest back to OKH-LOSH TOML.
11+
12+
## Field Mapping
13+
14+
| OKH-LOSH v2.4 field | OKH field | Notes |
15+
|---|---|---|
16+
| `okhv` | `okhv` | Passed through literally; not validated by OHM |
17+
| `name` | `title` | Rename |
18+
| `repo`, `license`, `function`, `version`, `licensor`, `organization`, `attestation`, `bom`, `readme` | Same names | Passed straight through; `license` bare strings and `licensor`/`organization` `"Name <email>"` strings/lists are already handled by `OKHManifest.from_dict()` |
19+
| `documentation-language` | `documentation_language` | Rename |
20+
| `technology-readiness-level` | `technology_readiness_level` | Rename |
21+
| `documentation-readiness-level` | `documentation_readiness_level` | Rename |
22+
| `cpc-patent-class` | `cpc_patent_class` | Rename |
23+
| `contribution-guide` | `contribution_guide` | Rename |
24+
| `tsdc` | `tsdc` | Wrapped in a list if given as a bare string |
25+
| `standard-compliance` | `standards_used` | Wrapped in a list if given as a bare string |
26+
| `manufacturing-instructions` | `making_instructions` | Each entry becomes a `DocumentRef` (`path` = the URL/file, `type=making-instructions`) |
27+
| `user-manual` | `operating_instructions` | Same pattern, `type=operating-instructions` |
28+
| `publication` | `publications` | Same pattern, `type=publications` |
29+
| `source` | `design_files` | Same pattern, `type=design-files` |
30+
| `[[software]]` | `software` | Structurally identical; `installation-guide` (kebab in the source) is renamed to `installation_guide` |
31+
| `[outer-dimensions]` | `manufacturing_specs.outer_dimensions` | Untyped dict on both sides; `width`/`depth`/`height` keys preserved as-is |
32+
| `[[image]]` | `image` + `metadata.images` | See below |
33+
| `mass` | `metadata.mass` | No top-level equivalent in OHM (only nested under a part's `mass`) |
34+
| `release` | `metadata.release` | Different concept from OHM's `Software.release` |
35+
36+
### Image handling
37+
38+
OKH-LOSH's `[[image]]` is a repeatable table (`location`, `depicts`, `slots`,
39+
`tags`); OHM's canonical model has a single scalar `image: Optional[str]`.
40+
The converter:
41+
42+
1. Picks one **primary** image for the `image` field — preferring the entry
43+
tagged with the `photo-thing-main` slot, falling back to the first image
44+
with a `location`.
45+
2. Preserves the **full array** (all entries, with their `slots`/`tags`/
46+
`depicts`) under `metadata.images`, so nothing is lost even though only
47+
one image is a first-class field.
48+
49+
## Access Methods
50+
51+
- **CLI**: `ohm convert from-okh-losh`
52+
- **API**: `POST /v1/api/convert/from-okh-losh`
53+
- **Python**: `OkhLoshConverter` class in `src.core.services.okh_losh_converter`
54+
55+
## Quick Start
56+
57+
### CLI
58+
59+
```bash
60+
# Convert an OKH-LOSH TOML manifest → OKH manifest (JSON)
61+
ohm convert from-okh-losh my-project.okh.toml -o my-project.okh.json
62+
63+
# Output as YAML
64+
ohm convert from-okh-losh my-project.okh.toml --format yaml
65+
```
66+
67+
### API
68+
69+
```bash
70+
# OKH-LOSH TOML → OKH (upload .toml, get JSON back)
71+
curl -X POST http://localhost:8001/v1/api/convert/from-okh-losh \
72+
-F "toml_file=@my-project.okh.toml"
73+
```
74+
75+
### Python
76+
77+
```python
78+
from src.core.services.okh_losh_converter import OkhLoshConverter
79+
80+
converter = OkhLoshConverter()
81+
manifest = converter.okh_losh_to_okh("my-project.okh.toml")
82+
print(manifest.title)
83+
```
84+
85+
## CLI Reference
86+
87+
### `ohm convert from-okh-losh`
88+
89+
```
90+
Usage: ohm convert from-okh-losh [OPTIONS] TOML_FILE
91+
92+
Convert an OKH-LOSH v2.4 TOML manifest to an OKH manifest.
93+
94+
Options:
95+
-o, --output PATH Output file path
96+
--format [json|yaml] Output format (default: json)
97+
-v, --verbose Enable verbose output
98+
--json Output in JSON format
99+
```
100+
101+
## API Reference
102+
103+
### `POST /v1/api/convert/from-okh-losh`
104+
105+
Accepts an OKH-LOSH `.toml` file upload and returns the parsed OKH manifest
106+
as JSON.
107+
108+
**Request**: Multipart form upload with a `toml_file` field.
109+
110+
**Response**: `ConvertFromOkhLoshResponse` containing the full manifest and
111+
conversion metadata.
112+
113+
## Bulk Import
114+
115+
For importing a directory of many OKH-LOSH TOML files at once (rather than
116+
one file via the CLI/API), see `scripts/import_okh_losh_batch.py`
117+
(`scripts/registry.toml` entry `import_okh_losh_batch`), which converts each
118+
file, validates and auto-fixes it, and persists it through
119+
`OKHService.create()`.

0 commit comments

Comments
 (0)