271 lines
15 KiB
Markdown
271 lines
15 KiB
Markdown
---
|
|
name: datasheet-extractor
|
|
description: >-
|
|
Extract key parameters from component datasheet PDFs into the Vecmocon master
|
|
template (18 component types incl. resistors, capacitors, inductors, diodes,
|
|
transistors, ICs, protection, power modules, connectors, sensors, and more).
|
|
Column A = MPN_make_typeid (make = first word of manufacturer, typeid from the
|
|
taxonomy). Writes ONE master workbook (Components_Master.xlsx) with sheets only for the
|
|
types whose datasheets were provided, plus a Meta sheet at the end (template version,
|
|
total components, date, time), assembles
|
|
a per-part DFS folder (datasheet, Altium footprint, Altium symbol), and pushes
|
|
design files to the Gitea DFS repo, Excel outputs to the Parameters repo, and skill
|
|
files plus templates to the Skill_Assets repo. Also appends new parameters to a
|
|
template as a new version. Use WHENEVER the user uploads component datasheets and
|
|
asks to extract parameters, build the parameter sheets or component library, or push
|
|
datasheets to Gitea. ALWAYS trigger when the user types "\datasheet".
|
|
---
|
|
|
|
# Datasheet Extractor
|
|
|
|
Read component datasheets, fill the customer's master template, assemble each part's
|
|
design-file folder, and publish everything to three Gitea repos. Be careful and honest:
|
|
put every value in the right column and unit, and flag what a datasheet does not state.
|
|
|
|
**Pushing is the default.** At the end of a run, push every output to Gitea without asking
|
|
for confirmation — that's the whole job. Only pause when there's a genuine need for the
|
|
user: a **login wall** while fetching a footprint/symbol, or an **MPN that already exists**
|
|
in Gitea (discard vs replace, because replace overwrites data). Nothing else warrants a
|
|
prompt.
|
|
|
|
## Inputs
|
|
|
|
- **Datasheet PDFs**, one per part. The filename is the part's MPN (search that exact
|
|
number inside a series datasheet to read the right variant).
|
|
- No project/version is needed — repos use a **flat layout**.
|
|
|
|
## The identifier: `MPN_make_typeid`
|
|
|
|
Column A of every sheet (header `MPN_make_type`) and each DFS folder name is:
|
|
|
|
```
|
|
<MPN>_<make>_<typeid> e.g. BAT46WJ_Nexperia_SCH
|
|
```
|
|
|
|
- **make** = the **first word of the manufacturer** name (Texas Instruments → `Texas`,
|
|
Nexperia → `Nexperia`, STMicroelectronics → `STMicroelectronics`).
|
|
- **typeid** = the Type ID for the part's subclass, from the taxonomy in
|
|
`references/taxonomy.md` (full source `assets/template/Type_ID.xlsx`). e.g. Schottky →
|
|
`SCH`, TVS → `TVS`, MOSFET → `MOS`, LDO → `LDO`, Common-mode choke → `CMC`.
|
|
|
|
## Workflow
|
|
|
|
1. **Read each datasheet.** Get MPN (from filename), manufacturer, and the parameters.
|
|
2. **Classify** to one of the 18 **types** (= template sheet names) and to a **subclass**
|
|
from `references/taxonomy.md`; record its **typeid**. The subclass name goes in the
|
|
`Class` column where the sheet has one.
|
|
3. **Extract values** into that type's columns (headers come from
|
|
`assets/template/template.xlsx`). Convert to each header's unit; leave blank if the
|
|
datasheet doesn't state it (an honest blank beats a guess).
|
|
4. **Build the master workbook** with `scripts/fill_templates.py` — a single
|
|
`Components_Master.xlsx` that mirrors the template but keeps **only the sheets for the
|
|
types you actually extracted** (the components whose datasheets were given), each with
|
|
column A = `MPN_make_typeid`, and a single **Meta** sheet appended at the end. (See
|
|
Producing outputs.)
|
|
5. **Assemble each part's DFS folder** `MPN_make_typeid/` containing `MPN_data` (the
|
|
datasheet), `MPN_fp` (footprint), `MPN_sym` (symbol). See Footprint & symbol.
|
|
6. **Push everything to Gitea — automatically.** At the end of a run, push all outputs to
|
|
all three repos with no confirmation step: DFS folders → **DFS**, per-type sheets →
|
|
**Parameters** (merged in), skill files + templates → **Skill_Assets**. The only reasons
|
|
to pause are a login wall or an already-present MPN (discard vs replace); otherwise it
|
|
all just goes. See Pushing to Gitea.
|
|
|
|
## Producing outputs
|
|
|
|
Collect what you extracted into `parts.json` (keys match template headers; `typeid` and
|
|
`subclass` from the taxonomy; `manufacturer` used for the make tag):
|
|
|
|
```json
|
|
{"parts":[
|
|
{"type":"Diode","mpn":"BAT46WJ","manufacturer":"Nexperia","typeid":"SCH","subclass":"Schottky",
|
|
"values":{"Description":"100 V 250 mA Schottky, SOD323F","Forward Voltage(V)":"0.71","Package":"SOD323F"}}
|
|
]}
|
|
```
|
|
|
|
```bash
|
|
python scripts/fill_templates.py parts.json \
|
|
--template assets/template/template.xlsx --dest <outputs-dir>
|
|
```
|
|
|
|
Produces a **single** `Components_Master.xlsx`. It starts from a copy of the reference
|
|
template (so every kept sheet keeps its exact headers, styling, widths and freeze), fills
|
|
this run's parts into the matching sheet (column A = `MPN_make_typeid`), then **drops every
|
|
type sheet with no parts** — so the file holds only the components whose datasheets were
|
|
provided. A single **Meta** sheet is appended **at the end** with: Template Version, Total
|
|
Components, Date, Time, and a per-sheet count breakdown. Deliver this one file to the user;
|
|
the Parameters repo stores the same master, accumulated across runs (see Pushing to Gitea).
|
|
|
|
Sheet naming follows the template (Diode, Resistor, …), not `Sheet1/Sheet2`. If the user
|
|
supplies a new reference template, drop it in at `assets/template/template.xlsx` and the
|
|
master mirrors whatever sheets/headers it has.
|
|
|
|
## Footprint & symbol (for the DFS folder)
|
|
|
|
For each part, the DFS folder needs `MPN_fp` (footprint) and `MPN_sym` (symbol) beside
|
|
`MPN_data` (the datasheet). **Deliver these as Altium files** — an Altium PCB footprint
|
|
(`.PcbLib`) and schematic symbol (`.SchLib`), or a single integrated library (`.IntLib`)
|
|
that carries both — because that's what the design team actually consumes. Get them in
|
|
this order:
|
|
|
|
1. **Auto-download via the user's pre-logged-in Chrome** (`scripts/fetch_cad.py`). The user
|
|
keeps signed-in CAD-site windows open; the script attaches to that running Chrome and
|
|
reuses those live sessions — it never logs in, and no password is ever handled. One-time
|
|
setup: the user quits Chrome, relaunches it with `--remote-debugging-port=9222
|
|
--user-data-dir="$HOME/cad-chrome"`, and signs into the sites. Then, per part:
|
|
|
|
```bash
|
|
python scripts/fetch_cad.py --mpn BAT46WJ --dest <DFS_folder> \
|
|
--sites snapeda,ultralibrarian,componentsearchengine,digikey
|
|
```
|
|
|
|
It tries each site in order, downloads the Altium model, and drops it into the DFS folder
|
|
named `MPN_fp` / `MPN_sym` (or `MPN_cad` for a bundle). **It never solves CAPTCHAs or
|
|
defeats bot-detection** — if a site shows a login wall, CAPTCHA, or bot-check, that
|
|
adapter stops and reports `manual` with the URL. Note: this runs on the *user's* machine
|
|
(where the browsers are), and some sites' terms restrict automated downloads — treat it
|
|
as a convenience with the manual fallback below.
|
|
|
|
2. **Manual fallback** (script returned `manual`/`notfound`, or no browser session): **share
|
|
the user the direct link** where the model lives and ask them to download it and send it
|
|
back; then attach it into the DFS folder with the agreed naming (`MPN_fp` / `MPN_sym`).
|
|
Never type, store, or ask for their password, and never write credentials into this skill
|
|
— it's pushed to Skill_Assets, and a secret in a repo is a real leak (same reason the
|
|
`GIT_TOKEN` is blanked before syncing).
|
|
|
|
Whichever path, once you have a candidate **cross-check** its pad/pin count and key
|
|
package dimensions against the datasheet's package drawing before trusting it — library
|
|
models are sometimes wrong, or drawn for a different variant of the series.
|
|
|
|
3. **If no good model exists, generate the footprint/symbol yourself** as Altium files
|
|
from the datasheet's package drawing and pinout — but only when you can do it reliably
|
|
— then **ask the user to verify** it against the datasheet before it's trusted, since a
|
|
generated land pattern that's slightly off is worse than an obvious blank.
|
|
|
|
4. **If none of that is possible**, still create the folder with the datasheet and **tell
|
|
the user that MPN needs a manual footprint/symbol build**, leaving a clearly-named
|
|
placeholder or listing it so nothing silently goes missing.
|
|
|
|
Keep the datasheet's extension on `MPN_data` (e.g. `BAT46WJ_data.pdf`). Name the
|
|
footprint/symbol files `MPN_fp` / `MPN_sym` with the Altium extension the model uses
|
|
(`.PcbLib` / `.SchLib`, or a single `.IntLib` when the source bundles both).
|
|
|
|
## Pushing to Gitea
|
|
|
|
Connection + repos are pre-configured in `config/gitea.env` (host, user, token, and the
|
|
three repos), so runs need no per-session token. Layout is **flat** (no project/version).
|
|
|
|
**Every run ends by pushing all three repos — no "shall I push?" step.** The user has
|
|
already asked for this to be automatic; don't re-ask. The reconcile step self-guards
|
|
against the one risky case (overwriting an existing part), so a straight push is safe by
|
|
default.
|
|
|
|
The three repos split into two kinds, and they're pushed differently:
|
|
|
|
- **DFS** and **Parameters** are **MPN-indexed** — DFS has one `MPN_make_typeid/` folder
|
|
per part; Parameters holds a **single master workbook** (`Components_Master.xlsx`) whose
|
|
type sheets each have one row per part (keyed on column A). Because a re-run can collide
|
|
with a part that's already there, these go through `scripts/gitea_reconcile.py`, which is
|
|
dedup-aware and **merge-safe** (it never blows away parts it isn't touching). See
|
|
*Handling parts already in Gitea* below.
|
|
- **Skill_Assets** holds the skill itself + templates — it is **not** per-part, so there's
|
|
nothing MPN-level to reconcile. Push it with `scripts/push_to_gitea.sh` as before.
|
|
|
|
```bash
|
|
# Skill files + templates -> Skill_Assets (flat copy; no dedup needed)
|
|
bash scripts/push_to_gitea.sh --repo "$SKILL_ASSETS_REPO" --src <skill-dir> --message "Sync skill assets"
|
|
```
|
|
|
|
The push script clones the repo, copies the source contents in (flat), commits, and
|
|
pushes; the repo must already exist. If the host is unreachable (e.g. Cowork without the
|
|
domain allowlisted) it fails clearly and leaves the staged files for a manual push.
|
|
|
|
**Push the skill files organised** to Skill_Assets: keep the skill's own structure
|
|
(`SKILL.md`, `scripts/`, `assets/`, `references/`, `config/`) — but do **not** push the
|
|
real token. Before syncing skill assets, blank the `GIT_TOKEN` line in the copy you push,
|
|
or push everything except `config/gitea.env`.
|
|
|
|
> Why not push Parameters with the flat script? `fill_templates.py` writes a master
|
|
> workbook holding **only this run's** rows. Copied flat over the repo, it would overwrite
|
|
> the stored master and delete every previously-stored part. `gitea_reconcile.py` opens the
|
|
> repo's master, merges this run's rows into the right sheets, and writes it back — so only
|
|
> the parts you decided on change, and the Meta sheet (totals, date, time) refreshes.
|
|
|
|
## Handling parts already in Gitea (discard vs replace)
|
|
|
|
A part's identity is its tag `MPN_make_typeid` (same tag = same part). A re-run that
|
|
brings in a *new* MPN is not a conflict — it just gets added, and you push without asking.
|
|
The prompt only exists for the case where an MPN **already lives in DFS/Parameters**,
|
|
because "replace" overwrites data that's already on the server.
|
|
|
|
The simplest path is a single push. It clones the repos, adds everything new, and stops
|
|
**only** if it hits an existing MPN it can't resolve on its own:
|
|
|
|
```bash
|
|
python scripts/gitea_reconcile.py --parts parts.json --dfs-src <dfs-stage> \
|
|
--template assets/template/template.xlsx --push
|
|
```
|
|
|
|
- **No existing MPNs** → it adds all the folders/rows and pushes. No prompt. Done.
|
|
- **An MPN already exists** → it refuses (listing which) so you can ask the user, per MPN,
|
|
**discard** (keep what's in Gitea, drop the new copy) or **replace** (overwrite that MPN's
|
|
DFS folder *and* its Parameters row with the fresh extraction). Every other folder/row is
|
|
always left alone — the Parameters sheet is merged, never wholesale-overwritten.
|
|
|
|
Feed the user's answers back as a small JSON map (`tag → replace|discard`):
|
|
|
|
```bash
|
|
# decisions.json e.g. {"BAT46WJ_Nexperia_SCH": "replace", "1N4148_onsemi_SCH": "discard"}
|
|
python scripts/gitea_reconcile.py --parts parts.json --dfs-src <dfs-stage> \
|
|
--template assets/template/template.xlsx --decisions decisions.json --push
|
|
```
|
|
|
|
**For fully unattended runs**, skip the prompt entirely with a standing policy — every
|
|
conflict resolved the same way, no questions:
|
|
|
|
```bash
|
|
python scripts/gitea_reconcile.py --parts parts.json --dfs-src <dfs-stage> \
|
|
--template assets/template/template.xlsx --on-conflict replace --push
|
|
```
|
|
|
|
`--on-conflict replace` (or `discard`) applies to all conflicts; an explicit per-MPN entry
|
|
in `--decisions` still wins over the blanket policy. Use `--report conflicts.json` (without
|
|
`--push`) if you ever want to preview conflicts first. Host unreachable → it fails clearly,
|
|
same as the push script.
|
|
|
|
## Updating a template (new parameter)
|
|
|
|
When the user wants a new parameter on a type, **append it at the end** of that type's
|
|
sheet and bump the version:
|
|
|
|
```bash
|
|
python scripts/append_parameter.py --type Diode --param "Reverse Recovery Time(ns)" \
|
|
--template assets/template/template.xlsx
|
|
```
|
|
|
|
This adds the column at the end and increments `assets/template/VERSION` (v1 → v2 → …).
|
|
Then **push the updated `assets/template/template.xlsx` + `VERSION` to the Skill_Assets
|
|
repo** so the new template version is archived. New masters record the new version in the
|
|
Meta sheet automatically.
|
|
|
|
## Resources
|
|
|
|
- `assets/template/template.xlsx` — master template, one sheet per type (source of headers,
|
|
styling, and sheet order the master workbook mirrors).
|
|
- `assets/template/Type_ID.xlsx` + `references/taxonomy.md` — Class → Subclass → Type ID.
|
|
- `assets/template/VERSION` — current template version (integer; the Meta sheet shows `vN`).
|
|
- `scripts/fill_templates.py` — build the single master workbook `Components_Master.xlsx`
|
|
(only sheets for the extracted types + a trailing Meta sheet); also exposes the shared
|
|
helpers (`part_to_row`, `template_headers`, `sheet_rows`, `read_all_rows`, `build_master`,
|
|
`MASTER_NAME`) the reconcile step reuses so the Gitea master is built and merged identically.
|
|
- `scripts/gitea_reconcile.py` — add new MPNs and push automatically; only stops on an MPN
|
|
that already exists (discard/replace), or run unattended with `--on-conflict replace`.
|
|
Merge-safe: merges into the repo's master workbook, other rows/sheets/folders untouched.
|
|
- `scripts/push_to_gitea.sh` — push a folder's contents to a Gitea repo (flat). Used for
|
|
Skill_Assets (not MPN-indexed).
|
|
- `scripts/append_parameter.py` — append a parameter to a template + bump version.
|
|
- `scripts/fetch_cad.py` — download Altium footprint/symbol by attaching to the user's
|
|
pre-logged-in Chrome (remote-debugging port); tries sites in order, defers on
|
|
CAPTCHA/login (never bypasses), and names files `MPN_fp`/`MPN_sym`. Runs on the user's
|
|
machine; needs `selenium`.
|
|
- `config/gitea.env` — host, user, token, and the DFS / Parameters / Skill_Assets repos (**secret**).
|