Commit ·
94fb32d
1
Parent(s): 10b0bc1
feat: deploy static interactive dashboard with zero-leakage sandbox and Karasek matrix
Browse files- README.md +14 -14
- index.html +912 -0
README.md
CHANGED
|
@@ -3,28 +3,28 @@ title: Workplace Pulse Telemetry v1.0
|
|
| 3 |
emoji: 🏢
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: slate
|
| 6 |
-
sdk:
|
| 7 |
-
app_file: app.py
|
| 8 |
pinned: false
|
| 9 |
license: mit
|
| 10 |
short_description: Local-First Occupational Telemetry & Burnout Detection Platform
|
| 11 |
---
|
| 12 |
|
| 13 |
-
# 🏢 Workplace-Pulse-Telemetry v1.0
|
| 14 |
-
### Local-First Occupational Telemetry, Organizational Climate & Early Burnout Detection Platform
|
| 15 |
-
**Zero Data Leakage Architecture** • Designed & Engineered by **[Fabio Torres](https://github.com/neurodeveloper11)**
|
| 16 |
|
| 17 |
[](https://www.linkedin.com/in/fabio-torres-39364b258/)
|
| 18 |
-
[](https://github.com/neurodeveloper11/workplace-pulse-telemetry)
|
| 19 |
[](LICENSE)
|
|
|
|
| 20 |
|
| 21 |
-
---
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
|
| 24 |
-
Workplace-Pulse-Telemetry provides automated behavioral telemetry directly on employee communications without sending confidential data to external cloud APIs.
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
|
|
|
|
|
| 3 |
emoji: 🏢
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: slate
|
| 6 |
+
sdk: static
|
|
|
|
| 7 |
pinned: false
|
| 8 |
license: mit
|
| 9 |
short_description: Local-First Occupational Telemetry & Burnout Detection Platform
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# 🏢 Workplace-Pulse-Telemetry v1.0: Local-First Occupational Telemetry & Burnout Detection Platform
|
|
|
|
|
|
|
| 13 |
|
| 14 |
[](https://www.linkedin.com/in/fabio-torres-39364b258/)
|
| 15 |
+
[](https://github.com/neurodeveloper11/workplace-pulse-telemetry)
|
| 16 |
[](LICENSE)
|
| 17 |
+
[](https://www.mintrabajo.gov.co)
|
| 18 |
|
| 19 |
+
An enterprise-grade, **Zero Data Leakage** occupational telemetry and behavioral NLP engine engineered to audit organizational climate, detect early signs of **burnout & verbal fatigue**, quantify **psychological safety**, and map teams into the **Karasek Demand-Control Matrix** directly on-premise without ever sending sensitive employee communications to external cloud APIs.
|
| 20 |
+
|
| 21 |
+
Designed and engineered by **[Fabio Torres](https://github.com/neurodeveloper11)** (M.Sc. Candidate in Data Engineering & Cloud Infrastructure • 10+ Years Directing Psychosocial Risk Batteries for 1,500+ Port Terminal Workers in Colombia).
|
| 22 |
|
| 23 |
+
---
|
|
|
|
| 24 |
|
| 25 |
+
## 🌟 Live Interactive Features
|
| 26 |
+
- **100% Client-Side / Local-First Zero Data Leakage:** Try pasting your own confidential chat logs in the **Live Playground** tab. All PII (emails, phone numbers, Colombian IDs, salaries, IP addresses, proper names) is redacted locally before computing psychometric telemetry.
|
| 27 |
+
- **Maslach Burnout Inventory (OSBI):** Verbal exhaustion & after-hours intrusion alarms.
|
| 28 |
+
- **Amy Edmondson Psychological Safety (PSI):** Quantifies vulnerability, error admission, and inquiry.
|
| 29 |
+
- **Robert Karasek 2D Matrix:** Visualizes department load across the 4 occupational health quadrants (High Strain, Active, Low Strain, Passive).
|
| 30 |
+
- **Resolución 2764/2022 Compliance:** Evidence-based organizational intervention directives for HR and leadership committees.
|
index.html
ADDED
|
@@ -0,0 +1,912 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="es">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Workplace-Pulse-Telemetry v1.0 • Fabio Torres</title>
|
| 7 |
+
<script src="https://cdn.plot.ly/plotly-2.35.2.min.js"></script>
|
| 8 |
+
<style>
|
| 9 |
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
| 10 |
+
body {
|
| 11 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
| 12 |
+
background-color: #0b0f19;
|
| 13 |
+
color: #f1f5f9;
|
| 14 |
+
line-height: 1.5;
|
| 15 |
+
min-height: 100vh;
|
| 16 |
+
display: flex;
|
| 17 |
+
flex-direction: column;
|
| 18 |
+
}
|
| 19 |
+
a { color: #38bdf8; text-decoration: none; }
|
| 20 |
+
a:hover { text-decoration: underline; }
|
| 21 |
+
|
| 22 |
+
/* Top Navbar */
|
| 23 |
+
.navbar {
|
| 24 |
+
background: rgba(15, 23, 42, 0.95);
|
| 25 |
+
backdrop-filter: blur(12px);
|
| 26 |
+
border-bottom: 1px solid #1e293b;
|
| 27 |
+
position: sticky;
|
| 28 |
+
top: 0;
|
| 29 |
+
z-index: 50;
|
| 30 |
+
}
|
| 31 |
+
.nav-container {
|
| 32 |
+
max-width: 1280px;
|
| 33 |
+
margin: 0 auto;
|
| 34 |
+
padding: 14px 20px;
|
| 35 |
+
display: flex;
|
| 36 |
+
align-items: center;
|
| 37 |
+
justify-content: space-between;
|
| 38 |
+
flex-wrap: wrap;
|
| 39 |
+
gap: 12px;
|
| 40 |
+
}
|
| 41 |
+
.brand-group {
|
| 42 |
+
display: flex;
|
| 43 |
+
align-items: center;
|
| 44 |
+
gap: 12px;
|
| 45 |
+
}
|
| 46 |
+
.brand-icon {
|
| 47 |
+
width: 44px;
|
| 48 |
+
height: 44px;
|
| 49 |
+
background: linear-gradient(135deg, #0284c7, #4f46e5);
|
| 50 |
+
border-radius: 12px;
|
| 51 |
+
display: flex;
|
| 52 |
+
align-items: center;
|
| 53 |
+
justify-content: center;
|
| 54 |
+
font-size: 22px;
|
| 55 |
+
box-shadow: 0 4px 14px rgba(2, 132, 199, 0.35);
|
| 56 |
+
}
|
| 57 |
+
.brand-title {
|
| 58 |
+
font-size: 18px;
|
| 59 |
+
font-weight: 800;
|
| 60 |
+
color: #ffffff;
|
| 61 |
+
display: flex;
|
| 62 |
+
align-items: center;
|
| 63 |
+
gap: 8px;
|
| 64 |
+
}
|
| 65 |
+
.badge-tag {
|
| 66 |
+
font-size: 11px;
|
| 67 |
+
font-weight: 700;
|
| 68 |
+
background: #0369a1;
|
| 69 |
+
color: #e0f2fe;
|
| 70 |
+
padding: 2px 8px;
|
| 71 |
+
border-radius: 6px;
|
| 72 |
+
text-transform: uppercase;
|
| 73 |
+
}
|
| 74 |
+
.brand-sub {
|
| 75 |
+
font-size: 12px;
|
| 76 |
+
color: #94a3b8;
|
| 77 |
+
}
|
| 78 |
+
.nav-links {
|
| 79 |
+
display: flex;
|
| 80 |
+
gap: 12px;
|
| 81 |
+
align-items: center;
|
| 82 |
+
}
|
| 83 |
+
.btn-nav {
|
| 84 |
+
background: #1e293b;
|
| 85 |
+
border: 1px solid #334155;
|
| 86 |
+
color: #e2e8f0;
|
| 87 |
+
padding: 6px 14px;
|
| 88 |
+
border-radius: 8px;
|
| 89 |
+
font-size: 13px;
|
| 90 |
+
font-weight: 600;
|
| 91 |
+
display: inline-flex;
|
| 92 |
+
align-items: center;
|
| 93 |
+
gap: 6px;
|
| 94 |
+
transition: all 0.2s ease;
|
| 95 |
+
}
|
| 96 |
+
.btn-nav:hover {
|
| 97 |
+
background: #334155;
|
| 98 |
+
border-color: #475569;
|
| 99 |
+
text-decoration: none;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
/* Hero Banner */
|
| 103 |
+
.hero-banner {
|
| 104 |
+
background: linear-gradient(180deg, rgba(15, 23, 42, 0.8) 0%, rgba(11, 15, 25, 1) 100%);
|
| 105 |
+
border-bottom: 1px solid #1e293b;
|
| 106 |
+
padding: 28px 20px;
|
| 107 |
+
}
|
| 108 |
+
.hero-content {
|
| 109 |
+
max-width: 1280px;
|
| 110 |
+
margin: 0 auto;
|
| 111 |
+
}
|
| 112 |
+
.hero-title {
|
| 113 |
+
font-size: 24px;
|
| 114 |
+
font-weight: 800;
|
| 115 |
+
color: #ffffff;
|
| 116 |
+
margin-bottom: 8px;
|
| 117 |
+
}
|
| 118 |
+
.hero-desc {
|
| 119 |
+
color: #94a3b8;
|
| 120 |
+
font-size: 14px;
|
| 121 |
+
max-width: 900px;
|
| 122 |
+
line-height: 1.6;
|
| 123 |
+
}
|
| 124 |
+
.compliance-pill {
|
| 125 |
+
display: inline-flex;
|
| 126 |
+
align-items: center;
|
| 127 |
+
gap: 6px;
|
| 128 |
+
background: rgba(16, 185, 129, 0.1);
|
| 129 |
+
border: 1px solid #059669;
|
| 130 |
+
color: #34d399;
|
| 131 |
+
padding: 4px 10px;
|
| 132 |
+
border-radius: 9999px;
|
| 133 |
+
font-size: 12px;
|
| 134 |
+
font-weight: 600;
|
| 135 |
+
margin-top: 12px;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
/* Main Container & Tabs */
|
| 139 |
+
.main-container {
|
| 140 |
+
max-width: 1280px;
|
| 141 |
+
margin: 0 auto;
|
| 142 |
+
padding: 24px 20px;
|
| 143 |
+
flex: 1;
|
| 144 |
+
width: 100%;
|
| 145 |
+
}
|
| 146 |
+
.tab-bar {
|
| 147 |
+
display: flex;
|
| 148 |
+
gap: 8px;
|
| 149 |
+
border-bottom: 1px solid #1e293b;
|
| 150 |
+
margin-bottom: 24px;
|
| 151 |
+
overflow-x: auto;
|
| 152 |
+
padding-bottom: 4px;
|
| 153 |
+
}
|
| 154 |
+
.tab-btn {
|
| 155 |
+
background: transparent;
|
| 156 |
+
border: none;
|
| 157 |
+
color: #94a3b8;
|
| 158 |
+
padding: 10px 18px;
|
| 159 |
+
font-size: 14px;
|
| 160 |
+
font-weight: 600;
|
| 161 |
+
cursor: pointer;
|
| 162 |
+
border-radius: 8px;
|
| 163 |
+
transition: all 0.2s ease;
|
| 164 |
+
white-space: nowrap;
|
| 165 |
+
}
|
| 166 |
+
.tab-btn:hover {
|
| 167 |
+
color: #f1f5f9;
|
| 168 |
+
background: #1e293b;
|
| 169 |
+
}
|
| 170 |
+
.tab-btn.active {
|
| 171 |
+
color: #38bdf8;
|
| 172 |
+
background: rgba(56, 189, 248, 0.1);
|
| 173 |
+
border-bottom: 2px solid #38bdf8;
|
| 174 |
+
}
|
| 175 |
+
.tab-panel {
|
| 176 |
+
display: none;
|
| 177 |
+
}
|
| 178 |
+
.tab-panel.active {
|
| 179 |
+
display: block;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
/* Grid & Cards */
|
| 183 |
+
.kpi-grid {
|
| 184 |
+
display: grid;
|
| 185 |
+
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
| 186 |
+
gap: 16px;
|
| 187 |
+
margin-bottom: 24px;
|
| 188 |
+
}
|
| 189 |
+
.card {
|
| 190 |
+
background: #131b2e;
|
| 191 |
+
border: 1px solid #1e293b;
|
| 192 |
+
border-radius: 12px;
|
| 193 |
+
padding: 20px;
|
| 194 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
| 195 |
+
}
|
| 196 |
+
.card-title {
|
| 197 |
+
font-size: 13px;
|
| 198 |
+
font-weight: 700;
|
| 199 |
+
text-transform: uppercase;
|
| 200 |
+
letter-spacing: 0.05em;
|
| 201 |
+
color: #94a3b8;
|
| 202 |
+
margin-bottom: 8px;
|
| 203 |
+
display: flex;
|
| 204 |
+
align-items: center;
|
| 205 |
+
justify-content: space-between;
|
| 206 |
+
}
|
| 207 |
+
.card-value {
|
| 208 |
+
font-size: 32px;
|
| 209 |
+
font-weight: 800;
|
| 210 |
+
color: #ffffff;
|
| 211 |
+
margin-bottom: 6px;
|
| 212 |
+
}
|
| 213 |
+
.card-meta {
|
| 214 |
+
font-size: 12px;
|
| 215 |
+
color: #64748b;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
.alert-box {
|
| 219 |
+
background: rgba(185, 28, 28, 0.15);
|
| 220 |
+
border: 1px solid #b91c1c;
|
| 221 |
+
border-radius: 10px;
|
| 222 |
+
padding: 16px;
|
| 223 |
+
margin-bottom: 24px;
|
| 224 |
+
color: #fecaca;
|
| 225 |
+
}
|
| 226 |
+
.alert-box h4 {
|
| 227 |
+
font-size: 15px;
|
| 228 |
+
font-weight: 700;
|
| 229 |
+
margin-bottom: 8px;
|
| 230 |
+
display: flex;
|
| 231 |
+
align-items: center;
|
| 232 |
+
gap: 8px;
|
| 233 |
+
color: #ef4444;
|
| 234 |
+
}
|
| 235 |
+
.alert-list {
|
| 236 |
+
list-style-type: none;
|
| 237 |
+
font-size: 13px;
|
| 238 |
+
}
|
| 239 |
+
.alert-list li {
|
| 240 |
+
margin-bottom: 6px;
|
| 241 |
+
line-height: 1.5;
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
.two-col {
|
| 245 |
+
display: grid;
|
| 246 |
+
grid-template-columns: 1fr 1fr;
|
| 247 |
+
gap: 20px;
|
| 248 |
+
margin-bottom: 24px;
|
| 249 |
+
}
|
| 250 |
+
@media (max-width: 900px) {
|
| 251 |
+
.two-col { grid-template-columns: 1fr; }
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
/* Sandbox Form */
|
| 255 |
+
.form-group {
|
| 256 |
+
margin-bottom: 16px;
|
| 257 |
+
}
|
| 258 |
+
.form-label {
|
| 259 |
+
display: block;
|
| 260 |
+
font-size: 13px;
|
| 261 |
+
font-weight: 600;
|
| 262 |
+
color: #cbd5e1;
|
| 263 |
+
margin-bottom: 6px;
|
| 264 |
+
}
|
| 265 |
+
.form-textarea {
|
| 266 |
+
width: 100%;
|
| 267 |
+
height: 130px;
|
| 268 |
+
background: #0f172a;
|
| 269 |
+
border: 1px solid #334155;
|
| 270 |
+
border-radius: 8px;
|
| 271 |
+
padding: 12px;
|
| 272 |
+
color: #f8fafc;
|
| 273 |
+
font-family: inherit;
|
| 274 |
+
font-size: 13px;
|
| 275 |
+
resize: vertical;
|
| 276 |
+
}
|
| 277 |
+
.form-textarea:focus {
|
| 278 |
+
outline: none;
|
| 279 |
+
border-color: #38bdf8;
|
| 280 |
+
box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.2);
|
| 281 |
+
}
|
| 282 |
+
.btn-primary {
|
| 283 |
+
background: linear-gradient(135deg, #0284c7, #2563eb);
|
| 284 |
+
color: #ffffff;
|
| 285 |
+
border: none;
|
| 286 |
+
padding: 12px 24px;
|
| 287 |
+
border-radius: 8px;
|
| 288 |
+
font-size: 14px;
|
| 289 |
+
font-weight: 700;
|
| 290 |
+
cursor: pointer;
|
| 291 |
+
display: inline-flex;
|
| 292 |
+
align-items: center;
|
| 293 |
+
gap: 8px;
|
| 294 |
+
transition: all 0.2s ease;
|
| 295 |
+
}
|
| 296 |
+
.btn-primary:hover {
|
| 297 |
+
background: linear-gradient(135deg, #0369a1, #1d4ed8);
|
| 298 |
+
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4);
|
| 299 |
+
}
|
| 300 |
+
.preset-group {
|
| 301 |
+
display: flex;
|
| 302 |
+
flex-wrap: wrap;
|
| 303 |
+
gap: 8px;
|
| 304 |
+
margin-top: 10px;
|
| 305 |
+
}
|
| 306 |
+
.preset-chip {
|
| 307 |
+
background: #1e293b;
|
| 308 |
+
border: 1px solid #334155;
|
| 309 |
+
color: #94a3b8;
|
| 310 |
+
padding: 5px 12px;
|
| 311 |
+
border-radius: 6px;
|
| 312 |
+
font-size: 12px;
|
| 313 |
+
cursor: pointer;
|
| 314 |
+
transition: all 0.2s;
|
| 315 |
+
}
|
| 316 |
+
.preset-chip:hover {
|
| 317 |
+
background: #334155;
|
| 318 |
+
color: #f1f5f9;
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
.gauge-bar-container {
|
| 322 |
+
margin-bottom: 12px;
|
| 323 |
+
}
|
| 324 |
+
.gauge-label {
|
| 325 |
+
display: flex;
|
| 326 |
+
justify-content: space-between;
|
| 327 |
+
font-size: 12px;
|
| 328 |
+
font-weight: 600;
|
| 329 |
+
color: #cbd5e1;
|
| 330 |
+
margin-bottom: 4px;
|
| 331 |
+
}
|
| 332 |
+
.gauge-track {
|
| 333 |
+
width: 100%;
|
| 334 |
+
height: 8px;
|
| 335 |
+
background: #1e293b;
|
| 336 |
+
border-radius: 4px;
|
| 337 |
+
overflow: hidden;
|
| 338 |
+
}
|
| 339 |
+
.gauge-fill {
|
| 340 |
+
height: 100%;
|
| 341 |
+
border-radius: 4px;
|
| 342 |
+
transition: width 0.3s ease;
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
.json-box {
|
| 346 |
+
background: #0a0f1d;
|
| 347 |
+
border: 1px solid #1e293b;
|
| 348 |
+
border-radius: 8px;
|
| 349 |
+
padding: 12px;
|
| 350 |
+
font-family: monospace;
|
| 351 |
+
font-size: 12px;
|
| 352 |
+
color: #38bdf8;
|
| 353 |
+
max-height: 160px;
|
| 354 |
+
overflow-y: auto;
|
| 355 |
+
white-space: pre-wrap;
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
/* Footer */
|
| 359 |
+
.footer {
|
| 360 |
+
background: #0f172a;
|
| 361 |
+
border-top: 1px solid #1e293b;
|
| 362 |
+
padding: 20px;
|
| 363 |
+
text-align: center;
|
| 364 |
+
font-size: 13px;
|
| 365 |
+
color: #64748b;
|
| 366 |
+
}
|
| 367 |
+
</style>
|
| 368 |
+
</head>
|
| 369 |
+
<body>
|
| 370 |
+
|
| 371 |
+
<!-- Top Navbar -->
|
| 372 |
+
<header class="navbar">
|
| 373 |
+
<div class="nav-container">
|
| 374 |
+
<div class="brand-group">
|
| 375 |
+
<div class="brand-icon">🏢</div>
|
| 376 |
+
<div>
|
| 377 |
+
<div class="brand-title">
|
| 378 |
+
Workplace-Pulse-Telemetry
|
| 379 |
+
<span class="badge-tag">v1.0</span>
|
| 380 |
+
</div>
|
| 381 |
+
<div class="brand-sub">Zero Data Leakage • Local-First Occupational Telemetry</div>
|
| 382 |
+
</div>
|
| 383 |
+
</div>
|
| 384 |
+
<div class="nav-links">
|
| 385 |
+
<a href="https://github.com/neurodeveloper11/workplace-pulse-telemetry" target="_blank" class="btn-nav">
|
| 386 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
| 387 |
+
GitHub Repo
|
| 388 |
+
</a>
|
| 389 |
+
<a href="https://www.linkedin.com/in/fabio-torres-39364b258/" target="_blank" class="btn-nav">
|
| 390 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg>
|
| 391 |
+
Fabio Torres (LinkedIn)
|
| 392 |
+
</a>
|
| 393 |
+
</div>
|
| 394 |
+
</div>
|
| 395 |
+
</header>
|
| 396 |
+
|
| 397 |
+
<!-- Hero Banner -->
|
| 398 |
+
<section class="hero-banner">
|
| 399 |
+
<div class="hero-content">
|
| 400 |
+
<h1 class="hero-title">Observabilidad Ocupacional & Detección Temprana de Burnout</h1>
|
| 401 |
+
<p class="hero-desc">
|
| 402 |
+
Motor de telemetría del comportamiento organizacional y NLP 100% On-Premise. Evalúa el riesgo psicosocial,
|
| 403 |
+
la seguridad psicológica (Amy Edmondson) y la matriz Demanda-Control de Karasek a partir de conversaciones corporativas
|
| 404 |
+
(Slack, Teams, WhatsApp, emails), garantizando que ningún byte confidencial salga a APIs públicas en la nube.
|
| 405 |
+
</p>
|
| 406 |
+
<div class="compliance-pill">
|
| 407 |
+
🛡️ Alineado con Resolución 2764/2022 y 2646/2008 (MinTrabajo Colombia) e ISO 45003
|
| 408 |
+
</div>
|
| 409 |
+
</div>
|
| 410 |
+
</section>
|
| 411 |
+
|
| 412 |
+
<!-- Main Workspace Tabs -->
|
| 413 |
+
<main class="main-container">
|
| 414 |
+
<nav class="tab-bar">
|
| 415 |
+
<button class="tab-btn active" onclick="switchTab('tab-overview', this)">📊 1. Resumen Ejecutivo & Alertas</button>
|
| 416 |
+
<button class="tab-btn" onclick="switchTab('tab-karasek', this)">🎯 2. Matriz Demanda-Control (Karasek)</button>
|
| 417 |
+
<button class="tab-btn" onclick="switchTab('tab-edmondson', this)">🧠 3. Seguridad Psicológica (Amy Edmondson)</button>
|
| 418 |
+
<button class="tab-btn" onclick="switchTab('tab-sandbox', this)">🔬 4. Inspector en Vivo (Zero-Leakage Sandbox)</button>
|
| 419 |
+
<button class="tab-btn" onclick="switchTab('tab-directives', this)">📋 5. Directivas de Intervención (Res. 2764/2022)</button>
|
| 420 |
+
</nav>
|
| 421 |
+
|
| 422 |
+
<!-- TAB 1: RESUMEN EJECUTIVO -->
|
| 423 |
+
<div id="tab-overview" class="tab-panel active">
|
| 424 |
+
<div class="kpi-grid">
|
| 425 |
+
<div class="card">
|
| 426 |
+
<div class="card-title">🔥 Índice Global de Burnout (OSBI) <span>MBI</span></div>
|
| 427 |
+
<div class="card-value" style="color: #f43f5e;" id="kpi-burnout">47.2 <span style="font-size: 16px;">/ 100</span></div>
|
| 428 |
+
<div class="card-meta">Agotamiento verbal y urgencia temporal</div>
|
| 429 |
+
</div>
|
| 430 |
+
<div class="card">
|
| 431 |
+
<div class="card-title">🛡️ Seguridad Psicológica (PSI) <span>Edmondson</span></div>
|
| 432 |
+
<div class="card-value" style="color: #10b981;" id="kpi-psi">48.7 <span style="font-size: 16px;">/ 100</span></div>
|
| 433 |
+
<div class="card-meta">Vulnerabilidad y ausencia de temor punitivo</div>
|
| 434 |
+
</div>
|
| 435 |
+
<div class="card">
|
| 436 |
+
<div class="card-title">⚡ Fricción Interpersonal (IFCI) <span>Clima</span></div>
|
| 437 |
+
<div class="card-value" style="color: #f59e0b;" id="kpi-friction">36.0 <span style="font-size: 16px;">/ 100</span></div>
|
| 438 |
+
<div class="card-meta">Comunicación pasivo-agresiva vs cohesión</div>
|
| 439 |
+
</div>
|
| 440 |
+
<div class="card">
|
| 441 |
+
<div class="card-title">🔒 Entidades PII Redactadas <span>Zero-Leak</span></div>
|
| 442 |
+
<div class="card-value" style="color: #38bdf8;" id="kpi-pii">184</div>
|
| 443 |
+
<div class="card-meta">Cédulas, emails, celulares, salarios y IPs protegidos</div>
|
| 444 |
+
</div>
|
| 445 |
+
</div>
|
| 446 |
+
|
| 447 |
+
<div class="alert-box">
|
| 448 |
+
<h4>🚨 Alertas Tempranas de Riesgo Ocupacional Inminente</h4>
|
| 449 |
+
<ul class="alert-list">
|
| 450 |
+
<li>• <strong>[ENGINEERING-CORE] Riesgo CRÍTICO:</strong> Índice de Burnout en <strong>72.8/100</strong>. El <strong>55%</strong> de los mensajes ocurren fuera de jornada (20:00 - 02:00) por incidentes en producción.</li>
|
| 451 |
+
<li>• <strong>[PORT-LOGISTICS] Riesgo CRÍTICO:</strong> Fricción Interpersonal en <strong>62.4/100</strong>. Frecuente evasión de responsabilidades (<em>"no es mi trabajo"</em>, <em>"como ya te había dicho"</em>) y baja seguridad psicológica.</li>
|
| 452 |
+
<li>• <strong>[CUSTOMER-OPERATIONS] Riesgo MODERADO:</strong> Cuadrante Karasek Pasivo. Alta densidad de órdenes rígidas (<em>"es obligatorio"</em>) y desconexión afectiva (<em>"da igual"</em>).</li>
|
| 453 |
+
</ul>
|
| 454 |
+
</div>
|
| 455 |
+
|
| 456 |
+
<div class="card">
|
| 457 |
+
<div id="plot-department-bars" style="width: 100%; height: 380px;"></div>
|
| 458 |
+
</div>
|
| 459 |
+
</div>
|
| 460 |
+
|
| 461 |
+
<!-- TAB 2: MATRIZ DE KARASEK -->
|
| 462 |
+
<div id="tab-karasek" class="tab-panel">
|
| 463 |
+
<div class="card" style="margin-bottom: 20px;">
|
| 464 |
+
<h3 style="font-size: 16px; margin-bottom: 8px; color: #ffffff;">Modelo Demanda-Control de Robert Karasek (Salud Ocupacional)</h3>
|
| 465 |
+
<p style="font-size: 13px; color: #94a3b8; line-height: 1.6;">
|
| 466 |
+
Cuantifica el riesgo de estrés crónico y somatización cruzando las <strong>Demandas Psicológicas Cuantitativas</strong> (eje Y)
|
| 467 |
+
con la <strong>Latitud de Decisión / Autonomía</strong> (eje X). Los equipos en <em>Alta Tensión</em> tienen hasta 3x mayor riesgo de trastornos psicosomáticos y rotación laboral.
|
| 468 |
+
</p>
|
| 469 |
+
</div>
|
| 470 |
+
<div class="card">
|
| 471 |
+
<div id="plot-karasek" style="width: 100%; height: 500px;"></div>
|
| 472 |
+
</div>
|
| 473 |
+
</div>
|
| 474 |
+
|
| 475 |
+
<!-- TAB 3: AMY EDMONDSON RADAR -->
|
| 476 |
+
<div id="tab-edmondson" class="tab-panel">
|
| 477 |
+
<div class="two-col">
|
| 478 |
+
<div class="card">
|
| 479 |
+
<div id="plot-radar" style="width: 100%; height: 420px;"></div>
|
| 480 |
+
</div>
|
| 481 |
+
<div class="card">
|
| 482 |
+
<h3 style="font-size: 16px; margin-bottom: 12px; color: #ffffff;">Constructo de Seguridad Psicológica (Dra. Amy Edmondson)</h3>
|
| 483 |
+
<div style="font-size: 13px; color: #cbd5e1; line-height: 1.6; display: flex; flex-direction: column; gap: 14px;">
|
| 484 |
+
<div>
|
| 485 |
+
<strong style="color: #38bdf8;">1. Admisión Transparente del Error:</strong>
|
| 486 |
+
<p style="color: #94a3b8;">En equipos de alto rendimiento (<em>AI-Research-Labs</em>), los ingenieros dicen abiertamente <em>"cometí un error en los datos"</em> sin miedo a represalias punitivas.</p>
|
| 487 |
+
</div>
|
| 488 |
+
<div>
|
| 489 |
+
<strong style="color: #10b981;">2. Indagación Abierta vs Órdenes:</strong>
|
| 490 |
+
<p style="color: #94a3b8;">Frecuencia de preguntas reflexivas (<em>"¿qué opinan?", "¿cómo lo ven?"</em>) que abren el disenso constructivo y estimulan la innovación colectiva.</p>
|
| 491 |
+
</div>
|
| 492 |
+
<div>
|
| 493 |
+
<strong style="color: #f59e0b;">3. Higiene Comunicacional:</strong>
|
| 494 |
+
<p style="color: #94a3b8;">Ausencia de micropenalizaciones pasivo-agresivas (<em>"favor leer el hilo con atención"</em>) que silencian el feedback en áreas operativas como <em>Port-Logistics</em>.</p>
|
| 495 |
+
</div>
|
| 496 |
+
<div>
|
| 497 |
+
<strong style="color: #a855f7;">4. Balance Demanda-Autonomía:</strong>
|
| 498 |
+
<p style="color: #94a3b8;">La autonomía protege contra el agotamiento extremo incluso bajo demandas altas (Zona Activa Karasek).</p>
|
| 499 |
+
</div>
|
| 500 |
+
</div>
|
| 501 |
+
</div>
|
| 502 |
+
</div>
|
| 503 |
+
</div>
|
| 504 |
+
|
| 505 |
+
<!-- TAB 4: LIVE SANDBOX ZERO-LEAKAGE -->
|
| 506 |
+
<div id="tab-sandbox" class="tab-panel">
|
| 507 |
+
<div class="card" style="margin-bottom: 20px;">
|
| 508 |
+
<h3 style="font-size: 16px; margin-bottom: 6px; color: #ffffff;">Inspector en Vivo: Prueba de Anonimización y Telemetría Local</h3>
|
| 509 |
+
<p style="font-size: 13px; color: #94a3b8;">
|
| 510 |
+
Ingresa cualquier texto real o confidencial con nombres, números de cédula, celulares, correos o sueldos.
|
| 511 |
+
El motor lo redacta al 100% de forma inmediata y extrae los vectores psicométricos sin enviar datos fuera de tu dispositivo.
|
| 512 |
+
</p>
|
| 513 |
+
</div>
|
| 514 |
+
|
| 515 |
+
<div class="two-col">
|
| 516 |
+
<!-- Input Column -->
|
| 517 |
+
<div class="card">
|
| 518 |
+
<div class="form-group">
|
| 519 |
+
<label class="form-label">Mensaje Raw de Entrada (Slack, Teams, WhatsApp, Email)</label>
|
| 520 |
+
<textarea id="raw-input" class="form-textarea">URGENTE: Se cayó el servidor de pagos en la IP 10.0.1.45. Hola Carlos, llama al celular +57 312 456 7890 del cliente Banco Santander (CC 12345678). Estoy totalmente agotado con este sprint de madrugada, no doy más!</textarea>
|
| 521 |
+
</div>
|
| 522 |
+
<button class="btn-primary" onclick="processSandbox()">⚡ Analizar con Telemetría Local-First</button>
|
| 523 |
+
|
| 524 |
+
<div style="margin-top: 18px;">
|
| 525 |
+
<span style="font-size: 12px; color: #64748b; font-weight: 600;">Cargar Ejemplos de Prueba:</span>
|
| 526 |
+
<div class="preset-group">
|
| 527 |
+
<span class="preset-chip" onclick="loadPreset(1)">🚨 Incidente Crítico y Burnout</span>
|
| 528 |
+
<span class="preset-chip" onclick="loadPreset(2)">⚡ Fricción Pasivo-Agresiva</span>
|
| 529 |
+
<span class="preset-chip" onclick="loadPreset(3)">🌱 Seguridad Psicológica (Edmondson)</span>
|
| 530 |
+
<span class="preset-chip" onclick="loadPreset(4)">💤 Desconexión y Apatía</span>
|
| 531 |
+
</div>
|
| 532 |
+
</div>
|
| 533 |
+
</div>
|
| 534 |
+
|
| 535 |
+
<!-- Output Column -->
|
| 536 |
+
<div class="card">
|
| 537 |
+
<div class="form-group">
|
| 538 |
+
<label class="form-label" style="color: #34d399;">Texto Sanitizado (Zero Data Leakage Output)</label>
|
| 539 |
+
<div id="clean-output" style="background: #0f172a; border: 1px solid #1e293b; border-radius: 8px; padding: 12px; font-size: 13px; color: #e2e8f0; min-height: 80px;"></div>
|
| 540 |
+
</div>
|
| 541 |
+
|
| 542 |
+
<div class="form-group">
|
| 543 |
+
<label class="form-label" style="color: #38bdf8;">Entidades PII Detectadas y Enmascaradas</label>
|
| 544 |
+
<pre id="pii-output" class="json-box"></pre>
|
| 545 |
+
</div>
|
| 546 |
+
|
| 547 |
+
<!-- Score Gauges -->
|
| 548 |
+
<div style="margin-top: 16px;">
|
| 549 |
+
<div class="gauge-bar-container">
|
| 550 |
+
<div class="gauge-label">
|
| 551 |
+
<span>🔥 Burnout / Estrés Ocupacional (OSBI)</span>
|
| 552 |
+
<span id="score-burnout-text" style="color: #f43f5e;">85.0 / 100</span>
|
| 553 |
+
</div>
|
| 554 |
+
<div class="gauge-track"><div id="score-burnout-bar" class="gauge-fill" style="width: 85%; background: #f43f5e;"></div></div>
|
| 555 |
+
</div>
|
| 556 |
+
|
| 557 |
+
<div class="gauge-bar-container">
|
| 558 |
+
<div class="gauge-label">
|
| 559 |
+
<span>🛡️ Seguridad Psicológica (PSI)</span>
|
| 560 |
+
<span id="score-psi-text" style="color: #10b981;">35.0 / 100</span>
|
| 561 |
+
</div>
|
| 562 |
+
<div class="gauge-track"><div id="score-psi-bar" class="gauge-fill" style="width: 35%; background: #10b981;"></div></div>
|
| 563 |
+
</div>
|
| 564 |
+
|
| 565 |
+
<div class="gauge-bar-container">
|
| 566 |
+
<div class="gauge-label">
|
| 567 |
+
<span>⚡ Fricción Interpersonal (IFCI)</span>
|
| 568 |
+
<span id="score-friction-text" style="color: #f59e0b;">25.0 / 100</span>
|
| 569 |
+
</div>
|
| 570 |
+
<div class="gauge-track"><div id="score-friction-bar" class="gauge-fill" style="width: 25%; background: #f59e0b;"></div></div>
|
| 571 |
+
</div>
|
| 572 |
+
|
| 573 |
+
<div class="gauge-bar-container">
|
| 574 |
+
<div class="gauge-label">
|
| 575 |
+
<span>🎮 Autonomía / Latitud Decisional</span>
|
| 576 |
+
<span id="score-autonomy-text" style="color: #38bdf8;">45.0 / 100</span>
|
| 577 |
+
</div>
|
| 578 |
+
<div class="gauge-track"><div id="score-autonomy-bar" class="gauge-fill" style="width: 45%; background: #38bdf8;"></div></div>
|
| 579 |
+
</div>
|
| 580 |
+
|
| 581 |
+
<div style="margin-top: 10px; font-size: 12px; color: #94a3b8;">
|
| 582 |
+
<strong>Marcadores Identificados:</strong> <span id="markers-text" style="color: #f1f5f9;">Exhaustion(1), Urgency(1)</span>
|
| 583 |
+
</div>
|
| 584 |
+
</div>
|
| 585 |
+
</div>
|
| 586 |
+
</div>
|
| 587 |
+
</div>
|
| 588 |
+
|
| 589 |
+
<!-- TAB 5: RESOLUCION 2764/2022 DIRECTIVAS -->
|
| 590 |
+
<div id="tab-directives" class="tab-panel">
|
| 591 |
+
<div class="card" style="margin-bottom: 20px;">
|
| 592 |
+
<h3 style="font-size: 18px; margin-bottom: 10px; color: #ffffff;">Marco Técnico-Legal: Resolución 2764/2022 (Ministerio del Trabajo de Colombia)</h3>
|
| 593 |
+
<p style="font-size: 13px; color: #94a3b8; line-height: 1.6;">
|
| 594 |
+
En Colombia, la evaluación y gestión de los factores de riesgo psicosocial intralaboral es obligatoria.
|
| 595 |
+
<em>Workplace-Pulse-Telemetry</em> transforma la telemetría en intervenciones preventivas alineadas con los dominios oficiales:
|
| 596 |
+
</p>
|
| 597 |
+
</div>
|
| 598 |
+
|
| 599 |
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
| 600 |
+
<div class="card">
|
| 601 |
+
<h4 style="color: #f43f5e; font-size: 15px; margin-bottom: 8px;">1. Dominio: Demandas del Trabajo (Carga Cuantitativa y Jornada Laboral)</h4>
|
| 602 |
+
<p style="font-size: 13px; color: #cbd5e1; line-height: 1.6;">
|
| 603 |
+
• <strong>Evidencia Detectada:</strong> El equipo de <code>Engineering-Core</code> presenta un <strong>55%</strong> de tráfico fuera de horario laboral y un índice de agotamiento de 72.8/100.<br>
|
| 604 |
+
• <strong>Plan de Acción Directivo:</strong> Establecer barreras automáticas de desconexión digital de 19:00 a 07:00, rediseñar el calendario de guardias para incidentes críticos y auditar cuellos de botella de entrega inmediata.
|
| 605 |
+
</p>
|
| 606 |
+
</div>
|
| 607 |
+
|
| 608 |
+
<div class="card">
|
| 609 |
+
<h4 style="color: #f59e0b; font-size: 15px; margin-bottom: 8px;">2. Dominio: Liderazgo y Relaciones Sociales en el Trabajo</h4>
|
| 610 |
+
<p style="font-size: 13px; color: #cbd5e1; line-height: 1.6;">
|
| 611 |
+
• <strong>Evidencia Detectada:</strong> En <code>Port-Logistics</code>, el índice de fricción alcanza 62.4/100 con alta recurrencia de respuestas pasivo-agresivas (<em>"eso te correspondía a ti"</em>).<br>
|
| 612 |
+
• <strong>Plan de Acción Directivo:</strong> Taller de alineación de interfaces interdepartamentales y adopción del protocolo de comunicación constructiva sin evasión de responsabilidades.
|
| 613 |
+
</p>
|
| 614 |
+
</div>
|
| 615 |
+
|
| 616 |
+
<div class="card">
|
| 617 |
+
<h4 style="color: #38bdf8; font-size: 15px; margin-bottom: 8px;">3. Dominio: Control sobre el Trabajo (Autonomía y Participación)</h4>
|
| 618 |
+
<p style="font-size: 13px; color: #cbd5e1; line-height: 1.6;">
|
| 619 |
+
• <strong>Evidencia Detectada:</strong> El área de <code>Customer-Operations</code> se sitúa en el cuadrante Karasek Pasivo (alta rigidez de mandatos y baja autonomía).<br>
|
| 620 |
+
• <strong>Plan de Acción Directivo:</strong> Otorgar facultades resolutivas a los operadores para resolver casos de usuarios sin requerir aprobación jerárquica piramidal permanente.
|
| 621 |
+
</p>
|
| 622 |
+
</div>
|
| 623 |
+
</div>
|
| 624 |
+
</div>
|
| 625 |
+
</main>
|
| 626 |
+
|
| 627 |
+
<!-- Footer -->
|
| 628 |
+
<footer class="footer">
|
| 629 |
+
<strong>Workplace-Pulse-Telemetry v1.0</strong> • Diseñado y Desarrollado por <strong>Fabio Torres</strong> (M.Sc. Data Engineering • Psicólogo Especialista en Riesgo Psicosocial)<br>
|
| 630 |
+
Código abierto en <a href="https://github.com/neurodeveloper11/workplace-pulse-telemetry" target="_blank">GitHub</a> •
|
| 631 |
+
Perfil Profesional en <a href="https://www.linkedin.com/in/fabio-torres-39364b258/" target="_blank">LinkedIn</a>
|
| 632 |
+
</footer>
|
| 633 |
+
|
| 634 |
+
<!-- Client-Side Engine & Charts Script -->
|
| 635 |
+
<script>
|
| 636 |
+
// Tab switching
|
| 637 |
+
function switchTab(tabId, btn) {
|
| 638 |
+
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
| 639 |
+
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
| 640 |
+
document.getElementById(tabId).classList.add('active');
|
| 641 |
+
btn.classList.add('active');
|
| 642 |
+
|
| 643 |
+
if (tabId === 'tab-overview') renderDepartmentBars();
|
| 644 |
+
if (tabId === 'tab-karasek') renderKarasekPlot();
|
| 645 |
+
if (tabId === 'tab-edmondson') renderRadarPlot();
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
// Benchmark Data
|
| 649 |
+
const benchmarkData = {
|
| 650 |
+
"Engineering-Core": { burnout: 72.8, psi: 41.2, friction: 28.5, demand: 78.0, autonomy: 42.0, quadrant: "High Strain" },
|
| 651 |
+
"Port-Logistics": { burnout: 45.6, psi: 32.4, friction: 62.4, demand: 54.0, autonomy: 35.0, quadrant: "High Strain / Friction" },
|
| 652 |
+
"AI-Research-Labs": { burnout: 22.4, psi: 83.2, friction: 11.2, demand: 58.0, autonomy: 78.0, quadrant: "Active" },
|
| 653 |
+
"Customer-Operations": { burnout: 48.0, psi: 38.0, friction: 42.0, demand: 38.0, autonomy: 32.0, quadrant: "Passive" }
|
| 654 |
+
};
|
| 655 |
+
|
| 656 |
+
function renderDepartmentBars() {
|
| 657 |
+
const depts = Object.keys(benchmarkData);
|
| 658 |
+
const burnout = depts.map(d => benchmarkData[d].burnout);
|
| 659 |
+
const psi = depts.map(d => benchmarkData[d].psi);
|
| 660 |
+
const friction = depts.map(d => benchmarkData[d].friction);
|
| 661 |
+
|
| 662 |
+
const traces = [
|
| 663 |
+
{ name: 'Burnout / Estrés (OSBI)', x: depts, y: burnout, type: 'bar', marker: { color: '#f43f5e' } },
|
| 664 |
+
{ name: 'Seguridad Psicológica (PSI)', x: depts, y: psi, type: 'bar', marker: { color: '#10b981' } },
|
| 665 |
+
{ name: 'Fricción Interpersonal (IFCI)', x: depts, y: friction, type: 'bar', marker: { color: '#f59e0b' } }
|
| 666 |
+
];
|
| 667 |
+
|
| 668 |
+
const layout = {
|
| 669 |
+
barmode: 'group',
|
| 670 |
+
paper_bgcolor: '#131b2e',
|
| 671 |
+
plot_bgcolor: '#0f172a',
|
| 672 |
+
title: { text: '<b>Comparativa de Índices Psicométricos por Departamento</b>', font: { color: '#ffffff', size: 15 } },
|
| 673 |
+
yaxis: { title: 'Puntuación (0 - 100)', range: [0, 100], gridcolor: '#1e293b', tickfont: { color: '#94a3b8' } },
|
| 674 |
+
xaxis: { tickfont: { color: '#f1f5f9' }, gridcolor: '#1e293b' },
|
| 675 |
+
legend: { orientation: 'h', y: 1.15, x: 1, xanchor: 'right', font: { color: '#cbd5e1' } },
|
| 676 |
+
margin: { l: 40, r: 20, t: 45, b: 40 }
|
| 677 |
+
};
|
| 678 |
+
|
| 679 |
+
Plotly.newPlot('plot-department-bars', traces, layout, { responsive: true, displayModeBar: false });
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
function renderKarasekPlot() {
|
| 683 |
+
const depts = Object.keys(benchmarkData);
|
| 684 |
+
const xAutonomy = depts.map(d => benchmarkData[d].autonomy);
|
| 685 |
+
const yDemand = depts.map(d => benchmarkData[d].demand);
|
| 686 |
+
const colors = ['#f43f5e', '#fb923c', '#10b981', '#facc15'];
|
| 687 |
+
|
| 688 |
+
const trace = {
|
| 689 |
+
x: xAutonomy,
|
| 690 |
+
y: yDemand,
|
| 691 |
+
mode: 'markers+text',
|
| 692 |
+
text: depts.map(d => `<b>${d}</b>`),
|
| 693 |
+
textposition: 'top center',
|
| 694 |
+
textfont: { color: '#ffffff', size: 12 },
|
| 695 |
+
marker: { size: 18, color: colors, line: { color: '#ffffff', width: 2 } },
|
| 696 |
+
type: 'scatter'
|
| 697 |
+
};
|
| 698 |
+
|
| 699 |
+
const layout = {
|
| 700 |
+
paper_bgcolor: '#131b2e',
|
| 701 |
+
plot_bgcolor: '#0f172a',
|
| 702 |
+
title: { text: '<b>Matriz Demanda-Control de Karasek (Distribución Ocupacional)</b>', font: { color: '#ffffff', size: 15 } },
|
| 703 |
+
xaxis: { title: 'Latitud de Decisión / Autonomía (0 - 100)', range: [0, 100], gridcolor: '#1e293b', tickfont: { color: '#94a3b8' } },
|
| 704 |
+
yaxis: { title: 'Demandas Psicológicas y Carga (0 - 100)', range: [0, 100], gridcolor: '#1e293b', tickfont: { color: '#94a3b8' } },
|
| 705 |
+
shapes: [
|
| 706 |
+
{ type: 'rect', x0: 0, y0: 45, x1: 50, y1: 100, fillcolor: '#ef4444', opacity: 0.15, line: { width: 0 } },
|
| 707 |
+
{ type: 'rect', x0: 50, y0: 45, x1: 100, y1: 100, fillcolor: '#10b981', opacity: 0.15, line: { width: 0 } },
|
| 708 |
+
{ type: 'rect', x0: 0, y0: 0, x1: 50, y1: 45, fillcolor: '#f59e0b', opacity: 0.15, line: { width: 0 } },
|
| 709 |
+
{ type: 'rect', x0: 50, y0: 0, x1: 100, y1: 45, fillcolor: '#3b82f6', opacity: 0.15, line: { width: 0 } }
|
| 710 |
+
],
|
| 711 |
+
annotations: [
|
| 712 |
+
{ x: 25, y: 95, text: '<b>🚨 ALTA TENSIÓN</b><br>Riesgo Crítico de Burnout', showarrow: false, font: { color: '#fca5a5', size: 11 } },
|
| 713 |
+
{ x: 75, y: 95, text: '<b>🚀 ACTIVO</b><br>Alto Desempeño y Motivación', showarrow: false, font: { color: '#6ee7b7', size: 11 } },
|
| 714 |
+
{ x: 25, y: 10, text: '<b>💤 PASIVO</b><br>Apatía y Desenganche', showarrow: false, font: { color: '#fde68a', size: 11 } },
|
| 715 |
+
{ x: 75, y: 10, text: '<b>🛡️ BAJA TENSIÓN</b><br>Confort y Estabilidad', showarrow: false, font: { color: '#93c5fd', size: 11 } }
|
| 716 |
+
],
|
| 717 |
+
showlegend: false,
|
| 718 |
+
margin: { l: 50, r: 30, t: 50, b: 50 }
|
| 719 |
+
};
|
| 720 |
+
|
| 721 |
+
Plotly.newPlot('plot-karasek', [trace], layout, { responsive: true, displayModeBar: false });
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
function renderRadarPlot() {
|
| 725 |
+
const categories = ['Seguridad Psicológica', 'Autonomía', 'Resistencia Fricción', 'Control Sobrecarga', 'Valencia Prosocial'];
|
| 726 |
+
const categoriesClosed = [...categories, categories[0]];
|
| 727 |
+
|
| 728 |
+
const data = Object.keys(benchmarkData).map((dept, idx) => {
|
| 729 |
+
const d = benchmarkData[dept];
|
| 730 |
+
const vals = [
|
| 731 |
+
d.psi,
|
| 732 |
+
d.autonomy,
|
| 733 |
+
Math.max(0, 100 - d.friction),
|
| 734 |
+
Math.max(0, 100 - d.burnout),
|
| 735 |
+
Math.min(100, d.psi * 0.9 + (100 - d.friction) * 0.1)
|
| 736 |
+
];
|
| 737 |
+
const colors = ['#f43f5e', '#fb923c', '#10b981', '#38bdf8'];
|
| 738 |
+
return {
|
| 739 |
+
type: 'scatterpolar',
|
| 740 |
+
r: [...vals, vals[0]],
|
| 741 |
+
theta: categoriesClosed,
|
| 742 |
+
fill: 'toself',
|
| 743 |
+
name: dept,
|
| 744 |
+
line: { color: colors[idx % colors.length] },
|
| 745 |
+
opacity: 0.6
|
| 746 |
+
};
|
| 747 |
+
});
|
| 748 |
+
|
| 749 |
+
const layout = {
|
| 750 |
+
polar: {
|
| 751 |
+
radialaxis: { visible: true, range: [0, 100], gridcolor: '#334155', tickfont: { color: '#94a3b8' } },
|
| 752 |
+
bgcolor: '#0f172a'
|
| 753 |
+
},
|
| 754 |
+
paper_bgcolor: '#131b2e',
|
| 755 |
+
title: { text: '<b>Huella Radar de Resiliencia Psicológica Ocupacional</b>', font: { color: '#ffffff', size: 15 } },
|
| 756 |
+
legend: { orientation: 'h', y: 1.15, x: 1, xanchor: 'right', font: { color: '#cbd5e1' } },
|
| 757 |
+
margin: { l: 40, r: 40, t: 50, b: 40 }
|
| 758 |
+
};
|
| 759 |
+
|
| 760 |
+
Plotly.newPlot('plot-radar', data, layout, { responsive: true, displayModeBar: false });
|
| 761 |
+
}
|
| 762 |
+
|
| 763 |
+
// ==========================================
|
| 764 |
+
// Client-Side Zero Data Leakage Anonymizer
|
| 765 |
+
// ==========================================
|
| 766 |
+
function clientAnonymize(text) {
|
| 767 |
+
const piiList = [];
|
| 768 |
+
let sanitized = text;
|
| 769 |
+
|
| 770 |
+
// 1. Email
|
| 771 |
+
const emailRegex = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,7}\b/g;
|
| 772 |
+
sanitized = sanitized.replace(emailRegex, (match) => {
|
| 773 |
+
piiList.push({ type: 'EMAIL', masked_value: '[EMAIL_REDACTED]' });
|
| 774 |
+
return '[EMAIL_REDACTED]';
|
| 775 |
+
});
|
| 776 |
+
|
| 777 |
+
// 2. Phone
|
| 778 |
+
const phoneRegex = /(?:\+?57\s*)?(?:\b3\d{2}[\s.-]?\d{3}[\s.-]?\d{4}\b|\b(?:\+?1[\s.-]?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}\b)/g;
|
| 779 |
+
sanitized = sanitized.replace(phoneRegex, (match) => {
|
| 780 |
+
piiList.push({ type: 'PHONE', masked_value: '[PHONE_REDACTED]' });
|
| 781 |
+
return '[PHONE_REDACTED]';
|
| 782 |
+
});
|
| 783 |
+
|
| 784 |
+
// 3. National IDs (CC, DNI)
|
| 785 |
+
const idRegex = /\b(?:CC|C\.C\.|Cédula|Cedula|DNI|Identificación|ID)[\s#:.]*([0-9]{1,3}(?:\.[0-9]{3}){2}|[0-9]{6,10})\b/gi;
|
| 786 |
+
sanitized = sanitized.replace(idRegex, (match) => {
|
| 787 |
+
piiList.push({ type: 'GOVERNMENT_ID', masked_value: '[ID_REDACTED]' });
|
| 788 |
+
return '[ID_REDACTED]';
|
| 789 |
+
});
|
| 790 |
+
|
| 791 |
+
// 4. Financial & Salaries
|
| 792 |
+
const finRegex = /(?:(?:\$|COP|USD|EUR)\s*[\d]{1,3}(?:[.,]\d{3})*(?:[.,]\d{2})?|\b\d+(?:[.,]\d+)*\s*(?:pesos|dólares|dolares|COP|USD|EUR)\b|\b(?:sueldo|salario|pago|honorarios|bono)\s+(?:de\s+)?[\$]?[\d.,]+(?:\s*(?:millones|mil|k|USD|COP))?\b)/gi;
|
| 793 |
+
sanitized = sanitized.replace(finRegex, (match) => {
|
| 794 |
+
piiList.push({ type: 'FINANCIAL_SALARY', masked_value: '[FINANCIAL_REDACTED]' });
|
| 795 |
+
return '[FINANCIAL_REDACTED]';
|
| 796 |
+
});
|
| 797 |
+
|
| 798 |
+
// 5. IP Addresses
|
| 799 |
+
const ipRegex = /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/g;
|
| 800 |
+
sanitized = sanitized.replace(ipRegex, (match) => {
|
| 801 |
+
piiList.push({ type: 'NETWORK_IP', masked_value: '[IP_REDACTED]' });
|
| 802 |
+
return '[IP_REDACTED]';
|
| 803 |
+
});
|
| 804 |
+
|
| 805 |
+
// 6. Name greetings
|
| 806 |
+
const greetingRegex = /\b(Hola|Buenos días|Buenas tardes|Estimado|Estimada|Dear|Hi|Hello)\s+([A-ZÁÉÍÓÚÑ][a-záéíóúñ]+(?:\s+[A-ZÁÉÍÓÚÑ][a-záéíóúñ]+)?)(?=[,\s!?\n]|$)/gi;
|
| 807 |
+
sanitized = sanitized.replace(greetingRegex, (match, p1, p2) => {
|
| 808 |
+
if (['equipo', 'todos', 'team', 'all', 'grupo'].includes(p2.toLowerCase())) return match;
|
| 809 |
+
piiList.push({ type: 'PERSON_NAME', masked_value: '[NAME_REDACTED]' });
|
| 810 |
+
return `${p1} [NAME_REDACTED]`;
|
| 811 |
+
});
|
| 812 |
+
|
| 813 |
+
return { sanitized, piiList };
|
| 814 |
+
}
|
| 815 |
+
|
| 816 |
+
// ==========================================
|
| 817 |
+
// Client-Side Telemetry Engine
|
| 818 |
+
// ==========================================
|
| 819 |
+
function clientComputeTelemetry(cleanText) {
|
| 820 |
+
const markers = [];
|
| 821 |
+
|
| 822 |
+
const matchCount = (regex) => (cleanText.match(regex) || []).length;
|
| 823 |
+
|
| 824 |
+
const exhaustion = matchCount(/\b(agotad[oa]s?|no doy m[aá]s|quemad[oa]s?|colaps[aoó]ndo?|drenad[oa]s?|sin energ[ií]a|al l[ií]mite|saturad[oa]s?|sobrecarga(?:da)?|insomnio|estr[eé]s|exhausted|burned out|overwhelmed)\b/gi);
|
| 825 |
+
const urgency = matchCount(/\b(urgente|ya mismo|para ayer|emergencia|asap|apaga(?:ndo)? incendios|inmediat[ao](?:mente)?|ahora mismo|bloqueante|cr[ií]tic[ao]|se cay[oó])\b/gi);
|
| 826 |
+
const cynicism = matchCount(/\b(da igual|me da lo mismo|qu[eé] m[aá]s da|no me pagan lo suficiente|no es mi problema|hagan lo que quieran|para qu[eé]|no vale la pena)\b/gi);
|
| 827 |
+
const vulnerability = matchCount(/\b(me equivoqu[eé]|comet[ií] un error|fue mi error|necesito ayuda|no s[eé] c[oó]mo|pido disculpas|i made a mistake)\b/gi);
|
| 828 |
+
const inquiry = matchCount(/\b(qu[eé] opinan|c[oó]mo lo ven|alguien tiene dudas|sugerencias|qu[eé] riesgos ven|feedback|qu[eé] piensan)\b/gi);
|
| 829 |
+
const constructive = matchCount(/\b(propongo|otra alternativa|otra perspectiva|y si probamos|desde mi punto de vista)\b/gi);
|
| 830 |
+
const friction = matchCount(/\b(como ya (?:te )?hab[ií]a dicho|como ya dije|favor leer el hilo|como mencion[eé] antes|otra vez con lo mismo|no vuelvo a repetir|no es mi trabajo|eso te correspond[ií]a)\b/gi);
|
| 831 |
+
const prosocial = matchCount(/\b(gracias|muchas gracias|gran trabajo|felicitaciones|trabajemos juntos|con gusto|te ayudo|te apoyo)\b/gi);
|
| 832 |
+
const command = matchCount(/\b(tienes que hacer|debes enviar ya|est[aá] prohibido|es obligatorio|haz lo que digo)\b/gi);
|
| 833 |
+
|
| 834 |
+
if (exhaustion) markers.push(`Agotamiento(${exhaustion})`);
|
| 835 |
+
if (urgency) markers.push(`Urgencia(${urgency})`);
|
| 836 |
+
if (vulnerability) markers.push(`Vulnerabilidad(${vulnerability})`);
|
| 837 |
+
if (inquiry) markers.push(`Indagación(${inquiry})`);
|
| 838 |
+
if (friction) markers.push(`Fricción(${friction})`);
|
| 839 |
+
if (prosocial) markers.push(`Prosocial(${prosocial})`);
|
| 840 |
+
if (cynicism) markers.push(`Cinismo(${cynicism})`);
|
| 841 |
+
|
| 842 |
+
// Caps words penalty
|
| 843 |
+
const capsWords = cleanText.split(/\s+/).filter(w => w === w.toUpperCase() && w.length >= 4 && !w.includes('REDACTED'));
|
| 844 |
+
const capsPenalty = Math.min(25, capsWords.length * 8);
|
| 845 |
+
|
| 846 |
+
// 1. Stress OSBI (0 - 100)
|
| 847 |
+
let stress = 15.0 + (exhaustion * 28) + (urgency * 18) + (cynicism * 22) + capsPenalty - (prosocial * 8);
|
| 848 |
+
stress = Math.max(0, Math.min(100, Math.round(stress)));
|
| 849 |
+
|
| 850 |
+
// 2. Psychological Safety PSI (0 - 100)
|
| 851 |
+
let psi = 55.0 + (vulnerability * 22) + (inquiry * 16) + (constructive * 14) + (prosocial * 10) - (friction * 25) - (command * 15) - (capsPenalty * 0.5);
|
| 852 |
+
psi = Math.max(0, Math.min(100, Math.round(psi)));
|
| 853 |
+
|
| 854 |
+
// 3. Friction IFCI (0 - 100)
|
| 855 |
+
let ifci = 10.0 + (friction * 32) + (cynicism * 16) + (command * 14) + (capsPenalty * 0.6) - (prosocial * 15);
|
| 856 |
+
ifci = Math.max(0, Math.min(100, Math.round(ifci)));
|
| 857 |
+
|
| 858 |
+
// 4. Autonomy
|
| 859 |
+
let autonomy = 45.0 + (constructive * 15) + (inquiry * 10) - (command * 22);
|
| 860 |
+
autonomy = Math.max(0, Math.min(100, Math.round(autonomy)));
|
| 861 |
+
|
| 862 |
+
return { stress, psi, ifci, autonomy, markers };
|
| 863 |
+
}
|
| 864 |
+
|
| 865 |
+
function processSandbox() {
|
| 866 |
+
const raw = document.getElementById('raw-input').value;
|
| 867 |
+
if (!raw.trim()) return;
|
| 868 |
+
|
| 869 |
+
const { sanitized, piiList } = clientAnonymize(raw);
|
| 870 |
+
const tele = clientComputeTelemetry(sanitized);
|
| 871 |
+
|
| 872 |
+
document.getElementById('clean-output').innerText = sanitized;
|
| 873 |
+
document.getElementById('pii-output').innerText = JSON.stringify({
|
| 874 |
+
total_redactions: piiList.length,
|
| 875 |
+
entities: piiList
|
| 876 |
+
}, null, 2);
|
| 877 |
+
|
| 878 |
+
// Update gauges
|
| 879 |
+
document.getElementById('score-burnout-text').innerText = `${tele.stress} / 100`;
|
| 880 |
+
document.getElementById('score-burnout-bar').style.width = `${tele.stress}%`;
|
| 881 |
+
|
| 882 |
+
document.getElementById('score-psi-text').innerText = `${tele.psi} / 100`;
|
| 883 |
+
document.getElementById('score-psi-bar').style.width = `${tele.psi}%`;
|
| 884 |
+
|
| 885 |
+
document.getElementById('score-friction-text').innerText = `${tele.ifci} / 100`;
|
| 886 |
+
document.getElementById('score-friction-bar').style.width = `${tele.ifci}%`;
|
| 887 |
+
|
| 888 |
+
document.getElementById('score-autonomy-text').innerText = `${tele.autonomy} / 100`;
|
| 889 |
+
document.getElementById('score-autonomy-bar').style.width = `${tele.autonomy}%`;
|
| 890 |
+
|
| 891 |
+
document.getElementById('markers-text').innerText = tele.markers.length > 0 ? tele.markers.join(', ') : 'Ninguno detectado';
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
function loadPreset(num) {
|
| 895 |
+
const presets = {
|
| 896 |
+
1: "URGENTE: Se cayó el cluster de Kubernetes en la IP 10.0.12.44. La pasarela de pagos está rechazada. Llevo 16 horas seguidas en esto, estoy totalmente agotado y con insomnio. No doy más con estos deploys!",
|
| 897 |
+
2: "Como ya te había dicho en el correo anterior, favor leer el hilo con atención. Otra vez con lo mismo, la orden con DNI 45678901 no es mi trabajo. No vuelvo a repetir.",
|
| 898 |
+
3: "Equipo, cometí un error en el preprocesamiento del dataset de entrenamiento. Pido disculpas, ya lo corregí en el repositorio. ¿Qué opinan sobre este enfoque? Muchas gracias por su apoyo.",
|
| 899 |
+
4: "Da igual el caso del cliente, aquí no me pagan lo suficiente para complicarme la vida. Qué más da si el ticket queda abierto, hagan lo que quieran."
|
| 900 |
+
};
|
| 901 |
+
document.getElementById('raw-input').value = presets[num];
|
| 902 |
+
processSandbox();
|
| 903 |
+
}
|
| 904 |
+
|
| 905 |
+
// Initialize initial charts
|
| 906 |
+
window.addEventListener('load', () => {
|
| 907 |
+
renderDepartmentBars();
|
| 908 |
+
processSandbox();
|
| 909 |
+
});
|
| 910 |
+
</script>
|
| 911 |
+
</body>
|
| 912 |
+
</html>
|