FastAPI app that parses CMM inspection reports (PDF/Excel/CSV), computes SPC metrics (Cp/Cpk/Pp/Ppk, control limits, Shapiro-Wilk), generates interactive Plotly charts, and provides AI-powered quality summaries via Azure OpenAI with graceful fallback. Includes 21 passing tests covering parsers, SPC calculations, and API endpoints.
87 lines
3.3 KiB
Python
87 lines
3.3 KiB
Python
from __future__ import annotations
|
||
|
||
import plotly.graph_objects as go
|
||
|
||
from app.analysis.spc import SPCResult
|
||
|
||
|
||
def histogram(result: SPCResult) -> dict:
|
||
"""Distribution histogram with spec limits overlay."""
|
||
fig = go.Figure()
|
||
fig.add_trace(go.Histogram(x=result.values, name="Measurements", nbinsx=20))
|
||
fig.add_vline(x=result.usl, line_dash="dash", line_color="red",
|
||
annotation_text="USL")
|
||
fig.add_vline(x=result.lsl, line_dash="dash", line_color="red",
|
||
annotation_text="LSL")
|
||
fig.add_vline(x=result.nominal, line_dash="dot", line_color="green",
|
||
annotation_text="Nominal")
|
||
fig.update_layout(
|
||
title=f"Distribution – {result.feature_name}",
|
||
xaxis_title="Value", yaxis_title="Count",
|
||
template="plotly_white", height=350,
|
||
)
|
||
return fig.to_plotly_json()
|
||
|
||
|
||
def control_chart(result: SPCResult) -> dict:
|
||
"""Individual values control chart (I-chart)."""
|
||
x_axis = list(range(1, result.n + 1))
|
||
fig = go.Figure()
|
||
fig.add_trace(go.Scatter(
|
||
x=x_axis, y=result.values, mode="lines+markers", name="Value",
|
||
))
|
||
fig.add_hline(y=result.mean, line_color="green", annotation_text="Mean")
|
||
fig.add_hline(y=result.ucl, line_dash="dash", line_color="red",
|
||
annotation_text="UCL")
|
||
fig.add_hline(y=result.lcl, line_dash="dash", line_color="red",
|
||
annotation_text="LCL")
|
||
fig.add_hline(y=result.usl, line_dash="dot", line_color="orange",
|
||
annotation_text="USL")
|
||
fig.add_hline(y=result.lsl, line_dash="dot", line_color="orange",
|
||
annotation_text="LSL")
|
||
fig.update_layout(
|
||
title=f"Control Chart – {result.feature_name}",
|
||
xaxis_title="Sample #", yaxis_title="Value",
|
||
template="plotly_white", height=350,
|
||
)
|
||
return fig.to_plotly_json()
|
||
|
||
|
||
def capability_bar(results: list[SPCResult]) -> dict:
|
||
"""Capability index bar chart comparing all features."""
|
||
names = [r.feature_name for r in results]
|
||
cpk_vals = [r.cpk if r.cpk is not None else 0.0 for r in results]
|
||
ppk_vals = [r.ppk if r.ppk is not None else 0.0 for r in results]
|
||
|
||
colors = ["#2ecc71" if v >= 1.33 else "#f39c12" if v >= 1.0 else "#e74c3c"
|
||
for v in cpk_vals]
|
||
|
||
fig = go.Figure()
|
||
fig.add_trace(go.Bar(x=names, y=cpk_vals, name="Cpk", marker_color=colors))
|
||
fig.add_trace(go.Bar(x=names, y=ppk_vals, name="Ppk", marker_color="rgba(52,152,219,0.6)"))
|
||
fig.add_hline(y=1.33, line_dash="dash", line_color="green",
|
||
annotation_text="Cpk=1.33")
|
||
fig.add_hline(y=1.0, line_dash="dot", line_color="orange",
|
||
annotation_text="Cpk=1.0")
|
||
fig.update_layout(
|
||
title="Process Capability Summary",
|
||
xaxis_title="Feature", yaxis_title="Index",
|
||
barmode="group", template="plotly_white", height=400,
|
||
)
|
||
return fig.to_plotly_json()
|
||
|
||
|
||
def generate_charts(results: list[SPCResult]) -> dict:
|
||
"""Generate all charts for a set of SPC results."""
|
||
charts: dict[str, list[dict] | dict] = {
|
||
"histograms": [],
|
||
"control_charts": [],
|
||
}
|
||
for r in results:
|
||
if r.n >= 2:
|
||
charts["histograms"].append(histogram(r))
|
||
charts["control_charts"].append(control_chart(r))
|
||
if results:
|
||
charts["capability_bar"] = capability_bar(results)
|
||
return charts
|