Adapt Pinscope to DeepSeek, auto datasheets, and a shared library.
Based on manvalan/pinscope main. Default LLM is DeepSeek with local skills and PDF ingest. Datasheets are fetched from LCSC/TI, stored in the component library, and review extracts abs-max with a deeper checklist. Adds scripts/update-pinscope.sh for the production host.
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
"""Shared component library: persist datasheets, catalog listing."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from backend.services import projects as proj_svc
|
||||
from backend.services.datasheet_store import resolve_datasheet
|
||||
from backend.services.storage import LocalStorageBackend
|
||||
|
||||
|
||||
PDF = b"%PDF-1.4\n" + b"x" * 8000
|
||||
|
||||
|
||||
def _client(tmp_path) -> TestClient:
|
||||
from backend.main import app
|
||||
|
||||
app.state.storage = LocalStorageBackend(tmp_path)
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
def test_save_datasheet_also_stores_in_library(storage):
|
||||
meta = proj_svc.create_project(storage, "local", "board")
|
||||
key = proj_svc.save_datasheet(storage, "local", meta.id, "CH340E", PDF)
|
||||
assert key.endswith("CH340E.pdf")
|
||||
assert storage.exists(key)
|
||||
assert resolve_datasheet(storage, "CH340E")
|
||||
assert proj_svc.library_has_datasheet(storage, "CH340E")
|
||||
|
||||
|
||||
def test_library_catalog_lists_ics_passives_and_pdfs(storage):
|
||||
storage.write_json(
|
||||
"library/extracted/CH340E.json",
|
||||
{
|
||||
"mpn": "CH340E",
|
||||
"pintable": [{"pin": 1}, {"pin": 2}],
|
||||
"component_subtype": "usb-uart",
|
||||
"absolute_maximum_ratings": {"vcc": "5V"},
|
||||
},
|
||||
)
|
||||
storage.write_json(
|
||||
"library/patterns/samsung_c.json",
|
||||
{
|
||||
"name": "Samsung CL10",
|
||||
"component_type": "capacitor",
|
||||
"description": "Samsung 0603 MLCC",
|
||||
"regex": r"^CL10",
|
||||
},
|
||||
)
|
||||
storage.write_json(
|
||||
"library/passives/CL10B474KA8NNNC.json",
|
||||
{
|
||||
"mpn": "CL10B474KA8NNNC",
|
||||
"specs": {
|
||||
"specs_type": "capacitor",
|
||||
"component_subtype": "mlcc",
|
||||
"values": {"capacitance": "470n"},
|
||||
},
|
||||
},
|
||||
)
|
||||
proj_svc.remember_datasheet(storage, "CH340E", PDF)
|
||||
|
||||
cat = proj_svc.list_library_catalog(storage)
|
||||
assert len(cat["ics"]) == 1
|
||||
assert cat["ics"][0]["mpn"] == "CH340E"
|
||||
assert cat["ics"][0]["pin_count"] == 2
|
||||
assert cat["ics"][0]["has_datasheet"] is True
|
||||
assert cat["passives"][0]["mpn"] == "Samsung CL10"
|
||||
assert cat["simple"][0]["mpn"] == "CL10B474KA8NNNC"
|
||||
assert any(d["mpn"] == "CH340E" and d["has_extraction"] for d in cat["datasheets"])
|
||||
|
||||
|
||||
def test_library_http_catalog_and_pdf(tmp_path):
|
||||
client = _client(tmp_path)
|
||||
empty = client.get("/api/library")
|
||||
assert empty.status_code == 200
|
||||
body = empty.json()
|
||||
assert body["ics"] == []
|
||||
assert body["datasheets"] == []
|
||||
|
||||
meta = client.post("/api/projects", json={"name": "lib"}).json()
|
||||
resp = client.post(
|
||||
f"/api/projects/{meta['id']}/upload/datasheets",
|
||||
params={"mpn": "MSPM0G3507"},
|
||||
files={"file": ("msp.pdf", PDF, "application/pdf")},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
|
||||
catalog = client.get("/api/library").json()
|
||||
assert any(d["mpn"] == "MSPM0G3507" for d in catalog["datasheets"])
|
||||
|
||||
pdf = client.get("/api/library/datasheet/MSPM0G3507")
|
||||
assert pdf.status_code == 200
|
||||
assert pdf.content.startswith(b"%PDF-")
|
||||
|
||||
|
||||
def test_fetch_datasheet_persists_to_library(tmp_path, monkeypatch):
|
||||
from backend.services.datasheet_finder import DatasheetHit
|
||||
|
||||
async def fake_find(mpn, lcsc_id=None):
|
||||
return DatasheetHit(
|
||||
mpn,
|
||||
pdf_bytes=PDF,
|
||||
url="https://datasheet.lcsc.com/x.pdf",
|
||||
source="lcsc",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"backend.services.datasheet_finder.find_datasheet", fake_find,
|
||||
)
|
||||
client = _client(tmp_path)
|
||||
resp = client.get("/api/datasheets/fetch", params={"mpn": "CH340E"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.content.startswith(b"%PDF-")
|
||||
|
||||
catalog = client.get("/api/library").json()
|
||||
assert any(d["mpn"] == "CH340E" for d in catalog["datasheets"])
|
||||
assert client.get("/api/library/datasheet/CH340E").status_code == 200
|
||||
Reference in New Issue
Block a user