<?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 Eric Giannini on Medium]]></title>
        <description><![CDATA[Stories by Eric Giannini on Medium]]></description>
        <link>https://medium.com/@unicornmobile?source=rss-e88b1f5b4048------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*K1Gev8OcTuRq_mKzBL94Uw.jpeg</url>
            <title>Stories by Eric Giannini on Medium</title>
            <link>https://medium.com/@unicornmobile?source=rss-e88b1f5b4048------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 04:47:58 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@unicornmobile/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[Streamline your List of Documentaries Celebrating the First Anniversary of the Syrian Revolution…]]></title>
            <link>https://unicornmobile.medium.com/streamline-your-list-of-documentaries-celebrating-the-first-anniversary-of-the-syrian-revolution-7e325c7ba196?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/7e325c7ba196</guid>
            <category><![CDATA[whisper]]></category>
            <category><![CDATA[videos]]></category>
            <category><![CDATA[syria]]></category>
            <category><![CDATA[osint]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Wed, 10 Dec 2025 05:41:17 GMT</pubDate>
            <atom:updated>2025-12-13T20:19:48.385Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VCj4WF6scv52y-DrCJ12Tg.jpeg" /></figure><h3>Streamline your List of Documentaries Celebrating the First Anniversary of the Syrian Revolution with the Command Line YT, OpenAI, &amp; NLP Cloud</h3><p>A lot of different Arabic speaking media throughout the Arabic speaking world before or right before the first anniversary of Syria’s revolution published documentaries. Many of these documentaries are raw; they have no subtitles, Arabic or English; they are not summarized; they have do not have logically categorized chapter pinned to a specific time in the documentary in an outline; they are not labeled, differentiated, specified for length, speakers, or analysis. They are published without any additional information.</p><p>You will coordinate the use of four tools in a script for the Command Line Interface (<em>henceforth </em>CLI). You will streamline processing for your list of documentaries with the script. The first tool is called YouTube Downloader. It is an extremely robust open source program available on GitHub for downloading publicly available material from streaming websites. The second tool is OpenAI’s Whisper. OpenAI’s Whisper is a CLI tool for generating transcripts from publicly available material like the ones downloaded from streaming sites. It is a major ingenuity for human kind; OpenAI’s Whisper provides developers with the ability to transcribe transcripts from a Desktop computer. The third tool is NLP Studio’s API for summarization. NLP Studio’s API for summarization stages a number of the most widely used summarization Large Language Models (<em>henceforth </em>LLMs) such as GPT-OSS 120B, LLaMA 3.1 405B, Fine-tuned LLaMA 3.3 70B, ChatDolphin, Dolphin Yi 34B, Dolphin Mixtral 8x7B, Bart Large CNN, T5 Base EN Generate Headline; these LLMs empower users with the ability to chose what might be best. You will bring everything together from video codecs to transcripts, summarizations to clips, with the ffmpeg tool, the fourth tool. You will collect these tools into a single script to streamline the implementation of these tools for processing.</p><p>While there are many documentaries celebrating Syria’s First Anniversary of its successful military coup d’état, you will limit your focus to no more than five of the most prominent. These are in successive order: 1) مفاتيح دمشق (i.e., Al-Jazeera), 2) سقوط منتظر .. كواليس عملية ردع العدوان وخفايا انهيار جيش بشار الأسد (i.e., Al-Araby), 3) خفايا تُكشف للمرة الأولى في معركة ردع العدوان | فيلم ساعة الصفر (i.e., Syria-TV), and 4) رحيل بلا عودة.. وثائقي يكشف اللحظات الحاسمة التي مهدت لسقوط نظام بشار الأسد وقصة هروبه المفاجئة (i.e., Al-Arabiya); 5) هل سقط الأسد بـ “قرار دولي”؟ خفايا الانهيار السريع وقصة ليلة تحرير دمشق | وثائقي (i.e., Almodon Plus).</p><p>These documentaries are exclusively from the Arab world; since they are in Arabic without English translations, they are largely inaccessible to the vast majority of the world’s population. AI, however, opens up the world. With the ability to translate documentaries like these about Syria’s first anniversary of its revolution, AI literally opens the door to the Arab World.</p><p>It is developers, however, who hold the keys to these doors. Unlocking the power of technology with key knowledge, developers, who have spent hour after hour concentrating on the power of the terminal, commands or, scripts, hold the keys to technology like OpenAI for unlocking the Arabic language.</p><h3><strong>Step 1</strong></h3><p>Your first step is to head over to GitHub to download the YouTube downloader tool. The link is the following: <a href="https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#installation">https://github.com/yt-dlp</a>. Since YT-DLP provides a lot of different options for installing the program, you can chose: <a href="https://github.com/yt-dlp/yt-dlp/wiki/Installation">https://github.com/yt-dlp/yt-dlp/wiki/Installation</a>.</p><p>To download one or more these publicly available documentaries, you run the following command:</p><pre>yt-dlp &quot;&lt;link&gt;&quot;</pre><p>The &lt;link&gt; entry is the full link. It could be hosted on a number of different sites but typically the full link is everything before the first &amp;, there are a lot of things on the link. If not, the first line after a = may be the full link up or until the first &amp;.</p><h3>Step 2</h3><p>Your second step is to download OpenAI’s Whisper. The link is the following: <a href="https://github.com/openai/whisper">https://github.com/openai/whisper</a>. OpenAI’s whisper is available for multiple different operating systems so its instructions on installation covers the most common. <a href="https://github.com/openai/whisper?tab=readme-ov-file#setup">https://github.com/openai/whisper?tab=readme-ov-file#setup</a></p><p>To use Whipser in the CLI, you run only a few commands. The first is the command to transcribe. Since these documentaries are in Arabic, you can transcribe them with the following command:</p><pre>whisper documentary.mp4 --model medium --language Arabic --output_format srt</pre><p>With your .srt you have what you need to produce a summary.</p><h3>Step 3</h3><p>Your second step is to create an account at NLP Cloud. After you create an account, grab the API key so that you can authenticate. Since you’re focused on the CLI, you will use curl for your API requests. You will collect sections of the transcripts into chunks. You will use these chunks for submitting your POST requests to NLP Cloud.</p><p>Create a curl request. Take your API key. Where &lt;token&gt; stands, add your API key. The following is an example:</p><pre>curl &quot;https://api.nlpcloud.io/v1/&lt;model_name&gt;/summarization&quot; \<br>  -H &quot;Authorization: Token &lt;token&gt;&quot; \<br>  -H &quot;Content-Type: application/json&quot; \<br>  -X POST -d &#39;{&quot;text&quot;:&quot;This army was hiding behind Iranian support, <br>which proved to be a failure The Iranians will continue in this operation<br> after the Lebanon operation Also the Russians were heavily involved in the Ukraine <br>war so they could not be as effective as in 2015.&quot;}&#39;</pre><p>The return data is a summary of your chunk.</p><h3>Step 4</h3><p>Your fourth step is to download the open source software at GitHub for ffmpeg at the following website: <a href="https://github.com/FFmpeg/FFmpeg">https://github.com/FFmpeg/FFmpeg</a>. With ffmpeg everything comes together. You run a series of commands on the videos. The first command converts the .srt into a .ass file.</p><pre>ffmpeg -i transcript_of_documentary.srt -c:s ass transcript_of_documentary.ass</pre><p>The .ass format is better for the Arabic language, since the .srt format often contains inexplicable squares in the font. With the transcript’s format converted, the next step is to add the transcripts.</p><pre>ffmpeg -i documentary.mp4 -vf ass=transcript_of_documentary.ass documentary_output_subtitles.mp4</pre><p>With the converted transcripts added to the video, you can now add the summarized chunks to the metadata of your documentary.</p><h3>The Script</h3><p>Your last step is to create a bash shell script. The bash shell script is composed of nested if statements. the user to provide a link</p><pre>#!/bin/bash<br><br># Ask the user if they want to download a video<br>read -p &quot;Do you want to download a video? (yes/no): &quot; RESPONSE<br><br># Check if user&#39;s response is yes <br>if [[ &quot;$RESPONSE&quot; == &quot;yes&quot; ]]; then <br># since user&#39;s response is yes, execute the following: <br><br>    # Prompt the user for link<br>    echo -e &quot;\033[31mGet your link ready\033[0m&quot;<br>    read -p &quot;Enter the link: &quot; VIDEO_URL<br>    echo &quot;Your link is: $VIDEO_URL!&quot;<br>    FILENAME=$(yt-dlp --get-filename -o &#39;video.%(ext)s&#39; &quot;$VIDEO_URL&quot;)<br>    echo &quot;The video will be saved as: $FILENAME&quot;<br>    echo &quot;We&#39;re downloading the file now.&quot;<br>    yt-dlp -o &quot;$FILENAME&quot; &quot;$VIDEO_URL&quot;<br>        if [$? -eq 0]; then # code<br>            echo &quot;The video downloaded successfully.&quot;<br>        else <br>            echo &quot;The video did not download successfully.&quot; <br>        fi<br>else <br>    echo &quot;The script is terminating.&quot; <br>    pkill -9 ./prompt.sh<br><br>fi<br><br># Ask the user if they want to download a video <br>read -p &quot;Do you want to transcribe your video? (yes/no): &quot; responseToProcessing<br><br># Check if user&#39;s response is yes<br>if [[ &quot;$responseToProcessing&quot; == &quot;yes&quot; ]]; then <br># since user&#39;s response is yes, execute the following: <br><br>    # Prompt the user for<br>    echo -e &quot;\e[31m Get your link ready. \e[0m&quot;<br>    read -p &quot;Enter the language: &quot; LANGUAGE<br>    echo &quot;Your language is: $LANGUAGE!&quot;<br>    echo &quot;We&#39;re starting the transcription now...&quot;<br>    whisper $FILENAME --model medium --language &quot;$LANGUAGE&quot; --output_format srt<br>        <br>        # Declare variables for handling .srt/.ass<br>        FULLFILENAME=$(basename -- &quot;$FILENAME&quot;)<br>        EXTENSION=&quot;${FILENAME##*.}&quot;<br>        FILENAMEWOEXT=&quot;${FILENAME%.*}&quot;<br><br>        echo &quot;Here is the file name $FILENAME&quot;<br>        echo &quot;Here is the $EXTENSION&quot; <br>        echo &quot;Here is the file name without the extension: $FILENAMEWOEXT&quot;<br>        <br>        # Check if whisper executed correctly<br>        if [ $? -eq 0 ]; then<br>            FILENAMEWOEXT=&quot;${FILENAME%.*}&quot;<br>            echo &quot;$FILENAMEWOEXT.srt exists!&quot;<br>        else<br>            echo &quot;FFmpeg command failed.&quot;<br>        fi<br>else <br>    echo &quot;The script is terminating.&quot; <br>    pkill -9 prompt<br>fi<br><br># Check if the .srt file exists<br>if [[ -e &quot;$FILENAMEWOEXT.srt&quot; ]]; then <br><br># since the .srt exists, execute the following: <br>    echo &quot;You have an $FILENAMEWOEXT.srt now!&quot; <br>    echo &quot;We&#39;re converting your .srt to an .ass&quot;<br>    ffmpeg -i $FILENAMEWOEXT.srt -c:s ass $FILENAMEWOEXT.ass<br>        if [ $? -eq 0 ]; then<br>            echo &quot;FFmpeg command succeeded!&quot;<br>        else<br>            echo &quot;FFmpeg command failed.&quot;<br>        fi<br>else <br>    echo &quot;There is no .srt yet!&quot; <br>fi <br><br># Check if the .ass file exists<br>if [[ -e &quot;$FILENAMEWOEXT.ass&quot; ]]; then # code to execute if true; <br><br>    # since the .ass exists, execute the following: <br>    # delete the .srt<br>    rm -rf $FILENAMEWOEXT.srt<br><br>    # append the .ass to the video<br>    echo &quot;We&#39;re appending your transcripts to your .mp4&quot;<br>    ffmpeg -i &quot;$FILENAME&quot; -vf ass=&quot;$FILENAMEWOEXT.ass&quot; &quot;$FILENAME&quot;+&quot;_output_subtitles&quot;.mp4<br>        if [ $? -eq 0 ]; then<br>            echo &quot;FFmpeg command succeeded with appending transcripts to your $EXTENSION!&quot;<br>        else<br>            echo &quot;FFmpeg command failed.&quot;<br>        fi<br><br>else <br>    echo &quot;There&#39;s no .srt&quot; <br>fi<br><br>exit 1</pre><h3>Conclusion</h3><p>With the commands from these four different tools, you can create a script, bringing the four of them together with prompts. The script prompts the user for a link. The downloaded video is passed over to WhisperAI, which processes the video for transcripts. You add the return data from NLP Cloud’s responses to the chunks of the transcripts into a file. The transcripts are converted from an .srt file to an .ass file before being added by the same command to the video itself.</p><h4>Disadvantages</h4><p>There are a few disadvantages. In a separate iteration with a different scripting language like Python, a more robust user prompt with far more safeguards against an unfriendly user experience (i.e., such as a message about Internet connectivity), far more layered `.json` processing for granularized inserts of the parsed response data from the NLPCloud.io API endpoint, or the implementation of programming principles such as the separation of concerns with individual functions (i.e., replacing the nested if statements), would all be a desirable.</p><h4><strong>Advantages</strong></h4><p>Despite the disadvantages, bash, nonetheless, produces results. With the material fully processed, you can create a schedule with crontabs that enables you to watch automatically the processed videos during your lunch hour so that you can make December 8th last five days instead of only one. Imagine being able to enjoy the last revolution in the Arab Spring during lunch for a whole week without having to write a program. It is just a script!</p><h4>Endnote</h4><p>For the meantime, the minimalist design of the script provides what is need to limit the number of repetitive commands an avid streaming programmer may have to enter to schedule his or her own personal TV Guide with fully transcribed Arabic documentaries on the fall of Bashar Al-Assad.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/474/0*tJRtSZD2w1kgNOss" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7e325c7ba196" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Summaries: AI and APIs]]></title>
            <link>https://unicornmobile.medium.com/summaries-ai-and-apis-e16d0cff950b?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/e16d0cff950b</guid>
            <category><![CDATA[summary]]></category>
            <category><![CDATA[summarization]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[api]]></category>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Fri, 15 Aug 2025 20:42:03 GMT</pubDate>
            <atom:updated>2025-09-01T03:11:17.240Z</atom:updated>
            <content:encoded><![CDATA[<p>The summaries AI algorithms generate forget the crucial element so uniquely characteristic of human affection. The topicalization of the most dear part of any story, reading or work is present in even the least artistic renditions of a summary.</p><p>AI cannot come close to the preferences — always motivated by an intuitive, innate, heartfelt sense of rightful righteousness like Socrates own mysterious εὐδαιμονία — producing that streaking red line of thought called passion. It just cannot. It is hardly a summary, since there is no hard logic to its decision to include some but preclude other facts. A summary is always a personal reflection, an <em>essai, </em>on one’s experience of an event. The summary APIs are the least powerful, least promising, least interesting algorithms.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aaWH1OCcyXL5G6X58C6lAg.png" /></figure><p>A summary is an opinion, plain and simple, and no machine, no matter how fantastic, is capable of producing an opinion, and so AI generated summaries, the vast majority of which inherit a human being’s opinion from the leading piece of data (i.e., the centerpiece) will lack the human touch so important for what a summary truly is. AI’s inability to generate music, especially classical music, demonstrates its limitations; it is merely an aggregator, whose production of aggregations <em>never</em> exceeds the threshold required for a qualitative transformation of quantified data. There is no way for AI to imitate, mock, or emulate the human mind for lack of experience with real life and its affect in producing the attachments serving a guideposts in any expression, let alone summary.</p><p>The APIs focusing on the sentence, phase, or word are far more useful; far more interesting, far more promising for in these algorithms the manifold to a new universe of connections opens up. It is not one resulting from the reduction but the transformation of information, an interpretation that is neither an infringement nor an imposition but a predictable extension of a theory.</p><p>Summaries are not useful, since the AI algorithms for their production lack a human touch for something undeniably personal. An outline API endpoint must come to replace summaries. An algorithm capable of parsing information into sections, subsections, or sub-subsections for reference, navigation within a document, book, program or film, or recall are far more useful, especially since the amount of information a person consumes at 200 to 300 wpms far exceeds the average ability to handle more than a small percentage of the wpms for any given minute (even though human beings do not remember words but images).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e16d0cff950b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What is the Best Platform for Learning How to Build ML Models and Implement LLMs]]></title>
            <link>https://unicornmobile.medium.com/what-is-the-best-platform-for-learning-how-to-build-ml-models-and-implement-llms-16e2d7c1b0f7?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/16e2d7c1b0f7</guid>
            <category><![CDATA[large-language-models]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[learning]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[api]]></category>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Thu, 29 Aug 2024 16:43:13 GMT</pubDate>
            <atom:updated>2024-08-29T16:43:13.918Z</atom:updated>
            <content:encoded><![CDATA[<p>There are a large number of learning platforms for learning how to build ML models and implement Large Language Models (LLMs).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iLIvCmKsFsAJa8YN9_ll9g.jpeg" /></figure><h3>Post Graduate Certification</h3><p>Tangential programs like the one offered at the University of Texas at Austin called a “Post Graduate Program in Artificial Intelligence &amp; Machine Learning: Business Applications” typifies the type of course universities are seeking to exploit as a side hustle for graduate programs. Offered by the McCombs School of Business, the program is slated to take no less than 7 months. It includes the study of Python for AI, Ensemble Techniques &amp; Model Tuning, Deep Learning (Neural Networks), Natural Language Processing, Supervised and Unsupervised Learning, Recommendation Systems, and Computer Vision. Delivered by the learning platform ‘Great Learning,’ taught by professors from a university, the course is one of the many platforms forbuilding a strong foundation in machine learning.</p><h3>Codeacademy</h3><p>Other platforms are more focused on programming than the concepts like Codeacademy. Codeacademy offers a program geared directly towards the profession a learner assumes upon completion: <a href="https://www.codecademy.com/learn/paths/machine-learning-engineer">Machine Learning / AI Engineer</a>. The syllabus is really straightforward. The syllabus covers 7 units, 39 lessons, 37 projects, 33 quizzes. The first module is called “Introduction to Machine Learning Engineering Career Path,” the second, “Machine Learning Fundamentals,” the third “Software Engineering for Machine Learning/AI Engineers,” the fourth “Intermediate Machine Learning,” the fifth, “Building Machine Learning Pipelines,” the sixth “Machine Learning/AI Engineer: Final Portfolio,” the seventh, “Machine Learning Career Paths: Next Steps.” The course offers a certificate of completion. Thematically centered on Netflix, the course asks: “Ever wonder how Netflix recommends what you should watch?”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RIsW9npVMVwgT8bjMm16rQ.png" /></figure><h3>DataCamp</h3><p>Codeacademy’s is slightly different from the ones DataCamp offers. DataCamp offers a series of different ‘career tracks’ based on a large body of Python courses. The two ‘career tracks’ DataCamp offers are 1) “Associate AI Engineer for Data Scientists” and 2) “<a href="https://app.datacamp.com/learn/career-tracks/associate-ai-engineer-for-developers">Associate AI Engineer for Developers</a>.” These are two extremely different career tracks. The first is focused on the following courses: a) “supervised learning with scikit-learning,” b) “unsupervised learning in Python,” c) “introduction to deep learning with Pytorch,” d) “developing multi input models for OCR,” e) “responsible for AI data management,” f) “introduction to LLMs in Python,” g) “analyzing car reviews with LLMs,” h) “working with Llama 3,” i) “MLOps Concepts,” j) “MLOps Deployment and LifeCycling,” k) “Introduction to Git,” l) “software engineering principles in Python”, m) “introduction to testing in Python”, n) “monitoring machine learning concepts.” This track appears to differ from the developer track in that this track focuses less on the actual models than on the science, theory, or concepts behind LLMs with a strong emphasis on programming in Python. The second career track appears to be focused on the actual models like the blockbuster APIs. The first course is a) “Working with OpenAI API,” b) “ChatGPT Prompt Engineering for Developers,” c) “Working with HuggingFace,” d) “LLMOps Concepts,” e) “Developing AI Systems with the OpenAI API,” f) “Organizing Medical Transcriptions with the OpenAI API,” g) “Introduction to Embeddings with the OpenAI API,” h) “Topic Analysis with Clothing Reviews with Embeddings,” i) “Vector Databases for Embeddings Pinecone,” j) “Software Engineering Principles in Python,” k) “Developing LLM Applications with LangChain.” The latter career track is clearly focused on implementation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6QJ4rcpV-LizanDJqp32jA.png" /></figure><h3>Deep Atlas</h3><p>Last but not least is a new program called DeepAtlas. The program is unique from the post-graduate certificate, online certifications, or career tracks. In line with the self-guided style of these courses, the program takes place biweekly or monthly with bootcamp-style cohort. The bootcamp is thus either two weeks long or four depending on the time commitment the student is prepared to make.</p><p>The program is a community driven educational experience. The Deep Atlas community is comprised of “a select group of talented technologist who want to build a strong foundation in ML.” The curriculum is divided into four parts: ‘fundamentals,’ ‘shallow learning,’ ‘deep learning,’ and ‘leveraged ML.’ In the ‘fundamentals’ students learn Problem Framing, Environment Setup, Linear Algebra Fundamentals, Data Tools and Techniques, Simple Linear Regression, Building with LLMs, Probability and Statistics, Intro to Neural Networks, and the ML Terrain. In the ‘shallow learning,’ students learn Spatializing Data, Vector &amp; Semantic Search, Inference &amp; Training Mechanics, Model Development Lifecycle, Multiple Linear Regression, Gradient Boosted Trees, Taxonomy, of Shallow Algorithms, Dimensionality Reduction, Classification &amp; Clustering, Nondeterministic Paradigm Shift, and Anomaly Detection. As for the other two parts, the Deep Atlas syllabus goes into more detail, if you seeking a blow-by-blow of the curriculum, and for that you have to sign up <a href="https://www.deepatlas.ai/?utm_source=eg3211">here</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ll8pVspYf2LX3xFJEwzNRg.png" /></figure><p>Out of all of the pathways for learning ML, Deep Atlas’ program is the <strong>shortest</strong> with the most intense focus on the fundamentals, as opposed to the other platforms. While many people prefer seven-month long courses or an emphasis on transient tools and libraries, the Deep Atlas program focuses exclusively on enrolling seasoned software engineers who want to compress their studies with a focus on the fundamentals. Sign up <a href="https://www.deepatlas.ai/?utm_source=eg3211">here</a>!</p><h4>References</h4><p>Microsoft Reactor Community : <a href="https://developer.microsoft.com/en-us/reactor/">https://developer.microsoft.com/en-us/reactor/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=16e2d7c1b0f7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Scrape HREFs from an Article with a Python Script with BeautifulSoup]]></title>
            <link>https://unicornmobile.medium.com/scrape-hrefs-from-an-article-with-a-python-script-with-beautifulsoup-bbb0dbe4f04d?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/bbb0dbe4f04d</guid>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Fri, 16 Aug 2024 15:55:05 GMT</pubDate>
            <atom:updated>2024-08-16T15:58:29.051Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/418/1*tOEtsw0P8SZVf3BJD5r72Q.png" /></figure><p>The hardest of Python for MacOS users isn’t the language. It is the installation. Python’s numerous versions together with Mac’s lack of a package manager (just like Microsoft before the company introduced Microsoft Package Manager) make Python much more difficult than the language itself.</p><p>The easiest way to get and running with Python is to install Brew. Brew is the package manager Mac should have but doesn’t. To install Brew, run the following command:</p><pre>/bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&quot;</pre><p>After Brew is installed, run the following command:</p><pre>python --version</pre><p>If you find no version, the next step is clear.</p><pre>command not found: python</pre><p>You install Python with Brew.</p><pre>brew install python</pre><p>If installed successfully, you will run into various ‘unversioned symlinks.’ The ‘unversioned symlinks’ are the most important missing part, since without the linkage for the following files, Python won’t run.</p><pre>Python has been installed as<br>  /opt/homebrew/bin/python3<br><br>Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to<br>`python3`, `python3-config`, `pip3` etc., respectively, have been installed into<br>  /opt/homebrew/opt/python@3.12/libexec/bin<br><br>See: https://docs.brew.sh/Homebrew-and-Python</pre><p>There is the problem! To fix the problem, you have to make your latest version of python the default version. To do so, access your `~/.bash_profile`.</p><pre>nano ~/.bash_profile</pre><p>The next step is to add Python to your $PATH. MacOS relies upon the Unix kernel but unlike more Linux distributions, MacOS does not provide the full functionality of a Linux distribution. The command wget, for instance, is one of the most commonly known aspects of the full functionality of a Linux distribution but no MacOS provides the command. The command together with the $PATH to its directory for executing the executable file for the command’s script must be installed just like Python, except Python is not a part of the full functionlaity of a Linux distribution like wget.</p><pre>export PATH=&quot;/opt/homebrew/opt/python@3.11/libexec/bin:$PATH&quot;</pre><p>With the hardest part of the problem of Python out of the way, the fun begins. Python, which is a lot easier to operate than install on MacOS, offers more than merely a language. There is also a lot of libraries. One of these libraries is called requests. The library is a great way to connect to your computer to data on the Internet. If, for instance, you would like to download an article with something other than a wget script, you can use requests.</p><h4>Downloading the Article</h4><p>The first step is to create a data.py file in your editor. After creating the file, add a line to import the packages.</p><pre># Import packages<br>import requests</pre><p>With the library accessible to your file, the next step is to save the url to your HREF as a variable.</p><pre># Specify url<br>url = &#39;&#39;</pre><p>With the url saved as url, you have to set up your request.</p><pre># Package the request, send the request and catch the response: r<br>r = requests.get(url)</pre><p>After fetching the url data with the .get request, the best thing to do is to return the data with a print().</p><pre># Package the request, send the request and catch the response: r<br>r = requests.get(url)</pre><p>To print the data immediately, execute the .text method within a print() statement.</p><pre># printing request text<br>print(r.text)</pre><p>The result is really unstructured data like soup that you just might like to beautify.</p><h4>Printing the Soup Beautifully</h4><p>Rename your variable to html_doc, executing the .text method on the data</p><pre># Extracts the response as html: html_doc<br>html_doc = r.text</pre><p>To print the soup beautifully, you will use the Python library called BeautifulSoup, which is designed to parse HTML documents.</p><p>Up at the top of your document, add the following lines.</p><pre># Import packages<br>from bs4 import BeautifulSoup</pre><p>With the BeautifulSoup library added to the document, create your frist instance of the object, just like below.</p><pre># create a BeautifulSoup object from the HTML: soup<br>soup = BeautifulSoup(html_doc, &quot;html.parser&quot; )</pre><p># With the BeautifulSoup library you can easily access different parts of a webpage with its &quot;html.parser&quot; argument, which parses the website for free. Isn’t the world of APIs a huge relief?</p><pre>#Print the webpage&#39;s title <br>print(soup.title)</pre><h4>Collecting the HREF</h4><p>With the parser at hand, the way to scrape the HREF links from an article is really simple.</p><pre># Find all &#39;a&#39; tags (with which HTML tags for HREFs begin): a_tags<br>a_tags = soup.find_all(&#39;a&#39;)</pre><p>Scraping the HREFs requires no more than a single for loop.</p><pre># Print the URLs to the shell<br>for link in a_tags:<br>  print(link.get(&#39;href&#39;))</pre><p>Scraping the HREFs requires no more than a single for loop. After adding the for loop, run your script.</p><p>python data.py</p><p>Since you linked your command for python in your $PATH to your latest version of Python, you do not have to do anything more than hit enter.</p><p>The result should be a list of HREFs.</p><pre># Import packages<br>import requests<br>from bs4 import BeautifulSoup<br><br># Specify url<br>url = &#39;https://uk.news.yahoo.com/russian-commander-fighting-ukraine-shot-125650646.html&#39;<br><br># Package the request, send the request and catch the response: r<br>r = requests.get(url)<br><br># Extracts the response as html: html_doc<br>html_doc = r.text<br><br># create a BeautifulSoup object from the HTML: soup<br>soup = BeautifulSoup(html_doc, &quot;html.parser&quot; )<br><br># Print the title of Guido&#39;s webpage<br>print(soup.title)<br><br># Find all &#39;a&#39; tags (which define hyperlinks): a_tags<br>a_tags = soup.find_all(&#39;a&#39;)<br><br># Print the URLs to the shell<br>for link in a_tags:<br>    print(link.get(&#39;href&#39;))</pre><p>The results are the following:</p><pre>https://www.standard.co.uk/topic/russian<br>https://www.standard.co.uk/topic/ukraine<br>https://www.standard.co.uk/topic/telegram<br>https://uk.news.yahoo.com/ukraine-making-point-treating-russian-115822776.html<br>https://uk.news.yahoo.com/ukraine-strikes-ferry-crossing-occupied-084729225.html<br>https://uk.news.yahoo.com/russian-state-tv-makes-rare-135623498.html<br>https://uk.news.yahoo.com/even-kremlin-paid-liars-begging-144957546.html<br>https://uk.news.yahoo.com/woman-enjoying-quiet-dip-middle-135944280.html<br>https://uk.news.yahoo.com/deeply-unhinged-getting-worse-trump-084220362.html<br>https://uk.news.yahoo.com/oops-trump-accidentally-hands-kamala-033027506.html<br>https://uk.news.yahoo.com/putin-promised-poorly-trained-conscripts-040502408.html<br>https://uk.news.yahoo.com/soon-jobless-biden-unloads-trump-201336550.html<br>https://uk.news.yahoo.com/humiliation-putin-over-100-troops-131050434.html<br>https://uk.news.yahoo.com/revealed-ukraine-plan-force-putin-162310337.html<br>https://uk.news.yahoo.com/ukraine-russia-war-live-joint-033914158.html<br>https://uk.news.yahoo.com/trumpworld-scrambling-clean-mess-ex-172121250.html<br>https://uk.news.yahoo.com/biden-hits-trump-nickname-slams-222419224.html<br>https://uk.news.yahoo.com/kamala-harris-beat-donald-trump-180442262.html<br>https://uk.news.yahoo.com/vladimir-putin-ally-alexander-lukashenko-022100956.html<br>https://uk.news.yahoo.com/ukraine-captures-town-sudzha-russia-143139664.html<br>https://uk.news.yahoo.com/seth-meyers-stunned-trumps-olympic-100906141.html<br>https://uk.finance.yahoo.com/news/russia-doubling-pay-recruit-more-224312977.html<br>https://uk.news.yahoo.com/cnn-fact-checker-exposes-2-124212445.html<br>https://uk.news.yahoo.com/<br>https://uk.news.yahoo.com/<br>https://uk.news.yahoo.com/tagged/ukoriginal/<br>https://uk.news.yahoo.com/uk/<br>https://uk.news.yahoo.com/weather/<br>https://uk.news.yahoo.com/tv-celebrity/<br>https://uk.yahoo.com/topics/yahoo-quizzes-uk/<br>https://uk.yahoo.com/topics/crime/<br>https://uk.news.yahoo.com/science-tech/<br>https://uk.yahoo.com/topics/royal-family-news/<br>https://uk.news.yahoo.com/motoring/<br>https://uk.news.yahoo.com/viral/<br>https://uk.news.yahoo.com/world/<br>https://uk.yahoo.com/topics/on-this-day/<br>https://uk.news.yahoo.com/video/<br>https://uk.finance.yahoo.com/<br>https://uk.sports.yahoo.com/<br>https://uk.style.yahoo.com/<br>https://uk.movies.yahoo.com/<br>https://guce.yahoo.com/terms?locale=en-GB<br>https://guce.yahoo.com/privacy-policy?locale=en-GB<br>https://guce.yahoo.com/privacy-dashboard?locale=en-GB<br>https://uk.help.yahoo.com/kb/news<br>https://yahoo.uservoice.com/forums/168902-uk-news<br>https://www.adtech.yahooinc.com/en-gb<br>https://legal.yahoo.com/ie/en/yahoo/aboutourads/index.html<br>https://tumblr.com/follow/yahoonews-uk<br>https://www.twitter.com/YahooNewsUK<br>https://www.facebook.com/YahooUK<br>https://app.appsflyer.com/id304158842?pid=inproduct&amp;c=US_Acquisition_YMktg_Desktopfooter__&amp;af_sub1=Acquisition&amp;af_sub2=US_YMktg&amp;af_sub3=&amp;af_sub4=&amp;af_sub5=Desktopfooter__Static_<br>https://app.appsflyer.com/com.yahoo.mobile.client.android.yahoo?pid=inproduct&amp;c=US_Acquisition_YMktg_YNewsfooter1__&amp;af_sub1=Acquisition&amp;af_sub2=US_YMktg&amp;af_sub3=&amp;af_sub4=&amp;af_sub5=YNewsfooter1__Static_</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*yc7kurfafeRmtf543y1spw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*yc7kurfafeRmtf543y1spw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*yc7kurfafeRmtf543y1spw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*yc7kurfafeRmtf543y1spw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*yc7kurfafeRmtf543y1spw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*yc7kurfafeRmtf543y1spw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*yc7kurfafeRmtf543y1spw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*yc7kurfafeRmtf543y1spw.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bbb0dbe4f04d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Symbl.ai with Paragon : How to Make Automated Speech Recognition Detect Action Items for the…]]></title>
            <link>https://unicornmobile.medium.com/symbl-ai-with-paragon-how-to-make-automated-speech-recognition-detect-action-items-for-the-30234e2cdf61?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/30234e2cdf61</guid>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Thu, 22 Feb 2024 16:18:45 GMT</pubDate>
            <atom:updated>2024-02-25T01:38:12.272Z</atom:updated>
            <content:encoded><![CDATA[<h3>Symbl.ai with Paragon : How to Make Automated Speech Recognition Detect Action Items for Automating JIRA Tickets</h3><p>Symbl.ai’s conversation AI platform provides developers with the ability to visualize, transform or connect a conversation far beyond merely live captioning transcripts in real-time.</p><p>Symbl.ai’s ability to detect contextual AI insights in real-time empowers developers to connect the results of their real-time conversations to Third Party SaaS providers such as JIRA. With the ability to log questions, follow-ups, or action-items in real time, Symbl.ai’s conversation AI platform empowers developers to process conversation data creating automatically. It easily integrates with Paragon, which helps with building productized integrations. Paragon’s embedded integration platform, for instance, is for product developers and in this case voice product developers that want to provide user-facing integrations between their app and their users’ other apps just like the one we’ve envisioned here for connecting Symbl.ai with JIRA. Enabled on the Paragon embedded integrations platform, Symbl.ai’s technology enables speakers in a conversation to process their conversation’s action-items automatically to JIRA. No post-meeting summaries or note taking is required. The JIRA tickets from action-items detected with Symbl.ai’s conversation AI platform update in a JIRA board automatically.</p><p>In the following blog you add Symbl.ai’s Action Items to JIRA in Real-Time with the Paragon Connect API. You integrate Symbl.ai’s real-time action items over a WebSocket’s connection, establishing the real-time tracking of conversational AI insights such as follow-ups, questions, or action items. After logging real-time conversational AI insights, you configure your WebSocket’s ws.onmessage method to capture action items specifically with a method called detectInsight. A previous blog helps developers onboard with logging action_items <a href="https://dev.to/symbldotai/configure-symbl-ai-to-listen-for-action-items-in-a-websocket-call-2l5f">here</a>. With action-items captured you will create a connection to Paragon’s embedded native SaaS API, making a call through its Connect API to deliver the Symbl.ai’s action item payload to a JIRA ticket.</p><h4>JIRA</h4><p>JIRA is a task management system. JIRA provides developers with the ability to open tickets for work tasks, schedule their completion, track progress, or announce its result at the end.</p><p>There are a few requirements for setting up JIRA. The first is to create an account on a separate JIRA account. You are creating a demo application so there is no requirement for you to connect to your regular task management software.</p><p>After creating an account you need to create a project from a Kanban board with the ability to create issues. With those two parts of JIRA set up there is nothing further for you to do with JIRA.</p><h3>Paragon</h3><p>With the JIRA account set up, the next step is for you to configure Paragon to handle Symbl.ai’s payload of action-items for configuring the creation of issues on the JIRA board automatically with Paragon’s POST request method.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FRuk4knOAuz4IgaGEY0rJQ.png" /><figcaption>Image courtesy of Sean Victory: sean@useparagon.com</figcaption></figure><p>Navigate from the Paragon portal select Paragon Connect. Inside of Paragon Connect select + New Integration. Within the + New Integrations select JIRA. After selecting the Connect button, the Connect button greys.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ylqRrEXdBg6CJxiYaT56WA.png" /></figure><p>After selecting JIRA from the +New Integrations section, JIRA requires you to authenticate. After authenticating return to the +New Integrations. There you select + Create Workflow where you have the option to create a Trigger.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9teFm20M7zUU3EXoe6U1pg.png" /></figure><p>Under the menu that says “Choose a step to add,” select JIRA. Configure your step to Create Issue.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YkLbA16_0NYhP23oxjbH-Q.png" /></figure><p>With JIRA integration set up the next step is to configure your JSON payload’s structure. The JSON payload’s structure is the JSON payload that is sent to the integration’s API through a POST request.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dvEGR2MyMzIjwWHjB3GsSg.png" /></figure><p>Configure a JSON payload structure in the following way:</p><pre>{</pre><pre>&quot;name&quot;: &quot;action_item_name&quot;,</pre><pre>&quot;userId&quot;: &quot;action_item_userId&quot;,</pre><pre>&quot;content&quot;: &quot;action_item_content&quot;</pre><pre>}</pre><p>The result is that the JSON structure becomes the object that a method in the following format paragon.event(&quot;&quot;,{}); handles for the POST request.</p><pre>paragon.event(&quot;upload_action_item&quot;,{</pre><pre>&quot;name&quot;: &quot;action_item_name&quot;,</pre><pre>&quot;userId&quot;: &quot;action_item_userId&quot;,</pre><pre>&quot;content&quot;: &quot;action_item_content&quot;</pre><pre>});</pre><p>With these two parts of Paragon configured, your next step is to configure an application to start handling events.</p><h3>Streaming API</h3><p>Symbl.ai’s API for its WebSockets is fully developed. Although a detailed explanation of best practices is found <a href="https://symbl.ai/best-practices-for-audio-integrations-with-symbl/">here</a>, Symbl.ai’s Real-Time WebSocket API recommends as the following best practices for its adoption:</p><ul><li><strong>Separate Channels per Person</strong>: audio for each person on a separate channel or over separate WebSocket connections for optimal results</li><li><strong>Lossless Codecs</strong>: FLAC or LINEAR16 codecs, if bandwidth is not an issue, or, if it is, Opus, AMR_WB, or Speex codecs.</li></ul><p>Another great part of the Streaming API is that the Streaming API enables you to run its code in a Chrome browser without much trouble at all. If you want to read more about JavaScript WebSockets or Symbl.ai’s Streaming API, here are a few blogs:</p><ul><li><a href="https://medium.com/codex/basic-javascript-code-for-live-conversational-ai-with-its-websockets-api-449d787ddd7a">https://medium.com/codex/basic-javascript-code-for-live-conversational-ai-with-its-websockets-api-449d787ddd7a</a></li><li><a href="https://javascript.plainenglish.io/real-time-sentiment-analysis-api-in-javascript-with-symbl-ai-9e39d50f0654">https://javascript.plainenglish.io/real-time-sentiment-analysis-api-in-javascript-with-symbl-ai-9e39d50f0654</a></li></ul><h3>Set up</h3><p>Register for an account at <a href="https://platform.symbl.ai/">Symbl</a> (i.e., <a href="https://platform.symbl.ai/">https://platform.symbl.ai/</a>). Grab both your appId and your appSecret. With both of those you should authenticate either with a cURL <a href="https://www.mit.edu/afs.new/sipb/user/ssen/src/curl-7.11.1/docs/curl.html">command</a> or with Postman so that you receive your x-api-key. Here is an example with cURL:</p><pre>curl -k -X POST &quot;<a href="https://api.symbl.ai/oauth2/token:generate">https://api.symbl.ai/oauth2/token:generate</a>&quot; \<br>     -H &quot;accept: application/json&quot; \<br>     -H &quot;Content-Type: application/json&quot; \<br>     -d &quot;{ \&quot;type\&quot;: \&quot;application\&quot;, \&quot;appId\&quot;: \&quot;&lt;appId&gt;\&quot;, \&quot;appSecret\&quot;: \&quot;&lt;appSecret&gt;\&quot;}&quot;</pre><p>Ideally a token server would handle authentication (with code that makes RESTful API call for generating token) so that neither the appSecret nor the appId were ever exposed. However, cURL sets you up immediately anyway. With thex-api-key handy you are now ready to establish a WebSocket endpoint for performing live transcription.Run the WebSocket</p><ul><li>Deploy to a browser</li><li>Open Console</li><li>Witness live captioning of transcripts</li></ul><p>Wrap the following lines of code to a file called index.js in method called openSocket():</p><pre>var openSocket = async function() {<br>  const uniqueMeetingId = btoa(&#39;<a href="/service/mailto:email@address.com">email@address.com</a>&#39;);<br>  const accessToken = &#39;&#39;;<br>  const symblEndpoint = `wss://api.symbl.ai/v1/realtime/insights/${uniqueMeetingId}?access_token=${accessToken}`;const ws = new WebSocket(symblEndpoint);// Fired when a message is received from the WebSocket server<br>  ws.onmessage = (event) =&gt; {<br>    console.log(event);<br>  };// Fired when the WebSocket closes unexpectedly due to an error or lost connetion<br>  ws.onerror  = (err) =&gt; {<br>    console.error(err);<br>  };// Fired when the WebSocket connection has been closed<br>  ws.onclose = (event) =&gt; {<br>    console.info(&#39;Connection to websocket closed&#39;);<br>  };// Fired when the connection succeeds.<br>  ws.onopen = (event) =&gt; {<br>    ws.send(JSON.stringify({<br>      type: &#39;start_request&#39;,<br>      meetingTitle: &#39;Websockets How-to&#39;, // Conversation name<br>      insightTypes: [&#39;question&#39;, &#39;action_item&#39;], // Will enable insight generation<br>      config: {<br>        confidenceThreshold: 0.5,<br>        languageCode: &#39;en-US&#39;,<br>        speechRecognition: {<br>          encoding: &#39;LINEAR16&#39;,<br>          sampleRateHertz: 44100,<br>        }<br>      },<br>      speaker: {<br>        userId: &#39;<a href="/service/mailto:example@symbl.ai">example@symbl.ai</a>&#39;,<br>        name: &#39;Example Sample&#39;,<br>      }<br>    }));<br>  };const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });const handleSuccess = (stream) =&gt; {<br>    const AudioContext = window.AudioContext;<br>    const context = new AudioContext();<br>    const source = context.createMediaStreamSource(stream);<br>    const processor = context.createScriptProcessor(1024, 1, 1);<br>    const gainNode = context.createGain();<br>    source.connect(gainNode);<br>    gainNode.connect(processor);<br>    processor.connect(context.destination);<br>    processor.onaudioprocess = (e) =&gt; {<br>      // convert to 16-bit payload<br>      const inputData = e.inputBuffer.getChannelData(0) || new Float32Array(this.bufferSize);<br>      const targetBuffer = new Int16Array(inputData.length);<br>      for (let index = inputData.length; index &gt; 0; index--) {<br>          targetBuffer[index] = 32767 * Math.min(1, inputData[index]);<br>      }<br>      // Send to websocket<br>      if (ws.readyState === WebSocket.OPEN) {<br>        ws.send(targetBuffer.buffer);<br>      }<br>    };<br>  };handleSuccess(stream);<br>}</pre><p>After creating your openSocket() method, create a page for rendering a button:</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html&gt;</pre><pre>&lt;head&gt;<br> &lt;title&gt;Parcel Sandbox&lt;/title&gt;<br> &lt;meta charset=&quot;UTF-8&quot; /&gt;</pre><pre>&lt;script src=&quot;src/index.js&quot;&gt;<br> &lt;/script&gt;<br>&lt;/head&gt;</pre><pre>&lt;body&gt;</pre><pre>&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;</pre><pre>&lt;button type=&quot;button&quot; onclick=&quot;openSocket()&quot;&gt;Click Me!&lt;/button&gt;<br> &lt;div id=&quot;table-parent&quot;&gt;<br> &lt;/div&gt;</pre><pre>&lt;/body&gt;</pre><pre>&lt;/html&gt;</pre><p>Inside of the project’s root directory run python3 -m http.server 8000 so that you can run your application on local host: <a href="http://localhost:8000/">http://localhost:8000/</a>. Run in Chrome. Press ⌥⌘J to open the console. You will run your Paragon Connect API code through the console there.</p><h4>Link the Paragon Connect API</h4><p>The final step after the Streaming API is up and running is to link the Streaming API to the Paragon Connect API.</p><p>Add the following snippet to your index.html:</p><pre>&lt;script</pre><pre>type=&quot;text/javascript&quot;</pre><pre>src=&quot;https://cdn.useparagon.com/latest/sdk/index.js&quot;</pre><pre>&gt;&lt;/script&gt;</pre><p>Run the following commands:</p><p>paragon.authenticate(&quot;&lt;session-token&gt;&quot;);</p><p>The method connects your application to Paragon Connect API. After authenticating your next step is to set up the connection to your integrated Third Party SaaS:</p><pre>paragon.connect(&quot;jira&quot;, {<br>   type: &quot;modal&quot;, <br>   onSuccess: (event) =&gt; {}, <br>   onFailure: (event) =&gt; {}<br>});</pre><p>After both authenticating as well as connecting, the next step is to schedule the paragon.event method to sync with Symbl.ai’s conversation AI platform for detecting real-time action-items with JIRA.</p><pre>paragon.event(&quot;upload_action_item&quot;,{</pre><pre>&quot;name&quot;: &quot;action_item_name&quot;,</pre><pre>&quot;userId&quot;: &quot;action_item_userId&quot;,</pre><pre>&quot;content&quot;: &quot;action_item_content&quot;</pre><pre>});</pre><h4>Results</h4><p>As you can see below, the Paragon Connect API sent the payload from Symbl.ai through a POST request to JIRA automatically right after the insight_response if-else statement captured an action-item.</p><p>As you can see below, the Paragon Connect API takes the JSON’s payload from Symbl.ai’s insight_response for insights detected as action-items logging those action-items into the JIRA board in real-time as the conversation over the WebSocket occurs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QE9RCzem-0G0GPbtFnxycw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6hAI4glmPK9k4Qi8rJbVsg.png" /></figure><h4>What’s Next?</h4><p>You completed your integration over a WebSocket protocol. However, there are several other protocols over which to voice automate the creation of real-time action-items from a Symbl.ai conversation. You can voice-automate over the Sessions Initiation Protocol, the Publicly Switched Telephone Network, the Real Time Messaging Protocol or over different technologies such as Node.js or different languages such as Python. Symbl.ai provides sample applications for all of these different protocols, technologies or languages!</p><p>After connecting with Paragon’s Connect API, the world is your oyster. You have the ability to create omni-channel, contextual, multi-channel conversations that extend beyond a voice, video, message conversation to such things as the Simple Mail Transfer protocol with an email provider or to the chat servers like Discord or Slack, both of which are integrated already in Paragon’s suite of API automations! You can create or update queries for real-time databases or servers like MongoDB or Firebase. The world is your oyster:</p><h3>Community</h3><p>Stuck? Free feel to ask us any questions on our <a href="https://join.slack.com/t/symbldotai/shared_invite/zt-4sic2s11-D3x496pll8UHSJ89cm78CA">Slack Channel</a> or send us an email at developer@symbl.ai.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=30234e2cdf61" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Program a Python Script to Track Bitcoin Automatically with Coindesk APIs & Coinbase APIs]]></title>
            <link>https://medium.com/coinmonks/how-to-program-a-python-script-to-track-bitcoin-automatically-with-coindesk-apis-coinbase-apis-9074d4b9403b?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/9074d4b9403b</guid>
            <category><![CDATA[cryptocurrency]]></category>
            <category><![CDATA[crypto]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[bash]]></category>
            <category><![CDATA[bitcoin]]></category>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Sat, 02 Jul 2022 06:21:15 GMT</pubDate>
            <atom:updated>2024-08-31T22:50:06.868Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/225/1*1qLanRQoqhC5uIgai63P_w.png" /><figcaption>initial script command</figcaption></figure><p>While ancient Greek pre-Socratic philosopher Heraclitus says, “τὰ πάντα ῥεῖ καὶ οὐδὲν μένει,” with many translating the phrases differently, at times emphasizing how the universe fluxes, at others how the flux is constant, the phrase’s meaning amounts more powerfully to delineating the inherent property of matter for movement against its complete absence in nothingness: Anything stationary is nothing. In terms crypto currency, nothing could be farther from the truth of its conversions from crypto to fiat. Cryptocurrencies as movement thus live accordingly.</p><h3><strong>Coindesk APIs</strong></h3><p>The Coindesk APIs asynchronously update the price by which a crypto currency converts into USD in realtime.</p><p>If, for instance, you make a call to the following API endpoint for current prices (i.e., <a href="https://api.coindesk.com/v1/bpi/currentprice.json">https://api.coindesk.com/v1/bpi/currentprice.json</a>) from Coindesk, the following .json data returns:</p><pre>{<br>  &quot;time&quot;: {<br>    &quot;updated&quot;: &quot;Mar 21, 2022 21:59:00 UTC&quot;,<br>    &quot;updatedISO&quot;: &quot;2022-03-21T21:59:00+00:00&quot;,<br>    &quot;updateduk&quot;: &quot;Mar 21, 2022 at 21:59 GMT&quot;<br>  },<br>  &quot;disclaimer&quot;: &quot;This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org&quot;,<br>  &quot;chartName&quot;: &quot;Bitcoin&quot;,<br>  &quot;bpi&quot;: {<br>    &quot;USD&quot;: {<br>      &quot;code&quot;: &quot;USD&quot;,<br>      &quot;symbol&quot;: &quot;&amp;#36;&quot;,<br>      &quot;rate&quot;: &quot;41,307.2125&quot;,<br>      &quot;description&quot;: &quot;United States Dollar&quot;,<br>      &quot;rate_float&quot;: 41307.2125<br>    },<br>    &quot;GBP&quot;: {<br>      &quot;code&quot;: &quot;GBP&quot;,<br>      &quot;symbol&quot;: &quot;&amp;pound;&quot;,<br>      &quot;rate&quot;: &quot;31,370.2668&quot;,<br>      &quot;description&quot;: &quot;British Pound Sterling&quot;,<br>      &quot;rate_float&quot;: 31370.2668<br>    },<br>    &quot;EUR&quot;: {<br>      &quot;code&quot;: &quot;EUR&quot;,<br>      &quot;symbol&quot;: &quot;&amp;euro;&quot;,<br>      &quot;rate&quot;: &quot;37,497.4483&quot;,<br>      &quot;description&quot;: &quot;Euro&quot;,<br>      &quot;rate_float&quot;: 37497.4483<br>    }<br>  }<br>}</pre><h4>Python Requests</h4><p>Python does not support HTTP/S requests natively. The Requests library does. It facilitates the process of calling API endpoints with the lanugage. The first step to installing the Python Requests library is to ensure pip is installed in your Python environment.</p><pre>pip3 install requests</pre><p>With macOS you need to install pip with Homebrew. With a Linux kernel like Ubuntu, you install in the following way:</p><p>Step 1 — Updating the System</p><pre>sudo apt-get update</pre><p>Step 2 — Installing pip3</p><pre>sudo apt-get -y install python3-pip</pre><p>Step 3 — Verifying</p><pre>pip3 --version</pre><p>After pip is installed, install Python’s requests library.</p><pre>pip3 install requests</pre><p>Script</p><p>The next step is to create a Python script in your environment for accessing the Coindesk API.</p><pre>#!/usr/bin/env python<br>#Bitcoin script<br>import requests<br>response = requests.get()<br>data = response.json()<br>print(data)</pre><p>Within the requests.get() section of the function call for the variable for response, add the url : <a href="https://api.coindesk.com/v1/bpi/currentprice.json">https://api.coindesk.com/v1/bpi/currentprice.json</a>.</p><pre>#!/usr/bin/env python<br>import requests<br>response = requests.get(&#39;<a href="https://api.coindesk.com/v1/bpi/currentprice.json">https://api.coindesk.com/v1/bpi/currentprice.json</a>&#39;)<br>data = response.json()<br>print(data)</pre><p>The script’s first line declares the script to be so. The second is the keyword for importing the requests library. The third line response is a variable set to receive the results of a function call for the HTTP/S verb .get.</p><h4>Parsing the data</h4><p>The return data should have the following structure:</p><pre>{&#39;time&#39;: {&#39;updated&#39;: &#39;Aug 31, 2024 22:23:01 UTC&#39;, &#39;updatedISO&#39;: &#39;2024-08-31T22:23:01+00:00&#39;, &#39;updateduk&#39;: &#39;Aug 31, 2024 at 23:23 BST&#39;}, &#39;disclaimer&#39;: &#39;This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org&#39;, &#39;chartName&#39;: &#39;Bitcoin&#39;, &#39;bpi&#39;: {&#39;USD&#39;: {&#39;code&#39;: &#39;USD&#39;, &#39;symbol&#39;: &#39;&amp;#36;&#39;, &#39;rate&#39;: &#39;59,107.08&#39;, &#39;description&#39;: &#39;United States Dollar&#39;, &#39;rate_float&#39;: 59107.0797}, &#39;GBP&#39;: {&#39;code&#39;: &#39;GBP&#39;, &#39;symbol&#39;: &#39;&amp;pound;&#39;, &#39;rate&#39;: &#39;45,016.839&#39;, &#39;description&#39;: &#39;British Pound Sterling&#39;, &#39;rate_float&#39;: 45016.8385}, &#39;EUR&#39;: {&#39;code&#39;: &#39;EUR&#39;, &#39;symbol&#39;: &#39;&amp;euro;&#39;, &#39;rate&#39;: &#39;53,436.819&#39;, &#39;description&#39;: &#39;Euro&#39;, &#39;rate_float&#39;: 53436.8193}}}</pre><p>Since there is no documentation on Coinbase’s APIs, one way to understand the data is to loop through the URI’s return data for key value pairs. These key value pairs tell us which aspect of the URI’s return data return which pieces of information.</p><pre>print(&quot;Print each key-value pair from JSON response&quot;)<br>for key, value in data.items():<br>    print(key, &quot;:&quot;, value)<br>print(data)<br>print(&quot;Access directly using a JSON key name&quot;)</pre><p>If we loop through the key value pairs, the nested keys are much easier to askance than if not.</p><pre>time : {&#39;updated&#39;: &#39;Aug 31, 2024 22:30:05 UTC&#39;, &#39;updatedISO&#39;: &#39;2024-08-31T22:30:05+00:00&#39;, &#39;updateduk&#39;: &#39;Aug 31, 2024 at 23:30 BST&#39;}<br>disclaimer : This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org<br>chartName : Bitcoin<br>bpi : {&#39;USD&#39;: {&#39;code&#39;: &#39;USD&#39;, &#39;symbol&#39;: &#39;&amp;#36;&#39;, &#39;rate&#39;: &#39;59,092.758&#39;, &#39;description&#39;: &#39;United States Dollar&#39;, &#39;rate_float&#39;: 59092.7582}, &#39;GBP&#39;: {&#39;code&#39;: &#39;GBP&#39;, &#39;symbol&#39;: &#39;&amp;pound;&#39;, &#39;rate&#39;: &#39;45,004.217&#39;, &#39;description&#39;: &#39;British Pound Sterling&#39;, &#39;rate_float&#39;: 45004.2173}, &#39;EUR&#39;: {&#39;code&#39;: &#39;EUR&#39;, &#39;symbol&#39;: &#39;&amp;euro;&#39;, &#39;rate&#39;: &#39;53,423.872&#39;, &#39;description&#39;: &#39;Euro&#39;, &#39;rate_float&#39;: 53423.8717}}</pre><p>There are really only two key value pairs. These are time and bpi. Data from these two key value pairs provides both the time as well as the amount of Bitcoin in a specific currency. While the bpi provides both the pound sterling as well as the Euro, you’ll print the dollar amount. To print both the time as well as the dollar amount, let’s access the following nested keys.</p><pre>print(data[&quot;time&quot;][&#39;updated&#39;])<br>print(data[&#39;bpi&#39;][&#39;USD&#39;][&#39;rate&#39;])</pre><p>Depending upon how fancy you would like these pieces of data to be displayed, there are a number of other ways to configure how the data is read into the terminal. Without anything fancy, these should display as follows:</p><pre>Aug 31, 2024 22:35:54 UTC<br>59,076.459</pre><h4>Conclusion</h4><p>If you would like to modify the script to run a specific intervals, you can do so with a simple command such as schedule. An example of that modification command could be schedule.every().day.at(&quot;01:00&quot;).do(job,&#39;It is 01:00&#39;)where the every method runs every at 1:00PM everyday (i.e., the close of market) where job is defined as the method call to the Coindesk API.</p><blockquote>New to trading? Try <a href="https://medium.com/coinmonks/crypto-trading-bot-c2ffce8acb2a">crypto trading bots</a> or <a href="https://medium.com/coinmonks/top-10-crypto-copy-trading-platforms-for-beginners-d0c37c7d698c">copy trading</a></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9074d4b9403b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coinmonks/how-to-program-a-python-script-to-track-bitcoin-automatically-with-coindesk-apis-coinbase-apis-9074d4b9403b">How to Program a Python Script to Track Bitcoin Automatically with Coindesk APIs &amp; Coinbase APIs</a> was originally published in <a href="https://medium.com/coinmonks">Coinmonks</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Perform a Timeseries Analysis of Separated Speakers from Recorded Calls with Symbl.ai’s Python SDK]]></title>
            <link>https://python.plainenglish.io/how-to-perform-a-timeseries-analysis-of-separated-speakers-from-recorded-calls-with-symbl-ais-3080c9ba0763?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/3080c9ba0763</guid>
            <category><![CDATA[time-series-analysis]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[conversations]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Wed, 09 Mar 2022 07:11:05 GMT</pubDate>
            <atom:updated>2022-03-11T06:01:44.623Z</atom:updated>
            <content:encoded><![CDATA[<h4>Uploading a recorded call with Symbl.ai’s Async API with the API call configured to enable speaker separation but with Symbl.ai’s Python SDK.</h4><p>Symbl.ai is a Conversation Intelligence API platform for developers to augment the speaking realities of conversations in real-time. Many of the realities that speakers face in conversations are limited by the current state of the art for voice, video, message, or broadcast platforms whose native functionality does not extend beyond enabling calls, streams, chats, or live events. Symbl.ai enables developers developing on any of the many streaming platforms to extend the functionalities of those platforms vastly through the introduction of no more than a few API calls.</p><p>Among the API calls with which you as a developer are empowered to extend the functionality of your calls is Symbl.ai’s Async API. With Symbl.ai’s Async API you have the power to augment the speaking realities of your speakers by separating their voices. With separated speakers, you are able to connect, transform or visualize the aspects of a conversation that are unique to the separated speaker.</p><p>Symbl.ai’s Python SDK. Symbl.ai’s Python SDK provides convenient methods for making calls to API endpoints like the one uploading a recorded call for processing with the Async API. In the following guide, you will upload a recorded call with Symbl.ai’s Async API with the API call configured to enable speaker separation but with Symbl.ai’s Python SDK.</p><p><a href="https://docs.symbl.ai/docs/async-api/tutorials/get-speaker-separation-audio-video/">How to implement speaker separation with Async Audio or Video Files | Symbl Docs</a></p><h3>Sign up</h3><p>Register for an account at <a href="https://platform.symbl.ai/">Symbl</a> (i.e., <a href="https://platform.symbl.ai/">https://platform.symbl.ai/</a>). Grab both your appId and your appSecret. With both of those you should authenticate either with a cURL <a href="https://www.mit.edu/afs.new/sipb/user/ssen/src/curl-7.11.1/docs/curl.html">command</a> or with Postman so that you receive your x-api-key. Here is an example with cURL:</p><pre>curl -k -X POST &quot;<a href="https://api.symbl.ai/oauth2/token:generate">https://api.symbl.ai/oauth2/token:generate</a>&quot; \<br>     -H &quot;accept: application/json&quot; \<br>     -H &quot;Content-Type: application/json&quot; \<br>     -d &quot;{ \&quot;type\&quot;: \&quot;application\&quot;, \&quot;appId\&quot;: \&quot;&lt;appId&gt;\&quot;, \&quot;appSecret\&quot;: \&quot;&lt;appSecret&gt;\&quot;}&quot;</pre><p>Ideally, a token server would handle authentication (with code that makes RESTful API call for generating token) so that neither the appSecret nor the appId were ever exposed. However, cURL sets you up immediately anyway. With thex-api-key handy you are now ready to establish a WebSocket endpoint for performing live transcription.</p><h3>Setting Up Symbl.ai’s Python SDK 🐍</h3><p>Symbl.ai’s Python SDK is a specially designed SDK to enable Pythonistas to program brand new experiences around conversations. In that respect Symbl.ai’s Python SDK empowers developers to access programmable intelligence directly in your mobile or web applications, client, or server.</p><h3>Installation</h3><p>Before you install the Symbl.ai Python SDK, please ensure that you have installed Python 2.7+ or Python 3.4+ (PyPy supported). Symbl.ai recommends you execute Python’s installation through Homebrew, the open-source package manager for macOS.</p><h3>Homebrew</h3><p>To <a href="https://brew.sh/#install">install Homebrew</a>, open Terminal or your favorite OS X terminal emulator and run:</p><pre>$ /bin/bash -c &quot;<strong>$(</strong>curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh<strong>)</strong>&quot;</pre><p>After <a href="https://brew.sh/#install">installing Homebrew</a>, run the following command:</p><pre>brew install python</pre><p>After the installation, check to see whether your version of Python is compatible with Symbl.ai’s installation requirements:</p><pre>python --version</pre><p>If the version is higher than Python 2.7+ or Python 3.4+, then you’re all set to download Symbl.ai’s Python SDK.</p><h3>Installing Symbl.ai’s Python SDK</h3><p>Now that Python is installed, the next step is to install Symbl.ai’s Python SDK. To install Symbl.ai’s Python SDK, you install pip in the following way:</p><pre>pip install --upgrade symbl</pre><p>In a similar way, you install the same:</p><pre>python -m pip install --upgrade symbl</pre><h3>Configuration</h3><p>In a testing environment like the one you create to transform your conversation into a time-series graph, you run credentials in-line. Since you quickly test the current code, you can utilize the credentials variable to pass your appId and appSecret as a part of the code itself. However, you must add the credentials variable every time make a new API call.</p><pre>import symbllocal_path = r&#39;c:/Users/john/Downloads/business_meeting.mp3&#39;# Process audio fileconversation_object = symbl.Audio.process_file(<br>file_path=local_path<br>credentials={app_id: &lt;app_id&gt;, app_secret: &lt;app_secret&gt;},  #This is optional if you didn’t setup the symbl.conf file in your home directory. <br>)</pre><h3>Making a Call to the Async API with the Python SDK</h3><p>To start the process of hacking your conversations with Symbl.ai’s Python SDK you import the Symbl SDK.</p><pre>import symbl</pre><p>The next step is to configure a payload in much the same way that you would configure a payload for an ordinary HTTP request in any one of your favorite programming languages. Here is a payload.</p><pre>payload = {&#39;url&#39;:&#39;https://symbltestdata.s3.us-east-2.amazonaws.com/sample_audio_file.wav&#39;,}</pre><p>After configuring the payload, create a dictionary for storing credentials in the following way:</p><pre>credentials_dict = {&#39;app_id&#39;: &#39;&lt;app_id&gt;&#39;, &#39;app_secret&#39;: &#39;&lt;app_secret&gt;&#39;}</pre><p>Last but not least create a conversation object. After the conversation object is created, the next step is to pipe the response selectively into the data you want to visualize in particular. The conversation object is a call to Symbl.ai’s Async API for processing audio through a URL.</p><pre>conversation = symbl.Audio.process_url(https://medium.com/payload=payload,%20credentials=credentials_dict)</pre><h3>Parameters for Speaker Separation</h3><p>To configure the conversation payload to deliver parameters directing the Async API to enable both a count as well as a separation of speakers, you configure a parameters dictionary with key-value pairs like so:</p><p>Note: If you made the call without specifying the number of speakers, you might have received the following message:</p><pre>{&quot;message&quot;:&quot;diarizationSpeakerCount must be greater than zero and needs to be passed to accurately determine unique speakers in the audio&quot;}</pre><p>To properly configure the conversation payload, you have to enable both a count as well as a separation of speakers in the following way:</p><pre>parameters={&#39;enableSpeakerDiarization&#39;: True, &#39;diarizationSpeakerCount&#39;: 2}</pre><h3>Separate Speakers</h3><p>By adding the following to your conversation payload, your proper configuration directs the Async API to both counts as well as separates the speakers in the recorded call.</p><p>With the proper configuration set up in your conversation payload, make your API call. After the API call is made, you receive a conversationId with which to check whether or not or how the numbered speakers were separated.</p><h4>Conversation API’s Message API</h4><p>After separating the speakers, number speaker labels appear within the messages of the Conversation API’s Message API’s return data. The data looks like the following:</p><pre>{</pre><pre>&quot;messages&quot;: [</pre><pre>{</pre><pre>&quot;id&quot;: &quot;5543101041999872&quot;,</pre><pre>&quot;text&quot;: &quot;But what?&quot;,</pre><pre>&quot;from&quot;: {</pre><pre>&quot;id&quot;: &quot;f0fe6722-49c7-47c4-9708-03e4e5182508&quot;,</pre><pre>&quot;name&quot;: &quot;Speaker 2&quot;</pre><pre>},</pre><pre>&quot;startTime&quot;: &quot;2021-08-16T19:38:01.747Z&quot;,</pre><pre>&quot;endTime&quot;: &quot;2021-08-16T19:38:02.147Z&quot;,</pre><pre>&quot;conversationId&quot;: &quot;0000-0000-0000-0000&quot;,</pre><pre>&quot;phrases&quot;: []</pre><pre>}]</pre><h3>Numpy, Matplotlib, Pandas</h3><p>Built on top of Numpy (i.e., multi-dimensional array objects) together with Matplotlib (i.e., capabilities for data visualizations), Pandas is a Python library for DataFrames, a programmatic object for two-dimensional, size-mutable, potentially heterogeneous tabular data (i.e., rectangular or tabular data of rows &amp; columns or <em>DataFrames</em>). Pandas handle CRUD operations within those objects at the same time that they provide access to statistical analysis. With more than 14 million downloads a month, Pandas is the key that releases the genies in the bottles of Data Science throughout the world.</p><p>Before passing back to the analysis, there are two sets of important keywords to mention about Pandas. 1) The three components are accessible through attributes: .values — data values in a two-dimension NumPy array, .columns, and .index — data values in row numbers or row labels. In addition to these attributes, there are display methods. These are .head() — displays the first row, .info() — display the names of columns, and .shape() — number of rows &amp; columns (attribute, not method, no ()).</p><p>One other convenience method called .describe() is used <strong>for calculating some statistical data like percentile, mean, </strong>and<strong> std of</strong> the numerical values of a Series or a DataFrame. It analyzes both numeric and object series and also the DataFrame column sets of mixed data types.</p><h3>Creating Separate Numpy Arrays for Analyzing the Speakers Separately</h3><p>The next step is to loop through the speaker-separated transcription with the conversationIdto create separate NumPy arrays for analyzing the speakers separately. Since Symbl.ai provides timestamped, speaker-separated data from the Message API within the Conversation API’s suite of API endpoints, your first step now is to perform an analysis of sentiments on your speaker separated timestamped data.</p><h4>Message API &amp; Sentiment Analysis</h4><p>Symbl.ai’s Python SDK makes the process of performing an analysis of sentiments on your speaker separated timestamped data convenient. You make a call to more than a single API endpoint with a payload. A payload is a dictionary just like the one for speaker separation, except with a new key-value pair: parameters={‘sentiment’: True}.</p><pre>response = conversation.get_messages(parameters={&#39;sentiment&#39;: True})</pre><p>After making the call to the conversation API through the .get_messages convenience method on the Conversation API’s Message API, you receive a JSON return data in the following format:</p><pre>{</pre><pre>&quot;messages&quot;: [</pre><pre>{</pre><pre>     &quot;id&quot;: &quot;5543101041999872&quot;,</pre><pre>     &quot;text&quot;: &quot;But what?&quot;,</pre><pre>    &quot;from&quot;: {</pre><pre>         &quot;id&quot;: &quot;f0fe6722-49c7-47c4-9708-03e4e5182508&quot;,</pre><pre>         &quot;name&quot;: &quot;Speaker 2&quot;</pre><pre>},</pre><pre>    &quot;startTime&quot;: &quot;2021-08-16T19:38:01.747Z&quot;,</pre><pre>    &quot;endTime&quot;: &quot;2021-08-16T19:38:02.147Z&quot;,</pre><pre>    &quot;conversationId&quot;: &quot;0000-0000-0000-0000&quot;,</pre><pre>    &quot;phrases&quot;: [],</pre><pre>    &quot;sentiment&quot;: {</pre><pre>        &quot;polarity&quot;: {</pre><pre>        &quot;score&quot;: -0.301</pre><pre>        },</pre><pre>        &quot;suggested&quot;: &quot;negative&quot;</pre><pre>        }</pre><pre>}]</pre><h4>Loading the Numpy Arrays</h4><p>The first step is to empty initialize a set of arrays.</p><pre>timestamps1, timestamps2, polarities1, polarities2 = [], [], [], []</pre><p>After having empty initialized these two empty arrays, your next step is to loop through the Message API’s return data to map both the timestamps as well as the sentiments correctly to the speaker-separated arrays.</p><p>As you may imagine, 1) your first step is to fetch the JSON data from the conversation payload. 2) Your second step is to create a Python if/else statement where the first condition is whether or not the speaker is speaker 1 while the second condition is whether or not the speaker is speaker 2. Based on which speaker is which, you configure the Python flow logic to map the speaker-separated timestamps to the NumPy array, the speaker-separated timestamps to the NumPy array.</p><pre>timestamps1, timestamps2, polarities1, polarities2 = [], [], [], []<br>for message in response.messages:<br>    if message.from.name == &quot;speaker 1&quot;:<br>        timestamps1.append(message.start_time)<br>        polarities1.append(message.sentiment.polarity.score)<br>    elif message.from.name == &quot;speaker 2&quot;:<br>        timestamps2.append(message.start_time)<br>        polarities2.append(message.sentiment.polarity.score)<br><br>print(timestamps1, timestamps2)<br>print(polarities1, polarities2)</pre><h4>Creating Speaker Separated DataFrames with Pandas</h4><p>The next step is to merely map the NumPy arrays directly to Pandas’ DataFrames in the following way:</p><pre>import pandas as pd</pre><pre>df1 = pd.DataFrame({&quot;timestamps&quot;: timestamps1,&quot;polarities&quot;: polarities1})</pre><pre>df2 = pd.DataFrame({&quot;timestamps&quot;: timestamps2,&quot;polarities&quot;: polarities2})</pre><h4>Plotting Multiple DataFrames with Matplotlib to a Single Plot: pandas.DataFrame.plot()</h4><p>To perform a simultaneous time series analysis of the timestamped, speaker separated data from the Message API, you load the DataFrames directly into a .plot call on Matplotlib, configuring the x-axis to display the timestamps, the y-axis to display the polarities.</p><p>You might think that the logical code implementation for that type of configuration is to run both DataFrames through the same method call.</p><pre>df1.plot(x=&quot;timestamps&quot;, y=&quot;polarities&quot;)<br>df2.plot(x=&quot;timestamps&quot;, y=&quot;polarities&quot;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/648/1*Huphp-RDHf-u0O_YG7fAfA.png" /></figure><p>You might think that the logical code implementation for that type of configuration is to run both DataFrames through the same method call.</p><p>The logical code implementation, however, is quite different in Pandas. You make the assignment of one DataFrame’s plot equivalent to the other in the following way:</p><pre>ax = df1.plot()</pre><pre>df2.plot(ax=ax)</pre><h3>What’s Next</h3><p>In addition to adding bells and whistles to your graphs like labels, you may consider how Symbl.ai’s Python SDK provides access to many of Symbl.ai’s APIs. In particular, you can enable Symbl.ai’s Python SDK on the real-time Telephony API (i.e., <a href="https://docs.symbl.ai/docs/python-sdk/python-sdk-telephony-api">Telephony API (in Real-time</a>) or any one of the Async APIs for voice, video, or messaging. A complete list is here:</p><ul><li><a href="https://docs.symbl.ai/docs/python-sdk/async-api">Async Text API</a></li><li><a href="https://docs.symbl.ai/docs/python-sdk/async-audio">Async Audio (File) API</a></li><li><a href="https://docs.symbl.ai/docs/python-sdk/async-audio#async-audio-url-api">Async Audio (URL) API</a></li><li><a href="https://docs.symbl.ai/docs/python-sdk/async-video">Async Video (File) API</a></li><li><a href="https://docs.symbl.ai/docs/python-sdk/async-video#async-video-url-api">Async Video (URL) API</a></li></ul><p>In addition, Symbl.ai’s Python SDK contains links to enable Symbl.ai on its Telephony APIs with Python special methods. The methods for dialing in to a call, work on the Session Initiation Protocol (SIP). With Symbl.ai’s Python SDK dialed into a call, you are in a position to expand the experiences around calls in <a href="https://docs.symbl.ai/docs/python-sdk/python-sdk-telephony-sips/"><em>real-time</em></a><em>. </em>After connecting to a SIP call in real-time, you subscribe to Symbl.ai’s events such as events for contextual insights like <a href="https://docs.symbl.ai/docs/python-sdk/python-sdk-telephony-sips/#subscribe-to-events">follow-ups, questions, or action-items</a>, or you create a request to deliver <a href="https://docs.symbl.ai/docs/python-sdk/python-sdk-telephony-sips/#receive-insights-on-email">a post-meeting summary directly to your inbox</a>.</p><h3>Community</h3><p><a href="https://symbl.ai/?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Symbl.ai</a>’s invites developers to reach out to us via email at <a href="https://mailto:developer@symbl.ai/">developer@symbl.ai</a>, join our <a href="https://join.slack.com/t/symbldotai/shared_invite/zt-4sic2s11-D3x496pll8UHSJ89cm78CA?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Slack</a> channels, participate in our <a href="https://developer.symbl.ai/hackathon?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">hackathons</a>, fork our <a href="https://www.postman.com/symbldotai/workspace/symbl-ai/overview?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Postman public workspace</a>, or git clone our repos at <a href="https://github.com/symblai?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Symbl.ai&#39;s GitHub</a>.</p><p><em>More content at </em><a href="https://plainenglish.io/"><strong><em>PlainEnglish.io</em></strong></a><em>. Sign up for our </em><a href="http://newsletter.plainenglish.io/"><strong><em>free weekly newsletter</em></strong></a><em>. Follow us on </em><a href="https://twitter.com/inPlainEngHQ"><strong><em>Twitter</em></strong></a><em> and </em><a href="https://www.linkedin.com/company/inplainenglish/"><strong><em>LinkedIn</em></strong></a><em>. Join our </em><a href="https://discord.gg/GtDtUAvyhW"><strong><em>community Discord</em></strong></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3080c9ba0763" width="1" height="1" alt=""><hr><p><a href="https://python.plainenglish.io/how-to-perform-a-timeseries-analysis-of-separated-speakers-from-recorded-calls-with-symbl-ais-3080c9ba0763">Perform a Timeseries Analysis of Separated Speakers from Recorded Calls with Symbl.ai’s Python SDK</a> was originally published in <a href="https://python.plainenglish.io/">Python in Plain English</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automate Symbl.ai’s Analysis of Telnyx PSTN Calls with Pipedream]]></title>
            <link>https://unicornmobile.medium.com/automate-symbl-ais-analysis-of-telnyx-pstn-calls-with-pipedream-1c26a1e20247?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/1c26a1e20247</guid>
            <category><![CDATA[api]]></category>
            <category><![CDATA[conversations]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[real-time-communication]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Wed, 09 Mar 2022 06:56:17 GMT</pubDate>
            <atom:updated>2022-03-09T06:56:17.177Z</atom:updated>
            <content:encoded><![CDATA[<p>Behind Artificial Intelligence/Machine Learning as the bleeding edge of the algorithmic revolution is automation. Automation is accelerating the rate of change in technology across industries around the world. The ability to interpret data to program reactive transformations in real-time from one state to another without a human hand is one of the most powerful ways to advance technology.</p><h3>Pipedream</h3><p>In pursuit of that goal is Pipedream. Pipedream is a serverless, real-time API platform for programmatically transforming data from one state to another without a human hand. It provides multiple points of entry for Third Party Software as a Service to enable developers to connect APIs remarkably fast with triggers or actions in Node.js. With managed authentication for 300+ OAuth or key-based APIs, Pipedream makes environment variables accessible for credentials or references in any workflow. It is serverless so the platform does not require developers to deploy their automation engines to the cloud.</p><p>Since Pipedream works with any or all APIs, Pipedream’s platform automates the process of connecting Telnyx PSTN calls seamlessly. Symbl.ai is already enabled Pipedream. Pipedream therefore empowers developers to combine Symbl.ai’s Conversation Intelligence API platform with Telnyx to create powerful automations that save time, money, or effort throughout the entire process of a call.</p><p>In your automation you program Pipedream to enable call recording through the interpretation of a WebHook’s response data. After automating the recording, you enable Symbl.ai to process the recorded call upon completion. You literally daisy chain the three together, Telnyx, Pipedream, Symbl.ai.</p><h3>Prerequisites</h3><ul><li>Pipedream Account</li><li>Telnyx Account</li><li>Symbl.ai Account</li><li>cURL</li></ul><h3>Telnyx</h3><p>Telnyx is a real-time communications platform with full, feature-rich voice functionalities, making it quick and easy to set up and port numbers around the world, configure messaging, control VoIP and IP network functions, and define how and where communications can be used in real time. The Telnyx API can power a host of specialty applications, from call tracking to cloud-based PBX, dynamic security, and authentication use cases.</p><h4>Telnyx</h4><p>Telnyx’s Voice APIs provide you as a developer with access to recorded calls through a single API call.</p><h4>Steps</h4><p>To analyze a recorded call with Telnyx, you set up your Voice API configuration with Telnyx’s Call Control within the Telnyx Portal. Just follow these simple steps:</p><ol><li>Sign up for a <strong>Telnyx account</strong>.</li><li>Create an <strong>application</strong> to configure how you connect your calls.</li><li>Buy or port a <strong>phone number</strong> to receive inbound calls, and assign this number to your new application.</li><li>Create an <strong>outbound voice profile</strong> to make outbound calls, and assign your application to this new profile.</li><li>Record the call</li><li>Generate a Public URL for recorded calls</li></ol><p>These steps are summarized on Telnyx’s <a href="https://developers.telnyx.com/docs/v2/call-control/quickstart">quickstart</a> guide.</p><h3>Portal Signup</h3><p>Let’s begin with the easiest step of all. Head to the <a href="http://telnyx.com/sign-up">signup page</a> to sign up for your free Telnyx account. It’ll give you access to our Mission Control Portal, where you can buy numbers, set up and manage connections and a lot more. The first step is to search and purchase a Telnyx Voice API number.</p><h3>Search and Purchase</h3><p>After clinking on numbers, you are provided with the ability to search and buy a number:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jfyC-diyPlTMLTsPSi91NQ.png" /></figure><p>After selecting a number, checkout.</p><h4>Editing your Call Control App</h4><p>After selecting a number, you navigate to the Call Control App.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U8J-ehAmTLe3ZLN0uXHb4g.png" /></figure><p>After clicking “Create Your First Application”, you edit your Call Control App.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MQqDGK4Fs7qekgLuh50yNQ.png" /></figure><p>There are three steps to take in editing the Call Control App:</p><ol><li>Create an App Name.</li><li>Copy of the Call Control Application number as later the number is used in a cURL command as a uuid.</li><li>Paste the link you called your “Your unique URL.”</li></ol><p>With those three steps out of the way, your Call Control App is ready to enable outbound calls through POST requests with cURL commands.</p><h4>The First cURL Request</h4><p>To initiate a Telnyx Voice API call for recording, you make the following POST request:</p><pre>curl -X POST \<br>  --header &quot;Content-Type: application/json&quot; \<br>  --header &quot;Accept: application/json&quot; \<br>  --header &quot;Authorization: Bearer YOUR_API_KEY&quot; \<br>  --data &#39;{&quot;connection_id&quot;: &quot;UUID&quot;, &quot;to&quot;: &quot;YOUR TELEPHONE NUMBER&quot;, &quot;from&quot;: &quot;YOUR TELNYX VOICE API NUMBER&quot;}&#39; \<br>  <a href="https://api.telnyx.com/v2/calls">https://api.telnyx.com/v2/calls</a></pre><p>As you can see above, you will need to change the variables for the following:</p><ol><li>YOUR_API_KEY</li><li>YOUR_TELEPHONE_NUMBER</li><li>YOUR_TELNYX_VOICE_API_NUMBER</li><li>UUID</li></ol><p>The UUID is the Call Control Application number from number 2 in the section above.</p><p>After the request successfully POSTs, the webhook server returns a POST request with return data like so:</p><pre>{<br>  &quot;data&quot;: {<br>    &quot;event_type&quot;: &quot;call.initiated&quot;,<br>    &quot;id&quot;: &quot;3d4d3f3a-cfd6-437e-9592-7554a9996a45&quot;,<br>    &quot;occurred_at&quot;: &quot;2021-09-14T18:52:40.155477Z&quot;,<br>    &quot;payload&quot;: {<br>      &quot;call_control_id&quot;: &quot;ef8ffc44-158c-11ec-8de2-02420a0d4168&quot;,<br>      &quot;call_leg_id&quot;: &quot;ef8ffc44-158c-11ec-8de2-02420a0d4168&quot;,<br>      &quot;call_session_id&quot;: &quot;ef8ab3d8-158c-11ec-b771-02420a0d4168&quot;,<br>      &quot;client_state&quot;: null,<br>      &quot;connection_id&quot;: &quot;1725531088727573914&quot;,<br>      &quot;direction&quot;: &quot;outgoing&quot;,<br>      &quot;from&quot;: &quot;+16182216200&quot;,<br>      &quot;state&quot;: &quot;bridging&quot;,<br>      &quot;to&quot;: &quot;+19168739475&quot;<br>    },<br>    &quot;record_type&quot;: &quot;event&quot;<br>  },<br>  &quot;meta&quot;: {<br>    &quot;attempt&quot;: 1,<br>    &quot;delivered_to&quot;: &quot;<a href="https://en50uuiv6hkdtwy.m.pipedream.net/">https://YOURPIPEDREAMWEBHOOK.pipedream.net</a>&quot;<br>  }<br>}</pre><h4>The Second cURL Request</h4><p>To initiate the recording for Telnyx’s Voice API call, you execute the following POST request withcURL:</p><pre>curl -X POST \<br>  --header &quot;Content-Type: application/json&quot; \<br>  --header &quot;Accept: application/json&quot; \<br>  --header &quot;Authorization: Bearer YOUR_API_KEY&quot; \<br>  --data &#39;{&quot;format&quot;: &quot;mp3&quot;, &quot;channels&quot;: &quot;single&quot;}&#39; \<br>  <a href="https://api.telnyx.com/v2/calls/ef8ffc44-158c-11ec-8de2-02420a0d4168/actions/record_start">https://api.telnyx.com/v2/calls/{call_control_id}/actions/record_start</a></pre><p>As you can see above, you will need to change the variables for the following:</p><ol><li>YOUR_API_KEY</li><li>call_control_id</li></ol><p>The call_control_id comes directly from the return data from the last POST request.</p><p>After the request successfully POSTs, the terminal returns the following data:</p><pre>{<br> &quot;data&quot;: {<br>  &quot;record_type&quot;: &quot;recording&quot;,<br>  &quot;recording_id&quot;: &quot;c84048c4-e4cd-48f6-a94e-cf8be3fbd884&quot;,<br>  &quot;result&quot;: &quot;ok&quot;<br>}</pre><p>The next step is to hang up the call. With the call hung up, the webhook server serves the public URL for accessing the recorded call.</p><h4>Public URLs for Recorded Calls</h4><p>After recording a call with Telnyx’s Voice API, you make a call with one of the call commands to expose the webhook for the public recording URL (e.g., public_recording_urls) in the call.recording.saved object.</p><p>After successfully making the call, the return data POSTs to the webhook server. Within the return data for the JSON, the recording_urls looks like the following before it is posted to the web hook:</p><pre>{<br> &quot;data&quot;: {<br>  &quot;event_type&quot;: &quot;call.recording.saved&quot;,<br>  &quot;id&quot;: &quot;0ccc7b54-4df3-4bca-a65a-3da1ecc777f0&quot;,<br>  &quot;occurred_at&quot;: &quot;2018-02-02T22:25:27.521992Z&quot;,<br>  &quot;payload&quot;: {<br>   &quot;call_leg_id&quot;: &quot;428c31b6-7af4-4bcb-b7f5-5013ef9657c1&quot;,<br>   &quot;call_session_id&quot;: &quot;428c31b6-abf3-3bc1-b7f4-5013ef9657c1&quot;,<br>   &quot;channels&quot;: &quot;single&quot;,<br>   &quot;client_state&quot;: &quot;aGF2ZSBhIG5pY2UgZGF5ID1d&quot;,<br>   &quot;connection_id&quot;: &quot;7267xxxxxxxxxxxxxx&quot;,<br>   &quot;public_recording_urls&quot;: {<br>    &quot;mp3&quot;: &quot;<a href="http://example.com/recording.mp3">http://example.com/recording.mp3</a>&quot;,<br>    &quot;wav&quot;: &quot;<a href="http://example.com/recording.wav">http://example.com/recording.wav</a>&quot;<br>   },<br>   &quot;recording_ended_at&quot;: &quot;2018-02-02T22:25:27.521992Z&quot;,<br>   &quot;recording_started_at&quot;: &quot;2018-02-02T22:20:27.521992Z&quot;,<br>   &quot;recording_urls&quot;: {<br>    &quot;mp3&quot;: &quot;<a href="http://example.com/recording.mp3">http://example.com/recording.mp3</a>&quot;,<br>    &quot;wav&quot;: &quot;<a href="http://example.com/recording.wav">http://example.com/recording.wav</a>&quot;<br>   }<br>  },<br>  &quot;record_type&quot;: &quot;event&quot;<br> }<br>}</pre><p>After posting to the webhook, the recording_urls looks like the following before it is posted to the web hook:</p><pre>{<br>  &quot;data&quot;: {<br>    &quot;event_type&quot;: &quot;call.recording.saved&quot;,<br>    &quot;id&quot;: &quot;47ee6238-6c0d-4f49-bd46-b2b00ea42fbd&quot;,<br>    &quot;occurred_at&quot;: &quot;2021-09-14T18:54:58.177200Z&quot;,<br>    &quot;payload&quot;: {<br>      &quot;call_control_id&quot;: &quot;ef8ffc44-158c-11ec-8de2-02420a0d4168&quot;,<br>      &quot;call_leg_id&quot;: &quot;ef8ffc44-158c-11ec-8de2-02420a0d4168&quot;,<br>      &quot;call_session_id&quot;: &quot;ef8ab3d8-158c-11ec-b771-02420a0d4168&quot;,<br>      &quot;channels&quot;: &quot;single&quot;,<br>      &quot;client_state&quot;: null,<br>      &quot;connection_id&quot;: &quot;1725531088727573914&quot;,<br>      &quot;end_time&quot;: &quot;2021-09-14T18:54:57.517467Z&quot;,<br>      &quot;format&quot;: &quot;mp3&quot;,<br>      &quot;public_recording_urls&quot;: {},<br>      &quot;recording_ended_at&quot;: &quot;2021-09-14T18:54:57.517467Z&quot;,<br>      &quot;recording_id&quot;: &quot;c84048c4-e4cd-48f6-a94e-cf8be3fbd884&quot;,<br>      &quot;recording_started_at&quot;: &quot;2021-09-14T18:54:38.008036Z&quot;,<br>      &quot;recording_urls&quot;: {<br>        &quot;mp3&quot;: &quot;https://s3.amazonaws.com/telephony-recorder-prod/b880fcdb-d93b-46e9-9c62-2aa7c5b2eb06/2021-09-14/ef8ffc44-158c-11ec-8de2-02420a0d4168-1631645677.mp3?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;X-Amz-Credential=AKIASDC5E2MJDPKMH7UW%2F20210914%2Fus-east-1%2Fs3%2Faws4_request&amp;X-Amz-Date=20210914T185458Z&amp;X-Amz-Expires=600&amp;X-Amz-SignedHeaders=host&amp;X-Amz-Signature=b586b5ed26263edb7fd13c7b227c094e4ee9dd45403278d6f9335ee034c4d65d&quot;<br>      },<br>      &quot;start_time&quot;: &quot;2021-09-14T18:54:38.008036Z&quot;<br>    },<br>    &quot;record_type&quot;: &quot;event&quot;<br>  },<br>  &quot;meta&quot;: {<br>    &quot;attempt&quot;: 1,<br>    &quot;delivered_to&quot;: &quot;<a href="https://en50uuiv6hkdtwy.m.pipedream.net/">https://YOURPIPEDREAMWEBHOOK.pipedream.net</a>&quot;<br>  }<br>}</pre><p>Symbl.ai requires nothing more than that URL to handle analyzing the Telnyx recorded call. The great thing about Telnyx is that Telnyx empowers developers to provide options with which to determine the file type of the recorded call hosted on the S3 bucket. In recording_urls above the file type is .mp3. Symbl.ai’s Conversation Intelligence API platform accepts .mp3 files right out of the box.</p><h3>Pipedream</h3><p>Pipedream is one of the most developer friendly platforms for automations. It greets developers with a special onboarding immediately upon login. In Pipedream’s special onboarding, Pipedream teaches you how to create an HTTP triggered workflow where you 1) trigger a workflow on an HTTP request, 2) retrieve data from an API using Node.js with npm, 3) deploy your changes for testing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZyETrr-WjYPOfDtXa1Ql6A.png" /></figure><h4>Automation Process for Pipedream with Telnyx</h4><p>Pipedream initiates its automation after the enabled WebHook server returns the response data from the final POST request in the chain of POST requests made to create a recorded call. The chain is 1) <a href="https://api.telnyx.com/v2/calls">v2/calls</a>, 2) <a href="https://api.telnyx.com/v2/calls/ef8ffc44-158c-11ec-8de2-02420a0d4168/actions/record_start">v2/calls/{call_control_id}/actions/record_start</a> where the response data to the latter call is an .mp3 file hosted by AWS from the section on recording_urls. You access that data from the data pipeline in the following way: event.body.data.recording_urls. Accordingly, the process by which you automate the analysis of recorded call is a multi-step process so after you have automated the call recording, the next step is to create another automation for transferring the recorded call to Symbl.ai for processing.</p><h4>Automating Telnyx Call Recording with Symbl.ai within Pipedream</h4><p>After familiarizing yourself with Pipedream, the next step is to create a workflow. A workflow is a set of steps designed to respond to events over a webhook. In your workflow for automating call recording, you configure two steps, one for a trigger, another for processing.</p><h4>Environment Variables</h4><p>However, before creating a workflow, you need to configure your environment variables appropriately. Navigate to Settings &gt; Environment Variables &gt; New Environment Variable. For YOUR_ENV_VAR_NAME, set the name as TELNYX_API_KEY, add the value. After adding the value, the next step is to add your Symbl.ai appId and appSecret with their respective values for each.</p><h4>The Event Flow</h4><p>Pipedream is a <em>reactive</em> platform that <em>reacts </em>to events in real-time. Telnyx, in the same regard, is reactive, an event driven architecture where every action creates an opposite and equal <em>reaction</em>. In that reactive system, Telnyx creates events when a call is initiated (i.e., call.initiated), hung up (i.e., call.hangup), answered (i.e., call.answered), or recorded (i.e., call.recording.saved) for each of which Telnyx issues a POST request on its webhook. The request / response model, common among all APIs of the world, is a basic HTTP framework <em>in motion</em>.</p><h4>Pipedream WebHook</h4><p>Here is where both Pipedream as well as Telnyx are exceptionally developer friendly. Pipedream creates a link for a webhook whereas Telnyx receives the created links for webhooks. One fits into the other like as in the two go together like hand and glove. The next step is to take your Pipedream webhook so that you can add it to Telnyx.</p><ol><li>Login into the Telnyx platform</li><li>Navigate from the Dashboard to Call Control / Applications</li><li>Select your number.</li><li>Navigate from Edit your Call Control App &gt; Send a webhook to the URL.</li><li>Paste your Pipedream webhook url: “delivered_to”: “<a href="https://en50uuiv6hkdtwy.m.pipedream.net/">https://YOURPIPEDREAMWEBHOOK.pipedream.net</a>&quot;</li></ol><p>After you have added your Pipedream WebHook url, close the Telnyx account. With the WebHook set up in the Telnyx platform, the next step is to create the workflow for responding to the events the Telnyx APIs POST to the Pipedream WebHook.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*luTONdJ-nj7jkDAvwTe60g.png" /><figcaption>Your Pipedream Webhook in Telnyx’s Call Control App</figcaption></figure><h4>Steps for Trigger</h4><p>The first step is to set up a trigger. A trigger in the Pipedream platform is a step in the portal where the events posted to the webhook are handled. The workflow triggers the workflow on each request. The advantage that Pipedream provides is that the platform’s triggers not only handle the event, they handle the event’s JSON return data, parsing it entirely upon receipt. In terms of Telnyx, the webhook therefore parses the return data for the Telnyx events mentioned earlier: (i.e., call.initiated), hung up (i.e., call.hangup), answered (i.e., call.answered), or recorded (i.e., call.recording.saved).</p><h4>Triggering</h4><p>Pipedream’s own developer onborading teaches you how to properly configure an HTTP API as a trigger. Pipedream generates a unique URL to trigger :(i.e., your <a href="https://en50uuiv6hkdtwy.m.pipedream.net/">https://YOURPIPEDREAMWEBHOOK.pipedream.net</a>). Since Pipedream automatically detects the JSON schema of the HTTP API’s return data, Pipedream provides developers with a readily made solution for enabling developers to gain access to the data contained in the step: steps.trigger.event. Consequently, you access the return data from that single instance (i.e., .event).</p><h4>Processing with Node.js</h4><p>In the next step, which is a sandbox for Node.js, Pipedream feeds the events or steps into a large async call (i.e., an invention of genius for its simplicity). In the async step, the Node.js app completes the calls to functions for handling the different types of functions with which to program automatic reactions. The async function call looks like the following:</p><pre><strong>async </strong>(event, steps) =&gt; {}</pre><p>In the async call declare the following:</p><pre><strong>const</strong> axios = require(&#39;axios&#39;)</pre><pre><strong>const</strong> name = &quot;Pipedream&#39;s Automation for Telnyx with Symbl.ai&quot;</pre><pre><strong>const</strong> type = event.body.data.event_type</pre><p>In the next step you need to program the Telnyx events mentioned earlier: (i.e., call.initiated), hung up (i.e., call.hangup), answered (i.e., call.answered), or recorded (i.e., call.recording.saved) in the following way:</p><p>After you have identified the async function call, the next step is to program a type to toggle, as you toggle from one type of event to another. In the following, you toggle from one type of Telnyx event to another:</p><pre><strong>const</strong> type = event.body.data.event_type</pre><pre><strong>if</strong> (type === &quot;call.recording.saved&quot;) {</pre><pre>console.log(&quot;The Call is Saved&quot;)</pre><pre>} <strong>else</strong> <strong>if</strong> (type === &quot;call.answered&quot;) {</pre><pre>console.log(&quot;The Call is Answered&quot;)</pre><pre><strong>const</strong> callControlId = event.body.data.payload.call_control_id</pre><pre><strong>const</strong> recordingInitiated = <strong>await</strong> startRecording(callControlId)</pre><pre>console.log(&quot;The recording is initiated:&quot;, recordingInitiated)</pre><pre>} <strong>else</strong> <strong>if</strong> (type === &quot;call.initiated&quot; || type === &quot;call.hangup&quot;) {</pre><pre>$end()</pre><pre>} <strong>else</strong>  {</pre><pre>$end()</pre><pre>}</pre><p>The code there is straight forward an if/else statement for toggling on different types of events. The next step is to program the reactions to be triggered in regards to different types of events. The first reaction is to trigger recording when the call is answered.</p><pre><strong>const</strong> startRecording = <strong>async</strong> (callControlId) =&gt; {</pre><pre><strong>const</strong> data = {</pre><pre>format: &#39;mp3&#39;,</pre><pre>channels: &#39;single&#39;</pre><pre>}</pre><pre><strong>try</strong> {</pre><pre><strong>const</strong> response = <strong>await</strong> axios({</pre><pre>method: &#39;POST&#39;,</pre><pre>url: `https://api.telnyx.com/v2/calls/${callControlId}/actions/record_start`,</pre><pre>headers: {Authorization: `Bearer ${process.env.TELNYX_API_KEY}`},</pre><pre>data: data</pre><pre>})</pre><pre><strong>return</strong> response.data</pre><pre>} <strong>catch</strong> (error) {</pre><pre>console.log(error)</pre><pre>}</pre><pre>}</pre><p>After a call is answered, the callControlId is returned. With the callControlId returned, the next step is to make a POST request to Telnyx’s API endpoint for recording calls: /actions/record_start. After the function for enabling call recording is configured, the next step is designed to save the call for processing.</p><pre><strong>if</strong> (type === &quot;call.recording.saved&quot;) {</pre><pre>// Save the url from the event for recording</pre><pre><strong>const</strong> url = event.body.data.payload.recording_urls.mp3</pre><pre><em>//Submit Job</em></pre><pre><strong>const</strong> token = <strong>await</strong> symblToken()</pre><pre><strong>const</strong> job = <strong>await</strong> pushAudioUrl(url, token)</pre><pre>console.log(job)</pre><pre>}</pre><p>The next step is to program the functions called to trigger both Symbl.ai’s authentication as well as its audio processing.</p><pre><strong>const</strong> symblToken = <strong>async</strong> () =&gt; {</pre><pre><strong>const</strong> data = {</pre><pre>type: &quot;application&quot;,</pre><pre>appId: process.env.SYMBL_APPID,</pre><pre>appSecret: process.env.SYMBL_SECRET</pre><pre>}</pre><pre><strong>try</strong> {</pre><pre><strong>const</strong> response = <strong>await</strong> axios({</pre><pre>method: &#39;POST&#39; ,</pre><pre>url: &#39;https://api.symbl.ai/oauth2/token:generate&#39;,</pre><pre>headers: {&#39;Content-Type&#39;: &#39;application/json&#39;},</pre><pre>data: data</pre><pre>})</pre><pre><strong>return</strong> response.data.accessToken</pre><pre>} <strong>catch</strong> (error) {</pre><pre>console.log(error)</pre><pre>}</pre><pre>}</pre><p>The function symblToken() is an HTTP POST request that passes the appId and appSecret over to Symbl.a’s authentication API, returning a token.</p><p>The next function is an HTTP POST request to Symbl.ai’s audio processing API. API sends the url from event.body.data.payload.recording_urls.mp3 over to Symbl.ai for processing.</p><pre><strong>const</strong> pushAudioUrl = <strong>async</strong> (url, token) =&gt; {</pre><pre><strong>const</strong> data = {</pre><pre>name: name,</pre><pre>url: url,</pre><pre>webhookUrl: &#39;<a href="https://en50uuiv6hkdtwy.m.pipedream.net/">https://YOURPIPEDREAMWEBHOOK.pipedream.net</a>&#39;</pre><pre>}</pre><pre><strong>try</strong> {</pre><pre><strong>const</strong> response = <strong>await</strong> axios({</pre><pre>method: &#39;POST&#39;,</pre><pre>url: &#39;https://api.symbl.ai/v1/process/audio/url&#39;,</pre><pre>headers: {</pre><pre>&#39;Content-Type&#39;: &#39;application/json&#39;,</pre><pre>Authorization: `Bearer ${token}`</pre><pre>},</pre><pre>data: data</pre><pre>})</pre><pre><strong>return</strong> response.data</pre><pre>} <strong>catch</strong> (error) {</pre><pre>console.log(error)</pre><pre>}</pre><pre>}</pre><h4>Upon Completion</h4><p>After the automation is complete, you receive both a conversationId as well as a jobId with which to check the results you have achieved through the automation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/623/1*vMSZCIbiw9gNTj4WrqqbZg.png" /><figcaption>Pipedream’s Node.js with a conversationId &amp; jobId</figcaption></figure><h3>Community</h3><p><a href="https://symbl.ai/?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Symbl.ai</a>’s invites developers to reach out to us via email at <a href="https://mailto:developer@symbl.ai/">developer@symbl.ai</a>, join our <a href="https://join.slack.com/t/symbldotai/shared_invite/zt-4sic2s11-D3x496pll8UHSJ89cm78CA?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Slack</a> channels, participate in our <a href="https://developer.symbl.ai/hackathon?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">hackathons</a>, fork our <a href="https://www.postman.com/symbldotai/workspace/symbl-ai/overview?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Postman public workspace</a>, or git clone our repos at <a href="https://github.com/symblai?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Symbl.ai&#39;s GitHub</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1c26a1e20247" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Timeseries Analysis of Calls with Symbl.ai’s Python SDK, Pandas, & Matplotlib]]></title>
            <link>https://python.plainenglish.io/timeseries-analyses-of-calls-with-symbl-ais-python-sdk-pandas-matplotlib-74752c1a1c3f?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/74752c1a1c3f</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[pandas]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Sat, 10 Jul 2021 02:20:37 GMT</pubDate>
            <atom:updated>2021-07-12T19:07:52.520Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HTYXzPAy9dGis74C2fuLIw.png" /></figure><p>Symbl.ai’s developer platform for programmable intelligence derived from voice, video, message, or broadcast streams, empowers developers to transform experiences around conversations digitally. In the following guide, you use Symbl.ai’s Python SDK, Message API to take sentiment analysis to the next level of digital transformation with time-series analyses.</p><h4>What is Symbl.ai?</h4><p>Symbl.ai enables developers take their user enabled, remote, virtual voice, video, chat, or broadcast streaming ecosystems to the next level of digital transformation. Digitally transforming Real-Time Communications (RTC) enables developers to transform conversations.</p><p>Symbl.ai’s proprietary algorithms simplify conversations so that conversation data such as topics, insight types like questions, follow-ups, or action-items, or sentiments are available for big data manipulation with digital transformation.</p><p>With the ability to program the intelligence you receive from your conversations, your ability to create schemes for enhancing real-time engagements widens to beyond mere transcription to greater connectivity, digital transformations or human readable visualizations.</p><h4>How to Get Up and Running with Symbl.ai</h4><p>Register for an account at <a href="https://platform.symbl.ai/">Symbl</a> (i.e., <a href="https://platform.symbl.ai/">https://platform.symbl.ai/</a>). Grab both your appId and your appSecret. With both of those you should authenticate either with a cURL <a href="https://www.mit.edu/afs.new/sipb/user/ssen/src/curl-7.11.1/docs/curl.html">command</a> or with Postman so that you receive your x-api-key. Here is an example with cURL:</p><pre>curl -k -X POST &quot;<a href="https://api.symbl.ai/oauth2/token:generate">https://api.symbl.ai/oauth2/token:generate</a>&quot; \<br>     -H &quot;accept: application/json&quot; \<br>     -H &quot;Content-Type: application/json&quot; \<br>     -d &quot;{ \&quot;type\&quot;: \&quot;application\&quot;, \&quot;appId\&quot;: \&quot;&lt;appId&gt;\&quot;, \&quot;appSecret\&quot;: \&quot;&lt;appSecret&gt;\&quot;}&quot;</pre><p>Ideally a token server would handle authentication (with code that makes RESTful API call for generating token) so that neither the appSecret nor the appId were ever exposed. However, cURL sets you up immediately anyway. With thex-api-key handy you are now ready to establish a WebSocket endpoint for performing live transcription.</p><h3>Python and Symbl.ai’s Python SDK 🐍</h3><p>Symbl.ai’s Python SDK is a specially designed SDK for enable Pythonistas to program brand new experiences around conversations. In that respect Symbl.ai’s Python SDK empowers developers to access programmable intelligence directly in your mobile or web applications, client or server.</p><h4>Installation</h4><p>Before you install the Symbl.ai Python SDK, please ensure that you have installed Python 2.7+ or Python 3.4+ (PyPy supported). Symbl.ai recommends you execute Python’s installation through Homebrew, the open source package manager for MacOS.</p><h4>Homebrew</h4><p>To <a href="https://brew.sh/#install">install Homebrew</a>, open Terminal or your favorite OS X terminal emulator and run:</p><pre>$ /bin/bash -c &quot;<strong>$(</strong>curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh<strong>)</strong>&quot;</pre><p>After <a href="https://brew.sh/#install">installing Homebrew</a>, run the following command:</p><pre>brew install python</pre><p>After the installation, check to see whether your version of Python is compatible with Symbl.ai’s installation requirements:</p><pre>python --version</pre><p>If the version is higher than Python 2.7+ or Python 3.4+, then you’re all set to download Symbl.ai’s Python SDK.</p><h4>Installing Symbl.ai’s Python SDK</h4><p>Now that Python is installed, the next step is to install Symbl.ai’s Python SDK. To install Symbl.ai’s Python SDK, you install pip in the following way:</p><pre>pip install --upgrade symbl</pre><p>In a similar way, you install the same:</p><pre>python -m pip install --upgrade symbl</pre><h4>Configuration</h4><p>In a testing environment like the one you create to transform your conversation into a time series graph, you run credentials in-line. Since you quickly test the current code, you can utilize the credentials variable to pass your appId and appSecret as a part of the code itself. However, you must add the credentials variable every time make a new API call.</p><pre>import symbl</pre><pre>local_path = r&#39;c:/Users/john/Downloads/business_meeting.mp3&#39;</pre><pre># Process audio file</pre><pre>conversation_object = symbl.Audio.process_file(<br>file_path=local_path<br>credentials={app_id: &lt;app_id&gt;, app_secret: &lt;app_secret&gt;},  </pre><pre>#This is optional if you didn’t setup the symbl.conf file in your home directory. <br>)</pre><h4>Using the Python SDK</h4><p>To start the process of hacking your conversations with Symbl.ai’s Python SDK you import the Symbl SDK.</p><pre>import symbl</pre><p>The next step is to configure a payload in much the same way that you would configure a payload for an ordinary HTTP request in any one of your favorite programming languages. Here is a payload.</p><pre>payload = {</pre><pre>&#39;url&#39;:&#39;https://symbltestdata.s3.us-east-2.amazonaws.com/sample_audio_file.wav&#39;,</pre><pre>}</pre><p>After configuring the payload, create a dictionary for storing credentials in the following way:</p><pre>credentials_dict = {&#39;app_id&#39;: &#39;&lt;app_id&gt;&#39;, &#39;app_secret&#39;: &#39;&lt;app_secret&gt;&#39;}</pre><p>Last but not least create a conversation object. After the conversation object is created, the next step is to pipe the response selectively into the data you want to visualize in particular. The conversation object is a call to Symbl.ai’s Async API for processing audio through a URL.</p><pre>conversation = symbl.Audio.process_url(https://medium.com/payload=payload,%20credentials=credentials_dict)</pre><h4>Making a Call to the Conversation API’s Message API</h4><p>To fetch the sentiments on the messages from the conversation, you make a call to the Conversation API’s Message API with a parameter. Below is the code.</p><pre>response = conversation.get_messages(parameters={&#39;sentiment&#39;: True})</pre><p>After fetching the sentiments on the messages from the conversation, you create two empty arrays. The first one is timestamps, where Symbl.ai’s data science algorithms prepares the data for a clocked index; the second one is polarities where Symbl.ai’s data science algorithms evaluates the sentiments on the words in the message to return a score.</p><pre>timestamps, polarities = [], []</pre><p>Since your goal is to create a human readable interpretation of a timeseries analysis of sentiments on messages, you create two arrays, the first corresponding to the y-axis, the second to the x-axis. After creating these arrays, you save these arrays.</p><h3>Pandas</h3><p>The next step in the process is to create DataFrames out of your arrays of data (i.e., timestamps and polarities) with Python’s Pandas library.</p><p>The first step to creating DataFrames from Python’s Pandas library is import the library.</p><pre>import pandas as pd</pre><p>After importing the library, the next step is to set the DataFrame’s data with the values from the two arrays. To do so, declare the following:</p><pre>df = pd.DataFrame({&quot;timestamps&quot;: timestamps,&quot;polarities&quot;: polarities})</pre><h3>Matplotlib</h3><p>After pitching your arrays of data in Pandas’ DataFrames, your next step is to create graphs of the DataFrames with Python’s Matplotlib library.</p><p>The first step is to import the Matplotlib. To do so, declare the following:</p><pre>import matplotlib as plt</pre><p>The next step is to plot the DataFrame by setting up the x and y axes of the graph.</p><pre>df.plot(x=&quot;timestamps&quot;, y=&quot;polarities&quot;)</pre><h3>Run the Code</h3><p>If you successfully integrated your Python code snippets into your code editor, then your code editor displays a graph mapping the timestamps to the y-axis, the sentiments to the x-axis. Below is a screenshot of the finished product.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/858/1*TuAftowLhp6fnlWial4lTg.png" /></figure><p>The graph reads much more easily than the sentiment’s polarity scores. Apart from attempting to infer whether a polarity score is up or down, your polarity scores are mapped to their respective timestamp. The respective timestamp is mapped to the polarity scores. In that way the rise and fall of polarities is much easier ‘to see’ than merely crunching numbers. It is a readily understand, human readable, colorful visualization.</p><h4>What’s Next</h4><p>In addition to adding bells and whistles to your graphs like labels, you may consider how Symbl.ai’s Python SDK provides access to many of Symbl.ai’s APIs. In particular, you can enable Symbl.ai’s Python SDK on the real-time Telephony API (i.e., <a href="https://docs.symbl.ai/docs/python-sdk/python-sdk-telephony-api">Telephony API (in Real-time</a>) or any one of the Async APIs for voice, video, or messaging. A complete list is here:</p><ul><li><a href="https://docs.symbl.ai/docs/python-sdk/async-api">Async Text API</a></li><li><a href="https://docs.symbl.ai/docs/python-sdk/async-audio">Async Audio (File) API</a></li><li><a href="https://docs.symbl.ai/docs/python-sdk/async-audio#async-audio-url-api">Async Audio (URL) API</a></li><li><a href="https://docs.symbl.ai/docs/python-sdk/async-video">Async Video (File) API</a></li><li><a href="https://docs.symbl.ai/docs/python-sdk/async-video#async-video-url-api">Async Video (URL) API</a></li></ul><p>In addition, Symbl.ai’s Python SDK contains links to enable Symbl.ai on its Telephony APIs with Python special methods. The methods for dialing into a call, work on the Session Initiation Protocol (SIP). With Symbl.ai’s Python SDK dialed into a call, your in a position to expand the experiences around calls in <a href="https://docs.symbl.ai/docs/python-sdk/python-sdk-telephony-sips/"><em>real-time</em></a><em>. </em>After connecting to a SIP call in real-time, you subscribe to Symbl.ai’s events such as events for contextual insights like <a href="https://docs.symbl.ai/docs/python-sdk/python-sdk-telephony-sips/#subscribe-to-events">follow-ups, questions, or action-items</a>, or you create a request to deliver <a href="https://docs.symbl.ai/docs/python-sdk/python-sdk-telephony-sips/#receive-insights-on-email">a post-meeting summary directly to your inbox</a>.</p><h4>Community</h4><p><a href="https://symbl.ai/?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Symbl.ai</a>’s invites developers to reach out to us via email at <a href="https://mailto:developer@symbl.ai/">developer@symbl.ai</a>, join our <a href="https://join.slack.com/t/symbldotai/shared_invite/zt-4sic2s11-D3x496pll8UHSJ89cm78CA?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Slack</a> channels, participate in our <a href="https://developer.symbl.ai/hackathon?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">hackathons</a>, fork our <a href="https://www.postman.com/symbldotai/workspace/symbl-ai/overview?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Postman public workspace</a>, or git clone our repos at <a href="https://github.com/symblai?utm_source=dev.to&amp;utm_medium=referral&amp;utm_campaign=devrel">Symbl.ai&#39;s GitHub</a>.</p><p><em>More content at </em><a href="http://plainenglish.io/"><strong><em>plainenglish.io</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=74752c1a1c3f" width="1" height="1" alt=""><hr><p><a href="https://python.plainenglish.io/timeseries-analyses-of-calls-with-symbl-ais-python-sdk-pandas-matplotlib-74752c1a1c3f">Timeseries Analysis of Calls with Symbl.ai’s Python SDK, Pandas, &amp; Matplotlib</a> was originally published in <a href="https://python.plainenglish.io/">Python in Plain English</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Real-Time Sentiment Analysis with JavaScript and Symbl.ai]]></title>
            <link>https://javascript.plainenglish.io/real-time-sentiment-analysis-api-in-javascript-with-symbl-ai-9e39d50f0654?source=rss-e88b1f5b4048------2</link>
            <guid isPermaLink="false">https://medium.com/p/9e39d50f0654</guid>
            <category><![CDATA[websocket]]></category>
            <category><![CDATA[sentiment-analysis]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Eric Giannini]]></dc:creator>
            <pubDate>Mon, 22 Mar 2021 23:04:46 GMT</pubDate>
            <atom:updated>2021-03-23T17:25:29.352Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TNCEr7FNrQaaAG9DhzMt6w.png" /></figure><p>Symbl.ai is non-assumptive, non-invasive, fully extensible, and has a user-friendly <a href="https://docs.symbl.ai/docs/conversation-api/concepts/sentiment">API for sentiment analysis</a> that provides insights into the polarity of messages in real-time. Let’s look at what this all means.</p><h4>1. Non-assumptive</h4><p>The API is non-assumptive in that results for polarity are not relayed as a particular emotion but as a value w.r.t. negativity or positivity. It doesn’t assume an emotion.</p><h4>2. Non-invasive</h4><p>The API is non-invasive, since the result of the analysis is from the completed message, of which a conversation is composed, rather than a voice, a highly personal, non-revocable biometric aspect of human identity.</p><h4>3. Fully extensible</h4><p>The API is extensible in that the analysis, which may be as to the conversation itself, its speakers, or their own individual or aggregate messages, is fully programmable. You as a developer decide how create statistics or data around the values derived from sentiments anytime anywhere.</p><h4>4. User-friendly API</h4><p>Users, whose aver quantification do not surrender of their unique, individual ‘credentials’, may have no fear any aspect of Symbl.ai’s sentiment analysis, making the API extremely friendly on the user end. It is not a tone analyzer, for instance.</p><h3>WebSockets for Symbl.ai</h3><p>WebSockets are a computer protocol for communications as a vast improvement over the request/response model of HTTP. They provide full-duplex channels over a single Transmission Control Protocol (TCP) connection. WebSockets facilitate communications between clients or serves in real-time without the connection suffering from racy, high-latency, and bandwidth-intensive exchange under HTTP. Specified as ws or wss, unencrypted or encrypted, a WebSocket endpoint is a persistent bi-directional channel of communication without any overhead from HTTP residuals such as headers, cookies or artifacts. Here is Symbl.ai’s API for WebSockets:</p><pre>wss://api.symbl.ai/v1/realtime/</pre><h3>Symbl.ai’s JavaScript WebSocket’s API</h3><p>In the following blog you will enable Symbl.ai’s JavaScript WebSocket’s API to transcribe live in your browser. To enable live transcription with Symbl.ai’s JavaScript WebSocket’s API in the browser, you: 1) set up your account, 2) configure the WebSocket’s endpoint, 3) run the code in the browser, 4) transcribe live. After setting up the live transcription, you implement Symbl.ai’s non-assumptive, non-invasive, fully extensible, user-friendly <a href="https://docs.symbl.ai/docs/conversation-api/concepts/sentiment">API for sentiment analysis</a>.</p><h3>Set up</h3><p>Register for an account at <a href="https://platform.symbl.ai/">Symbl</a> (i.e., <a href="https://platform.symbl.ai/">https://platform.symbl.ai/</a>). Grab both your appId and your appSecret. With both of those you should authenticate either with a cURL <a href="https://www.mit.edu/afs.new/sipb/user/ssen/src/curl-7.11.1/docs/curl.html">command</a> or with Postman so that you receive your x-api-key. Here is an example with cURL:</p><pre>curl -k -X POST &quot;<a href="https://api.symbl.ai/oauth2/token:generate">https://api.symbl.ai/oauth2/token:generate</a>&quot; \<br>     -H &quot;accept: application/json&quot; \<br>     -H &quot;Content-Type: application/json&quot; \<br>     -d &quot;{ \&quot;type\&quot;: \&quot;application\&quot;, \&quot;appId\&quot;: \&quot;&lt;appId&gt;\&quot;, \&quot;appSecret\&quot;: \&quot;&lt;appSecret&gt;\&quot;}&quot;</pre><p>Ideally a token server would handle authentication (with code that makes RESTful API call for generating token) so that neither the appSecret nor the appId were ever exposed. However, cURL sets you up immediately anyway. With thex-api-key handy you are now ready to establish a WebSocket endpoint for performing live transcription.</p><h3>WebSocket’s Endpoint</h3><p>To enable the WebSocket, you configure two values as query parameters that are fed directly into the WebSocket API’s endpoint. In turn you feed the WebSocket API’s endpoint <em>directly</em> into JavaScript’s own software for enabling real-time conversations.</p><p>Here are the first two values:</p><pre>const uniqueMeetingId = btoa(&#39;EMAIL@ADDRESS.COM&#39;);<br>const accessToken = &#39;&#39;;</pre><p>With these two values for the WebSocket’s API endpoint set, you feed these directly into the WebSocket API’s endpoint:</p><pre>const symblEndpoint = `wss://api.symbl.ai/v1/realtime/insights/${uniqueMeetingId}?access_token=${accessToken}</pre><p>If you want to test your WebSocket before any further integration, you load that endpoint with the data for uniqueMeetingId together with the accessToken into <a href="https://hoppscotch.io/realtime/">Hoppscotch.io</a>, a free, fast, sleek API request builder.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6nKj-pX0-dgjvHUT.png" /></figure><h3>Creating an Instance of JavaScript’s native WebSocket API</h3><p>The next step is to create an instance of JavaScript’s native WebSocket API:</p><pre>const ws = new WebSocket(symblEndpoint);</pre><p>On that instance, you call methods specific to handling live transcription.</p><pre>// Fired when a message is received from the WebSocket server<br>ws.onmessage = (event) =&gt; {<br>  console.log(event);<br>};</pre><pre>// Fired when the WebSocket closes unexpectedly due to an error or lost connetion<br>ws.onerror  = (err) =&gt; {<br>  console.error(err);<br>};</pre><pre>// Fired when the WebSocket connection has been closed<br>ws.onclose = (event) =&gt; {<br>  console.info(&#39;Connection to websocket closed&#39;);<br>};</pre><pre>// Fired when the connection succeeds.<br>ws.onopen = (event) =&gt; {<br>  ws.send(JSON.stringify({<br>    type: &#39;start_request&#39;,<br>    meetingTitle: &#39;Websockets How-to&#39;, // Conversation name<br>    insightTypes: [&#39;question&#39;, &#39;action_item&#39;], // Will enable insight generation<br>    config: {<br>      confidenceThreshold: 0.5,<br>      languageCode: &#39;en-US&#39;,<br>      speechRecognition: {<br>        encoding: &#39;LINEAR16&#39;,<br>        sampleRateHertz: 44100,<br>      }<br>    },<br>    speaker: {<br>      userId: &#39;example@symbl.ai&#39;,<br>      name: &#39;Example Sample&#39;,<br>    }<br>  }));<br>};</pre><p>To set up the stream for accessing a user’s media devices such as their laptop’s microphone, program the brower’s navigator accordingly:</p><pre>const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });</pre><p>The code above asks the user for permission to access his or her device through a pop-up. In mobile applications permission for access to devices is hardcoded into the controlling directory of an application binary such as in the manifest for Android of the property list for iOS. JavaScript doesn’t compile so there is no need to ask for permission so that you can ask for permission!</p><p>To set up the stream to handle events, program the following:</p><pre>const handleSuccess = (stream) =&gt; {<br>  const AudioContext = window.AudioContext;<br>  const context = new AudioContext();<br>  const source = context.createMediaStreamSource(stream);<br>  const processor = context.createScriptProcessor(1024, 1, 1);<br>  const gainNode = context.createGain();<br>  source.connect(gainNode);<br>  gainNode.connect(processor);<br>  processor.connect(context.destination);<br>  processor.onaudioprocess = (e) =&gt; {<br>    // convert to 16-bit payload<br>    const inputData = e.inputBuffer.getChannelData(0) || new Float32Array(this.bufferSize);<br>    const targetBuffer = new Int16Array(inputData.length);<br>    for (let index = inputData.length; index &gt; 0; index--) {<br>        targetBuffer[index] = 32767 * Math.min(1, inputData[index]);<br>    }<br>    // Send to websocket<br>    if (ws.readyState === WebSocket.OPEN) {<br>      ws.send(targetBuffer.buffer);<br>    }<br>  };<br>};</pre><h4>Trying Out the the Code</h4><p>It might be a great idea to try out your WebSocket’s connection right now. After running your code directly in the browser, then you see the console logging events in real-time as you speak.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*RCaQ1uJwV05FLMPU.gif" /></figure><h4>Stopping the Conversation</h4><p>To stop your live transcription, you close your browsers or you send a stop_request directly to the server from within the browser’s console.</p><pre>ws.send(JSON.stringify({<br>  &quot;type&quot;: &quot;stop_request&quot;<br>}));</pre><h4>Real-Time Sentiment Analysis</h4><p>Within the ws method for onmessage program the API endpoint to capture the polarity of Symbl.ai’s conversation’s messages, logging the value to through the console.</p><p>The first step is to capture the conversationId as a constant. You capture the conversationId through the parsed data that comes from the WebSocket’s API’s onmessage method.</p><pre>const conversationId = data.message.data.conversationId;</pre><p>The second step is to create the request. There are multiple libraries for handling HTTP requests so feel free to refactor theXMLHttpRequest here.</p><pre>const request = new XMLHttpRequest();</pre><p>The third step is to configure the request, setting the response’s type to text.</p><pre>request.responseType = &quot;text&quot;;</pre><p>The fourth step is to configure the endpoint:</p><pre>const sentimentEndpoint = `<a href="https://api.symbl.ai/v1/conversations/$%7BconversationId%7D/messages?sentiment=true">https://api.symbl.ai/v1/conversations/${conversationId}/messages?sentiment=true</a>`;</pre><p>The fifth step is to set the request.</p><pre>request.open(&quot;GET&quot;, sentimentEndpoint)</pre><p>The sixth step is to set the request’s headers.</p><pre>request.setRequestHeader(&#39;Authorization&#39;, `Bearer ${accessToken}`);<br>request.setRequestHeader(&#39;Content-Type&#39;, &#39;application/json&#39;);</pre><p>The seventh step is to create a function to log the sentiment’s into the console.</p><pre>request.onreadystatechange=(e)=&gt; {<br>      console.log(request.responseText)<br>    }</pre><p>The last step is send the request.</p><pre>request.send()</pre><p>Here is the fully programmable sentiment analysis API implemented in your ws method for onmessage in your WebSocket:</p><pre>// Fired when a message is received from the WebSocket server<br>ws.onmessage = (event) =&gt; {<br>  // You can find the conversationId in event.message.data.conversationId;<br>  const data = JSON.parse(event.data);<br>  if (data.type === &#39;message&#39; &amp;&amp; data.message.hasOwnProperty(&#39;data&#39;)) {<br>    console.log(&#39;conversationId&#39;, data.message.data.conversationId);<br>    const conversationId = data.message.data.conversationId;<br>    console.log(&#39;onmessage event&#39;, event);<br>    // You can log sentiments on messages from data.message.data.conversationId <br>    const request = new XMLHttpRequest();<br>    request.responseType = &quot;text&quot;;<br>    const sentimentEndpoint = `<a href="https://api.symbl.ai/v1/conversations/$%7BconversationId%7D/messages?sentiment=true">https://api.symbl.ai/v1/conversations/${conversationId}/messages?sentiment=true</a>`;<br>    request.open(&quot;GET&quot;, sentimentEndpoint)<br>    request.setRequestHeader(&#39;Authorization&#39;, `Bearer ${accessToken}`);<br>    request.setRequestHeader(&#39;Content-Type&#39;, &#39;application/json&#39;);<br>    request.onreadystatechange=(e)=&gt; {<br>      console.log(request.responseText)<br>    }<br>    request.send()<br>  }<br>};</pre><p>If your console logged sentiments upon a change in the state of events, then your code delivered real-time sentiment analysis in API!</p><h3>What’s Next?</h3><p>A Symbl.ai conversation configured to relay messages over a real-time websocket with its sentiment analysis API is neither the beginning nor the end of conversation data.</p><p>If you look closely at the data from your live WebSocket connection, the conversationId may be applied to new API calls to access to more AI insights for action items, topics, or analytics. Within a fully programmable Symbl.ai conversation you receive not just sentiment analysis but access to an analytics API that provides access to the following conversation data:</p><ol><li>Speaker Ratio — Speaker’s talk and listen ratio and time.</li><li>Talk Time — Overall duration of the conversation.</li><li>Silence — Overall duration of silence.</li><li>Pace — Words per minute spoken in the conversation.</li><li>Overlap — When more than 1 speaker are speaking the same time, then conversation has overlap.</li></ol><p>With Speaker Ratio, Talk Time, Silence, Pace, or Overlap, you have the ability to create application logic or notifications that augment conversational experiences to a step far beyond merely transcribing a speaker or speakers in a real-time speech-to-text application or automating speech recognition through no more than a single a API endpoint.</p><p>Since real-time sentiment analysis is based on messages rather than tonality, Symbl.ai’s API for topics, which aggregates the most salient subjects of a conversation in a set of word groups called ‘topics’, are fully programmable as data on messages not unlike the data on messages for speaker events.</p><p>Analytics into data for sentiment or speaker events in general is but a part of Symbl.ai’s extensible, fully programmable, developer platform for conversations. Symbl.ai’s real-time sentiment analysis or analytics APIs operate across protocols, channels, companies freely for developers to create freely augmented conversation experiences.</p><h3>Community</h3><p>Stuck? Free feel to ask us any questions on our <a href="https://join.slack.com/t/symbldotai/shared_invite/zt-4sic2s11-D3x496pll8UHSJ89cm78CA">Slack Channel</a> or send us an email at <a href="/service/mailto:devrelations@symbl.ai">devrelations@symbl.ai</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9e39d50f0654" width="1" height="1" alt=""><hr><p><a href="https://javascript.plainenglish.io/real-time-sentiment-analysis-api-in-javascript-with-symbl-ai-9e39d50f0654">Real-Time Sentiment Analysis with JavaScript and Symbl.ai</a> was originally published in <a href="https://javascript.plainenglish.io/">JavaScript in Plain English</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>