reconnaissance vocal

bonjour,


J'ai commencé par regarder les outils de reconnaissance vocal et je me suis trouver fortement intéressé par NSSpeechRecognizer je me suis donc mit au swift et j'ai pondu ce code :



import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var stopButton: NSButton!
@IBOutlet weak var startButton: NSButton!
@IBOutlet weak var descriptionAction: NSTextField!
@IBOutlet weak var historiqueAction: NSTextField!

@IBOutlet weak var window: NSWindow!
var recognition = NSSpeechRecognizer()
var commandeTab : [String] = [String]()




func applicationDidFinishLaunching(aNotification: NSNotification) {
window.center()
let location = "/Users/XXX/Desktop/commandes.txt"
let fileContent = NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)
var tmp :String = toString(fileContent)
commandeTab = tmp.componentsSeparatedByString("\n")
recognition.commands = commandeTab
window.showsResizeIndicator = false
}


@IBAction func startClicked(sender: NSButton) {
recognition.startListening()
descriptionAction.stringValue = "en écoute"
}

@IBAction func stopClicked(sender: NSButton) {
recognition.stopListening()
descriptionAction.stringValue = "en pause"

}

func speechRecognizer(recognition : NSSpeechRecognizer, command: String){


}
}


mon problème est petit, mon app se lance mais lorsque je la lance la fenêtre qui affiche les commandes disponibles a un "Optional()" que j'aimerai faire disparaitre  voici une image qui est plus compréhensible que mon charabia. Si vous avez des remarques sur mon code je suis ouvert à  toutes  idées d'améliorations 


 


Réponses

  • AliGatorAliGator Membre, Modérateur
    Je ne comprends pas trop ta question.

    Tu as un Optional<String> (Autrement appellé "String?", donc une String qui est Optional) quelque part et tu l'affiches donc c'est normal qu'il t'affiche ça.


    Si tu veux extraire la valeur faut utiliser un "if let" ou ce genre de construction classique en Swift pour gérer les Optionals


    Je vois pas trop dans ton code où tu affectes ta String? à  ton élément d'interface (une NSTableView?) et donc où ce trouve cette chaà®ne qui en fait est une Optional<String> (pas très clair juste en lisant ton code comment tu gères tout ça) mais le problème me paraà®t logique, tu as une Optional il t'affiche une Optional dans le texte.
  • d3m0t3pd3m0t3p Membre
    mai 2015 modifié #3

    Tout d'abord merci de ta réponse elle m'a permis de trouvé la solution.


    J'ai affiché le contenu de commandeTab et il contient :


    "Optional(jouer une musique


    saluer)"


    dans commandeTab[0] il y a "Optional(jouer une musique"


    j'en ai conclu que le problème venait d'ailleurs.


    Et le problème viens de NSString(contentOfFile: location, encoding: SNUTF8StringEncoding, error: nil) Il retourne un string? j'ai donc rajouter un ! après cet instruction et ça fonctionne.


    j'ai aussi fait une variante avec le if let, laquelle des deux solutions est la plus élégante (celle avec le ! ou celle avec le if let )?

  • AliGatorAliGator Membre, Modérateur
    Le "!" pour unwrapper un Optional est à  éviter à  tout prix, dans la mesure où si l'Optional se trouve être "nil", cela va faire planter ton programme (avec une Exception de type "trying to force-unwrap a nil optional value" un truc comme ça), car justement "!" va forcer à  sortir la valeur de l'Optional... c'est à  dire que tu supposes d'avance, sans vérification préalable, que la valeur n'est pas nil. C'est loin d'être sécurisant comme assertion !
    Donc à  éviter à  tout prix, sauf si tu sais vraiment que ça peut vraiment pas être nil, c'est à  dire par exemple que ton code est déjà  dans un "if" qui a testé avant si justement la valeur était non-nil par exemple, ce genre de choses.

    Il faut toujours préférer un "if let", qui va te forcer à  définir ce que tu dois faire / te forcer à  réfléchir à  la quesiton "tiens, d'ailleurs, si jamais ma valeur est nil, je veux faire quoi dans ce cas particulier ?". Dans ton cas ça peut être peut-être ne rien faire, peut-être masquer ta NSTableView et afficher à  la place un message en rouge "aucun élément", etc... mais au moins tu traites le cas, et sans risque de plantage au runtime, contrairement à  "!" qui force la main et plante si l'Optional était nil.
  • Merci de ta longue réponse, à  l'avenir je ferai un if let.


    Une autre chose me dérange dans ce code, la fonction NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)


    Habituellement pour spécifié le type de la variable je mettais var nom : typeVar = valeur, pareil dans les déclarations de fonctions(pour spécifier le type du paramètre). 


    Je suis un peut perdu je ne comprends pas à  quoi correspondes toutes ces choses. contentOfFile est le type d'objet qu'attend la fonction NSString ? si oui pourquoi n'est-il pas après la nom comme ceci


    func sayGoodbye(personName: String) {


        println("Goodbye, \(personName)!")


     

    Si non qu'est ce que c'est ?


  • LarmeLarme Membre

    Dans l'doute (ne parlant pas Swift), j'aurais tendance à  dire Class Method (Type Method) vs Instance Method. 


  • AliGatorAliGator Membre, Modérateur
    let fileContent = NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)
    • "fileContent" : nom de la variable/constante
    • "let" devant : indique que fileContent sera une constante, qu'on ne compte pas la modifier par la suite
    • ici, le type de la variable est omis et va être déterminé automatiquement par le compilateur (typage implicite). Il est fréquent en Swift que, quand on déclare une variable et qu'on lui affecte dans la foulée une valeur (ou le résultat d'une fonction), on ne s'embête pas à  indiquer le type de la variable, car le compilateur peut la déduire tout seul en fonction du type de la donnée qu'on lui affecte.
    • "NSString(contentsOfFile: ...)" est un appel au constructeur de NSString. C'est une fonction qui va te construire une instance d'objet NSString.
    • Une classe a parfois plusieurs constructeurs (initializer), c'est le cas de NSString, où tu peux construire une NSString avec "NSString(format:, ...)" ou "NSString(string: ...)", etc. qui construisent des NSString et sont sûrs de ne jamais échouer, du coup ils ne retournent pas d'Optional mais vraiment une NSString (jamais nil).
    • D'autres constructeurs (appelés "failable initializers") peuvent échouer, et vont alors retourner soit une NSString s'ils ont réussi, soit nil s'ils ont échoué... donc le type de retour sera en fait "Optional<NSString>" (ou "NSString?", c'est pareil). C'est le cas de "NSString(contentsOfFile:...encoding:...error:...)" qui peut effectivement échouer dans certains cas (par exemple si le fichier n'existe pas, ou s'il n'a pas réussi à  lire le fichier avec l'encoding indiqué, etc)
    Si tu voulais donc spécifier explicitement le type de ta constante "fileContent" (plutôt que de laisser le compilateur le déterminer pour toi implicitement), tu devrais alors écrire :
    let fileContent : Optional<NSString> = NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)
    Ou encore, si tu préfères cette notation (totalement équivalente, le "?" n'était que du "sucre syntaxique" pour déclarer un Optional) :
    let fileContent : NSString? = NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)
    Si tu avais essayé de déclarer "let fileContent : NSString" en indiquant un type "NSString" (et pas "NSString?" ou "Optional<NSString>"), le compilateur t'aurais indiqué une erreur, disant que puisque tu lui dit, de force, que fileContent est de type NSString, ce n'est pas compatible avec le type retourné par "NSString(contentsOfFile: ... encoding:... error:...)", qui lui retourne une "NSString?".
  • d'accord je crois que je compris.


    Dernière question et j'arrête de vous embêter promis


    Comment associer une action à  une commande ? Dans la doc d'apple je dois utilisé un truc appelé delegate mais je sais pas du tout ce que c'est, habituellement je m'aidais de mes bases du c++ pour faire des rapports et comprendre mais la, il n'existe rien de telle en c++(à  ma connaissance) et je suis donc (à  nouveau) perdu. Ma fonction func speechRecognizer(recognition, command) n'est pas appelée lorsque une commande est reconnue (je sais qu'elle est reconnue car il y a la commande qui s'affiche au dessus du micro lorsque je prononce la commande). 


  • La délégation est un design pattern, c'est une façon de structurer des classes d'objet et de les faire causer entre elles.


    Un design pattern est peu dépendant du langage de programmation utilisé. Le principe de fonctionnement est identique en C++ et en Objective-C ou en Swift.


    Une introduction aux Design Patterns se trouve dans la doc d'Apple, avec un exemple explicatif.


     


    Plus concrètement pour déclencher une action sur la commande, les explications se trouvent dans la doc de NSSpeechRecognizer et de NSSpeechRecognizerDelegate, ainsi que dans le document d'introduction, on y trouve des petits bouts de code en exemple.


  • tout d'abord un grand merci à  vous. Voici ce que fait : j'ai créé une classe qui hérite (ça se dit pour un protocole "hériter" ?) de NSObject et de NSSpeechRecognizerDelegate puis j'ai créer une instance de cette classe et j'ai fait instanceDeSpeechReco.delegate = maClass()


    voici le code si vous avez n'importe quelles remarques je suis preneur 



    import Cocoa

    @NSApplicationMain
    class AppDelegate: NSObject, NSApplicationDelegate {
    @IBOutlet weak var stopButton: NSButton!
    @IBOutlet weak var startButton: NSButton!
    @IBOutlet weak var descriptionAction: NSTextField!
    @IBOutlet weak var historiqueAction: NSTextField!

    @IBOutlet weak var window: NSWindow!
    var recognition = NSSpeechRecognizer()
    var commandeTab : [String] = [String]()
    var delegate = delegateOfSpeechRecognition()



    func applicationDidFinishLaunching(aNotification: NSNotification) {
    window.center()
    recognition.delegate = delegate
    let location = "/Users/joris/Desktop/commandes.txt"
    if let fileContent = NSString(contentsOfFile :location, encoding: NSUTF8StringEncoding, error: nil){
    var tmp :String = toString(fileContent)
    commandeTab = tmp.componentsSeparatedByString("\n")
    recognition.commands = commandeTab
    }

    window.showsResizeIndicator = false
    }


    @IBAction func startClicked(sender: NSButton) {
    recognition.startListening()
    descriptionAction.stringValue = "en écoute"
    }

    @IBAction func stopClicked(sender: NSButton) {
    recognition.stopListening()
    descriptionAction.stringValue = "en pause"

    }




    }

    class delegateOfSpeechRecognition : NSObject, NSSpeechRecognizerDelegate
    {
    func speechRecognizer(sender: NSSpeechRecognizer, didRecognizeCommand command: AnyObject?)
    {
    if command != nil
    {

    let cmd : String = command as! String

    switch cmd
    {
    case "jouer une musique" :
    println("play a music")
    default :
    println("default")
    }
    }

    }
    }

  • CéroceCéroce Membre, Modérateur

    j'ai créé une classe qui hérite (ça se dit pour un protocole "hériter" ?) de NSObject et de NSSpeechRecognizerDelegate

    On dit plutôt qu'une classe se conforme à  un protocole.
    D'ailleurs, il existe la classe NSObject, mais aussi le protocole NSObject. Les nommer différemment aurait été une bonne idée, mais c'est ainsi.
  • AliGatorAliGator Membre, Modérateur
    mai 2015 modifié #12

    D'ailleurs, il existe la classe NSObject, mais aussi le protocole NSObject. Les nommer différemment aurait été une bonne idée, mais c'est ainsi.

    En Swift ils *sont* nommés différemment (aussi par ce que l'héritage d'une classe et la conformance à  un protocole ont la même syntaxe en Swift : "class NomDeClasse : ClasseParentOuProtocole, Protocole, Protocole ...")

    Du coup en Swift "NSObject" désigne la classe, quant au protocole, il est nommé "NSObjectProtocol".
  • AliGatorAliGator Membre, Modérateur
    mai 2015 modifié #13

    Voici ce que fait : j'ai créé une classe qui hérite (ça se dit pour un protocole "hériter" ?) de NSObject et de NSSpeechRecognizerDelegate
    ...

    class delegateOfSpeechRecognition : NSObject, NSSpeechRecognizerDelegate

    Du coup d'après la déclaration dans ton code, ta classe "delegateOfSpeechRecognition" :
    - hérite de la classe NSObject
    - se conforme au protocole NSSpeechRecognizerDelegate


    Note également que par convention, on nomme toujours une classe avec une majuscule, pour les différencier des instances / variables / propriétés, qu'on commence toujours par une minuscule. Du coup je t'invite à  renommer ta classe en "DelegateOfSpeechRecognition" (ou pour faire + anglophone, "SpeechRecognitionDelegate" par exemple), avec donc la première lettre en majuscule.
Connectez-vous ou Inscrivez-vous pour répondre.