Default to DeepSeek V4.1 Flash, show API cost in USD, and re-analyze after replacing BOM and netlist.

V4.1 is natively multimodal so every stage uses deepseek-flash; pricing and the UI now surface dollars instead of empty credits. KiCad netlists and neighborhood fingerprints land in the same cut so a second run can keep the project and skip unchanged ICs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-10 20:55:35 +02:00
co-authored by Cursor
parent d454cf75af
commit 61f85f519b
29 changed files with 1174 additions and 118 deletions
+59
View File
@@ -0,0 +1,59 @@
from backend.pinscopex.models import (
Component,
ComponentType,
DesignGraph,
Net,
NetType,
PinConnection,
)
from backend.pinscopex.review_fingerprint import (
graph_ic_fingerprints,
skip_unchanged_ics,
)
def _g():
u1 = Component(
reference="U1", value="", footprint="",
component_type=ComponentType.IC, mpn="IC1",
pins={"1": "3V3", "2": "SDA"},
)
r1 = Component(
reference="R1", value="4k7", footprint="",
component_type=ComponentType.RESISTOR, mpn="R",
pins={"1": "SDA", "2": "3V3"},
)
return DesignGraph(
components={"U1": u1, "R1": r1},
nets={
"3V3": Net(name="3V3", net_type=NetType.POWER, pins=[
PinConnection(component_ref="U1", pin_number="1"),
PinConnection(component_ref="R1", pin_number="2"),
]),
"SDA": Net(name="SDA", net_type=NetType.SIGNAL, pins=[
PinConnection(component_ref="U1", pin_number="2"),
PinConnection(component_ref="R1", pin_number="1"),
]),
},
)
def test_fingerprint_changes_when_neighbor_added():
g = _g()
fp1 = graph_ic_fingerprints(g)["U1"]
c2 = Component(
reference="C1", value="100n", footprint="",
component_type=ComponentType.CAPACITOR, mpn="C",
pins={"1": "3V3", "2": "GND"},
)
g.components["C1"] = c2
g.nets["3V3"].pins.append(PinConnection(component_ref="C1", pin_number="1"))
fp2 = graph_ic_fingerprints(g)["U1"]
assert fp1 != fp2
def test_skip_unchanged_drops_changed_refs():
prev = {"U1": "aaa", "U2": "bbb"}
cur = {"U1": "aaa", "U2": "ccc"}
skip = skip_unchanged_ics({"U1", "U2"}, prev, cur)
assert skip == {"U1"}