Der Bayer und der Würschtlmann

Von Würsten und Bayern

Tag: Swift

Happy Reads – eine Microsoft Cognitive Service App für gute oder schlechte Neuigkeiten

by tobonaut

tl;dr

Was ist Happy Reads?

Happy Reads ist eine iOS App (Github) welche mittels der Text Analytics API von den Microsoft Cognitive Services englischsprachige Meldungen der Deutschen Welle auf ihre „Fröhlichkeit“ analysiert und danach diese in „fröhlich“ oder „traurig“ einteilt.

Hintergrund

Noch sind für mich KI-gestütze Applikationen Neuland. Mir fehlten für private Projekte immer die Szenarien wo sich gelohnt hätte sich näher mit dieser Thematik zu befassen. Bis eines Tages die Nachrichten nur aus sehr traurigen, wenn nicht gar barbarischen Beiträgen bestanden hatten. Es schien so, als ob die ganze Welt nichts glückliches mehr zu bieten hätte. Um hiergegen anzukommen und auch für mein privates Wohlsein einen gewissen Ausgleich zu schaffen suchte ich im Netz dediziert nach glücklichen Meldungen. Natürlich fand ich diese, es war nur sehr zeitaufwendig und somit nicht für den täglichen Gebrauch geeignet.

Dadurch entstand die Idee, eine kleine App zu bauen, die mir auf eine einfache Art Nachrichten nach glücklich und traurig einteilt. Hierdurch merkte ich, wie toll es ist, dass man sich heutzutage damit einfach selber helfen kann und nach wenigen Stunden das Problem rudimentär gelöst ist. Eine wirklich tolle Erfahrung!

Aufbau der Applikation

Happy Reads ist sehr simpel gestrickt. Die App holt aus dem RSS Feed der Deutschen Welle Top-News Beiträge ab, schiebt diese gebündelt Richtung Text Analytics API und stellt diese, nun mit einer Fröhlichkeitsprozentwert versehen Beiträge, tabellarisch dar. Alles ab 75% Glücklichkeit ist für Happy Reads ein fröhlicher Beitrag, darunter zählt eher zu den traurigen. Natürlich kommt es hier vereinzelt zu False-Positives and es rutscht ein trauriger Beitrag zu den fröhlichen oder vice versa. Irren ist eben nicht nur menschlich.




Alle Icons stammen von GDJ von openclipart.org.

Weiter führende Informationen

Generell lohnt es sich der werten @codeprincess (TE bei Microsoft) auf Twitter zu folgen. Neben Cognitive Services bietet sie auch immer wieder erheiternde und – positive gemeint – etwas anders grafisch aufbereitete Tutorials rund um Azure und Co an.

@trikkser (Community Lead bei Microsoft) versorgt euch mit Informationen rund um die „große“ Kategorie AI. Beispielsweise bezüglich des CNTK oder Eventideen rund um diese Thematik.

Für state-of-the-art Informationen rund um Microsofts AI, lohnt ein Blick Richtung Microsoft Research und deren Projekte wie zum Beispiel CRIS.

Advertisements

[Lesetipp] Get back to playground … emotionally – Swift Playgrounds ausgereizt

by tobonaut

TL;DR

Wer einmal in die Erstellung eines komplexeren Swift Playground Book hinein schnüffeln mag, sollte sich unbedingt das freiverfügbare Slidedeck von der werten @codeprincess einmal genauer ansehen.


Auf der diesjährigen WWDC hat Apple die Swift Playground for iPad der Öffentlichkeit vorgestellt. Mit der Hilfe dieser App, beziehungsweise dieses Xcode Projekttypes lässt sich neben dem Einstieg in die Welt des Programmierens auch komplexe Frameworks verständlich und interaktiv gestalten.

Slidedeck von @codeprincess

Quelle: @codeprincess

Ich gebe zu, bis auf kleinere Codeschnippeseltests habe ich die Playgrounds (für Xcode) noch nie benutzt, auch die App für das iPad blieb mir bisher fern. Nichtsdestotrotz haben mich die Slides als auch das Beispiel von der wohl in der deutschsprachigen iOS-Szene sehr bekannten und charmanten Manu Rink aka @codeprincess beeindruckt und neugierig auf mehr gemacht.

Sie erklärt unter anderem einmal verständlich den Unterschied zwischen einem Swift Playground und einem Swift Playground Book. Bei letzterem steigt Manu auch gleich mit verständlichen, dennoch realitätsnahen Beispielen in die Slides ein. Zeigt hierbei manche Pitfalls auf und auf welche Ärgernisse man sich einstellen sollte.

Das Resultat, also der frei herunterladbare Playground, ist wie die Präsentation wunderschön mit Illustrationen ausgeschmückt und im gleichen Zuge lehrreich durchdacht.

Das Slidedeck in *.pdf-Form als selbstverständlich auch den Quelltext zum Playground findet ihr im passende Repository von codeprincess auf Github.

Auf Grund von semi-positiven Bemerkungen: Ja, bei dem Slidedeck geht es im späteren Verlauf um die Microsoft Cognitive Services, ja die Autorin ist bei Microsoft angestellt. Und ja, es ist mir völlig egal. Ich steh auf tolle Technologien, tolle Menschen und Community. Nicht jedoch auf ideologische Grabenkämpfe und IT-Stammtischparolen.

Swift: Array Extensions für einen gewissen Objekttyp

by tobonaut

Die Features von Swift sind vielseitig. Eines davon ist das es möglich ist, für einen genauen Typ eines Arrays Extensions zu definieren. Somit hat man innerhalb der Methoden und Computed Variables die volle Datenmacht des jeweiligen Types.

Swift Playground

Die spezielle Schreibweise des Extensionkopfes extension Array where Element : Vehicle zeigt schon genau an, für welchen Typ man diese Erweiterung eines Arrays schreibt.

Als Beispiel dient ein rudimentäres Vehicle-Objekt:

/// Represents an abstract data model
/// of a vehicle 
class Vehicle
{
    /// Vendor of the vehicle
    var vendor  = ""
    
    /// Defines wether the vehicle is able to fly
    var flyable = false
    
    /// Defines the type of the vehicle
    var type = VehicleType.Unknown
    
    // MARK: - Init -
    
    convenience init(vendor: String, flyable: Bool, type: VehicleType)
    {
        self.init()
        
        self.vendor     = vendor
        self.flyable    = flyable
        self.type       = type
    }
}

Die passende Extension hierzu lässt sich wie folgt erstellen:

extension Array where Element : Vehicle
{
    /// Contains all flyable vehicles
    var flyables: [Vehicle]
    {
        return self.filter({$0.flyable})
    }
    
    /// Returns all vehicles of the given type
    ///
    /// - parameter type: Desired VehicleType
    /// - return        : List of vehicles with desired type
    func ofType(type: VehicleType) -> [Vehicle]
    {
        return self.filter({$0.type == type})
    }
}

Diese neuen Funktionen und Variablen lassen sich schließlich wie gewohnt aufrufen. Als Beispielsausgabe:

// Create dataset

var vehicles = [Vehicle]()
vehicles.append(Vehicle(vendor: "Eurocopter", flyable: true, type: .Helicopter))
vehicles.append(Vehicle(vendor: "BMW", flyable: false, type: .Car))
vehicles.append(Vehicle(vendor: "Audi", flyable: false, type: .Car))

// Call custom array type extension method

vehicles.flyables
// Output: [{vendor "Eurocopter", flyable true, Helicopter}]

vehicles.ofType(.Car)
// Output: [{vendor "BMW", flyable false, Car}, 
//          {vendor "Audi", flyable false, Car}]

Swift: Enum-basierende UIControl Styles (nicht nur für den Interface Builder)

by tobonaut

Heutzutage findet ein Kampf um die schönste und die am besten durchgestaltete App in der iOS Welt statt. Die Zeiten sind vorbei als alleinig das moderne Aussehen von iOS 7 Controls ausreichte um Kunden (und deren Kunden) zufrieden zu stellen wenn es um das Aussehen einer neue App ging. Dies ist nichts Neues. Dieses „sattsehen“ an gewohnten Designs konnte man schon zum Ende von iOS 6 sehen als die Standard-Controls im Skeuomorphic Design schon länger als altbacken und „sattgesehen“ galten.

Zum Glück gibt es ja extra Menschen auf dieser Welt was das Handwerk vom Gestalten von UI und UX nicht nur sehr gut beherrschen sondern meist auch noch von der Pike auf gelernt haben. Eventuell deswegen ärgere ich mich in der iOS Welt gefühlt nur noch sehr wenig über hässliche Apps – die in den Charts trenden.

Des einen Freud, des anderen Leid. UI Designer können noch so gute und abgesprochene Vorarbeit im Gestaltungsprozess leisten, am Ende liegt es am ausführenden Entwickler das erdachte App Design auch in baubaren Quelltext umzusetzen.

Hierbei können kleinere Helferlein unnötigen Stress und Aufwand sparen. Vor allem in agilen Prozessen wo es durch aus einmal sein kann, dass eine Überschrift vom Typ A plötzlich eine andere Farbe haben soll oder gar sich ein ganzes Farbkonzept ändert. In solchen Fällen ist es pure Qual eine komplexe App per Hand durchzugehen und im Interface Builder alle Farbwerte, States und Paddings anzupassen.

Aus diesem Grund haben mir meine tollen Kollegen einen Trick beigebracht um sich selbst und damit dem Projekt Zeit zu sparen: Enum-Basierende Styles für (nicht nur) den Interface Builder.

Um dies zu verdeutlichen habe ich eine kleine, simple Demo für einen einfachen Usecase erstellt. Ein UIButton soll je nach Status (Normal, gedrückt, deaktiviert) eine andere Hintergrundfarbe bekommen. Hierzu kommt noch etwas allgemeines Styling.

Enum based Button style

Quelltext

Generell benötigt man für dieses Feature eine eigene, auf beispielsweise UIButton basierende Klasse. Dieser Trick ist auf nahezu alle UIControl-basierenden Klassen anwendbar. Das gesamte Demoprojekt gibt es auf Github.

@IBDesignable
public class Button: UIButton
{
    /// MARK: - Properties -
    
    // 1.
    /// Style identifier
    /// Default value = MyStyle
    @IBInspectable
    public var styleIdentifier: String = "MyStyle"
    {
        didSet
        {
            applyNormalStyle(styleIdentifier)
        }
    }
    
    // 2.
    /// Overrides enabled property
    /// Will apply normal or disabled state
    override public var enabled: Bool
    {
        didSet
        {
            if enabled
            {
                applyNormalStyle(styleIdentifier)
            }
                
                
            else
            {
                applyDisabledStyle(styleIdentifier)
            }
        }
    }
    
    
    // MARK: - Initialization & Setup -
    
    // 3.
    override init(frame: CGRect)
    {
        super.init(frame: frame)
        setup()
    }
    
    
    required public init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)
    }
    
    
    override public func awakeFromNib()
    {
        super.awakeFromNib()
        setup()
    }
    
    
    // 4.
    override public func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool
    {
        let touched = super.beginTrackingWithTouch(touch, withEvent: event)
        
        if touched
        {
            applyPressedStyle(styleIdentifier)
        }
        
        return touched
    }
    
    
    // 4.
    override public func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?)
    {
        applyNormalStyle(styleIdentifier)
        return super.endTrackingWithTouch(touch, withEvent: event)
    }
    
    
    // 5.
    override public func prepareForInterfaceBuilder()
    {
        setup()
    }
    
    
    // MARK: - Helper
    
    // 6.
    /// Applies default styles
    private func setup()
    {
        // Apply generic styling
        setTitleColor(UIColor.whiteColor(), forState: .Normal)
        setTitleColor(UIColor.whiteColor(), forState: .Selected)
        contentEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10)

        enabled = (enabled)
        
        // Apply style
        applyNormalStyle(styleIdentifier)
    }
    
    // 7.
    /// Applies normal style
    ///
    /// - parameter styleIdentifier: Defines the requested style
    private func applyNormalStyle(styleIdentifier: String)
    {
        switch styleIdentifier
        {
        case ButtonStyle.MyStyle.rawValue:
            backgroundColor = UIColor.grayColor()
            
        default:
            return
        }
    }
    
    
    // 7.
    /// Applies pressed style
    ///
    /// - parameter styleIdentifier: Defines the requested style
    private func applyPressedStyle(styleIdentifier: String)
    {
        switch styleIdentifier
        {
        case ButtonStyle.MyStyle.rawValue:
            backgroundColor = UIColor.darkGrayColor()

        default:
            return
        }
    }
    
    // 7.
    /// Applies disabled style
    ///
    /// - parameter styleIdentifier: Defines the requested style
    private func applyDisabledStyle(styleIdentifier: String)
    {
        switch styleIdentifier
        {
        case ButtonStyle.MyStyle.rawValue:
            backgroundColor = UIColor.lightGrayColor()
            
        default:
            return
        }
    }
}


// 0.
/// Defines different button styles
public enum ButtonStyle: String
{
    // Default styling (MyStyle)
    case MyStyle = "MyStyle"
    
    // other styles ...
}

Natürlich kann man diese Styles jetzt nicht nur im Interface Builder setzen. Im Quelltext lässt sich der styleIdentifier ebenfalls wie jede andere (öffentliche) Property setzen. Dank des didSet{ … } werden Änderungen auch zur Laufzeit angewendet.

let button             = UIButton(...)
button.styleIdentifier = ButtonStyle.MyStyle.rawValue

Erklärung

0.)
Definiert das Enum mit dem verfügbaren Styles. Der rawValue ist zum einfachen Matching auf String eingestellt.

1.)
Das styleIdentifier-Property enthält dem in Interface Builder eingestellten Wert. Leider unterstützt der IB noch keine Enums als IBInspectable Datenquelle.

2.)
Die überschriebene enabled-Property benötigt man um den aktivierten beziehungsweise reaktivierten Wert Zustand zu erkennen und somit die entsprechenden gestalterischen Werte zu setzen.

3.)
Benötigte Methoden um bei jedem Initialisieren der Control den Style-Prozess anzustoßen.

4.)
Diese Event Handler werden benötigt um den „gedrückt“ Style zu setzen als auch wieder zu entfernen.

5.)
Wichtig um die angewendeten Styles bereits beim ersten Laden im IB sehen zu können.

6.)
Die generische setup()-Methode setzt allgemein gültige Gestaltungsparameter wie in diesem Beispiel die Textfarbe oder die contentEdgeInsets-Property.

7.)
Methoden welche je nach ausgewählten styleIdentifier die entsprechenden Werte setzen.

Lessons learned
@IBDesignables strapazieren Xcode (Version 7.x) wirklich sehr. Die IDE kommt bei komplexen Oberflächen mit vielen solcher Custom Controls an ihre Grenzen und straft den Entwickler mit anderen Kompilierungsvorgängen oder gar mit regelmäßigen abstürzen. Eine Abhilfe ist, die Designables eines Projektes in ein eigenes Framework zu stopfen – deswegen die public-Indikatoren. Dieser Fix hat natürlich auch an sich selbst wieder negative Seiteneffekte, konnte jedoch bei mir für eine größere Linderung bei meinen Xcode Probleme sorgen.

Swift: Microsoft Cognitive Services Computed Vision ausprobiert

by tobonaut

MSFT CV Logo

Quelle:  microsoft.com

Auf der diesjährigen BUILD stellte Microsoft eine Vielzahl an neuen und recht interessanten APIs auf Grundlage von künstlicher Intelligenz vor. Die Insider mögen Gnade walten lassen bei dieser Formulierung. Generell ist ja das 2016ner „Ich bau eine Twitter-App“ eine App die Bilder erkennen kann.

Aus diesem Grund habe ich eine kleine und rein für Testzwecke gebaute swiftige Demo gebaut, die ein aufgenommenes Bild Richtung Redmond schickt und mir im besten Falle die erkannten Tags aka Objekte zurück liefert.

Generell ist dies hier nicht wirklich eine spezielle iOS Sache. Es handelt sich bei der Kommunikation mit den Microsoft Cognitive Services um bequeme und plattformübergreifend auf http-Anfragen und JSON-basierenden Antworten.

Den Quelltext zur Demo findet ihr hier auf Github. Für das „Original“ als auch weitere, spaßige Ideen was man mit CV bauen kann findet ihr die Demos im Repository von Alex Repty.

Pädagogisch wertvolle Erklärungen was die Cogntive Services eigentlich sind und wie man diese nutzt findet man im entsprechenden, deutschsprachigen Kurs in der MVA. Auch udemy hat einen entsprechenden Kurs für 35 Euro im Angebot.

Demo benutzen
Damit die Demo läuft, braucht man einen API Key von Microsoft. Diesen gibt es mit fairen Quotas als Probevariante gratis auf der Produktseite von Microsoft. Den Schlüssel muss noch als Wert der entsprechenden Konstanten in der

// CognitiveServiceConfiguration.swift
static let ApiKey = ""

-Datei gesetzt werden.

Im selbigen File findet man noch den Konfigurationswert:

static let RequiredConfidence

Dieser gibt in einer Spanne von 0…1 an, wie sicher sich die KI sein muss bevor sie ein Objekt als erkannt ansieht. Zwischen 0.75 und 0.9 fuhr ich am besten.

CV Demo Screenshot

Lessons learned
Die Erkennung von einfachen Dingen ist meist nicht so ausführlich wie ich gehofft habe. Im angehängten Screenshot hätte ich beispielsweise noch Tags wie „panda“, „green“ oder „leave“ erwartet. Ob dies an einer fehlenden Konfiguration meinerseits des Requests liegt oder am Service an sich kann ich jedoch noch nicht sagen. Ansonsten funktionieren Bilder von Gesichtern besser. Hierbei werden neben Geschlecht auch ob die Person eine Brille trägt und vereinzelt wohl auch, welche ethnische Zugehörigkeit diese Person hat.

Ansonsten gab es noch ein offensichtliches Learning für mich. Es ist eine sehr ungute Idee ein 1:1 Bild der iPhone Kamera im mobilen Internet Richtung Redmond zu schicken. Hierdurch dauerte ein Request bis zu 20 Sekunden. Mit Auflösungen von 250 bis 500 Pixeln ging alles nahezu instantan. Selbst mit so kleinen Auflösungen konnte ich keine Einbusen in der Objekterkennung bemerken.

Follow Tipps
Wer nun Interesse an dieser Thematik gewonnen hat, dem kann ich auf Twitter neben dem sehr netten iOS- und Mac-Entwickler Alex Repty (@arepty) auch die, im deutschsprachigen Twitter-Universum bekannten, @codeprincess, ihrerseits Technical Evangelist bei Microsoft, empfehlen. Folgen lohnt so oder so. :)

Natürlich laden auch andere APIs der Cogntive Services zum experimentieren ein. Eine Übersicht welche Funktionen existierenden findet man auf der relativ übersichtlichen Produktseite von Microsoft.


Artikelbild: https://www.microsoft.com/cognitive-services/en-us/apis

[Linktipp] Swift Applikationen auf dem Raspberry Pi ausführen

by tobonaut

TL;DR: Link

Apple verfolgt im Moment einen ähnlichen Weg wie Microsoft, Amazon und Co.: „Open Source it!“.

Natürlich steht Apple als BDF-basiertes Unternehmen schon immer mit einem Fuß in der FOSS-Schiene, jedoch waren sie nie öffentlich dafür bekannt zum Beispiel den allseits geliebten Drucker-Damon CUPS entwickelt zu haben oder maßgeblich WebKit weiterentwickelt zu haben.

In den Mainstream gelang dieser neue Weg von Apple wohl durch die Offenlegung von Swift – welche im Moment meine Lieblingssprache ist. Nicht nur dass interessierte und fähige Menschen ausserhalb von Apple sich an der Entwicklung beteiligen können, nein, auch ganz andere Betriebssysteme werden nun offiziell unterstützt – so lang diese eine Linuxbasis haben.

Swift auf RP

Wer sich bisschen tiefer mit Swift auf Linuxmaschinen auseinander gesetzt hat der wird sicherlich wissen, dass der Funktionsumfang noch sehr begrenzt ist und noch viel Wasser die Isar herunterfließen muss bevor es wirklich 1:1 API konform mit der OS X beziehungsweise iOS Variante ist. Dennoch, der Anfang ist gemacht.

Damit man auch einmal fernab des Apple Ökosystems mit Swift auf richtiger Hardware experimentieren kann eigenen sich natürlich kleine Bastelrechner wie der Raspberry Pi super.

Hierzu hat Andrew Madsen einen recht einfachen Leitfaden geschrieben. Dieser funktioniert auch noch mit späteren Versionen von Swift als im Text beschrieben.

Wer einen kleinen Editor für Linux mit Swift-Highlighting sucht, der kann sich ja einmal mein Post zu „Visual Studio Code auf Linux in 5 Minuten installieren“ ansehen. Netter, feiner Editor.

Artikelbild: Quelle

NSTableView mittels NSSortDescriptor aber ohne NSMutableArray sortieren

by tobonaut

Wie schon im letzen Post gesagt versuche ich mich gerade in einer kleinen Mac App. Ein Desktop-Programm bringt ganz andere UI-Konzepte mit als eine mobile App auf dem Smartphone. Beispielsweise können natürlich auf dem Desktop Tabellen mehrere Spalten haben – dies ist auf iOS und co. ja eher unüblich.

Irgendwie war es für mich ein bisschen irritierend eine Lösung zu finden wie ich den Inhalt einer NSTableView ohne die Benutzung eines NSMutableArrays aber mit NSSortDescriptor sortieren kann. Ich will so gut wie möglich den NS-Namespace in modernen Swift Anwendungen vermeiden. Sprich: Array statt NSArray, String statt NSString, etc.

Dank dem NSHipster habe ich eine fast schöne Lösung gefunden. Fast schön da diese etliche Forced-Casts enthält die man ja eigentlich immer versucht zu vermeiden. Falls also jemand eine bessere Idee hat, nur her damit!

Schlussendlich musste ich nur folgende paar dinge tun und schon sortiert sich mache NSTableView als hätte sie noch nie was anderes getan.

  1. Jeder sortierbaren Spalte einen SortDescriptor Key geben. Entweder über Quelltext oder (wie ich) über den Attributes Inspector in Xcode
    Attribute Inspector
  2. Im NSTableViewController die folgende NSTableViewDelegate-Methode hinzufügen:
    // MARK: - NSTableViewDelegate -
    extension ParserViewController: NSTableViewDelegate
    {
        func tableView(tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor])
        {
            myList = (myList as NSArray).sortedArrayUsingDescriptors(tableView.sortDescriptors) as! Array
            tableView.reloadData()
        }
    }

Et viola, schon klappt es auch mit der Sortierung.