| | import os |
| | from functools import lru_cache |
| | from typing import Optional |
| |
|
| | DESIGN_SYSTEM = { |
| | 'colors': { |
| | 'primary': '#1E40AF', |
| | 'secondary': '#059669', |
| | 'accent': '#DC2626', |
| | 'warning': '#D97706', |
| | 'success': '#10B981', |
| | 'background': '#F8FAFC', |
| | 'text': '#1F2937', |
| | 'border': '#E5E7EB' |
| | }, |
| | 'fonts': { |
| | 'title': 'font-family: "Inter", sans-serif; font-weight: 700;', |
| | 'subtitle': 'font-family: "Inter", sans-serif; font-weight: 600;', |
| | 'body': 'font-family: "Inter", sans-serif; font-weight: 400;' |
| | } |
| | } |
| |
|
| | DATA_URLS = { |
| | "2024": "https://huggingface.co/spaces/entropy25/production-data-analysis/resolve/main/2024.csv", |
| | "2025": "https://huggingface.co/spaces/entropy25/production-data-analysis/resolve/main/2025.csv" |
| | } |
| |
|
| | SAMPLE_MATERIALS = ['steel', 'aluminum', 'plastic', 'copper'] |
| | SAMPLE_SHIFTS = ['day', 'night'] |
| | SAMPLE_BASE_WEIGHTS = { |
| | 'steel': 1500, |
| | 'aluminum': 800, |
| | 'plastic': 600, |
| | 'copper': 400 |
| | } |
| |
|
| | TRANSLATIONS = { |
| | 'English': { |
| | 'page_title': 'Production Monitor with AI Insights', |
| | 'page_subtitle': 'Nilsen Service & Consulting AS | Real-time Production Analytics & Recommendations', |
| | 'sidebar_data_source': 'Data Source', |
| | 'sidebar_upload': 'Upload Production Data', |
| | 'sidebar_quick_load': 'Quick Load', |
| | 'sidebar_format_hint': '**Expected TSV format:**\n- `date`: MM/DD/YYYY\n- `weight_kg`: Production weight\n- `material_type`: Material category\n- `shift`: day/night (optional)', |
| | 'ai_ready': 'AI Assistant Ready', |
| | 'ai_unavailable': 'AI Assistant Unavailable', |
| | 'ai_config_hint': 'To enable AI features, set GROQ_API_KEY as environment variable or in Streamlit secrets', |
| | 'data_uploaded': 'Data uploaded successfully', |
| | 'data_loaded': 'data loaded successfully', |
| | 'data_health': 'Data Health Check', |
| | 'section_material_overview': 'Material Overview', |
| | 'section_production_trends': 'Production Trends', |
| | 'section_materials_analysis': 'Materials Analysis', |
| | 'section_shift_analysis': 'Shift Analysis', |
| | 'section_quality_check': 'Quality Check', |
| | 'section_export': 'Export Reports', |
| | 'section_ai_insights': 'AI Insights', |
| | 'section_ai_config': 'AI Configuration', |
| | 'time_period': 'Time Period', |
| | 'select_materials': 'Select Materials', |
| | 'metric_total': 'Total Production', |
| | 'metric_daily_avg': 'Daily avg', |
| | 'quality_normal': 'All values normal', |
| | 'quality_outliers': 'outliers detected', |
| | 'quality_normal_range': 'Normal range', |
| | 'btn_generate_pdf': 'Generate PDF Report', |
| | 'btn_download_pdf': 'Download PDF Report', |
| | 'btn_generate_csv': 'Generate CSV Summary', |
| | 'btn_download_csv': 'Download CSV Summary', |
| | 'btn_download_raw': 'Download Raw Data', |
| | 'pdf_generating': 'Generating comprehensive PDF report...', |
| | 'pdf_success': 'PDF report generated successfully', |
| | 'pdf_failed': 'PDF generation failed', |
| | 'csv_success': 'CSV summary generated successfully', |
| | 'csv_failed': 'CSV generation failed', |
| | 'ai_quick_q1': 'How does production distribution on weekdays compare to weekends?', |
| | 'ai_quick_q2': 'Which material exhibits the most volatility in our dataset?', |
| | 'ai_quick_q3': 'To improve stability, which material or shift needs immediate attention?', |
| | 'ai_custom_placeholder': "e.g., 'Compare steel vs aluminum last month'", |
| | 'ai_ask_label': 'Ask about your production data:', |
| | 'ai_ask_btn': 'Ask AI', |
| | 'ai_analyzing': 'Analyzing...', |
| | 'welcome_title': 'How to Use This Platform', |
| | 'welcome_quick_start': 'Quick Start', |
| | 'welcome_features': 'Key Features', |
| | 'welcome_ready': 'Ready to start? Upload your production data or use Quick Load buttons to begin analysis', |
| | 'welcome_steps': '1. Upload your TSV data in the sidebar\n2. Or click Quick Load buttons for preset data\n3. View production by material type\n4. Analyze trends (daily/weekly/monthly)\n5. Check anomalies in Quality Check\n6. Export reports (PDF with AI, CSV)\n7. Ask the AI assistant for insights', |
| | 'welcome_features_list': '- Real-time interactive charts\n- One-click preset data loading\n- Time-period comparisons\n- Shift performance analysis\n- Outlier detection with dates\n- AI-powered PDF reports\n- Intelligent recommendations', |
| | 'ai_config_info': '**AI Assistant is currently unavailable.**\n\nTo enable AI features, configure your Groq API key:\n\n**Option 1: Environment Variable**\n```bash\nexport GROQ_API_KEY="your_api_key_here"\n```\n\n**Option 2: Streamlit Secrets**\nCreate `.streamlit/secrets.toml`:\n```toml\nGROQ_API_KEY = "your_api_key_here"\n```\n\nGet free API key at: https://console.groq.com/keys', |
| | 'chart_total_production': 'Total Production Trend', |
| | 'chart_total_production_weekly': 'Total Production Trend (Weekly)', |
| | 'chart_total_production_monthly': 'Total Production Trend (Monthly)', |
| | 'chart_materials_trends': 'Materials Production Trends', |
| | 'chart_materials_trends_weekly': 'Materials Production Trends (Weekly)', |
| | 'chart_materials_trends_monthly': 'Materials Production Trends (Monthly)', |
| | 'chart_shift_trends': 'Daily Shift Production Trends (Stacked)', |
| | 'chart_shift_trends_period': 'Shift Production Trends', |
| | 'label_date': 'Date', |
| | 'label_weight': 'Weight (kg)', |
| | 'label_week': 'Week', |
| | 'label_month': 'Month', |
| | 'label_material': 'Material', |
| | 'label_day_shift': 'Day Shift', |
| | 'label_night_shift': 'Night Shift' |
| | }, |
| | 'Norsk': { |
| | 'page_title': 'Produksjonsovervaking med AI-innsikt', |
| | 'page_subtitle': 'Nilsen Service & Consulting AS | Sanntidsanalyse og anbefalinger', |
| | 'sidebar_data_source': 'Datakilde', |
| | 'sidebar_upload': 'Last opp produksjonsdata', |
| | 'sidebar_quick_load': 'Hurtiglasting', |
| | 'sidebar_format_hint': '**Forventet TSV-format:**\n- `date`: MM/DD/YYYY\n- `weight_kg`: Produksjonsvekt\n- `material_type`: Materialkategori\n- `shift`: dag/natt (valgfritt)', |
| | 'ai_ready': 'AI-assistent klar', |
| | 'ai_unavailable': 'AI-assistent utilgjengelig', |
| | 'ai_config_hint': 'For a aktivere AI-funksjoner, sett GROQ_API_KEY som miljovariabel eller i Streamlit secrets', |
| | 'data_uploaded': 'Data lastet opp', |
| | 'data_loaded': 'data lastet inn', |
| | 'data_health': 'Datakvalitetssjekk', |
| | 'section_material_overview': 'Materialoversikt', |
| | 'section_production_trends': 'Produksjonstrender', |
| | 'section_materials_analysis': 'Materialanalyse', |
| | 'section_shift_analysis': 'Skiftanalyse', |
| | 'section_quality_check': 'Kvalitetskontroll', |
| | 'section_export': 'Eksporter rapporter', |
| | 'section_ai_insights': 'AI-innsikt', |
| | 'section_ai_config': 'AI-konfigurasjon', |
| | 'time_period': 'Tidsperiode', |
| | 'select_materials': 'Velg materialer', |
| | 'metric_total': 'Total produksjon', |
| | 'metric_daily_avg': 'Daglig gj.snitt', |
| | 'quality_normal': 'Alle verdier normale', |
| | 'quality_outliers': 'avvik funnet', |
| | 'quality_normal_range': 'Normalomrade', |
| | 'btn_generate_pdf': 'Generer PDF-rapport', |
| | 'btn_download_pdf': 'Last ned PDF-rapport', |
| | 'btn_generate_csv': 'Generer CSV-sammendrag', |
| | 'btn_download_csv': 'Last ned CSV-sammendrag', |
| | 'btn_download_raw': 'Last ned radata', |
| | 'pdf_generating': 'Genererer omfattende PDF-rapport...', |
| | 'pdf_success': 'PDF-rapport generert', |
| | 'pdf_failed': 'PDF-generering mislyktes', |
| | 'csv_success': 'CSV-sammendrag generert', |
| | 'csv_failed': 'CSV-generering mislyktes', |
| | 'ai_quick_q1': 'Hvordan er produksjonsfordelingen pa hverdager sammenlignet med helger?', |
| | 'ai_quick_q2': 'Hvilket materiale viser mest volatilitet i datasettet?', |
| | 'ai_quick_q3': 'For a forbedre stabilitet, hvilket materiale eller skift trenger umiddelbar oppmerksomhet?', |
| | 'ai_custom_placeholder': "f.eks. 'Sammenlign stal og aluminium forrige maned'", |
| | 'ai_ask_label': 'Still sporsmal om produksjonsdataene:', |
| | 'ai_ask_btn': 'Spor AI', |
| | 'ai_analyzing': 'Analyserer...', |
| | 'welcome_title': 'Slik bruker du plattformen', |
| | 'welcome_quick_start': 'Hurtigstart', |
| | 'welcome_features': 'Hovedfunksjoner', |
| | 'welcome_ready': 'Klar til a starte? Last opp produksjonsdata eller bruk Hurtiglasting-knappene', |
| | 'welcome_steps': '1. Last opp TSV-data i sidepanelet\n2. Eller klikk Hurtiglasting-knappene for forhandsinnstilte data\n3. Se produksjon etter materialtype\n4. Analyser trender (daglig/ukentlig/manedlig)\n5. Sjekk anomalier i Kvalitetskontroll\n6. Eksporter rapporter (PDF med AI, CSV)\n7. Still AI-assistenten sporsmal for innsikt', |
| | 'welcome_features_list': '- Sanntids interaktive diagrammer\n- Ett-klikks forhandsinnlasting\n- Tidsperiodesammenligninger\n- Skiftytelsesanalyse\n- Avviksdeteksjon med datoer\n- AI-drevne PDF-rapporter\n- Intelligente anbefalinger', |
| | 'ai_config_info': '**AI-assistent er for oyeblikket utilgjengelig.**\n\nFor a aktivere AI-funksjoner, konfigurer Groq API-nokkel:\n\n**Alternativ 1: Miljovariabel**\n```bash\nexport GROQ_API_KEY="din_api_nokkel_her"\n```\n\n**Alternativ 2: Streamlit Secrets**\nOpprett `.streamlit/secrets.toml`:\n```toml\nGROQ_API_KEY = "din_api_nokkel_her"\n```\n\nFa gratis API-nokkel pa: https://console.groq.com/keys', |
| | 'chart_total_production': 'Total produksjonstrend', |
| | 'chart_total_production_weekly': 'Total produksjonstrend (Ukentlig)', |
| | 'chart_total_production_monthly': 'Total produksjonstrend (Manedlig)', |
| | 'chart_materials_trends': 'Materialproduksjonstrender', |
| | 'chart_materials_trends_weekly': 'Materialproduksjonstrender (Ukentlig)', |
| | 'chart_materials_trends_monthly': 'Materialproduksjonstrender (Manedlig)', |
| | 'chart_shift_trends': 'Daglig skiftproduksjonstrend (Stablet)', |
| | 'chart_shift_trends_period': 'Skiftproduksjonstrender', |
| | 'label_date': 'Dato', |
| | 'label_weight': 'Vekt (kg)', |
| | 'label_week': 'Uke', |
| | 'label_month': 'Maned', |
| | 'label_material': 'Material', |
| | 'label_day_shift': 'Dagskift', |
| | 'label_night_shift': 'Nattskift' |
| | } |
| | } |
| |
|
| | def get_translation(lang: str = 'English') -> dict: |
| | return TRANSLATIONS.get(lang, TRANSLATIONS['English']) |
| |
|
| | class Settings: |
| | def __init__(self): |
| | self.environment = os.getenv("ENV", "development") |
| | |
| | @property |
| | def groq_api_key(self) -> Optional[str]: |
| | if key := os.getenv("GROQ_API_KEY"): |
| | return key |
| | |
| | try: |
| | import streamlit as st |
| | if key := st.secrets.get("GROQ_API_KEY"): |
| | return key |
| | except: |
| | pass |
| | |
| | if self.environment == "development": |
| | try: |
| | from dotenv import load_dotenv |
| | load_dotenv() |
| | return os.getenv("GROQ_API_KEY") |
| | except ImportError: |
| | pass |
| | |
| | return None |
| | |
| | @property |
| | def is_production(self) -> bool: |
| | return self.environment == "production" |
| |
|
| | @lru_cache() |
| | def get_settings() -> Settings: |
| | return Settings() |
| |
|
| | def get_css_styles() -> str: |
| | colors = DESIGN_SYSTEM['colors'] |
| | fonts = DESIGN_SYSTEM['fonts'] |
| | |
| | return f""" |
| | <style> |
| | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); |
| | |
| | .main-header {{ |
| | background: linear-gradient(135deg, {colors['primary']} 0%, {colors['secondary']} 100%); |
| | padding: 1.5rem 2rem; |
| | border-radius: 12px; |
| | margin-bottom: 2rem; |
| | color: white; |
| | text-align: center; |
| | }} |
| | |
| | .main-title {{ |
| | {fonts['title']} |
| | font-size: 2.2rem; |
| | margin: 0; |
| | text-shadow: 0 2px 4px rgba(0,0,0,0.1); |
| | }} |
| | |
| | .main-subtitle {{ |
| | {fonts['body']} |
| | font-size: 1rem; |
| | opacity: 0.9; |
| | margin-top: 0.5rem; |
| | }} |
| | |
| | .section-header {{ |
| | {fonts['subtitle']} |
| | color: {colors['text']}; |
| | font-size: 1.4rem; |
| | margin: 2rem 0 1rem 0; |
| | padding-bottom: 0.5rem; |
| | border-bottom: 2px solid {colors['primary']}; |
| | }} |
| | |
| | .chart-container {{ |
| | background: white; |
| | border-radius: 12px; |
| | padding: 1rem; |
| | box-shadow: 0 1px 3px rgba(0,0,0,0.1); |
| | margin-bottom: 1rem; |
| | }} |
| | |
| | .alert-success {{ |
| | background: linear-gradient(135deg, {colors['success']}15, {colors['success']}25); |
| | border: 1px solid {colors['success']}; |
| | border-radius: 8px; |
| | padding: 1rem; |
| | color: {colors['success']}; |
| | }} |
| | |
| | .alert-warning {{ |
| | background: linear-gradient(135deg, {colors['warning']}15, {colors['warning']}25); |
| | border: 1px solid {colors['warning']}; |
| | border-radius: 8px; |
| | padding: 1rem; |
| | color: {colors['warning']}; |
| | }} |
| | |
| | .quality-dates {{ |
| | font-size: 0.85em; |
| | margin-top: 0.5rem; |
| | max-height: 150px; |
| | overflow-y: auto; |
| | padding: 0.3rem; |
| | background: rgba(255,255,255,0.3); |
| | border-radius: 4px; |
| | }} |
| | |
| | .stButton > button, .stDownloadButton > button {{ |
| | background: {colors['primary']} !important; |
| | color: white !important; |
| | border: none !important; |
| | border-radius: 8px !important; |
| | padding: 0.5rem 1rem !important; |
| | font-weight: 500 !important; |
| | }} |
| | </style> |
| | """ |
| |
|
| | def get_chart_theme() -> dict: |
| | colors = DESIGN_SYSTEM['colors'] |
| | return { |
| | 'layout': { |
| | 'plot_bgcolor': 'white', |
| | 'paper_bgcolor': 'white', |
| | 'font': {'family': 'Inter, sans-serif', 'color': colors['text']}, |
| | 'colorway': [colors['primary'], colors['secondary'], colors['accent'], colors['warning']], |
| | 'margin': {'t': 60, 'b': 40, 'l': 40, 'r': 40} |
| | } |
| | } |