<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Martin Hartt on Medium]]></title>
        <description><![CDATA[Stories by Martin Hartt on Medium]]></description>
        <link>https://medium.com/@martinhartt?source=rss-764458bcc662------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*VjX4iYiAzFBddzaOO5nexw.jpeg</url>
            <title>Stories by Martin Hartt on Medium</title>
            <link>https://medium.com/@martinhartt?source=rss-764458bcc662------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 18:24:30 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@martinhartt/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Adding voice control to your projects]]></title>
            <link>https://medium.com/hackers-at-cambridge/adding-voice-control-to-your-projects-7096fdee7c45?source=rss-764458bcc662------2</link>
            <guid isPermaLink="false">https://medium.com/p/7096fdee7c45</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[ux]]></category>
            <category><![CDATA[nlp]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Martin Hartt]]></dc:creator>
            <pubDate>Tue, 13 Feb 2018 19:44:52 GMT</pubDate>
            <atom:updated>2018-02-13T19:44:52.357Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Xmfstx8hchgE8amg-ZaRtQ.png" /></figure><p><strong><em>Summary </em></strong><em>— With the advancements in the field of Natural Language Processing, adding voice control to applications has never been easier. This post will show how to add a voice interface which transcribes a user’s speech, understands their intent and responds with spoken feedback.</em></p><p>There’s something inherently futuristic about voice assistants. Until recently, we would see these interfaces predominantly in sci-fi movies such as HAL 9000 in 2001: A Space Odyssey. But with the recent advancements in the research of Natural Language Processing and Machine Learning, voice interfaces have become a lot more common in our everyday lives. Voice assistants such as Siri, Google Assistant or Amazon Echo best showcase how voice interfaces provide useful functionality in a natural, convenient way.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*gNlkLsah7JcHl2575tIW9A.gif" /><figcaption>HAL 9000 from 2001: A Space Odyssey (<a href="https://giphy.com/gifs/uP8PqQeRawSI0">source</a>)</figcaption></figure><p>Although the technology has long been available for developers to use, voice interfaces have been generally lacking in most mobile and web apps. This could be due to a number of reasons: it’s possible the technology is still in its early stages, there isn’t the motivation for adding it, or there is a perceived difficulty in implementing it. In this blog post, I will aim to tackle the last point and show how simple it is to integrate a voice control interface into any project.</p><p>You may be asking yourself “Why add a voice interface when I already have a user interface?”. Numerous benefits result from having a voice controlled application:</p><ul><li>It allows your application to be controlled in a hands-free way without having to look at your device. This is most beneficial in situations such as cooking, when the user’s hands are occupied and their visual focus is needed.</li><li>It can improve accessibility and provide a better experience for visually impaired users.</li><li>In my opinion, having a voice interface is just plain bad-ass, and brings us closer to a future where we interact with our technology like it’s Jarvis (the talking AI in Iron Man’s suit).</li></ul><p>In the examples, I will use modern Javascript (<a href="https://babeljs.io/learn-es2015/">ES2015</a>), which is transpiled with Babel to a version compatible with old browsers. I will aim to express the ideas in a platform-independent manner.</p><h4>Starting point</h4><p>Let’s begin with a simple application which generates jokes on certain topics. The implementation is pretty simple. Jokes are stored by their topic and when they are generated, we randomly choose a joke from a given topic. If a topic isn’t supplied, a random topic is used instead. To make it a bit more interesting, we also add functionality for retrieving the current time. You can see it implemented here:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fmartinhartt%2Fembed%2Fpreview%2FBYopmR%3Fheight%3D600%26slug-hash%3DBYopmR%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fmartinhartt%2Fpen%2FBYopmR&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F1731468.BYopmR.small.11f94e5a-cea7-4096-9069-a31bb8bcfaf2.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/d7c2b2f40c39f58799bbde496cd245ca/href">https://medium.com/media/d7c2b2f40c39f58799bbde496cd245ca/href</a></iframe><p>Currently, the user interface is kind of boring and there isn’t a way to specify topics. Rather than improving the user interface, let’s go ahead with the less orthodox option of adding a voice interface!</p><h3>Transcribing the user’s voice commands</h3><p>The first step is capturing what a user says when they interact with our application. It would be useful to get this in a string format, which can then be processed programmatically to understand the intent. Attempting to manually implement this functionality is futile, due to all the complexity from processing audio signals and extracting the individual words said.</p><p>Fortunately, many environments provide native Speech to Text functionality. For web apps, there is the experimental <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API">Web Speech API</a>’s SpeechRecognition interface. Although it currently has limited support with browsers, it is bound to improve in the future.</p><p>Similarly, iOS applications can make use of the <a href="https://developer.apple.com/documentation/speech/sfspeechrecognizer">SFSpeechRecognizer</a> class and Android developers can utilise <a href="https://developer.android.com/reference/android/speech/SpeechRecognizer.html">SpeechRecognizer</a>. In environments without this functionality, the <a href="https://azure.microsoft.com/en-gb/services/cognitive-services/speech/">Bing Speech API</a> can be used to extract text from uploaded audio files, at the cost of increased network bandwidth.</p><p>Let’s add this transcription functionality to our joke generator. As it’s a web app, we’ll utilise the speech recognition API, which is fairly straightforward to set up:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ef73b9a43089d765827488040f46b6ae/href">https://medium.com/media/ef73b9a43089d765827488040f46b6ae/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fmartinhartt%2Fembed%2Fpreview%2FJpYmNM%3Fheight%3D600%26slug-hash%3DJpYmNM%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fmartinhartt%2Fpen%2FJpYmNM%3Feditors%3D1111&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F1731468.JpYmNM.small.35afef66-a4fa-4ef4-85ad-6d1f3d7c7157.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/140c1fc39aa72ec15bb4a25c513eb5ef/href">https://medium.com/media/140c1fc39aa72ec15bb4a25c513eb5ef/href</a></iframe><p>Note that the speech recognition purposely isn’t continuous to ensure compatibility between the different demos, as Web Speech API doesn’t work across multiple tabs and iframes simultaneously. To enable continuous speech recognition, simply start the recognizer again from the event listeners that are triggered after the session finishes.</p><h3>Understanding the intent</h3><p>Now we arrive at the part of finding out what the user wants from their transcription. There are multiple ways of approaching this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wrjzpj7U5IjBYCIKqZyCQA.png" /><figcaption>We need a function which can determine the intent and other parameters</figcaption></figure><p>With very simple applications, which have a limited set of intents and parameters, we can use pattern matching with <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">regex</a> to find keywords within the user’s command. Due to the flexibility in phrasing (think of the number of ways you can say a command), it may be useful to look for synonyms of these keywords. It’s also helpful to lemmatise each word, which removes all inflections and converts it into its base form (e.g. “running” -&gt; run”), thus making it easier to find certain keywords.</p><p>With more complex applications where there are more intents and parameters which are harder to distinguish, a sequence-based machine learning classifier such as <a href="http://mallet.cs.umass.edu/sequences.php">Mallet</a> can be employed. However, this will require substantial effort to setup and prepare the dataset.</p><p>To achieve machine learning level performance with little effort, we can use <a href="https://wit.ai/">wit.ai</a>, a free (at the the time of this writing) API which can determine the user’s intent and extract corresponding parameters. It works by teaching the model with examples of user commands and defining the possible intents and parameters. The more examples trained, the more accurate it becomes. Other alternatives include <a href="https://www.luis.ai/home">LUIS</a> and <a href="https://developer.amazon.com/alexa-voice-service">Alexa API</a>.</p><p>This service provides the best balance of performance and ease of use, so we’ll use it for our joke generator. After registering and creating a new app, the “understand” screen will show up where we can train the model from examples.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgfycat.com%2Fifr%2FImportantRealHarvestmouse&amp;url=https%3A%2F%2Fgfycat.com%2FImportantRealHarvestmouse&amp;image=https%3A%2F%2Fthumbs.gfycat.com%2FImportantRealHarvestmouse-size_restricted.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=gfycat" width="2020" height="1112" frameborder="0" scrolling="no"><a href="https://medium.com/media/9542b18303fb87267325364db1a52965/href">https://medium.com/media/9542b18303fb87267325364db1a52965/href</a></iframe><p>Here we can type examples of user commands and teach the model to recognise entities. The most important entity is the intent, which determines which functionality is triggered.</p><p>Other entities can also be recognised as parameters. For specific types of parameters (e.g. locations, dates, emails) we can use the wit entities, which are pre-trained to recognise these types.</p><p>In our simple application, we just want to recognise the topic of the joke. For this, we can specify our entity to be keyword based, and supply a list of our topics with additional synonyms to allow for flexibility.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgfycat.com%2Fifr%2FImportantColdGermanspaniel&amp;url=https%3A%2F%2Fgfycat.com%2FImportantColdGermanspaniel&amp;image=https%3A%2F%2Fthumbs.gfycat.com%2FImportantColdGermanspaniel-size_restricted.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=gfycat" width="2052" height="1620" frameborder="0" scrolling="no"><a href="https://medium.com/media/c3a86b8c101f664c745c1df7fb643b16/href">https://medium.com/media/c3a86b8c101f664c745c1df7fb643b16/href</a></iframe><p>Once the model is successfully trained to recognise the intents and other entities, we can make requests to the <a href="https://wit.ai/docs/http/20170307">wit.ai’s API</a> with our user transcript. This will return a list of entities, where the confidence represents the certainty that the right entity was extracted.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*A122idojm-959IweFICGVQ.png" /><figcaption>A response from the wit.ai message endpoint in <a href="https://www.getpostman.com/">Postman</a></figcaption></figure><p>From the response, we can simply access the intent value and the corresponding parameters and trigger the correct application functionality.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fmartinhartt%2Fembed%2Fpreview%2FjZqNQb%3Fheight%3D600%26slug-hash%3DjZqNQb%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fmartinhartt%2Fpen%2FjZqNQb&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F1731468.jZqNQb.small.53bd9993-e736-4bbe-a063-55a0717f1234.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/b30cdad78bf1c4de41b1761d69c5ff9e/href">https://medium.com/media/b30cdad78bf1c4de41b1761d69c5ff9e/href</a></iframe><h3>Replying with spoken feedback</h3><p>Now that we have our small project fully controllable by voice, let’s take the extra step and respond with spoken feedback. This step is the inverse of the previous task of generating text from speech. We have some data about the result of the user’s command, and we want to say it back in a user friendly way.</p><p>To begin, let’s format our data to express it in a more coherent form. This is easy to do with templates, where the data is incorporated into a pre-made response.</p><p>Essentially, we define the possible replies where the data is represented with variables. When the response is generated, a random response template is chosen, and the variables are replaced with the data. Alternatively, <a href="https://lodash.com/docs/4.17.4#template">lodash’s template</a> function can be used.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/30097833d285f6a6ccc96f9e2df9e0ab/href">https://medium.com/media/30097833d285f6a6ccc96f9e2df9e0ab/href</a></iframe><p>Now that we have a string of what to reply to the user, we can use Text to Speech to generate audio and play it. Like Speech to Text, this functionality is present on most platforms, such as <a href="https://developer.apple.com/documentation/avfoundation/avspeechsynthesizer">AVSpeechSynthesizer</a> on iOS and <a href="https://developer.android.com/reference/android/speech/tts/TextToSpeech.html">TextToSpeech</a> on Android. In environments where this is not supported, the Text to Speech functionality in the <a href="https://azure.microsoft.com/en-gb/services/cognitive-services/speech/">Bing Speech API</a> can be used instead.</p><p>For web apps there is <a href="https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis">SpeechSynthesis</a>, which is simple to setup:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4f44ef345e0bb098bb976511e5f92824/href">https://medium.com/media/4f44ef345e0bb098bb976511e5f92824/href</a></iframe><p>Finally, we integrate all this functionality into our application which results in a fully voice controlled joke generator. Try it out by saying “Tell me a dad joke”:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fmartinhartt%2Fembed%2Fpreview%2FoExNYJ%3Fheight%3D600%26slug-hash%3DoExNYJ%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fmartinhartt%2Fpen%2FoExNYJ&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F1731468.oExNYJ.small.ef019b82-3f3f-4f85-bdf8-d2b76f0fb4f0.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/53925bd198aea228db48122404953480/href">https://medium.com/media/53925bd198aea228db48122404953480/href</a></iframe><h3>Conclusion</h3><p>In the end, we achieve a fully voice-controllable application just by integrating the speech and wit.ai APIs. I hope this post showed you how easy it is to add voice control functionality to any project. I highly recommend reading the <a href="https://wit.ai/docs/recipes">wit.ai</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API">Web Speech API</a> documentations, which explain how to customise the voice recognition to suit your application.</p><p>Special thanks to Christian Silver, Charlie Crisp, Lucia Bura for their feedback and Hari Prasad for editing this blog post.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7096fdee7c45" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackers-at-cambridge/adding-voice-control-to-your-projects-7096fdee7c45">Adding voice control to your projects</a> was originally published in <a href="https://medium.com/hackers-at-cambridge">Hackers at Cambridge</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[My first hackathon (MLH Launch Hack)]]></title>
            <link>https://medium.com/@martinhartt/my-first-hackathon-mlh-launch-hack-af94d586d605?source=rss-764458bcc662------2</link>
            <guid isPermaLink="false">https://medium.com/p/af94d586d605</guid>
            <dc:creator><![CDATA[Martin Hartt]]></dc:creator>
            <pubDate>Thu, 08 Jan 2015 00:16:48 GMT</pubDate>
            <atom:updated>2015-01-08T00:16:48.919Z</atom:updated>
            <content:encoded><![CDATA[<p>Last weekend I attended Launch Hack, a hackathon for students organised by <a href="https://www.google.co.uk/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=0CCQQFjAA&amp;url=http%3A%2F%2Fmlh.io%2F&amp;ei=gE46VIacOYH_ygPO6IGABQ&amp;usg=AFQjCNFZ5jSx-lR3qYFDvMgKXdAM3FaKIA&amp;sig2=Ozy26EVd1pWOPZL0DEnMFg&amp;bvm=bv.77161500,d.bGQ">MLG</a>. This was the first hackathon I have ever attended and it was a fantastic experience. My two friends Nali and Ivaylo joined me and together we were to build a project in 24 hours. We also recruited a fourth team member called Ong Cher Wei from Glasgow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*3QHheyTWEIkhnCqB.jpg" /></figure><p>While Nali remarked he was going to attend it to learn from other people and enjoy complimentary food and drinks, I was determined to make the 24 hours worthwhile. We came up with the idea to build an web application, since our most combined programming expertise was in PHP. I thought that we should solve a problem that has been on the internet since its launch: Broken links.</p><p>We all know what it’s like to want to see a video that has been shared numerous times on the internet, only to be disappointed to find out its deleted. Well what our application would do is to use reddit to search for mirrors. The reason for that is, that in the comments, the users are always keen to provide mirror links to other users for karma (upvotes).</p><p>Well since I have had expertise with the Reddit API (with <a href="http://x-posting.sodabit.com/">x-posting</a> and r/delay) a very basic prototype of this web-app should be no problem. Since I had the most experience out of our entire group and came up with the idea, I was called to be the leader.</p><p>In the beginning, I had the task to not only start coding the base, but to also assign things to do to my team-members. One of them, Ivaylo, had done some php in the past so I thought of giving him the task to connect the reddit api to our app. On Cher only had experience in Visual Basic, so he his task was to build an html template which we could serve the information on.</p><p>Unfortunately, one hour into the hackathon, my HP laptop broke down and refused to start up again. This was captured by the organisers and <a href="https://twitter.com/MLHacks/status/518410422173843456">put on twitter</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*yeGAWA6QKWUiZ2SI.jpg" /></figure><p>After we shared a few laughs, Nali graciously offered me his macbook so that we could actually get some work done. He went on to assist On Cher with the task of building the html template and researching more of how we could get other sources of mirror sites.</p><p>Around 5 hours in, we had built a basic file structure and the html template was looking great. Unfortunately, the heart of the whole web-app, the reddit integration, was not looking so well and it set us back by about 4 hours. During these 4 hours we were frustratedly wondering why reddit kept wanting to for us to log in and allow permissions. After figuring out what we wanted was the basic mode instead of the oauth mode and some tinkering, we finally managed to get it running.</p><p>After that, I took over integrating the reddit api into our project, while Ivaylo had the task of handling broken links which were not submitted to reddit. This process was tedious as I had to parse my way through all the arrays and stdobjects in php to get to what we really wanted: the comments.</p><p>In between working we had a good time eating delicious food and drinks catered by Bloomberg and occasionally playing New Super Mario Bros for Wii U. The presentation room was changed into the sleeping room at night and I had a comfortable good sleep, even though it was only for two hours.</p><p>The next morning we did all the finishing touches to the web-app and we were surprised and delighted to see it actually working. When it came to the presenting, me and Ivaylo were to present about how our application worked in 2 minutes time. We were incredibly nervous, but we managed to do a pretty good job. The presentation can be viewed <a href="http://youtu.be/xCBOUsWZTUw?t=47m18s">here</a>, but please keep in mind that we only had 2 hours of sleep in the past 2 days.</p><p>In conclusion, this hackathon was one of the best experiences in my life so far, and even though we didn’t manage to win any prizes, we received a goodybag containing some pretty awesome swag!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*agz_EGNX8WdTKIak.jpg" /></figure><p><em>Originally published at </em><a href="http://martinkubat.tumblr.com/post/99805390386/my-first-hackathon-mlh-launch-hack"><em>martinkubat.tumblr.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=af94d586d605" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>