Meine ersten Skills:

Der Mathematiker – Einfache Rechnungen lösen

Ein leichter, praxisnaher Skill: einfache Rechnungen lösen, freundlich formatiert ausgeben – ganz ohne externe APIs.


Inhaltsverzeichnis


Einführung

Nach dem Erfolg meines ersten Bildanalyse‑Skills wollte ich einen zweiten Skill erstellen – diesmal einen „Mathematiker“, der einfache Rechnungen lösen kann. Keine komplexen mathematischen Bibliotheken, nur grundlegende Python‑Mathematik mit benutzerfreundlicher Ausgabe.


Warum ein Mathematiker-Skill?

Ich suchte nach einem Skill, der:

  • ✅ Einfache mathematische Operationen löst
  • ✅ Benutzerfreundliche Ausgaben erstellt
  • ✅ Verschiedene Eingabeformate unterstützt
  • ✅ Schritt‑für‑Schritt Lösungen zeigt
  • ✅ Keine externen APIs benötigt

Schritt 1: Die Grundidee entwickeln

Der Mathematiker‑Skill sollte folgende Operationen unterstützen:

  • Grundrechenarten: +, -, *, /
  • Potenzierung: x^y
  • Wurzel: √x
  • Prozentrechnung: x% von y
  • Durchschnitt: Mittelwert von Zahlen
  • Runden: Auf n Nachkommastellen

Schritt 2: Mein Mathematiker‑Skill

Ich erstellte skills/mathematician.py:

#!/usr/bin/env python3
import os
import json
import logging
import math
import re
from datetime import datetime

def parse_expression(expression):
    """
    Parst mathematische Ausdrücke und gibt sie in sicherer Form zurück
    """
    # Gefährliche Zeichen entfernen
    dangerous_chars = ['import', 'eval', 'exec', '__', 'open', 'file']
    expression_lower = expression.lower()
    
    for char in dangerous_chars:
        if char in expression_lower:
            return None, "Gefährliche Zeichen nicht erlaubt"
    
    # Nur erlaubte Zeichen
    allowed_chars = r'^[0-9+\-*/().,^√% ]+$'
    if not re.match(allowed_chars, expression):
        return None, "Nur mathematische Zeichen erlaubt"
    
    return expression, None

def calculate_basic(expression):
    """
    Führt grundlegende Berechnungen durch
    """
    try:
        # Sicherheitscheck
        parsed_expr, error = parse_expression(expression)
        if error:
            return None, error
        
        # Mathematische Symbole ersetzen
        expr = parsed_expr.replace('^', '**')
        expr = expr.replace('√', 'math.sqrt')
        expr = expr.replace('π', str(math.pi))
        expr = expr.replace('e', str(math.e))
        
        # Berechnung durchführen
        result = eval(expr)
        
        return result, None
    except ZeroDivisionError:
        return None, "Division durch Null nicht erlaubt"
    except ValueError as e:
        return None, f"Ungültige Berechnung: {str(e)}"
    except Exception as e:
        return None, f"Berechnungsfehler: {str(e)}"

def calculate_percentage(value, percentage):
    """
    Berechnet Prozentwerte
    """
    try:
        result = (value * percentage) / 100
        return result, None
    except Exception as e:
        return None, f"Prozentberechnung fehlgeschlagen: {str(e)}"

def calculate_average(numbers):
    """
    Berechnet den Durchschnitt einer Zahlenliste
    """
    try:
        if not numbers:
            return None, "Keine Zahlen zum Berechnen"
        
        total = sum(numbers)
        average = total / len(numbers)
        return average, None
    except Exception as e:
        return None, f"Durchschnittsberechnung fehlgeschlagen: {str(e)}"

def round_number(number, decimals=2):
    """
    Rundet eine Zahl auf n Nachkommastellen
    """
    try:
        return round(number, decimals), None
    except Exception as e:
        return None, f"Rundung fehlgeschlagen: {str(e)}"

def format_result(result, operation_type="basic"):
    """
    Formatiert das Ergebnis benutzerfreundlich
    """
    if isinstance(result, (int, float)):
        if result == int(result):
            return str(int(result))
        else:
            return f"{result:.6f}".rstrip('0').rstrip('.')
    else:
        return str(result)

def create_calculation_report(expression, result, operation_type="basic", steps=None):
    """
    Erstellt einen detaillierten Berechnungsbericht
    """
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    report = {
        "timestamp": timestamp,
        "expression": expression,
        "result": format_result(result),
        "operation_type": operation_type,
        "steps": steps or [],
        "formatted_result": format_result(result)
    }
    
    return report

def main(raw_input, **unused):
    """
    Mathematiker-Skill für einfache Rechnungen
    Eingabe: Mathematischer Ausdruck oder JSON mit Parametern
    Ausgabe: Berechnungsbericht
    """
    try:
        logging.info(f"Mathematiker-Skill aufgerufen mit: {raw_input[:100]}...")
        
        # Input parsen
        if raw_input.strip().startswith('{'):
            params = json.loads(raw_input)
            operation = params.get("operation", "basic")
        else:
            # Einfacher String - als Grundrechnung behandeln
            params = {"expression": raw_input.strip()}
            operation = "basic"
        
        # Operation ausführen
        if operation == "basic":
            expression = params.get("expression", "")
            if not expression:
                return {"error": "Kein mathematischer Ausdruck angegeben"}
            
            result, error = calculate_basic(expression)
            if error:
                return {"error": error}
            
            report = create_calculation_report(expression, result, "basic")
            
        elif operation == "percentage":
            value = params.get("value")
            percentage = params.get("percentage")
            
            if value is None or percentage is None:
                return {"error": "Wert und Prozentsatz müssen angegeben werden"}
            
            result, error = calculate_percentage(value, percentage)
            if error:
                return {"error": error}
            
            expression = f"{value} * {percentage}%"
            report = create_calculation_report(expression, result, "percentage")
            
        elif operation == "average":
            numbers = params.get("numbers", [])
            if not numbers:
                return {"error": "Keine Zahlen für Durchschnittsberechnung angegeben"}
            
            result, error = calculate_average(numbers)
            if error:
                return {"error": error}
            
            expression = f"Durchschnitt von {numbers}"
            report = create_calculation_report(expression, result, "average")
            
        elif operation == "round":
            number = params.get("number")
            decimals = params.get("decimals", 2)
            
            if number is None:
                return {"error": "Keine Zahl zum Runden angegeben"}
            
            result, error = round_number(number, decimals)
            if error:
                return {"error": error}
            
            expression = f"Runden von {number} auf {decimals} Nachkommastellen"
            report = create_calculation_report(expression, result, "round")
            
        else:
            return {"error": f"Unbekannte Operation: {operation}"}
        
        logging.info(f"Berechnung erfolgreich: {expression} = {result}")
        return {
            "success": True,
            "calculation": report,
            "message": f"Berechnung erfolgreich: {expression} = {report['formatted_result']}"
        }
        
    except json.JSONDecodeError:
        return {"error": "Ungültiges JSON-Format"}
    except Exception as e:
        logging.error(f"Unerwarteter Fehler: {e}")
        return {"error": f"Skill fehlgeschlagen: {str(e)}"}

# Test-Code für lokales Testen
if __name__ == "__main__":
    # Test-Berechnungen
    test_cases = [
        "2 + 3 * 4",
        "10^2",
        "√16",
        "π * 2",
        {"operation": "percentage", "value": 200, "percentage": 15},
        {"operation": "average", "numbers": [1, 2, 3, 4, 5]},
        {"operation": "round", "number": 3.14159, "decimals": 2}
    ]
    
    for test in test_cases:
        print(f"\nTest: {test}")
        result = main(json.dumps(test) if isinstance(test, dict) else test)
        print(f"Ergebnis: {result}")

Schritt 3: Den Skill testen

Lokaler Test

# In Python-Konsole
import sys
sys.path.append('skills')
import mathematician

# Test mit einfachem Ausdruck
result = mathematician.main("2 + 3 * 4")
print(result)

# Test mit JSON
result = mathematician.main('{"operation": "percentage", "value": 200, "percentage": 15}')
print(result)

Schritt 4: Integration in die Anwendung

Über den Assistants Editor

  1. Anwendung öffnenAssistants Library
  2. „Add Assistant“ klicken
  3. Felder ausfüllen:
    • Name: „Mathematiker“
    • Instructions: „Löst einfache mathematische Rechnungen und zeigt detaillierte Berechnungsberichte“
    • Model: „gpt-4o-mini“
    • Description: „Mathematiker-Skill für Grundrechenarten, Prozentrechnung und Durchschnittsberechnung“
  4. Skill auswählen: mathematician.py
  5. Save klicken

Schritt 5: Den Skill verwenden

Einfache Verwendung

"Berechne: 2 + 3 * 4"
"Was ist 15% von 200?"
"Berechne den Durchschnitt von 1, 2, 3, 4, 5"
"Runde 3.14159 auf 2 Nachkommastellen"

JSON-Verwendung

{"operation": "percentage", "value": 200, "percentage": 15}
{"operation": "average", "numbers": [1, 2, 3, 4, 5]}
{"operation": "round", "number": 3.14159, "decimals": 2}

Beispiel-Ausgaben

Grundrechnung

{
  "success": true,
  "calculation": {
    "timestamp": "2024-12-20 15:30:22",
    "expression": "2 + 3 * 4",
    "result": "14",
    "operation_type": "basic",
    "formatted_result": "14"
  },
  "message": "Berechnung erfolgreich: 2 + 3 * 4 = 14"
}

Prozentrechnung

{
  "success": true,
  "calculation": {
    "timestamp": "2024-12-20 15:30:22",
    "expression": "200 * 15%",
    "result": "30.0",
    "operation_type": "percentage",
    "formatted_result": "30"
  },
  "message": "Berechnung erfolgreich: 200 * 15% = 30"
}

Durchschnittsberechnung

{
  "success": true,
  "calculation": {
    "timestamp": "2024-12-20 15:30:22",
    "expression": "Durchschnitt von [1, 2, 3, 4, 5]",
    "result": "3.0",
    "operation_type": "average",
    "formatted_result": "3"
  },
  "message": "Berechnung erfolgreich: Durchschnitt von [1, 2, 3, 4, 5] = 3"
}

Was der Skill kann

1. Grundrechenarten

  • Addition: 2 + 3
  • Subtraktion: 10 - 5
  • Multiplikation: 4 * 7
  • Division: 15 / 3
  • Klammern: (2 + 3) * 4

2. Erweiterte Operationen

  • Potenzierung: 2^3 oder 2**3
  • Wurzel: √16 oder sqrt(16)
  • Konstanten: π (Pi), e (Eulersche Zahl)

3. Prozentrechnung

  • x% von y berechnen
  • Automatische Formatierung

4. Durchschnittsberechnung

  • Mittelwert von Zahlenlisten
  • Robuste Fehlerbehandlung

5. Rundung

  • Auf n Nachkommastellen
  • Intelligente Formatierung

Sicherheitsfeatures

1. Eingabevalidierung

def parse_expression(expression):
    # Gefährliche Zeichen entfernen
    dangerous_chars = ['import', 'eval', 'exec', '__', 'open', 'file']
    # Nur mathematische Zeichen erlaubt
    allowed_chars = r'^[0-9+\-*/().,^√% ]+$'

2. Fehlerbehandlung

try:
    result = eval(expr)
except ZeroDivisionError:
    return None, "Division durch Null nicht erlaubt"
except ValueError as e:
    return None, f"Ungültige Berechnung: {str(e)}"

Erweiterte Funktionen (für Fortgeschrittene)

Trigonometrische Funktionen

def calculate_trigonometric(expression):
    """Trigonometrische Funktionen"""
    try:
        # Sinus, Cosinus, Tangens
        if 'sin(' in expression:
            expr = expression.replace('sin(', 'math.sin(')
        elif 'cos(' in expression:
            expr = expression.replace('cos(', 'math.cos(')
        elif 'tan(' in expression:
            expr = expression.replace('tan(', 'math.tan(')
        
        result = eval(expr)
        return result, None
    except Exception as e:
        return None, f"Trigonometrische Berechnung fehlgeschlagen: {str(e)}"

Statistische Funktionen

def calculate_statistics(numbers):
    """Statistische Funktionen"""
    try:
        import statistics
        
        stats = {
            "mean": statistics.mean(numbers),
            "median": statistics.median(numbers),
            "mode": statistics.mode(numbers) if len(set(numbers)) < len(numbers) else "Kein Modus",
            "variance": statistics.variance(numbers),
            "std_dev": statistics.stdev(numbers)
        }
        
        return stats, None
    except Exception as e:
        return None, f"Statistische Berechnung fehlgeschlagen: {str(e)}"

Einheitenumrechnung

def convert_units(value, from_unit, to_unit):
    """Einfache Einheitenumrechnung"""
    conversions = {
        "km_to_m": lambda x: x * 1000,
        "m_to_km": lambda x: x / 1000,
        "kg_to_g": lambda x: x * 1000,
        "g_to_kg": lambda x: x / 1000,
        "celsius_to_fahrenheit": lambda x: (x * 9/5) + 32,
        "fahrenheit_to_celsius": lambda x: (x - 32) * 5/9
    }
    
    conversion_key = f"{from_unit}_to_{to_unit}"
    if conversion_key in conversions:
        result = conversions[conversion_key](value)
        return result, None
    else:
        return None, f"Umrechnung {from_unit} zu {to_unit} nicht unterstützt"

Häufige Fehler und Lösungen

1. „Ungültige Berechnung“

# Lösung: Ausdruck vereinfachen
# Statt: "2 + 3 * 4 +"
# Verwenden: "2 + 3 * 4"

2. „Division durch Null“

# Lösung: Null-Check hinzufügen
if divisor == 0:
    return {"error": "Division durch Null nicht erlaubt"}

3. „Gefährliche Zeichen“

# Lösung: Nur mathematische Zeichen verwenden
# Erlaubt: 0-9, +, -, *, /, (, ), ., ^, √, %
# Nicht erlaubt: import, eval, exec, etc.

4. „Komplexe Ausdrücke“

# Lösung: Ausdruck in einfachere Teile aufteilen
# Statt: "sin(π/2) + cos(0)"
# Verwenden: "1 + 1"

Best Practices für Mathematiker‑Skills

1. Sicherheit zuerst

def safe_eval(expression):
    """Sichere Auswertung von mathematischen Ausdrücken"""
    # Whitelist von erlaubten Funktionen
    allowed_names = {
        'abs': abs, 'round': round, 'min': min, 'max': max,
        'sum': sum, 'len': len, 'math': math
    }
    
    # Nur erlaubte Namen verwenden
    return eval(expression, {"__builtins__": {}}, allowed_names)

2. Benutzerfreundliche Ausgaben

def format_math_result(result):
    """Formatiert mathematische Ergebnisse benutzerfreundlich"""
    if isinstance(result, (int, float)):
        if result == int(result):
            return str(int(result))
        else:
            # Entferne unnötige Nullen
            return f"{result:.6f}".rstrip('0').rstrip('.')
    return str(result)

3. Schritt‑für‑Schritt Lösungen

def show_calculation_steps(expression):
    """Zeigt die Berechnungsschritte"""
    steps = []
    
    # Vereinfachungsschritte
    if '*' in expression and '+' in expression:
        steps.append("Punkt-vor-Strich-Regel beachten")
    
    # Klammern auflösen
    if '(' in expression:
        steps.append("Klammern zuerst berechnen")
    
    return steps

Nächste Schritte

Wenn alles funktioniert könnte man auf die Funktionalität aufbauen:

  1. Gleichungslöser für lineare und quadratische Gleichungen
  2. Geometrie‑Berechnungen für Flächen und Volumen
  3. Finanzmathematik für Zins‑ und Rentenberechnungen
  4. Einheitenumrechner für verschiedene Maßeinheiten

Fazit

Dieser Mathematiker‑Skill zeigt, wie man:

  • Sichere mathematische Berechnungen implementiert
  • Benutzerfreundliche Ausgaben erstellt
  • Verschiedene Eingabeformate unterstützt
  • Robuste Fehlerbehandlung einbaut

Für Anfänger perfekt geeignet, weil:

  • Keine externen APIs nötig
  • Einfache mathematische Logik
  • Praktisch nutzbar
  • Einfach zu erweitern

Nächste Schritte für Sie:

  1. Erstellen Sie den Mathematiker‑Skill
  2. Testen Sie ihn mit verschiedenen Rechnungen
  3. Erweitern Sie ihn um eigene mathematische Funktionen
  4. Kombinieren Sie ihn mit anderen Skills!

Viel Erfolg beim Skills-Bauen! 🧮✨

Tags:

No responses yet

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Latest Comments

Es sind keine Kommentare vorhanden.