1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/vendor-ai-LcOSHxZq.js","assets/vendor-react-Mjzju8Fo.js"])))=>i.map(i=>d[i]); 2import{j as e}from"./vendor-ui-WIutmQvu.js";import{r as w}from"./vendor-react-Mjzju8Fo.js";import{C as U,B as de,y as wt,w as st,p as G,n as J,o as Q,_ as vt,b as ae}from"./index-CGeKhxlS.js";import{D as Nt}from"./DashboardPageLayout-BDYR88x8.js";import{P as Ct}from"./ProcessingOverlay-evG_HBZ3.js";import{P as At}from"./PrivacyBadge-DGgCDIWT.js";import{cY as St,bA as Ae,aD as Rt,dt as Tt,aB as ot,aL as Se,bD as Re,ct as Ft,aV as It,aA as kt,cZ as Dt,cb as at,cl as nt,bz as Mt,aJ as Lt}from"./ToolLoadingSkeleton-BoTumGG9.js";import{U as Et}from"./useWhiteLabel-3vub9u51.js";import{y as Le,$ as te,bp as Ot,v as ce,a5 as Ve,a6 as Ke,a7 as Ge,a8 as He,a9 as ue,ar as pe,P as _t,V as zt,cC as Pt,ab as $t,ac as Ut,T as Bt}from"./ToolShell-Cj1RulUX.js";import{C as Yt}from"./checkbox-RmNFHI00.js";import{S as Vt}from"./SectionHelpDialog-e0h1wWDm.js";import{S as Kt}from"./separator-DrbQlTgs.js";import{C as Gt,a as Ht,b as qt}from"./collapsible-i4zlFhDZ.js";import{C as rt}from"./calendar-C5nEUwlL.js";import{m as ke}from"./toolIconMap-BbtlN4gT.js";import{S as Wt}from"./settings-DfUKR5RB.js";import{T as it,a as lt,b as xe,c as ne,d as ct,e as Z}from"./table-BxaeIIo_.js";import{p as Xt}from"./pcaProjection-BLEtc8OC.js";import{R as je,S as dt,C as be,X as we,Y as ve,T as Ne,o as mt,H as De,k as ht,B as qe,j as We}from"./vendor-charts-Dtasu9Ii.js";import{R as Zt}from"./reset-button-BGVfFqt7.js";import{u as Jt}from"./useFileLoader-4_J3GMz-.js";import{L as Qt}from"./LargeDatasetHandler-DrR0Pk3m.js";import{u as es}from"./useAnalysisCache-BxDbiygZ.js";import{a as ts}from"./datasetDigest-yhPemAuh.js";import{a as ss,b as os,s as Xe,c as as}from"./statHelpers-BPWyQTE9.js";import{m as ns,f as rs}from"./truncation-DX7k8PX-.js";import{S as Ee,a as Oe,r as is}from"./analyticValue-DfkeHOsA.js";import{T as ls}from"./TruncationBanner-DKW30tHo.js";import{A as cs}from"./AIAnalysisSuggestions-6rZA8gYM.js";import{R as ds}from"./ReportHistoryPanel-BMQWyXqc.js";import{u as ms}from"./useUniversalAI-UcnUR_vm.js";import{A as hs}from"./AIInsightsPanel-B5272VRh.js";import{u as us}from"./useBrainTraining-BEX9vhfu.js";import{B as ps}from"./BrainTrainingStatus-TPHpMowG.js";import"./vendor-ai-LcOSHxZq.js";import"./vendor-data-DfX1IQMU.js";import{A as xs}from"./AmBestPracticesPanel-DSwFFlyS.js";import{u as fs}from"./useToolNarrative-Bb6ihplS.js";import{n as gs}from"./aiNarrativeReportSection-Bv6Y65fZ.js";import{b as ys,a as js}from"./predictiveMlKpis-B6CHrIBS.js";import"./vendor-supabase-4AdVcAsc.js";import"./EnterprisePageHeader-CtAQ7jpB.js";import"./SEO-CUKSF61s.js";import"./userBrainLoader-61slGmfL.js";import"./index-BFAz8H1a.js";import"./trending-down-ChmSmJyA.js";import"./package-DIcsIJtw.js";import"./copy-C-9BUvXl.js";import"./useToolReset-DSS0G6sO.js";import"./rotate-ccw-BpsxbSaS.js";import"./useDataWorker-CGfdnIeB.js";import"./demoAccessGuard-CRWjDrXP.js";import"./dataProcessingConfig-DAJSaH9g.js";import"./centralizedDataHandler-CIjlIF4h.js";import"./dataSampling-BLby5lRG.js";import"./columnFillStats-C7YBe9Ri.js";import"./radio-group-D-LJwyJ2.js";import"./resolveClientPath-WlVc4fwr.js";import"./industryContext-Wq2pxxo3.js";import"./formatDistanceToNow-cjMq7XX2.js";import"./getRoundingMethod-DCA_wHQN.js";import"./en-US-DG8oYhKj.js";import"./endOfMonth-CUa0PFDd.js";import"./aiTierConfig-CBqBc7fJ.js";import"./tabs-CCPzWN16.js";import"./minus-DCVssX1V.js";import"./blockedFieldGuard-CchPMkRM.js";const bs=.15,ws=t=>Number.isFinite(t)?Math.min(1,Math.max(0,t)):0;function vs(t,o,a){const i=a>1e-9?a:1,m=ws(Math.abs(t-o)/i);return{confidence:+m.toFixed(4),borderline:m<bs}}function Ns(t){if(t.length===0)return 1;let o=t[0],a=t[0];for(const i of t)i<o&&(o=i),i>a&&(a=i);return a-o}const _e="Every scored row carries a confidence (distance from the deciding boundary) and a borderline flag. Borderline rows would flip under a small threshold change â treat the label as a suggestion, not a fact.",Ze=`server_id,cpu_usage,memory_gb,response_time_ms,error_rate,requests_per_sec 3srv-01,45,6.2,120,0.02,850 4srv-02,52,7.1,135,0.03,920 5srv-03,38,5.8,110,0.01,780 6srv-04,48,6.5,125,0.02,870 7srv-05,99,15.8,520,0.45,1200 8srv-06,41,5.9,115,0.02,810 9srv-07,55,7.3,140,0.03,940 10srv-08,43,6.1,118,0.01,830 11srv-09,50,6.8,130,0.02,890 12srv-10,47,6.4,122,0.02,860 13srv-11,39,5.7,108,0.01,770 14srv-12,53,7.0,132,0.03,910 15srv-13,44,6.3,121,0.02,840 16srv-14,15,2.1,95,0.35,50 17srv-15,51,6.9,128,0.02,900 18srv-16,46,6.5,124,0.02,850 19srv-17,40,5.8,112,0.01,790 20srv-18,54,7.2,138,0.03,930 21srv-19,42,6.0,116,0.02,820 22srv-20,49,6.7,127,0.02,880 23srv-21,37,5.6,105,0.01,760 24srv-22,56,7.4,142,0.03,950 25srv-23,58,7.0,380,0.28,900 26srv-24,43,6.1,119,0.02,835 27srv-25,50,6.8,131,0.02,895 28srv-26,45,6.3,120,0.02,845 29srv-27,47,6.5,123,0.02,855 30srv-28,41,5.9,114,0.01,800 31srv-29,95,14.2,450,0.01,1180 32srv-30,52,7.1,134,0.03,915`,Cs=[{icon:Tt,title:"Isolation Forest",desc:"Tree-based anomaly detection that isolates unusual records"},{icon:ot,title:"Neural Autoencoder",desc:"Deep learning model that learns normal patterns to spot deviations"},{icon:Se,title:"Feature Contributions",desc:"See which columns made each record suspicious"},{icon:Re,title:"Method Comparison",desc:"Compare which anomalies are caught by multiple algorithms"}],As=({onFileUpload:t})=>{const{toast:o}=St(),a=s=>{s.preventDefault();const l=s.dataTransfer.files[0];l&&t(l)},i=s=>{const l=s.target.files?.[0];l&&t(l)},m=()=>{const s=new Blob([Ze],{type:"text/csv"}),l=new File([s],"server_metrics_sample.csv",{type:"text/csv"});t(l),o({title:"Sample Data Loaded",description:"30 rows of server metrics with 3 planted anomalies loaded"})},y=()=>{const s=new Blob([Ze],{type:"text/csv"}),l=URL.createObjectURL(s),f=document.createElement("a");f.href=l,f.download="server_metrics_sample.csv",f.click(),URL.revokeObjectURL(l)};return e.jsxs("div",{className:"space-y-8",children:[e.jsx(U,{className:"border-2 border-dashed border-muted-foreground
32/25 hover:border-primary/50 transition-colors cursor-pointer",onDragOver:s=>s.preventDefault(),onDrop:a,children:e.jsxs("label",{htmlFor:"anomaly-upload",className:"flex flex-col items-center justify-center py-16 cursor-pointer",children:[e.jsx("div",{className:"w-16 h-16 rounded-2xl bg-primary/10 flex items-center justify-center mb-4",children:e.jsx(Ae,{className:"h-8 w-8 text-primary"})}),e.jsx("h3",{className:"text-lg font-semibold text-foreground mb-1",children:"Upload your dataset"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-4",children:"Detect anomalies across multiple dimensions using Isolation Forest or Autoencoders"}),e.jsxs("div",{className:"flex gap-2 flex-wrap justify-center",children:[e.jsxs(de,{variant:"outline",size:"sm",className:"pointer-events-none",children:[e.jsx(Et,{className:"h-4 w-4 mr-2"}),"Browse Files"]}),e.jsxs(de,{variant:"secondary",size:"sm",className:"pointer-events-auto",onClick:s=>{s.preventDefault(),m()},children:[e.jsx(Rt,{className:"h-4 w-4 mr-2"}),"Try Sample Data"]}),e.jsxs(de,{variant:"ghost",size:"sm",className:"pointer-events-auto",onClick:s=>{s.preventDefault(),y()},children:[e.jsx(Le,{className:"h-4 w-4 mr-2"}),"Download Sample"]})]}),e.jsx("input",{id:"anomaly-upload",type:"file",accept:".csv,.xlsx,.xls",onChange:i,className:"hidden"}),e.jsx(At,{})]})}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-semibold text-muted-foreground uppercase tracking-wider mb-4",children:"What You'll Get"}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",children:Cs.map(s=>e.jsxs(U,{className:"p-4 space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(s.icon,{className:"h-4 w-4 text-primary"}),e.jsx("span",{className:"text-sm font-medium text-foreground",children:s.title})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:s.desc})]},s.title))})]})]})},ut={algorithmSettings:{icon:e.jsx(Wt,{className:"h-4 w-4"}),title:"Algorithm Settings â Choosing the Right Method",shortDesc:"Understand the 3 anomaly detection algorithms and when to use each.",details:`Three algorithms are available, each with different strengths: 33 34⢠Isolation Forest â Randomly partitions data using decision trees. Anomalies require fewer splits to isolate, so they get shorter paths. Best for: tabular data with clear outliers. Fast, no training needed. Configurable via 'Number of Trees' (more trees = more stable scores). 35 36⢠Autoencoder (TF.js) â A neural network that compresses data into a small latent space and reconstructs it. Normal data reconstructs well; anomalies produce high reconstruction error. Best for: complex, high-dimensional data with non-linear patterns. Slower (requires training epochs). Configurable via 'Training Epochs' (more = better learning, but risk of overfitting). 37 38⢠Local Outlier Factor (LOF) â Compares each point's local density to its neighbors' density. Points in sparse regions relative to neighbors are anomalies. Best for: clustered data where anomalies live in low-density regions. Configurable via 'K Neighbors' (higher K = smoother boundaries, lower K = more sensitive).`,whatYouGet:"An anomaly score (0-1) for every record. Higher scores mean more anomalous. The algorithm assigns scores based on how 'different' each record is from the majority. A threshold (based on contamination %) splits records into normal vs. anomaly.",businessUse:"Choose Isolation Forest for fast, general-purpose scanning (fraud detection, quality control). Use Autoencoder for complex patterns (network intrusion, manufacturing sensor data). Use LOF when anomalies exist in context (a $500 purchase is normal for corporate cards but anomalous for personal cards).",tip:"Start with Isolation Forest â it's fastest and works well in most cases. Only switch to Autoencoder if you suspect complex non-linear patterns, or LOF if context matters more than absolute values."},featureSelection:{icon:e.jsx(nt,{className:"h-4 w-4"}),title:"Feature Selection",shortDesc:"Choose which numeric columns the algorithm uses to detect anomalies.",details:"Select 2 or more numeric features that the algorithm will analyze for unusual patterns. The algorithm considers all selected features simultaneously â a record might look normal on any single feature but be anomalous when features are combined (multivariate anomalies). Non-numeric columns are excluded automatically.",whatYouGet:"Multivariate anomaly detection across your selected feature space. The more relevant features you include, the more patterns the algorithm can detect. But including irrelevant features adds noise and can mask true anomalies.",businessUse:"Select features that represent the behavior you want to monitor. For fraud detection: select transaction amount, frequency, time-of-day. For manufacturing: select sensor readings, temperature, pressure. Excluding irrelevant features (like IDs or names) improves detection quality.",tip:"Start with 3-5 strongly related features rather than all available columns. Too many features dilute the signal. Use the Feature Importance chart after detection to see which features actually drove the anomaly scores."},contamination:{icon:e.jsx(ke,{className:"h-4 w-4"}
38),title:"Contamination Rate",shortDesc:"The expected percentage of anomalies in your data.",details:"Contamination sets the anomaly threshold: a 5% contamination means the algorithm labels the top 5% highest-scoring records as anomalies. This is a prior assumption â you're telling the algorithm 'I expect roughly X% of my data to be unusual.' Lower contamination = stricter threshold (only the most extreme outliers). Higher contamination = more records flagged.",whatYouGet:"Direct control over the sensitivity of detection. A 2% contamination catches only the most extreme outliers. A 10% contamination casts a wider net, catching subtle anomalies but also more false positives.",businessUse:"Set contamination based on domain knowledge. In fraud detection, typical fraud rates are 1-3%. In manufacturing defect detection, 2-5% is common. In data quality auditing, 5-10% may be appropriate. When unsure, start at 5% and adjust using the Threshold Tuner after results.",tip:"The contamination rate is a starting point â use the Interactive Threshold Tuner in the results to fine-tune without re-running the algorithm."},summaryCards:{icon:e.jsx(Ae,{className:"h-4 w-4"}),title:"Detection Summary",shortDesc:"Key metrics from your anomaly detection run at a glance.",details:`Four summary cards show: (1) Anomalies Found â total count of records flagged as anomalous. (2) Anomaly Rate â percentage of total records that are anomalies. (3) Threshold â the score cutoff used to separate normal from anomalous (records scoring above this are flagged). (4) Training Time â how long the detection algorithm took to run. 39 40For Isolation Forest: threshold is derived from path length percentiles. For Autoencoder: threshold is based on reconstruction error percentiles. For LOF: threshold is derived from local outlier factor percentiles.`,whatYouGet:"Instant health check of your detection run. An anomaly rate of 1-5% is typical for most datasets. Rates above 10% suggest either genuinely n
40oisy data or too-high contamination. Very low rates (<0.5%) may mean the algorithm needs more features or a different method.",businessUse:"Report these numbers to stakeholders: 'We detected 342 anomalous transactions (2.1%) in 16,000 records using Isolation Forest.' The training time helps plan for recurring detection: 'Detection completes in 1.2s â suitable for hourly batch processing.'",tip:"If the anomaly rate seems too high or too low, don't re-run â use the Interactive Threshold Tuner to adjust the cutoff in real-time."},thresholdTuner:{icon:e.jsx(ke,{className:"h-4 w-4"}),title:"Interactive Threshold Tuner",shortDesc:"Adjust the anomaly cutoff in real-time without re-running the algorithm.",details:`A slider that lets you dynamically change the score threshold. Moving right (higher threshold) = stricter, fewer anomalies flagged. Moving left (lower threshold) = more lenient, more anomalies flagged. The anomaly count and percentage update instantly as you drag. All charts and tables below also reflect the new threshold. 41 42This works because the algorithm already scored every record â the threshold just determines which scores count as 'anomalous.' You're not re-running the detection, just moving the decision boundary.`,whatYouGet:"Real-time sensitivity control. Find the sweet spot between catching true anomalies (high recall) and avoiding false alarms (high precision). The instant feedback lets you experiment with different thresholds to match your business tolerance.",businessUse:"Critical for operationalizing anomaly detection. In fraud, a low threshold catches more fraud but generates more false alerts for the investigation team. Find the threshold where alert volume matches your team's capacity: 'At threshold 0.72, we get ~50 alerts/day â manageable for our 3-person review team.'",tip:"Look for a natural 'knee' in the score distribution â a point where scores jump sharply. This natural break point is often the best threshold."},scoreDistribution:{icon:e.jsx(Se,{className:"h-4 w-4"}),title:"Score Distribution",shortDesc:"Histogram showing how anomaly scores are distributed across all records.",details:`A 20-bucket histogram of anomaly scores (0% to 100%). Normal records cluster in the low-score region (left side). Anomalies appear in the high-score region (right side, colored red). The dashed vertical line marks the current threshold. 43 44For Isolation Forest: scores represent normalized path length (shorter paths = more anomalous). For Autoencoder: scores represent normalized reconstruction error (higher error = more anomalous). For LOF: scores represent the local outlier factor (higher factor = more anomalous).`,whatYouGet:"Visual understanding of your data's anomaly landscape. A clear bimodal distribution (two peaks) means anomalies are well-separated â the algorithm works well. A single peak with a long tail means anomalies are subtle â consider using a different algorithm or more features.",businessUse:"Share this chart with stakeholders to show detection confidence: 'Clear separation between normal and anomalous scores â high confidence in flagged records.' A smooth, gradual distribution means borderline cases exist and some flagged records may need manual review.",tip:"If all scores cluster in a narrow range with no clear separation, the selected features may not contain the anomaly signal. Try adding or changing features."},pcaProjection:{icon:e.jsx(at,{className:"h-4 w-4"}),title:"PCA 2D Projection",shortDesc:"Visualize anomalies in a 2D space derived from all features.",details:`Principal Component Analysis (PCA) reduces your multi-dimensional feature space to 2 dimensions (PC1 and PC2) for visualization. Each dot is a record. Green = normal, Red
44= anomaly. The percentage labels (e.g., 'PC1: 45%') show how much of the original data's variance each component captures. 45 46Anomalies that appear far from the green cluster are 'globally' unusual. Anomalies embedded within the green cluster are 'contextually' unusual (detected via features not captured in the 2D view).`,whatYouGet:"Spatial understanding of where anomalies sit relative to normal data. Well-separated red dots indicate strong anomalies. Red dots mixed with green suggest the anomalies are subtle and might need domain expert review.",businessUse:"Use this visualization in reports to show spatial separation of anomalies. 'Fraudulent transactions cluster in the upper-right quadrant, far from normal activity.' Helps non-technical stakeholders intuitively understand detection results.",tip:"If variance explained (PC1 + PC2) is below 50%, the 2D projection is losing too much information â some anomalies may not be visually separable even though the algorithm detected them correctly in full-dimensional space."},temporalChart:{icon:e.jsx(rt,{className:"h-4 w-4"}),title:"Anomalies Over Time",shortDesc:"Timeline view showing when anomalies occurred in your data.",details:`A scatter plot with time on the X-axis and anomaly score on the Y-axis. Each dot is a record, positioned at its timestamp. Red dots (above threshold) are flagged anomalies. Green dots (below threshold) are normal. The horizontal dashed line marks the threshold. 47 48This chart only appears when a date/time column is detected in your data. It reveals temporal patterns: spikes in anomalies at certain times, gradual increases, or seasonal patterns.`,whatYouGet:"Temporal context for anomalies. Instead of just knowing 'record #5678 is anomalous,' you see 'a cluster of anomalies occurred in March 2024.' This enables root cause investigation: what changed in March that caused a spike in unusual activity?",businessUse:"Essential for incident investigation and trend monitoring. 'Anomaly rate spiked from 2% to 8% during Black Friday â likely due to unusual purchase patterns, not fraud.' Helps distinguish systemic issues (sustained high anomaly rate) from one-off events (single spike).",tip:"Clusters of anomalies at the same time period often indicate a shared root cause â investigate those periods as a group rather than individual records."},featureImportance:{icon:e.jsx(Dt,{className:"h-4 w-4"}),title:"Feature Importance",shortDesc:"Which features contributed most to detecting anomalies.",details:`A horizontal bar chart ranking features by their importance in the anomaly detection. Higher importance means that feature had more influence on the anomaly scores. 49 50For Isolation Forest: importance is based on how often each feature was used as a split point. For Autoencoder: importance is derived from reconstruction error per feature. For LOF: importance is based on which features show the most density variation. 51 52Importance values are normalized to 0-1 (1 = most important, 0 = no contribution).`,whatYouGet:"Clear understanding of WHY anomalies were flagged. If 'transaction_amount' has importance 0.85 and 'merchant_id' has 0.12, anomalies are primarily driven by unusual amounts. This focuses investigation: check the high-importance features first when reviewing flagged records.",businessUse:"Guides the investigation process: 'Focus review on transaction amount and frequency â these drove 80% of detections.' Also informs feature selection for future runs: drop low-importance features to reduce noise and improve detection speed.",tip:"If a feature you expected to be important ranks low, it may not vary enough in your data. Consider creating derived features (ratios, rolling averages) that better capture the behavior you want to monitor."},topAnomalies:{icon:e.jsx(kt,{className:"h-4 w-4"}),title:"Top Anomalies Table",shortDesc:"Detailed view of the most anomalous records with expandable explanations.",details:`A sortable table listing the top 50 highest-scoring anomalies. Each row shows: row number, anomaly score, and feature values. Click the expand arrow (â¸) on any row to see feature-level contributions â which specific features made this record anomalous and by how much. 53 54For Isolation Forest: contributions show which features caused shorter isolation paths. For Autoencoder: contributions show which features had the highest reconstruction error. For LOF: contributions show which features deviated most from local neighbors.`,whatYouGet:"Actionable drill-down into individual anomalies. The expandable explanations answer 'why is this record flagged?' â critical for deciding whether to act on each anomaly. A record might be flagged because of a single extreme feature value or because of an unusual combination of normal-looking values.",businessUse:"The primary investigation tool. Review the top anomalies, expand each to understand the cause, then decide: investigate, flag, or dismiss. Export the table with scores for downstream processing (e.g., sending to a case management system or fraud review queue).",tip:"Sort by score to review the most extreme anomalies first. Records with scores close to the threshold (borderline) are the ones most likely to be false positives â focus your limited review time on high-score records."},methodComparison:{icon:e.jsx(Re,{className:"h-4 w-4"}
54),title:"Method Comparison",shortDesc:"Side-by-side comparison of two detection algorithms on the same data.",details:`Runs both Isolation Forest and Autoencoder on identical data and compares results. Shows three groups: (1) Both Agree â records flagged by both methods (highest confidence). (2) Method 1 Only â flagged by Isolation Forest but not Autoencoder. (3) Method 2 Only â flagged by Autoencoder but not Isolation Forest. 55 56Consensus anomalies (both agree) are almost certainly true anomalies. Single-method anomalies may be false positives specific to that algorithm's detection style.`,whatYouGet:"Confidence-calibrated anomaly detection. The 'Both Agree' set is your high-confidence list â act on these first. Single-method anomalies require more investigation. The agreement rate tells you how consistent detection is: high agreement (>70%) means clear anomalies; low agreement (<30%) means subtle, method-dependent anomalies.",businessUse:"Use for critical decisions where false positives are costly. 'We only escalate records flagged by both methods â this reduces false positive rate by 60% compared to single-method detection.' The comparison also validates your primary method: if it agrees with the backup method on most anomalies, you can trust it.",tip:"Use 'Compare IF vs AE' when accuracy matters more than speed. For routine monitoring, pick one method. For high-stakes detection (fraud, safety), always compare methods."},exportScores:{icon:e.jsx(Le,{className:"h-4 w-4"}),title:"Export with Scores",shortDesc:"Download your full dataset enriched with anomaly scores and flags.",details:"Exports a CSV file containing all original data columns plus two new columns: 'anomaly_score' (0-1 score) and 'is_anomaly' (TRUE/FALSE based on current threshold). This enriched dataset can be imported into other tools, databases, or BI platforms for further analysis.",whatYouGet:"A ready-to-use dataset where every record has an anomaly classification. Feed this into dashboards (filter to is_anomaly=TRUE), case management systems (create investigation tickets), or further analysis tools (correlate anomaly scores with other business metrics).",businessUse:"Operationalizes detection results. Import the scored dataset into your BI tool to create anomaly monitoring dashboards. Set up alerts when anomaly rates exceed thresholds. Build historical trend anal
56ysis: 'Anomaly rate decreased from 5% to 2% after we fixed the data pipeline.'",tip:"The exported scores reflect the current threshold setting â adjust the Threshold Tuner to your desired sensitivity before exporting."}},ee=({sectionKey:t,compact:o=!1})=>{const a=ut[t];return a?e.jsx(Vt,{entry:a,compact:o}):null},Ss=()=>{const[t,o]=w.useState(!1),a=Object.entries(ut);return e.jsx(U,{className:"border-primary/20 bg-primary/[0.02] mb-6",children:e.jsxs(Gt,{open:t,onOpenChange:o,children:[e.jsx(Ht,{asChild:!0,children:e.jsxs("button",{className:"w-full flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors rounded-t-lg",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ft,{className:"h-4 w-4 text-primary"}),e.jsx("span",{className:"font-medium text-sm text-foreground",children:"Understanding Your Anomaly Detection Report"}),e.jsx(te,{variant:"secondary",className:"text-xs",children:"Output Guide"})]}),t?e.jsx(wt,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(st,{className:"h-4 w-4 text-muted-foreground"})]})}),e.jsx(qt,{children:e.jsxs(G,{className:"pt-0 pb-4 px-4 space-y-4",children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Your anomaly detection report contains ",a.length," sections. Each section helps you understand, tune, and act on detected anomalies. Click any ",e.jsx(Ot,{className:"h-3 w-3 inline text-primary"})," icon next to a section header for quick explanations."]}),e.jsx(Kt,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("h4",{className:"text-sm font-semibold flex items-center gap-2 text-foreground",children:[e.jsx(It,{className:"h-4 w-4 text-primary"}),"Report Sections"]}),e.jsx("div",{className:"grid gap-2",children:a.map(([i,m],y)=>e.jsxs("div",{className:"flex items-start gap-3 p-2 rounded-md hover:bg-muted/40 transition-colors",children:[e.jsx(te,{variant:"outline",className:"text-xs shrink-0 mt-0.5 w-6 h-6 flex items-center justify-center rounded-full p-0",children:y+1}),e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[m.icon,e.jsx("span",{className:"text-sm font-medium text-foreground",children:m.title})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-0.5",children:m.shortDesc})]})]},i))})]})]})})]})})},Rs=({columns:t,onRun:o,onCompare:a,isRunning:i})=>{const[m,y]=w.useState("isolation-forest"),[s,l]=w.useState([]),[f,k]=w.useState(5),[n,c]=w.useState(100),[j,P]=w.useState(30),[v,T]=w.useState(20),[S,L]=w.useState("zscore"),u=p=>{l(R=>R.includes(p)?R.filter($=>$!==p):[...R,p])},d=()=>m==="isolation-forest"?{nTrees:n}:m==="autoencoder"?{epochs:j}:{kNeighbors:v},N=()=>{o(m,s,f/100,d(),S)},D=()=>{a?.(s,f/100,{nTrees:n,epochs:j},S)};return e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-4",children:[e.jsxs(U,{className:"lg:col-span-2",children:[e.jsx(J,{className:"pb-3",children:e.jsxs(Q,{className:"text-sm font-medium flex items-center gap-2",children:[e.jsx(nt,{className:"h-4 w-4 text-primary"}),"Select Numeric Features",e.jsx(ee,{sectionKey:"featureSelection",compact:!0}),e.jsxs(te,{variant:"secondary",className:"text-[10px]",children:[s.length," selected"]})]})}),e.jsxs(G,{children:[e.jsx("div",{className:"flex flex-wrap gap-2 max-h-48 overflow-y-auto",children:t.map(p=>e.jsxs("label",{className:`flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-xs cursor-pointer transition-colors ${s.includes(p)?"bg-primary/10 text-primary border border-primary/20":"bg-muted/50 text-muted-foreground hover:bg-muted"}`,children:[e.jsx(Yt,{checked:s.includes(p),onCheckedChange:()=>u(p),className:"h-3.5 w-3.5"}),p]},p))}),t.length===0&&e.jsx("p",{className:"text-xs text-muted-foreground text-center py-4",children:"No numeric columns detected"})]})]}),e.jsxs(U,{children:[e.jsx(J,{className:"pb-3",children:e.jsxs(Q,{className:"text-sm font-medium flex items-center gap-2",children:["Algorithm Settings",e.jsx(ee,{sectionKey:"algorithmSettings",compact:!0})]})}),e.jsxs(G,{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(ce,{className:"text-xs",children:"Algorithm"}),e.jsxs(Ve,{value:m,onValueChange:p=>y(p),children:[e.jsx(Ke,{className:"h-9 text-xs",children:e.jsx(Ge,{})}),e.jsxs(He,{children:[e.jsx(ue,{value:"isolation-forest",className:"text-xs",children:"Isolation Forest"}),e.jsx(ue,{value:"autoencoder",className:"text-xs",children:"Autoencoder (TF.js)"}),e.jsx(ue,{value:"lof",className:"text-xs",children:"Local Outlier Factor"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(ce,{className:"text-xs",children:"Feature Normalisation"}),e.jsxs(Ve,{value:S,onValueChange:p=>L(p),children:[e.jsx(Ke,{className:"h-9 text-xs",children:e.jsx(Ge,{})}),e.jsxs(He,{children:[e.jsx(ue,{value:"zscore",className:"text-xs",children:"Z-score (mean / standard deviation)"}),e.jsx(ue,{value:"robust",className:"text-xs",children:"Robust (median / MAD)"})]})]}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Z-score uses the mean and standard deviation, which the outliers themselves inflate â on skewed SAP quantity and price columns it under-detects. Robust scaling centres on the median and scales by MAD, so extreme values do not hide each other."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(ce,{className:"text-xs",children:"Contamination"}),e.jsxs("span",{className:"text-xs font-mono text-primary",children:[f,"%"]})]}),e.jsx(pe,{value:[f],onValueChange:([p])=>k(p),min:1,max:20,step:1}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Expected % of anomalies in data"})]}),m==="isolation-forest"&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(ce,{className:"text-xs",children:"Number of Trees"}),e.jsx("span",{className:"text-xs font-mono text-primary",children:n})]}),e.jsx(pe,{value:[n],onValueChange:([p])=>c(p),min:50,max:300,step:10}
56)]}),m==="autoencoder"&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(ce,{className:"text-xs",children:"Training Epochs"}),e.jsx("span",{className:"text-xs font-mono text-primary",children:j})]}),e.jsx(pe,{value:[j],onValueChange:([p])=>P(p),min:10,max:100,step:5})]}),m==="lof"&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(ce,{className:"text-xs",children:"K Neighbors"}),e.jsx("span",{className:"text-xs font-mono text-primary",children:v})]}),e.jsx(pe,{value:[v],onValueChange:([p])=>T(p),min:5,max:50,step:1}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Number of neighbors for local density estimation"})]}),e.jsxs(de,{onClick:N,size:"sm",className:"w-full gap-1.5",disabled:s.length<2||i,children:[e.jsx(_t,{className:"h-3.5 w-3.5"})," ",i?"Running...":"Detect Anomalies"]}),a&&e.jsxs(de,{onClick:D,size:"sm",variant:"outline",className:"w-full gap-1.5",disabled:s.length<2||i,children:[e.jsx(Re,{className:"h-3.5 w-3.5"})," Compare IF vs AE"]}),s.length<2&&e.jsx("p",{className:"text-[10px] text-destructive text-center",children:"Select at least 2 numeric features"})]})]})]})},Ts=({contributions:t})=>{const o=[...t].sort((a,i)=>i.contribution-a.contribution);return e.jsxs("div",{className:"p-3 space-y-1.5",children:[e.jsx("p",{className:"text-[10px] font-medium text-muted-foreground mb-2",children:"Feature Contributions to Anomaly Score"}),o.map(a=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-[10px] text-muted-foreground w-24 truncate text-right",children:a.feature}),e.jsx("div",{className:"flex-1 h-3 bg-muted rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full transition-all",style:{width:`${Math.round(a.contribution*100)}%`,backgroundColor:a.contribution>.7?"hsl(0, 72%, 51%)":a.contribution>.4?"hsl(38, 92%, 50%)":"hsl(var(--primary))"}})}),e.jsxs("span",{className:"text-[10px] font-mono w-10 text-right text-muted-foreground",children:[(a.contribution*100).toFixed(0),"%"]})]},a.feature))]})},Fs=({scores:t,threshold:o,onThresholdChange:a})=>{const i=t.filter(y=>y>=o).length,m=(i/t.length*100).toFixed(1);return e.jsxs(U,{children:[e.jsx(J,{className:"pb-2",children:e.jsxs(Q,{className:"text-sm flex items-center gap-2",children:[e.jsx(ke,{className:"h-4 w-4 text-primary"}),"Interactive Threshold Tuner",e.jsx(ee,{sectionKey:"thresholdTuner",compact:!0})]})}),e.jsxs(G,{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx(pe,{value:[o*1e3],onValueChange:([y])=>a(y/1e3),min:0,max:1e3,step:1,className:"flex-1"}),e.jsx("span",{className:"text-xs font-mono w-16 text-right text-primary",children:o.toFixed(3)})]}),e.jsxs("div",{className:"flex items-center gap-3 text-xs text-muted-foreground",children:[e.jsxs(te,{variant:"destructive",className:"text-[10px]",children:[i," anomalies"]}),e.jsxs("span",{children:[m,"% of ",t.length," records"]})]})]})]})},Is="hsl(142, 71%, 45%)",Ie="hsl(0, 72%, 51%)",ks=({scores:t,data:o,dateColumn:a,threshold:i})=>{const m=t.slice(0,3e3).map(s=>{const l=o[s.rowIndex]?.[a],f=new Date(l).getTime();return isNaN(f)?null:{x:f,y:s.score,isAnomaly:s.score>=i}}).filter(Boolean);if(m.length===0)return null;m.sort((s,l)=>s.x-l.x);const y=s=>{const l=new Date(s);return`${l.getMonth()+1}/${l.getDate()}/${l.getFullYear().toString().slice(-2)}`};return e.jsxs(U,{children:[e.jsx(J,{className:"pb-2",children:e.jsxs(Q,{className:"text-sm flex items-center gap-2",children:[e.jsx(rt,{className:"h-4 w-4 text-primary"}),"Anomalies Over Time (",a,")",e.jsx(ee,{sectionKey:"temporalChart",compact:!0})]})}),e.jsx(G,{children:e.jsx("div",{className:"h-64",children:e.jsx(je,{width:"100%",height:"100%",children:e.jsxs(dt,{children:[e.jsx(be,{strokeDasharray:"3 3",className:"opacity-30"}),e.jsx(we,{dataKey:"x",type:"number",domain:["dataMin","dataMax"],tickFormatter:y,tick:{fontSize:9}}),e.jsx(ve,{dataKey:"y",tick:{fontSize:10},name:"Score"}),e.jsx(Ne,{contentStyle:{fontSize:11},labelFormatter:s=>y(s),formatter:s=>s.toFixed(4)}),e.jsx(mt,{y:i,stroke:Ie,strokeDasharray:"5 5",label:{value:"Threshold",fill:Ie,fontSize:10}}),e.jsx(De,{data:m,name:"Scores",children:m.map((s,l)=>e.jsx(ht,{fill:s.isAnomaly?Ie:Is,opacity:s.isAnomaly?.9:.3,r:s.isAnomaly?4:2},l))})]})})})})]})},Ds="hsl(142, 71%, 45%)",ye="hsl(0, 72%, 51%)",Ms=({result:t,data:o,features:a,onExport:i,dateColumn:m,onThresholdChange:y})=>{const[s,l]=w.useState(null),[f,k]=w.useState(t.threshold),n=f,c=w.useMemo(()=>t.scores.map(d=>({...d,isAnomaly:d.score>=n})),[t.scores,n]),j=c.filter(d=>
56d.isAnomaly).length,P=(j/t.totalRecords*100).toFixed(1),v=d=>{k(d),y?.(d)},T=20,S=Array.from({length:T},(d,N)=>{const D=N/T,p=(N+1)/T,R=t.scores.filter($=>$.score>=D&&$.score<p).length;return{range:`${(D*100).toFixed(0)}%`,count:R,lo:D,hi:p}}),L=w.useMemo(()=>{const d=c.slice(0,2e3).map(p=>a.map(R=>Number(o[p.rowIndex]?.[R])||0));if(d.length<2||a.length<2)return null;const{projected:N,varianceExplained:D}=Xt(d);return{points:N.map((p,R)=>({x:p[0],y:p[1],isAnomaly:c[R].isAnomaly})),variance:D}},[c,o,a]),u=c.filter(d=>d.isAnomaly).sort((d,N)=>N.score-d.score).slice(0,50);return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-3",children:[e.jsx(U,{children:e.jsxs(G,{className:"p-3 text-center",children:[e.jsx("div",{className:"text-2xl font-bold text-destructive",children:j}),e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"Anomalies Found"})]})}),e.jsx(U,{children:e.jsxs(G,{className:"p-3 text-center",children:[e.jsxs("div",{className:"text-2xl font-bold text-foreground",children:[P,"%"]}),e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"Anomaly Rate"})]})}),e.jsx(U,{children:e.jsxs(G,{className:"p-3 text-center",children:[e.jsx("div",{className:"text-2xl font-bold text-foreground",children:n.toFixed(3)}),e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"Threshold"})]})}),e.jsx(U,{children:e.jsxs(G,{className:"p-3 text-center",children:[e.jsxs("div",{className:"text-2xl font-bold text-foreground",children:[(t.trainingTimeMs/1e3).toFixed(1),"s"]}),e.jsxs("div",{className:"text-[10px] text-muted-foreground flex items-center justify-center gap-1",children:[e.jsx(Mt,{className:"h-3 w-3"})," Training Time"]})]})})]}),e.jsx(Fs,{scores:t.scores.map(d=>d.score),threshold:f,onThresholdChange:v}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4",children:[e.jsxs(U,{children:[e.jsx(J,{className:"pb-2",children:e.jsxs(Q,{className:"text-sm flex items-center gap-2",children:[e.jsx(Se,{className:"h-4 w-4 text-primary"}),"Score Distribution",e.jsx(ee,{sectionKey:"scoreDistribution",compact:!0})]})}),e.jsx(G,{children:e.jsx("div",{className:"h-64",children:e.jsx(je,{width:"100%",height:"100%",children:e.jsxs(qe,{data:S,children:[e.jsx(be,{strokeDasharray:"3 3",className:"opacity-30"}),e.jsx(we,{dataKey:"range",tick:{fontSize:9},interval:3}),e.jsx(ve,{tick:{fontSize:10}}),e.jsx(Ne,{contentStyle:{fontSize:11}}),e.jsx(We,{dataKey:"count",radius:[2,2,0,0],children:S.map((d,N)=>e.jsx(ht,{fill:d.lo>=n?ye:"hsl(var(--primary))"},N))}),e.jsx(mt,{x:`${(n*100).toFixed(0)}%`,stroke:ye,strokeDasharray:"5 5",label:{value:"Threshold",fill:ye,fontSize:10}})]})})})})]}),e.jsxs(U,{children:[e.jsx(J,{className:"pb-2",children:e.jsxs(Q,{className:"text-sm flex items-center gap-2",children:[e.jsx(at,{className:"h-4 w-4 text-primary"}),"PCA 2D Projection",e.jsx(ee,{sectionKey:"pcaProjection",compact:!0}),L&&e.jsxs(te,{variant:"secondary",className:"text-[9px] ml-1",children:["PC1: ",L.variance[0],"% · PC2: ",L.variance[1],"%"]})]})}),e.jsx(G,{children:e.jsx("div",{className:"h-64",children:L?e.jsx(je,{width:"100%",height:"100%",children:e.jsxs(dt,{children:[e.jsx(be,{strokeDasharray:"3 3",className:"opacity-30"}),e.jsx(we,{dataKey:"x",name:"PC1",tick:{fontSize:10}}),e.jsx(ve,{dataKey:"y",name:"PC2",tick:{fontSize:10}}),e.jsx(Ne,{contentStyle:{fontSize:11}}),e.jsx(De,{data:L.points.filter(d=>!d.isAnomaly),fill:Ds,opacity:.4,r:2,name:"Normal"}),e.jsx(De,{data:L.points.filter(d=>d.isAnomaly),fill:ye,opacity:.8,r:4,name:"Anomaly"})]})}):e.jsx("div",{className:"h-full flex items-center justify-center text-xs text-muted-foreground",children:"Need at least 2 features for PCA projection"})})})]})]}),m&&e.jsx(ks,{scores:c,data:o,dateColumn:m,threshold:n}),e.jsxs(U,{children:[e.jsx(J,{className:"pb-2",children:e.jsxs(Q,{className:"text-sm flex items-center gap-2",children:[e.jsx(Ae,{className:"h-4 w-4 text-primary"}),"Feature Importance",e.jsx(ee,{sectionKey:"featureImportance",compact:!0})]})}),e.jsx(G,{children:e.jsx("div",{className:"h-48",children:e.jsx(je,{width:"100%",height:"100%",children:e.jsxs(qe,{data:t.featureImportance,layout:"vertical",children:[e.jsx(be,{strokeDasharray:"3 3",className:"opacity-30"}),e.jsx(we,{type:"number",tick:{fontSize:10},domain:[0,1]}),e.jsx(ve,{dataKey:"feature",type:"category",tick:{fontSize:10},width:120}),e.jsx(Ne,{contentStyle:{fontSize:11},formatter:d=>d.toFixed(3)}
56),e.jsx(We,{dataKey:"importance",radius:[0,4,4,0],fill:"hsl(var(--primary))"})]})})})})]}),e.jsxs(U,{children:[e.jsxs(J,{className:"pb-2 flex flex-row items-center justify-between",children:[e.jsxs(Q,{className:"text-sm flex items-center gap-2",children:["Top Anomalies ",e.jsx(ee,{sectionKey:"topAnomalies",compact:!0})]}),e.jsxs(de,{onClick:i,size:"sm",variant:"outline",className:"gap-1.5 text-xs",children:[e.jsx(Le,{className:"h-3.5 w-3.5"})," Export with Scores"]})]}),e.jsx(G,{className:"p-0",children:e.jsx("div",{className:"overflow-x-auto max-h-96",children:e.jsxs(it,{children:[e.jsx(lt,{children:e.jsxs(xe,{children:[e.jsx(ne,{className:"text-[11px] w-8"}),e.jsx(ne,{className:"text-[11px]",children:"Row"}),e.jsx(ne,{className:"text-[11px]",children:"Score"}),a.slice(0,6).map(d=>e.jsx(ne,{className:"text-[11px]",children:d},d))]})}),e.jsx(ct,{children:u.map(d=>{const N=t.scores.find(R=>R.rowIndex===d.rowIndex),D=!!N?.featureContributions,p=s===d.rowIndex;return e.jsxs(e.Fragment,{children:[e.jsxs(xe,{className:D?"cursor-pointer hover:bg-muted/50":"",onClick:()=>D&&l(p?null:d.rowIndex),children:[e.jsx(Z,{className:"text-xs w-8 px-2",children:D&&(p?e.jsx(st,{className:"h-3 w-3"}):e.jsx(zt,{className:"h-3 w-3"}))}),e.jsx(Z,{className:"text-xs font-mono",children:d.rowIndex+1}),e.jsx(Z,{className:"text-xs",children:e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(te,{variant:"destructive",className:"text-[10px]",children:d.score.toFixed(3)}),N&&e.jsx(te,{variant:N.borderline?"outline":"secondary",className:"text-[10px]",title:"Confidence = distance from the contamination cut. Borderline rows would flip under a small threshold change.",children:N.borderline?"borderline":`conf ${(N.confidence??0).toFixed(2)}`})]})}),a.slice(0,6).map(R=>e.jsx(Z,{className:"text-xs font-mono",children:o[d.rowIndex]?.[R]!=null?String(o[d.rowIndex][R]):"â"},R))]},d.rowIndex),p&&N?.featureContributions&&e.jsx(xe,{children:e.jsx(Z,{colSpan:a.slice(0,6).length+3,className:"p-0 bg-muted/30",children:e.jsx(Ts,{contributions:N.featureContributions})})},`${d.rowIndex}-exp`)]})})})]})})})]})]})},Ls=({results:t,data:o,features:a})=>{if(t.length<2)return null;const i=t[0],m=t[1],y=new Set(i.scores.filter(c=>c.isAnomaly).map(c=>c.rowIndex)),s=new Set(m.scores.filter(c=>c.isAnomaly).map(c=>c.rowIndex)),l=[...y].filter(c=>s.has(c)),f=[...y].filter(c=>!s.has(c)),k=[...s].filter(c=>!y.has(c)),n=c=>c==="isolation-forest"?"IF":c==="autoencoder"?"AE":"LOF";return e.jsxs(U,{children:[e.jsx(J,{className:"pb-2",children:e.jsxs(Q,{className:"text-sm flex items-center gap-2",children:[e.jsx(Re,{className:"h-4 w-4 text-primary"}),"Method Comparison: ",n(i.method)," vs ",n(m.method),e.jsx(ee,{sectionKey:"methodComparison",compact:!0})]})}),e.jsxs(G,{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-3 gap-3",children:[e.jsxs("div",{className:"text-center p-3 rounded-lg bg-destructive/10",children:[e.jsx("div",{className:"text-xl font-bold text-destructive",children:l.length}),e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"Both Agree"})]}),e.jsxs("div",{className:"text-center p-3 rounded-lg bg-muted/50",children:[e.jsx("div",{className:"text-xl font-bold text-foreground",children:f.length}),e.jsxs("div",{className:"text-[10px] text-muted-foreground",children:[n(i.method)," Only"]})]}),e.jsxs("div",{className:"text-center p-3 rounded-lg bg-muted/50",children:[e.jsx("div",{className:"text-xl font-bold text-foreground",children:k.length}),e.jsxs("div",{className:"text-[10px] text-muted-foreground",children:[n(m.method)," Only"]})]})]}),l.length>0&&e.jsxs("div",{children:[e.jsx("p",{className:"text-xs font-medium text-muted-foreground mb-2",children:"High-Confidence Anomalies (Both Methods Agree)"}),e.jsx("div",{className:"overflow-x-auto max-h-60",children:e.jsxs(it,{children:[e.jsx(lt,{children:e.jsxs(xe,{children:[e.jsx(ne,{className:"text-[11px]",children:"Row"}),e.jsxs(ne,{className:"text-[11px]",children:[n(i.method)," Score"]}),e.jsxs(ne,{className:"text-[11px]",children:[n(m.method)," Score"]}),a.slice(0,4).map(c=>e.jsx(ne,{className:"text-[11px]",children:c},c))]})}),e.jsx(ct,{children:l.slice(0,30).map(c=>{const j=i.scores.find(v=>v.rowIndex===c),P=m.scores.find(v=>v.rowIndex===c);return e.jsxs(xe,{children:[e.jsx(Z,{className:"text-xs font-mono",children:c+1}),e.jsx(Z,{className:"text-xs",children:e.jsx(te,{variant:"destructive",className:"text-[10px]",children:j?.score.toFixed(3)})}),e.jsx(Z,{className:"text-xs",children:e.jsx(te,{variant:"destructive",className:"text-[10px]",children:P?.score.toFixed(3)})}),a.slice(0,4).map(v=>e.jsx(Z,{className:"text-xs font-mono",children:o[c]?.[v]!=null?String(o[c][v]):"â"},v))]},c)})})]})})]})]})]})},Es=({loader:t,data:o,onDataReady:a,operationType:i="processing"})=>{const{guard:m}=t;return!m.showWarning||!m.datasetAnalysis?null:e.jsx(Qt,{datasetAnalysis:m.datasetAnalysis,samplingConfig:m.samplingConfig,onSamplingConfigChange:m.setSamplingConfig,onProceed:y=>{const s=m.proceed(o,y);a(s)},operationType:i})},ze="anomaly-engine-v3",Ce=5e4,Je=1e4,Te="zscore";function Pe(t,o,a){return ns("Rows analysed",o,t,`${a}
56 caps input at ${o.toLocaleString()} rows; rows beyond that position were not scored and cannot appear as anomalies.`)}function $e(t,o,a){const i=[],m=[],y=[];for(let s=0;s<a;s++){const l=[];let f=!0;for(const k of o){const n=is(t[s]?.[k]);if(n===null){f=!1;break}l.push(n)}f?(i.push(l),m.push(s)):y.push(s)}return{matrix:i,rowIndices:m,excludedRows:y}}function Ue(t,o){const a=Ns(t.map(i=>i.score));return t.map(i=>({...i,...vs(i.score,o,a)}))}function Be(t,o=Te){const a=t[0].length,i=new Array(a).fill(0),m=new Array(a).fill(1);for(let s=0;s<a;s++){const l=t.map(f=>f[s]);if(o==="robust"){i[s]=ss(l);const f=os(l)/.6745;m[s]=f||Xe(l)||1}else i[s]=as(l),m[s]=Xe(l)||1}return{normalized:t.map(s=>s.map((l,f)=>(l-i[f])/m[f])),means:i,stds:m}}function pt(t){return t<=1?0:t===2?1:2*(Math.log(t-1)+.5772156649)-2*(t-1)/t}function Me(t,o,a,i){if(t.length<=1||a>=o)return{size:t.length};const m=t[0].length,y=Math.floor(i()*m),s=t.map(j=>j[y]);let l=s[0],f=s[0];for(let j=1;j<s.length;j++)s[j]<l&&(l=s[j]),s[j]>f&&(f=s[j]);if(l===f)return{size:t.length};const k=l+i()*(f-l),n=[],c=[];for(const j of t)j[y]<k?n.push(j):c.push(j);return{splitFeature:y,splitValue:k,size:t.length,left:Me(n,o,a+1,i),right:Me(c,o,a+1,i)}}function me(t,o,a){return!o.left||!o.right||o.splitFeature===void 0?a+pt(o.size):t[o.splitFeature]<o.splitValue?me(t,o.left,a+1):me(t,o.right,a+1)}function Os(t,o,a,i,m,y,s){const l=o.reduce((c,j)=>c+me(t,j,0),0)/a,f=Math.pow(2,-l/i),k=m.map((c,j)=>{const P=[...t];P[j]=0;const v=o.reduce((S,L)=>S+me(P,L,0),0)/a,T=Math.pow(2,-v/i);return{feature:c,contribution:Math.abs(f-T)}});let n=.001;for(const c of k)c.contribution>n&&(n=c.contribution);return k.forEach(c=>c.contribution=c.contribution/n),k}function Qe(t,o,a={}){const i=performance.now(),{nTrees:m=100,sampleSize:y=256,contamination:s=.05,normalisation:l=Te}=a,f=Ce,k=Math.min(t.length,f),n=[],c=Pe(t.length,Ce,"Isolation Forest");c&&n.push(c);const{matrix:j,rowIndices:P,excludedRows:v}=$e(t,o,k),{normalized:T}=Be(j,l),S=Pt(ts(T)),L=Math.ceil(Math.log2(y)),u=pt(y),d=[];for(let A=0;A<m;A++){const F=[];for(let z=0;z<Math.min(y,T.length);z++)F.push(T[Math.floor(S()*T.length)]);d.push(Me(F,L,0,S))}const N=T.map(A=>{const F=d.reduce((z,B)=>z+me(A,B,0),0)/m;return Math.pow(2,-F/u)}),D=[...N].sort((A,F)=>F-A),p=Math.max(0,Math.floor(s*D.length)-1),R=D[p],$=Ue(N.map((A,F)=>({rowIndex:P[F],score:A,isAnomaly:A>=R,confidence:0,borderline:!1,featureContributions:A>=R?Os(T[F],d,m,u,o):void 0})),R),V=N,H=o.map((A,F)=>{const z=T.map(h=>[...h]);for(let h=z.length-1;h>0;h--){const r=Math.floor(S()*(h+1));[z[h][F],z[r][F]]=[z[r][F],z[h][F]]}const B=z.map(h=>{const r=d.reduce((C,_)=>C+me(h,_,0),0)/m;return Math.pow(2,-r/u)}),W=V.reduce((h,r,C)=>h+Math.abs(r-B[C]),0)/V.length;return{feature:A,importance:W}});let q=.001;for(const A of H)A.importance>q&&(q=A.importance);return H.forEach(A=>A.importance=A.importance/q),H.sort((A,F)=>F.importance-A.importance),{method:"isolation-forest",anomalyCount:$.filter(A=>A.isAnomaly).length,borderlineCount:$.filter(A=>A.borderline).length,confidenceNote:_e,totalRecords:P.length,threshold:R,contamination:s,scores:$,featureImportance:H,trainingTimeMs:performance.now()-i,excludedRowCount:v.length,rowCap:f,inputRowCount:t.length,normalisation:l,truncationNotices:n,parseVersion:Oe,engineVersion:ze,parsingNote:Ee}}async function et(t,o,a={}){const i=performance.now(),{epochs:m=30,contamination:y=.05,normalisation:s=Te}=a,l=Ce,f=Math.min(t.length,l),k=[],n=Pe(t.length,Ce,"Autoencoder");n&&k.push(n);const c=await vt(()=>import("./vendor-ai-LcOSHxZq.js").then(r=>r.C),__vite__mapDeps([0,1])),{matrix:j,rowIndices:P,excludedRows:v}=$e(t,o,f),{normalized:T}=Be(j,s),S=o.length,L=Math.max(2,Math.round(S*2/3)),u=Math.max(1,Math.round(S/3)),d=c.sequential();d.add(c.layers.dense({inputShape:[S],units:L,activation:"relu"})),d.add(c.layers.dense({units:u,activation:"relu"})),d.add(c.layers.dense({units:L,activation:"relu"})),d.add(c.layers.dense({units:S,activation:"linear"})),d.compile({optimizer:"adam",loss:"meanSquaredError"});const N=c.tensor2d(T);await d.fit(N,N,{epochs:m,batchSize:Math.min(64,f),shuffle:!0,verbose
56:0});const D=d.predict(N),p=await D.array(),R=T.map((r,C)=>r.map((_,M)=>(_-p[C][M])**2)),$=R.map(r=>r.reduce((C,_)=>C+_,0)/r.length);let V=.001;for(const r of $)r>V&&(V=r);const H=$.map(r=>r/V),q=[...H].sort((r,C)=>C-r),A=Math.max(0,Math.floor(y*q.length)-1),F=q[A],z=H.map((r,C)=>{const _=r>=F;let M;if(_){const K=R[C];let Y=.001;for(const X of K)X>Y&&(Y=X);M=o.map((X,ie)=>({feature:X,contribution:K[ie]/Y}))}return{rowIndex:P[C],score:r,isAnomaly:_,confidence:0,borderline:!1,featureContributions:M}}),B=Ue(z,F),W=o.map((r,C)=>{const _=T.reduce((M,K,Y)=>M+(K[C]-p[Y][C])**2,0)/T.length;return{feature:r,importance:_}});let h=.001;for(const r of W)r.importance>h&&(h=r.importance);return W.forEach(r=>r.importance=r.importance/h),W.sort((r,C)=>C.importance-r.importance),N.dispose(),D.dispose(),d.dispose(),{method:"autoencoder",anomalyCount:B.filter(r=>r.isAnomaly).length,borderlineCount:B.filter(r=>r.borderline).length,confidenceNote:_e,totalRecords:P.length,threshold:F,contamination:y,scores:B,featureImportance:W,trainingTimeMs:performance.now()-i,excludedRowCount:v.length,rowCap:l,inputRowCount:t.length,normalisation:s,truncationNotices:k,parseVersion:Oe,engineVersion:ze,parsingNote:Ee}}function _s(t,o){let a=0;for(let i=0;i<t.length;i++)a+=(t[i]-o[i])**2;return Math.sqrt(a)}function zs(t,o,a={}){const i=performance.now(),{kNeighbors:m=20,contamination:y=.05,normalisation:s=Te}=a,l=Je,f=Math.min(t.length,l),k=[],n=Pe(t.length,Je,"Local Outlier Factor");n&&k.push(n);const{matrix:c,rowIndices:j,excludedRows:P}=$e(t,o,f),{normalized:v}=Be(c,s),T=v.length,S=Math.min(m,T-1),L=Array.from({length:T},()=>new Array(T).fill(0));for(let h=0;h<T;h++)for(let r=h+1;r<T;r++){const C=_s(v[h],v[r]);L[h][r]=C,L[r][h]=C}const u=v.map((h,r)=>{const C=L[r].map((M,K)=>({d:M,j:K})).filter(M=>M.j!==r);C.sort((M,K)=>M.d-K.d);const _=C.slice(0,S);return{indices:_.map(M=>M.j),distances:_.map(M=>M.d)}}),d=u.map(h=>h.distances[h.distances.length-1]||.001),N=(h,r)=>Math.max(d[r],L[h][r]),D=v.map((h,r)=>{const C=u[r].indices.reduce((_,M)=>_+N(r,M),0)/S;return C>0?1/C:1}),p=v.map((h,r)=>u[r].indices.reduce((_,M)=>_+D[M]/D[r],0)/S);let R=.001;for(const h of p)h>R&&(R=h);const $=p.map(h=>Math.min(h/R,1)),V=[...$].sort((h,r)=>r-h),H=Math.max(0,Math.floor(y*V.length)-1),q=V[H],A=$.map((h,r)=>{const C=h>=q;let _;if(C){const M=o.map((Y,X)=>{const ie=u[r].indices.reduce((le,fe)=>le+v[fe][X],0)/S;return Math.abs(v[r][X]-ie)});let K=.001;for(const Y of M)Y>K&&(K=Y);_=o.map((Y,X)=>({feature:Y,contribution:M[X]/K}))}return{rowIndex:j[r],score:h,isAnomaly:C,confidence:0,borderline:!1,featureContributions:_}}),F=Ue(A,q),z=F.filter(h=>h.isAnomaly&&h.featureContributions),B=o.map((h,r)=>{if(z.length===0)return{feature:h,importance:0};const C=z.reduce((_,M)=>_+(M.featureContributions[r]?.contribution||0),0)/z.length;return{feature:h,importance:C}});let W=.001;for(const h of B)h.importance>W&&(W=h.importance);return B.forEach(h=>h.importance=h.importance/W),B.sort((h,r)=>r.importance-h.importance),{method:"lof",anomalyCount:F.filter(h=>h.isAnomaly).length,borderlineCount:F.filter(h=>h.borderline).length,confidenceNote:_e,totalRecords:j.length,threshold:q,contamination:y,scores:F,featureImportance:B,trainingTimeMs:performance.now()-i,excludedRowCount:P.length,rowCap:l,inputRowCount:t.length,normalisation:s,truncationNotices:k,parseVersion:Oe,engineVersion:ze,parsingNote:Ee}}const tt="anomaly-detection",Qo=({workstationData:t})=>{const o=Jt(),{isLoading:a,progress:i,stage:m,loadFile:y,reset:s}=o,{cached:l,save:f,clear:k}=es("anomaly-detection"),[n,c]=w.useState(l?.data??null),[j,P]=w.useState(l?.columns??[]),[v,T]=w.useState(l?.allColumns??[]),[S,L]=w.useState(l?.fileName??""),[u,d]=w.useState(l?.result??null),[N,D]=w.useState(l?.comparisonResults??[]),[p,R]=w.useState(l?.features??[]),[$,V]=w.useState(!1),[H,q]=w.useState(l?.dateColumn),{reports:A,isLoading:F,isLoggedIn:z,save:B,remove:W}=$t(tt),h=w.useRef(!1),{insights:r,loading:C,runAnalysis:_}=ms(),{triggerTraining:M,brainTrainingStatus:K}=us(),Y=Ut(),X=w.useMemo(()=>{const g=n?.length??u?.totalRecords??0,b=u?.anomalyCount??0;return g>0?b/g*100:0},[u,n]),{narrative:ie}=fs({toolName:"Anomaly Detection",enabled:!!u,headline:u?`Detected ${u.anomalyCount} anomalies (${X.toFixed(2)}
56%) across ${(n?.length??u.totalRecords??0).toLocaleString()} rows.`:void 0,dimensions:{"Anomaly Rate %":Math.round(X*100)/100,Features:p.length,"Total Rows":n?.length??0},deps:[u]}),le=w.useRef(null);w.useEffect(()=>{if(!u)return;const g=u.scores?.filter(I=>I.isAnomaly)||[],b=n?.length||1,E=g.length/b,O=Math.max(0,Math.round(100-E*300));_({toolName:"Anomaly Detection",toolCategory:"data_quality",overallScore:O,rowCount:b,columnCount:j?.length,issues:g.map((I,x)=>({id:`anomaly-${x}`,title:`Anomaly at row ${I.rowIndex??x}: score ${I.score?.toFixed(2)??"N/A"}`,severity:I.score>.8?"critical":I.score>.6?"high":"medium",category:"accuracy",affectedRows:1,affectedPercent:Number((1/b*100).toFixed(2))})),totalChecks:b,failingChecks:g.length})},[u]),w.useEffect(()=>{if(h.current||!z||F||A.length===0)return;h.current=!0;const g=A[0];if(g?.report_data&&!u)try{d(g.report_data),L(g.file_name||"")}catch{}},[z,F,A,u]),w.useEffect(()=>{n&&u&&f({data:n,columns:j,allColumns:v,fileName:S,result:u,comparisonResults:N,features:p,dateColumn:H})},[n,j,v,S,u,N,p,H,f]);const fe=w.useRef(!1),he=w.useRef(0);w.useEffect(()=>{t&&(!fe.current||t.totalRows!==he.current)&&(t.totalRows!==he.current&&he.current!==0&&n&&(d(null),D([]),k()),he.current=t.totalRows,fe.current=!0,t.readAllData().then(b=>{if(b.length>0){const E=Object.keys(b[0]||{}).filter(I=>I!=="_rowId"),O=E.filter(I=>{const x=b.slice(0,50).map(se=>se[I]);return x.filter(se=>!isNaN(Number(se))&&se!=null&&se!=="").length>x.length*.5});c(b),P(O),T(E),L(`Workstation (${b.length} rows)`),d(null),D([]),he.current=b.length,ae.success(`Workstation data loaded: ${b.length} rows, ${O.length} numeric features`)}}))},[t,n,k]);const xt=(g,b)=>{for(const E of g){const O=b.slice(0,Math.min(1e3,b.length)).map(x=>x[E]);if(O.filter(x=>x!=null&&!isNaN(new Date(String(x)).getTime())).length>O.length*.5)return E}},ft=w.useCallback(async g=>{try{const b=await y(g),E=b.columns.filter(O=>{const I=b.data.slice(0,50).map(x=>x[O]);return I.filter(x=>!isNaN(Number(x))&&x!=null&&x!=="").length>I.length*.5});c(b.data),P(E),T(b.columns),L(b.fileName),d(null),D([]),q(xt(b.columns,b.data)),k(),ae.success(`Loaded ${b.data.length} rows, ${E.length} numeric features`)}catch{ae.error("Failed to parse file")}},[y,k]),gt=w.useCallback(async(g,b,E,O,I="zscore")=>{if(n){V(!0),R(b),D([]);try{let x;g==="isolation-forest"?x=Qe(n,b,{nTrees:O.nTrees,contamination:E,normalisation:I}):g==="lof"?x=zs(n,b,{kNeighbors:O.kNeighbors,contamination:E,normalisation:I}):x=await et(n,b,{epochs:O.epochs,contamination:E,normalisation:I}),d(x),le.current=g,B(S,{method:g,anomalyCount:x.anomalyCount,totalRecords:x.totalRecords,anomalyRate:(x.anomalyCount/x.totalRecords*100).toFixed(1)},{anomalies:x.anomalyCount,total:x.totalRecords,method:g}).catch(console.warn),await M({rawData:n??[],columns:j,overallScore:Math.max(0,Math.round(100-x.anomalyCount/x.totalRecords*300)),totalRows:n?.length??0,sourceTool:"Anomaly Detection"}),ae.success(`Found ${x.anomalyCount} anomalies (${(x.anomalyCount/x.totalRecords*100).toFixed(1)}%)`)}catch(x){ae.error("Anomaly detection failed: "+(x instanceof Error?x.message:"Unknown error"))}finally{V(!1)}}},[n,S,B]);w.useEffect(()=>{if(!u){Y(null);return}const g=n?.length??u.totalRecords??0,b=v.length||j.length,E=u.anomalyCount??0,O=g>0?E/g*100:0,I=le.current==="isolation-forest"?"Isolation Forest":le.current==="lof"?"Local Outlier Factor":le.current==="autoencoder"?"Autoencoder":"Isolation Forest";Y({toolResult:{toolId:tt,toolName:"Anomaly Detection",toolCategory:"analytics",overallScore:Math.max(0,Math.round(100-O*3)),rowCount:g,columnCount:b,datasetName:S,passingChecks:g-E,failingChecks:E,warningChecks:0,issues:[]},kpis:[{id:"rows",label:"Rows",value:g.toLocaleString(),tone:"info"},{id:"features",label:"Features",value:p.length||b,tone:"info"},{id:"anomalies",label:"Anomalies",value:E.toLocaleString(),tone:E>0?"warning":"success"},{id:"anomaly-rate",label:"Anomaly Rate",value:`${O.toFixed(2)}
56%`,tone:O>5?"warning":"success"},ys({name:I,scoreLabel:`contamination ${O.toFixed(1)}%`}),js({rowCount:g,columnCount:b})],useTabbedReport:!0,reportMethodology:`Anomaly Detection runs the selected algorithm (${I}) entirely on-device. Numeric features are standardized, missing values are imputed with column medians, and the model assigns an outlier score to each row. Rows above the contamination threshold (currently ${O.toFixed(2)}%) are flagged. The overall score is derived from the anomaly rate â lower rates yield higher scores. No row-level data is transmitted; all computation happens in your browser. Feature scaling: ${u.normalisation==="robust"?"robust (median / MAD)":"z-score (mean / standard deviation)"}. Row cap for this algorithm: ${u.rowCap.toLocaleString()} rows.${u.truncationNotices?.length?` PARTIAL RESULTS â ${u.truncationNotices.map(x=>`${x.scope}: analysed ${x.limit.toLocaleString()} of ${x.actual.toLocaleString()} â ${x.reason}`).join(" ")}`:""}`,reportSections:(()=>{const x=gs(ie);return x?[x]:void 0})()})},[u,n,v,j,p,S,Y,ie]);const yt=w.useCallback(async(g,b,E,O="zscore")=>{if(n){V(!0),R(g);try{const I=Qe(n,g,{nTrees:E.nTrees,contamination:b,normalisation:O}),x=await et(n,g,{epochs:E.epochs,contamination:b,normalisation:O});d(I),D([I,x]),ae.success("Comparison complete â both methods finished")}catch(I){ae.error("Comparison failed: "+(I instanceof Error?I.message:"Unknown error"))}finally{V(!1)}}},[n]),jt=w.useCallback(()=>{if(!n||!u)return;const g=new Map(u.scores.map(oe=>[oe.rowIndex,oe])),b=[...Object.keys(n[0]||{}),"anomaly_score","is_anomaly","anomaly_confidence","anomaly_borderline"],E=n.map((oe,re)=>({...oe,anomaly_score:g.get(re)?.score.toFixed(4)??"",is_anomaly:g.get(re)?.isAnomaly?"TRUE":"FALSE",anomaly_confidence:g.get(re)?.confidence?.toFixed(4)??"",anomaly_borderline:g.get(re)?g.get(re).borderline?"TRUE":"FALSE":""})),O=rs(u.truncationNotices),I=[...O?O.split(` 57`).map(oe=>`# ${oe}`):[],...u.confidenceNote?[`# ${u.confidenceNote}`]:[],b.join(","),...E.map(oe=>b.map(re=>{const Ye=oe[re];if(Ye==null)return"";const ge=String(Ye);return ge.includes(",")||ge.includes('"')?`"${ge.replace(/"/g,'""')}"`:ge}).join(","))].join(` 58`),x=new Blob([I],{type:"text/csv"}),se=URL.createObjectURL(x),Fe=document.createElement("a");Fe.href=se,Fe.download=`${S.replace(/\.[^/.]+$/,"")}_anomalies.csv`,Fe.click(),URL.revokeObjectURL(se),ae.success("Exported with anomaly scores")},[n,u,S]),bt=()=>{c(null),d(null),D([]),R([]),P([]),T([]),L(""),q(void 0),s(),k()};return e.jsx(Nt,{seoTitle:"Anomaly Detection | Puridex",seoDescription:"Detect multidimensional anomalies using Isolation Forest, Autoencoder, or Local Outlier Factor algorithms.",icon:Ae,title:"Anomaly Detection",description:"Detect multidimensional anomalies using Isolation Forest, Autoencoder, or Local Outlier Factor. Analyze feature contributions and compare methods.",badges:[{icon:Se,label:"Isolation Forest"},{icon:ot,label:"Autoencoder"},{icon:Lt,label:"LOF"}],headerActions:n?e.jsx(Zt,{onReset:bt}):void 0,helpToolId:"anomaly-detection",children:e.jsxs(Bt,{toolId:"anomaly-detection",toolName:"Anomaly Detection",toolCategory:"analytics",children:[e.jsx(Ct,{isVisible:a||$,progress:i,stage:$?"Running anomaly detection...":m}),e.jsx(Es,{loader:o,data:n??[],onDataReady:g=>c(g),operationType:"anomaly"}),e.jsx(ds,{reports:A,isLoading:F,isLoggedIn:z,onLoad:g=>{try{d(g.report_data),L(g.file_name||"")}catch{}},onDelete:W,toolLabel:"Anomaly Detection"}),n?e.jsxs("div",{className:"space-y-6",children:[u&&e.jsxs("div",{className:"rounded-md border border-border bg-muted/40 p-3 text-xs text-muted-foreground",children:[e.jsxs("span",{className:"font-medium text-foreground",children:["SAP-aware value reads (",u.engineVersion," / ",u.parseVersion,")"]}),typeof u.excludedRowCount=="number"&&u.excludedRowCount>0&&e.jsxs(e.Fragment,{children:[" â ",u.excludedRowCount.toLocaleString()," row(s) excluded because a selected feature was not a genuine measure (blank, text or a leading-zero SAP key)."]}),e.jsx("div",{className:"mt-1",children:u.parsingNote})]}),u&&e.jsx(ls,{notices:u.truncationNotices}),u&&e.jsx(Ss,{}),n&&e.jsx(cs,{columns:v,data:n,currentTool:"anomaly-detection"}),n&&e.jsx(Rs,{columns:j,onRun:gt,onCompare:yt,isRunning:$}),u&&n&&e.jsx(Ms,{result:u,data:n,features:p,onExport:jt,dateColumn:H}),N.length>=2&&n&&e.jsx(Ls,{results:N,data:n,features:p}),u&&e.jsxs(e.Fragment,{children:[e.jsx(ps,{status:K}),e.jsx(hs,{insights:r,loading:C})]})]}):e.jsx(As,{onFileUpload:ft}),e.jsx(xs,{toolId:"anomaly-detection"})]})})};export{Qo as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.