<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hyperskill</title>
    <description>The latest articles on DEV Community by Hyperskill (@hyperskill).</description>
    <link>https://dev.to/hyperskill</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F6815%2F12d954cb-f410-4641-b2c6-52e8ada83ce9.png</url>
      <title>DEV Community: Hyperskill</title>
      <link>https://dev.to/hyperskill</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hyperskill"/>
    <language>en</language>
    <item>
      <title>Why Frontend Development is a Great Way to Start Programming in 2024/2025</title>
      <dc:creator>nastuxacool</dc:creator>
      <pubDate>Thu, 14 Nov 2024 06:11:26 +0000</pubDate>
      <link>https://dev.to/hyperskill/why-frontend-development-is-a-great-way-to-start-programming-in-20242025-2mep</link>
      <guid>https://dev.to/hyperskill/why-frontend-development-is-a-great-way-to-start-programming-in-20242025-2mep</guid>
      <description>&lt;p&gt;As technology continues to grow, front-end development has become one of the easiest ways to start learning programming. Whether you’re new to coding or thinking about a career change, front-end development offers a highly visual and rewarding entry point with many possible career paths. Here’s why starting with front-end development could be your perfect choice.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Instant Visual Results Make Learning Fun
&lt;/h4&gt;

&lt;p&gt;One of the best parts of front-end development is seeing your results right away. As you code, you see your work appear on a webpage instantly, which makes learning more engaging and satisfying. Unlike back-end development, where much of the work happens behind the scenes, front-end development lets you create the parts of a website that users actually see and interact with. This instant feedback helps you learn quickly, make changes as you go, and feel a sense of accomplishment as you build real web interfaces.&lt;br&gt;
Take a look what the combination of HTML, CSS and JavaScript has to offer&lt;br&gt;
&lt;a href="https://hyperskill.org/projects/230/stages/2415/implement" rel="noopener noreferrer"&gt;https://hyperskill.org/projects/230/stages/2415/implement&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  2. High Demand for JavaScript Skills Across Many Jobs
&lt;/h4&gt;

&lt;p&gt;Front-end development uses HTML, CSS, and especially JavaScript—a language that powers interactivity on the web and is highly valued in the tech industry. Learning JavaScript can open doors to many roles, from web and mobile app development to jobs in other tech fields. JavaScript is one of the most popular programming languages worldwide, so learning it gives you a foundation that will stay relevant for a long time.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. A Foundation for Diverse Career Paths
&lt;/h4&gt;

&lt;p&gt;Front-end development doesn’t limit you to just one type of job—it gives you a strong base to build many different skills. As you learn HTML, CSS, and JavaScript, you can start exploring other areas like back-end development, mobile app development, or even game creation. You can even use JavaScript with tools like Node.js and Express to learn back-end programming, making it easier to become a full-stack developer if you choose. With tools like Ionic and React Native, developers can create apps that work on iOS, Android, and desktops—all without having to rewrite code for each platform. Learning front-end skills gives you the freedom to try many paths in the tech world.&lt;br&gt;
If you still don’t believe us, see for yourself: here’s a recent job offer by Telegram: Javascript + SQL Developer. No React, no Figma, just JS and databases! &lt;a href="https://jobs.ton.org/companies/wallet-2/jobs/40637883-sql-javascript-developer#content" rel="noopener noreferrer"&gt;https://jobs.ton.org/companies/wallet-2/jobs/40637883-sql-javascript-developer#content&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  4. Access to a Helpful and Active Community
&lt;/h4&gt;

&lt;p&gt;Front-end development has one of the most welcoming and helpful communities in tech. From online forums and coding events (e.g. CSS Days) to documentation, there is a lot of support available to help you learn. Tutorials, open-source libraries, and websites dedicated to front-end development make it easier for beginners to find solutions to common problems. If you like blogs, you can always read “Overreacted” by Dan Abramov (&lt;a href="https://overreacted.io/" rel="noopener noreferrer"&gt;https://overreacted.io/&lt;/a&gt;). You prefer to listen rather than to read? No worries, Google team got you covered: here’s a CSS podcast: &lt;a href="https://thecsspodcast.libsyn.com/" rel="noopener noreferrer"&gt;https://thecsspodcast.libsyn.com/&lt;/a&gt; &lt;br&gt;
This active community provides guidance and encouragement as you grow.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Work Flexibly and Remotely
&lt;/h4&gt;

&lt;p&gt;If flexibility and remote work are important to you, front-end development is a great choice. Many front-end and full-stack jobs are remote-friendly, and tech companies, startups, and freelance work all often welcome front-end developers who work from home. This flexibility lets you work from anywhere, whether in a home office or while traveling as a digital nomad. Front-end skills are very adaptable, so you can build a career that fits your lifestyle.&lt;/p&gt;

&lt;h4&gt;
  
  
  6. A Mix of Creativity and Problem-Solving
&lt;/h4&gt;

&lt;p&gt;Front-end development is ideal if you enjoy combining creativity with logical problem-solving. In this field, you can design visually appealing websites while making sure they work well for users. Front-end development taps into both artistic and technical abilities, letting you create and innovate in the digital space.&lt;br&gt;
Just take a look at the stunning creations of Julia Miocene: &lt;a href="https://codepen.io/miocene" rel="noopener noreferrer"&gt;https://codepen.io/miocene&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  7. Tasks for Every Skill Level
&lt;/h4&gt;

&lt;p&gt;Front-end development includes tasks for everyone, from beginners to experts. Beginners might start by creating basic user interfaces or simple web pages, while experienced developers can work on complex projects like improving website performance. This range of tasks allows you to find projects at your skill level while leaving room to grow. The field values contributions at all levels, so you can continue advancing within front-end development.&lt;/p&gt;

&lt;h4&gt;
  
  
  8. A Fast-Changing Field with New Trends
&lt;/h4&gt;

&lt;p&gt;Front-end development is a dynamic field with new tools, libraries, and trends appearing frequently. This keeps the work interesting but also means that staying up to date is important. Recent trends include new frameworks (like SolidJS or Svelte), CSS improvements for design, and better tools for faster websites. A solid base in front-end development makes it easier to keep up with these changes. With resources like Hyperskill, you can stay on top of new trends and make learning part of your regular routine.&lt;/p&gt;

&lt;h4&gt;
  
  
  Common Beginner Challenges
&lt;/h4&gt;

&lt;p&gt;While front-end development has many benefits, beginners should be ready for a few common challenges. For example, learning how to make websites look good on any screen size (called “responsive design”) can be tricky at first. Debugging JavaScript errors and handling differences between browsers are also skills that take time to learn. &lt;br&gt;
Fortunately, the active front-end community and available resources make it easier to overcome these challenges and build confidence. One resource that we highly recommend is our 6-month mentor-led learning program! See for yourself: &lt;a href="https://go.hyperskill.org/frontend-developer" rel="noopener noreferrer"&gt;https://go.hyperskill.org/frontend-developer&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;Front-end development is an accessible and flexible way to start programming. With immediate visual feedback, high demand for skills, and many career options, it’s a great choice for anyone looking to enter tech. Whether you want to become a web developer or explore related fields, front-end skills give you a solid foundation with many possibilities. You can succeed in this fast-changing field with commitment, enjoying both the challenges and rewards. If you’re ready to start your journey in programming, front-end development could be your first step toward a fulfilling, flexible, and creative career.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Preparing for Your Technical Interview: A Developer's Guide</title>
      <dc:creator>Victoria Lisitsyna</dc:creator>
      <pubDate>Thu, 11 May 2023 13:13:30 +0000</pubDate>
      <link>https://dev.to/hyperskill/preparing-for-your-technical-interview-a-developers-guide-1p0g</link>
      <guid>https://dev.to/hyperskill/preparing-for-your-technical-interview-a-developers-guide-1p0g</guid>
      <description>&lt;p&gt;The interview is an important step to getting the job. The course of the interview determines whether they will be hired or not. It also defines the final salary and grade. Even if an interviewee knows a programming language well, an interview is always stressful, and it can be an obstacle to put one's best foot forward.&lt;/p&gt;

&lt;p&gt;Considering that to get a good job, you need to prepare for your interview carefully. In this article, I want to share a few tips to help developers prepare for technical interviews, and tell how &lt;a href="https://hyperskill.org/?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;Hyperskill&lt;/a&gt; will be useful for this. These tips helped me to prepare and pass several developer interviews.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're looking for a way to learn new skills and advance your career, Hyperskill's project-based learning platform offers a personalized curriculum and a variety of tracks to help you achieve your goals.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Six tips for preparing for an interview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tip 1: Get details about the upcoming interview
&lt;/h3&gt;

&lt;p&gt;If you are interested in joining a particular company or team, you can get information before the interview about what to expect. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;google other people's feedback about the interview process and the questions they were asked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;find a few articles about the hiring process in this company.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;look at the list of skills in the job description (in LinkedIn, for example). Most likely, the interviewer will ask you skill-related questions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tip 2: Structure your previous experience
&lt;/h3&gt;

&lt;p&gt;Structure your previous work experience or pet projects. Recall difficult problems that you were able to solve. During the interview, you may be asked to talk about the projects where you have been involved, the challenges you have encountered, and the topics you have learned.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you are preparing for your first interview and don't have any work experience, it is helpful to publish several training pet projects on GitHub.&lt;/em&gt; As a project-based educational platform, Hyperskill engages you in solving projects related to different domain areas so that you could publish the results. And what's more, some of the projects are based on real test assignments. For example, if you are a Java developer, pay attention to the following projects: &lt;a href="https://hyperskill.org/projects/49?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;Java Online chat&lt;/a&gt;, &lt;a href="https://hyperskill.org/projects/52?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;File Server&lt;/a&gt;, &lt;a href="https://hyperskill.org/projects/171?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;SQLite Viewer&lt;/a&gt;. And here are the Python projects based on real test assignments: &lt;a href="https://hyperskill.org/projects/145?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;Web Scraper&lt;/a&gt;, &lt;a href="https://hyperskill.org/projects/105?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;To-Do List&lt;/a&gt;, &lt;a href="https://hyperskill.org/projects/114?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;Regex Engine&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip 3: Find and answer the top interview questions
&lt;/h3&gt;

&lt;p&gt;To prepare for a job interview, google the top questions on a programming language, a framework, or a tool you're interested in and find the answers.&lt;br&gt;
For example, there is &lt;a href="https://www.interviewbit.com/python-interview-questions/#freshers" rel="noopener noreferrer"&gt;a list of top Python interview questions&lt;/a&gt;. You can easily find similar question lists for other languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip 4: Fill the knowledge gaps in your programming language and tools
&lt;/h3&gt;

&lt;p&gt;Revise the programming language concepts. Focus on your gaps. Interviewers often ask questions to check your competencies and understand whether you are following trends in your domain.&lt;br&gt;
Take note of &lt;a href="https://hyperskill.org/tracks?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;the Hyperskill tracks&lt;/a&gt;. Hyperskill covers all popular programming languages and more. Tracks combine theory with practice, which helps you better understand and remember information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuhxpj75ic9zj51lh09r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuhxpj75ic9zj51lh09r.png" alt="Tracks in Hyperskill"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip 5: Learn basic algorithms and data structures
&lt;/h3&gt;

&lt;p&gt;Interviewers often ask questions about computer science fundamentals, basic algorithms, and structures. They include specifics on sorting and search algorithms, arrays, lists, stacks and queues, hash maps, trees, and others. Before the interview, it is worth reviewing these concepts and solving some exercises using them. You can repeat them by solving the &lt;a href="https://hyperskill.org/tracks/54?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;Practicing Algorithms with Python&lt;/a&gt; track on Hyperskill.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip 6: Prepare for live coding exercises
&lt;/h3&gt;

&lt;p&gt;If you are supposed to solve a live coding exercise during your interview with time constraints, practice it beforehand. There is an approach that makes it much easier to deal with coding exercises:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understand the problem statement, and try to rephrase it in your own words.&lt;/li&gt;
&lt;li&gt;Make up or take a look at test input-output examples.&lt;/li&gt;
&lt;li&gt;Describe your approach to solving the problem. Demonstrate how it will work on the input-output examples.&lt;/li&gt;
&lt;li&gt;Write your code according to the standards of the programming language.&lt;/li&gt;
&lt;li&gt;Estimate the complexity of an algorithm using &lt;a href="https://hyperskill.org/learn/step/16699?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=interview&amp;amp;utm_term=11.05.2023" rel="noopener noreferrer"&gt;the Big O notation&lt;/a&gt;. Think about how to optimize it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep in mind that interviewers evaluate not only your solutions. They also pay attention to your way of thinking and communicating, your depth of knowledge, and whether or not you can write well-readable code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Good luck with your interviews, and have interesting projects!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>technology</category>
      <category>career</category>
      <category>interview</category>
    </item>
    <item>
      <title>Testing and Benchmarking in Go</title>
      <dc:creator>Hermann Rösch</dc:creator>
      <pubDate>Thu, 27 Apr 2023 11:53:22 +0000</pubDate>
      <link>https://dev.to/hyperskill/testing-and-benchmarking-in-go-34en</link>
      <guid>https://dev.to/hyperskill/testing-and-benchmarking-in-go-34en</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Testing is a crucial aspect of software development that helps ensure the quality and reliability of your code. In Go, testing is built into the language through the &lt;a href="https://pkg.go.dev/testing#pkg-overview" rel="noopener noreferrer"&gt;&lt;code&gt;testing&lt;/code&gt;&lt;/a&gt; package, which makes it easy to write and execute tests for your programs.&lt;/p&gt;

&lt;p&gt;Tests are essential because they:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Validate the correctness of your code, ensuring that it behaves as expected under various conditions.&lt;/li&gt;
&lt;li&gt;Provide a safety net for future modifications, allowing you to make changes with confidence that you won't inadvertently break existing functionality.&lt;/li&gt;
&lt;li&gt;Act as documentation complement for other developers, demonstrating how the code is supposed to work and serving as a guide for using and modifying it.&lt;/li&gt;
&lt;li&gt;Facilitate better code design, as writing tests often encourages developers to create modular and reusable components.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Go developers, incorporating tests into the development process can lead to more reliable and maintainable code, ultimately improving the overall quality of your applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hyperskill.org/learn/step/20861?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=testinggo&amp;amp;utm_term=27.04.2023" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A-s51XTBhWBY0nQPCKvvKwg.png" alt="Testing and benchmarking in Go"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, you'll learn how to write and run &lt;strong&gt;table-driven tests&lt;/strong&gt; and &lt;strong&gt;benchmarks&lt;/strong&gt; in Go. If you're new to testing or feel uncertain about the topic, read the &lt;a href="https://hyperskill.org/learn/step/20861?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=testinggo&amp;amp;utm_term=27.04.2023" rel="noopener noreferrer"&gt;&lt;strong&gt;Introduction to Testing in Go&lt;/strong&gt;&lt;/a&gt; topic on &lt;a href="https://hyperskill.org/tracks?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=testinggo&amp;amp;utm_term=27.04.2023" rel="noopener noreferrer"&gt;&lt;strong&gt;Hyperskill&lt;/strong&gt;&lt;/a&gt;, which covers the basics of tests in Go.&lt;/p&gt;




&lt;h3&gt;
  
  
  Table-Driven Tests 📋🧪
&lt;/h3&gt;

&lt;p&gt;Table-driven tests are a typical pattern in Go for testing multiple input and output cases using a single test function. Instead of writing separate test functions for each case, you can define a table (a slice of structs) that includes the input values, expected output, and an optional description for each test case. You can then loop through the table and execute the test function for each case.&lt;/p&gt;

&lt;p&gt;Compared to individual unit tests, table-driven tests offer several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They reduce code duplication and make your test suite more maintainable.&lt;/li&gt;
&lt;li&gt;They make it easy to add new test cases, as you simply need to extend the table.&lt;/li&gt;
&lt;li&gt;They provide a clear overview of the various input-output combinations being tested.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started! First, create a new Go project named &lt;code&gt;example&lt;/code&gt; and initialize Go modules via the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;example &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;example
go mod init example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a new file &lt;em&gt;main.go&lt;/em&gt; and within it, let's write the code of the &lt;code&gt;DiscountedPrice()&lt;/code&gt; function that calculates the discounted price of a product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// main.go&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="c"&gt;// DiscountedPrice calculates the discounted price of a product,&lt;/span&gt;
&lt;span class="c"&gt;// given its original price and discount percentage.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;DiscountedPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discountPercent&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;discountPercent&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;discountPercent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"invalid negative discount percentage: %.2f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;discountPercent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;discountPercent&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"invalid discount percentage greater than 100: %.2f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;discountPercent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;discount&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discountPercent&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to create a new file &lt;em&gt;main_test.go&lt;/em&gt;, and within it, write a table-driven test for the &lt;code&gt;DiscountedPrice()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// main_test.go&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"testing"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestDiscountedPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;testCases&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;price&lt;/span&gt;           &lt;span class="kt"&gt;float64&lt;/span&gt;
        &lt;span class="n"&gt;discountPercent&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;
        &lt;span class="n"&gt;expected&lt;/span&gt;        &lt;span class="kt"&gt;float64&lt;/span&gt;
        &lt;span class="n"&gt;expectError&lt;/span&gt;     &lt;span class="kt"&gt;bool&lt;/span&gt;
        &lt;span class="n"&gt;desc&lt;/span&gt;            &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"no discount"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"50% discount"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"100% discount"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;110.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"discount greater than 100%"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;testCases&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;DiscountedPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discountPercent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectError&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="s"&gt;"DiscountedPrice(%.2f, %.2f) should return an error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discountPercent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectError&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="s"&gt;"DiscountedPrice(%.2f, %.2f) returned an error: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discountPercent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectError&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="s"&gt;"DiscountedPrice(%.2f, %.2f) = %.2f; want %.2f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discountPercent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Running tests 👨‍🔬🖥️👩‍🔬
&lt;/h3&gt;

&lt;p&gt;To run the tests, you can use the &lt;code&gt;go test&lt;/code&gt; command to execute all test functions in the package and report the results. By default, &lt;code&gt;go test&lt;/code&gt; runs all tests for the current package. However, you can also provide a package name, a directory, or a list of packages to test multiple packages simultaneously.&lt;/p&gt;

&lt;p&gt;After executing the &lt;code&gt;go test&lt;/code&gt; command, you should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; go &lt;span class="nb"&gt;test
&lt;/span&gt;PASS
ok      example 0.236s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;PASS&lt;/code&gt; indicates all the tests have passed, &lt;code&gt;ok&lt;/code&gt; confirms that the text execution was successful, &lt;code&gt;example&lt;/code&gt; is the name of the Go module being tested, and &lt;code&gt;0.236s&lt;/code&gt; is the duration of the test execution in seconds.&lt;/p&gt;

&lt;p&gt;Even though all tests passed, how can you be sure there were no untested code paths left? The answer is simple you will need to check the &lt;strong&gt;test coverage&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Running tests with coverage 📄🔍
&lt;/h3&gt;

&lt;p&gt;Test coverage is a metric that measures the proportion of your code that is exercised by your test suite. High test coverage indicates that your tests are comprehensive, while low test coverage suggests that some parts of your code may not be adequately tested. By tracking test coverage, you can identify untested portions of your code and write additional tests to improve the reliability of your application.&lt;/p&gt;

&lt;p&gt;To run the tests with coverage, use the &lt;code&gt;go test -cover&lt;/code&gt; command. It will execute all test functions in the package, report the results, and provide a coverage percentage indicating the proportion of your code exercised by your tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cover&lt;/span&gt;
&lt;span class="n"&gt;PASS&lt;/span&gt;
&lt;span class="n"&gt;coverage&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;85.7&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;statements&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt;      &lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="m"&gt;0.253&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After examining the output, the coverage is only &lt;code&gt;85.7%&lt;/code&gt;, which indicates that one of the code paths wasn't tested. Upon closer inspection, you might notice the absence of a test case for the "negative discount" scenario.&lt;/p&gt;

&lt;p&gt;To improve test coverage, you can add the "negative discount" test case below to the &lt;code&gt;testCases&lt;/code&gt; slice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"negative discount"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;code&gt;go test -cover&lt;/code&gt; once again, and you should get &lt;code&gt;100%&lt;/code&gt; coverage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-cover&lt;/span&gt;
PASS
coverage: 100.0% of statements
ok      example 0.250s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's important to remember that while achieving high test coverage is a good practice, the primary focus should be on writing meaningful tests that cover a wide range of inputs and edge cases rather than just aiming for &lt;code&gt;100%&lt;/code&gt; coverage.&lt;/p&gt;




&lt;h3&gt;
  
  
  Benchmarking 📊
&lt;/h3&gt;

&lt;p&gt;Now that you're familiar with testing let's move on to &lt;strong&gt;benchmarking&lt;/strong&gt;.  Benchmarking is a valuable technique to measure the performance of your code, helping you identify bottlenecks and optimize your functions for better efficiency.&lt;/p&gt;

&lt;p&gt;Benchmarks can be beneficial for developers in Go when comparing the performance of different implementations, optimizing code for specific use cases, or determining the impact of a change in the codebase. &lt;/p&gt;

&lt;p&gt;For instance, suppose you want to compare the efficiency of various approaches to a common problem, like string concatenation, to optimize your code's performance and minimize memory allocations. By benchmarking different methods, you can make more informed decisions about the best way to implement a particular feature or operation in your application.&lt;/p&gt;

&lt;p&gt;Let's write benchmarks to compare the performance of three different string concatenation methods:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using &lt;code&gt;strings.Builder&lt;/code&gt; and its &lt;code&gt;WriteString()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;+=&lt;/code&gt; operator for string concatenation.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;fmt.Sprintf()&lt;/code&gt; for string concatenation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First, create a new file called &lt;em&gt;benchmarks_test.go&lt;/em&gt; and add to it the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// benchmarks_test.go&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkStringBuilderConcatenation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"h"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkStringConcatenation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"h"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkFmtSprintfConcatenation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"h"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running benchmarks and comparing results 🚀📈
&lt;/h3&gt;

&lt;p&gt;You can use the command &lt;code&gt;go test -bench .&lt;/code&gt; to run benchmarks. This command will execute all benchmark functions in your code once. Nonetheless, remember that benchmark outcomes may be prone to variations.&lt;/p&gt;

&lt;p&gt;In order to achieve precise and dependable results, it's crucial to carry out benchmark tests repeatedly and evaluate the results. This process lets you detect discrepancies and better comprehend your code's performance attributes.&lt;/p&gt;

&lt;p&gt;You can run benchmarks multiple times using the &lt;code&gt;-count&lt;/code&gt; flag. Additionally, you can include the &lt;code&gt;-benchmem&lt;/code&gt; flag to gather memory allocation statistics for each benchmark.&lt;/p&gt;

&lt;p&gt;Let's go ahead and run the benchmarks with &lt;code&gt;-count 10&lt;/code&gt; and &lt;code&gt;-count 20&lt;/code&gt; to compare the performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-bench&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-benchmem&lt;/span&gt; &lt;span class="nt"&gt;-count&lt;/span&gt; 10 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 10_runs_bench.txt
go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-bench&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-benchmem&lt;/span&gt; &lt;span class="nt"&gt;-count&lt;/span&gt; 20 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 20_runs_bench.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have the results from two sets of benchmarks with 10 and 20 runs each. To compare these results, you can use &lt;code&gt;benchstat&lt;/code&gt;, a command-line tool that helps analyze and compare benchmark results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;golang.org/x/perf/cmd/benchstat@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing &lt;code&gt;benchstat&lt;/code&gt; run the following command to compare the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; benchstat 10_runs_bench.txt 20_runs_bench.txt           
goos: windows
goarch: amd64
pkg: example
                              │ 10_runs_bench.txt │           20_runs_bench.txt           │
                              │      sec/op       │   sec/op     vs base                  │
StringBuilderConcatenation-12         2.385µ ± 2%   2.315µ ± 1%  &lt;span class="nt"&gt;-2&lt;/span&gt;.96% &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.000 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt;
StringConcatenation-12                171.2µ ± 2%   163.6µ ± 3%  &lt;span class="nt"&gt;-4&lt;/span&gt;.46% &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.000 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt;
FmtSprintfConcatenation-12            241.2µ ± 5%   240.5µ ± 2%       ~ &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.619 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt;
geomean                               46.18µ        44.99µ       &lt;span class="nt"&gt;-2&lt;/span&gt;.58%

                              │ 10_runs_bench.txt │            20_runs_bench.txt             │
                              │       B/op        │     B/op      vs base                    │
StringBuilderConcatenation-12        3.242Ki ± 0%   3.242Ki ± 0%       ~ &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.000 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt; ¹
StringConcatenation-12               517.8Ki ± 0%   517.8Ki ± 0%       ~ &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.000 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt;
FmtSprintfConcatenation-12           533.8Ki ± 0%   533.8Ki ± 0%  +0.00% &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.034 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt;
geomean                              96.42Ki        96.42Ki       +0.00%
¹ all samples are equal

                              │ 10_runs_bench.txt │            20_runs_bench.txt            │
                              │     allocs/op     │  allocs/op   vs base                    │
StringBuilderConcatenation-12          9.000 ± 0%    9.000 ± 0%       ~ &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.000 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt; ¹
StringConcatenation-12                 999.0 ± 0%    999.0 ± 0%       ~ &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.000 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt; ¹
FmtSprintfConcatenation-12            1.998k ± 0%   1.998k ± 0%       ~ &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.000 &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10+20&lt;span class="o"&gt;)&lt;/span&gt; ¹
geomean                                261.9         261.9       +0.00%
¹ all samples are equal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see a table with multiple columns when comparing benchmark results using the &lt;code&gt;benchstat&lt;/code&gt; command. Let's break down each column from left to right:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function name:&lt;/strong&gt; The name of the benchmark function, such as &lt;code&gt;StringBuilderConcatenation-12&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time per operation:&lt;/strong&gt; The average time it took to complete one operation for each benchmark file, represented in seconds or microseconds (e.g., &lt;code&gt;2.385µ ± 2%&lt;/code&gt; for &lt;em&gt;10_runs_bench.txt&lt;/em&gt; and &lt;code&gt;2.315µ ± 1%&lt;/code&gt; for &lt;em&gt;20_runs_bench.txt&lt;/em&gt;). The percentage value represents the standard deviation, which indicates the variability of the execution time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time difference:&lt;/strong&gt; The percentage difference in the average execution time between the two benchmark files (e.g., &lt;code&gt;-2.96%&lt;/code&gt;). The p-value (e.g., &lt;code&gt;p=0.000&lt;/code&gt;) helps determine if the difference is statistically significant. A p-value of &lt;code&gt;0.05&lt;/code&gt; or lower typically indicates statistical significance, and a negative value indicates that the second benchmark file has faster execution times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bytes allocated per operation:&lt;/strong&gt; The average number of bytes allocated per operation for each benchmark file (e.g., &lt;code&gt;3.242Ki ± 0%&lt;/code&gt; for both files). The percentage value represents the standard deviation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory difference:&lt;/strong&gt; The proportionate disparity in the mean memory allocation between the two benchmark files (e.g., &lt;code&gt;~ (p=1.000 n=10+20)&lt;/code&gt;). The p-value aids in establishing the statistical significance of the difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Number of memory allocations per operation:&lt;/strong&gt; The mean number of memory allocations per operation for each benchmark file (e.g., &lt;code&gt;9.000 ± 0%&lt;/code&gt; for both files). The percentage figure denotes the standard deviation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Allocation discrepancy:&lt;/strong&gt; The percentage divergence in the average number of memory allocations between the two benchmark files (e.g., &lt;code&gt;~ (p=1.000 n=10+20)&lt;/code&gt;). The p-value assists in determining the statistical significance of the difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Geomean:&lt;/strong&gt; The &lt;code&gt;geomean&lt;/code&gt; row at the bottom of each table displays the geometric mean of the values for each column, providing an overall summary of the benchmark results.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Finally, based on the benchmark results, we can determine that:&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using a string builder with the &lt;code&gt;WriteString()&lt;/code&gt; method is the best choice for performance and memory efficiency, mainly when dealing with numerous concatenations or resource-limited environments.&lt;/p&gt;

&lt;p&gt;Using string concatenation with the &lt;code&gt;+=&lt;/code&gt; operator and &lt;code&gt;fmt.Sprintf()&lt;/code&gt; is slower and less memory-efficient than using a string builder. They may be suitable for more straightforward tasks where performance is not a top priority or readability and ease of use are more important.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Wrapping up 📝
&lt;/h3&gt;

&lt;p&gt;To sump up, testing and benchmarking are essential aspects of Go development, ensuring code reliability, efficiency and quality.&lt;/p&gt;

&lt;p&gt;If you want to keep learning about Go software quality, you can take a look at some other topics with great theory and practical problems on &lt;a href="https://hyperskill.org/tracks?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=testinggo&amp;amp;utm_term=27.04.2023" rel="noopener noreferrer"&gt;Hyperskill&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hyperskill.org/learn/step/24920?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=testinggo&amp;amp;utm_term=27.04.2023" rel="noopener noreferrer"&gt;&lt;strong&gt;Best practices for writing Go code&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hyperskill.org/learn/step/23076?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=testinggo&amp;amp;utm_term=27.04.2023" rel="noopener noreferrer"&gt;&lt;strong&gt;Debugging Go code&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Soon, you'll also be able to learn more about software quality, testing, and benchmarking in the upcoming &lt;strong&gt;Go for Developers&lt;/strong&gt; track that is in the works right now, so keep an eye on the &lt;a href="https://dev.to/hyperskill"&gt;Hyperskill blog&lt;/a&gt; for future announcements!&lt;/p&gt;

&lt;p&gt;And if you want to learn the fundamentals of the Go programming language along with essential Computer Science concepts 💻, you can start your learning journey today with the &lt;a href="https://hyperskill.org/tracks/25?utm_source=devto_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=testinggo&amp;amp;utm_term=27.04.2023" rel="noopener noreferrer"&gt;&lt;strong&gt;Introduction to Go track&lt;/strong&gt;&lt;/a&gt; on Hyperskill!&lt;/p&gt;

&lt;p&gt;Let us know in the comments below if you have any questions or feedback regarding this blog. You can also follow us on social media to stay up-to-date with our latest articles and projects. We are on &lt;a href="https://www.reddit.com/r/Hyperskill/" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt;, &lt;a href="https://www.linkedin.com/company/hyperskill" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, and &lt;a href="https://www.facebook.com/myhyperskill" rel="noopener noreferrer"&gt;Facebook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading, and keep on coding!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Telegram Conversation Summarizer Bot with ChatGPT and Flask (Quart)</title>
      <dc:creator>aliona matveeva</dc:creator>
      <pubDate>Fri, 21 Apr 2023 12:00:00 +0000</pubDate>
      <link>https://dev.to/hyperskill/telegram-conversation-summarizer-bot-with-chatgpt-and-flask-quart-3dga</link>
      <guid>https://dev.to/hyperskill/telegram-conversation-summarizer-bot-with-chatgpt-and-flask-quart-3dga</guid>
      <description>&lt;p&gt;Everybody talks about ChatGPT right now. The exceptionally smart AI keeps dazzling the internet even a couple of months after its release. Having the ChatGPT available on the website is awesome, however, the real fun begins when you gain API access. This gives you a great opportunity to integrate smart AI into your projects and applications to make them more powerful and introduce amazing features.&lt;/p&gt;

&lt;p&gt;This article brings you a guide on how to create your own Telegram bot and integrate ChatGPT with it, using the OpenAI's Python library. This may sound like the simplest thing to do, but let's spice things up a bit by introducing the summarize command to get you a summary of several posts in the chat.&lt;/p&gt;




&lt;p&gt;The post assumes you have basic knowledge of Python. However, I recommend checking out Hyperskill's &lt;a href="https://hyperskill.org/tracks/2?utm_source=medium_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=chatgpt&amp;amp;utm_term=20.04.2023" rel="noopener noreferrer"&gt;Python&lt;/a&gt; and &lt;a href="https://hyperskill.org/tracks/29?utm_source=medium_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=chatgpt&amp;amp;utm_term=20.04.2023" rel="noopener noreferrer"&gt;Flask&lt;/a&gt; tracks to learn more about Python and developing web applications with Flask.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting everything up
&lt;/h2&gt;

&lt;p&gt;Before jumping right into the code, you'll need to do some preparations to get all the required accesses.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register your bot in Telegram and retrieve the Telegram access token (using &lt;a class="mentioned-user" href="https://dev.to/botfather"&gt;@botfather&lt;/a&gt; in Telegram)&lt;/li&gt;
&lt;li&gt;Get access to the &lt;a href="https://my.telegram.org/auth" rel="noopener noreferrer"&gt;Telegram Core API&lt;/a&gt; and retrieve &lt;code&gt;api_hash&lt;/code&gt; and &lt;code&gt;app_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Sign up to &lt;a href="//ttps://platform.openai.com/"&gt;OpenAI&lt;/a&gt; and retrieve the API access token.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Save those secret strings and guard them with your life. No stranger should get access to them: this may lead to security violations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the skeleton
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: the full final project code (split into stages with commits) is available on my GitHub, please refer here for details: &lt;a href="https://github.com/yellalena/telegram-gpt-summarizer" rel="noopener noreferrer"&gt;https://github.com/yellalena/telegram-gpt-summarizer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Python libraries you need to install for this step: flask, pydantic, requests, and pyngrok.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's begin with writing the code for the very basic Telegram bot. It should receive messages from chat and be able to respond to them. &lt;br&gt;
First thing first - create a directory for your project and initialize a Python virtual environment. By the way, if you use PyCharm, it will create a virtual environment for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkl10ma3mai74jcl3v2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkl10ma3mai74jcl3v2c.png" alt="PyCharm screenshot" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this stage, the goal is split into four parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a simple Flask app with one root route to handle webhook with telegram messages.&lt;/li&gt;
&lt;li&gt;Create a class for the Telegram bot and make it able to send messages to a chat.&lt;/li&gt;
&lt;li&gt;Make the application visible to the big internet.&lt;/li&gt;
&lt;li&gt;Register the application address in Telegram.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is what &lt;em&gt;main.py&lt;/em&gt; looks like at this point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_webhook&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chat_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a response for message: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_ngrok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;http_tunnel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ngrok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http_tunnel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;public_url&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TelegramBot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_ngrok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_reloader&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Few things need clarification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I like to put all configuration things in one place, so I created the &lt;em&gt;config.py&lt;/em&gt; file, which will be gathering and storing our tokens and other useful information from exported environment variables.&lt;/li&gt;
&lt;li&gt;Telegram sends updates as a nested JSON, so let's create a set of pydantic models to parse the input to be more convenient later.&lt;/li&gt;
&lt;li&gt;To expose the application to the web, I use ngrok. It makes your localhost's specific port visible to everyone else, giving it a temporary public address. This is why it's important to make sure you expose the same port you're running your Flask app on.&lt;/li&gt;
&lt;li&gt;Finally, I initialize the bot and set a webhook to the ngrok's public URL, so that the bot knows it has to communicate to this URL whenever it receives any message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To set up a webhook, you will need to send a request to your bot's telegram API address, built using your acquired secret token. The telegram bot code looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TelegramBot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot_api_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TELEGRAM_API&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/bot&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;set_webhook_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot_api_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/setWebhook?url=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;set_webhook_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;send_message_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot_api_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/sendMessage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_message_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that everything is ready (don't forget I omitted some of the basic code, you can find it in the repo), export your bot token in an environment variable and hit that "Run"!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpftf0yg66jum85bxdl9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpftf0yg66jum85bxdl9.png" alt="Telegram chat screenshot" width="752" height="1104"&gt;&lt;/a&gt;&lt;br&gt;
Yay! It's alive!&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding a brain
&lt;/h2&gt;

&lt;p&gt;Amazing, the next step now should be adding a pinch of intelligence to our smart bot. Install an official OpenAI's lib for Python using pip: &lt;code&gt;pip install openai&lt;/code&gt;.&lt;br&gt;
After that, we will be able to create a helper class to communicate with the AI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAiHelper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message_text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message_text&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API &lt;a href="https://platform.openai.com/docs/models/overview" rel="noopener noreferrer"&gt;suggests&lt;/a&gt; a variety of models to use for your project. The most popular are, of course, the GPTs. GPT-4 is the one that made the most noise lately, but (and because of that) it has limited access now, so for easier testing purposes, I choose GPT-3 instead. No big deal, you can always choose whichever you like the most, just change the string name you pass to the helper.&lt;/p&gt;

&lt;p&gt;Don't forget to add &lt;code&gt;OPENAI_TOKEN&lt;/code&gt; property to the config and let's use the helper in the code.&lt;/p&gt;

&lt;p&gt;First, of course, instantiate it in the &lt;code&gt;main()&lt;/code&gt; method:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1f3de8zn1abu4lc36g6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1f3de8zn1abu4lc36g6.png" alt="Initializing the OpenAI helper in main" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then call this guy from the view function, just like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openai_helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whoosh! The magic is happening!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff32ivkvhncjpb0tkfs1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff32ivkvhncjpb0tkfs1n.png" alt="Telegram chat screenshot with OpenAI response" width="756" height="1102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summarize it!
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Python libraries to install for this step: quart, telethon.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I bet you've been there - you have been added to a chat with a group of friends who like to discuss interesting things or share some news or ideas. You've had a lot of stuff to do and you've missed all the fun in the chat. Next thing you see - a hundred unread messages there. Wouldn't it be nice if someone could give you a brief overview of what happened there instead of reading all that? Well, GPT can do that, of course. We only need to ask it.&lt;/p&gt;

&lt;p&gt;This is where the fun begins. For some reason, Telegram's bot API doesn't allow bots to read conversation history. We have webhooks, and we have the explicit GetUpdates() method, but they only work if someone has mentioned the bot. Another option is to make the bot get all the updates if it's added as an admin, but this approach has a few cons as well. First, you would need to set up whole storage for the messages. Second, what if you want to summarize the conversation that was going on before the bot was added to the chat? Not our case.&lt;/p&gt;

&lt;p&gt;Obviously, that's not the reason to give up. Telegram provides the Core API, and this one can help with retrieving a chat history. The only thing is that it's asynchronous. And the most popular Python library for it, Telethon, is asynchronous, too. And Flask is synchronous. Uh-oh.&lt;/p&gt;

&lt;p&gt;And that's where the mysterious &lt;a href="https://pgjones.gitlab.io/quart/tutorials/quickstart.html" rel="noopener noreferrer"&gt;Quart&lt;/a&gt; mentioned in the title comes onto the stage. Quart is the Flask API re-implemented using async, await, and ASGI web server (rather than synchronous and WSGI). Its main advantage in our case is that the syntax is basically the same. Let's do a quick code reorganization.&lt;/p&gt;

&lt;p&gt;The changes are simple. First, adjust imports and change every &lt;em&gt;Flask&lt;/em&gt; to &lt;em&gt;Quart&lt;/em&gt;:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7r5vc1ckx1fj4qqpqcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7r5vc1ckx1fj4qqpqcj.png" alt="Image description" width="758" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, make all web application's methods async. And await all the properties and methods that have become asynchronous now:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6lb038yazuqd32llzuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6lb038yazuqd32llzuc.png" alt="Image description" width="800" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're not sure about what's async Python, I encourage you to check this part of Telethon &lt;a href="https://docs.telethon.dev/en/stable/concepts/asyncio.html" rel="noopener noreferrer"&gt;documentation on the asyncio basics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have also moved ngrok and TelegramBot to launch them in a separate method decorated with &lt;code&gt;@app.before_serving&lt;/code&gt;. This is a Quart built-in decorator that will ensure everything inside this method will run before the web app is up and serving. It's required so that the bot and the helper are both initialized in the same event loop as the main application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.before_serving&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;startup&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_ngrok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TelegramBot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openai_helper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAiHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OPENAI_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the app has slightly changed as well, but not much. Hypercorn is the ASGI server used to run Quart asynchronously, and if we want to specify an application's port, we need to do it in a config. Note that the &lt;code&gt;main()&lt;/code&gt; is now also async and is run using asyncio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;quart_cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hypercorn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;quart_cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;hypercorn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quart_cfg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Let's check if the changes went smoothly for our bot. Run, text, enter:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finid8ehg07sfi7adjf7r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finid8ehg07sfi7adjf7r.png" alt="Image description" width="758" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's speaking. Great. Now, get the chat history for AI to summarize. Let's use Telegram's Core API with the help of Telethon lib. There, we will need the last two secret strings you have - export them as environment variables too.&lt;/p&gt;

&lt;p&gt;TelegramBot has slight changes in the &lt;code&gt;__init__&lt;/code&gt; method: it will need to have a new &lt;code&gt;core_api_client&lt;/code&gt; property which initializes a Telethon's client and of course, you need to pass the Core API secrets as arguments.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhp9z3k1nooimp6i5smfm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhp9z3k1nooimp6i5smfm.png" alt="Image description" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this tiny method will be responsible for retrieving the history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_chat_history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core_api_client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core_api_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Telethon's get_messages has many more different parameters you can pass beside the &lt;code&gt;limit&lt;/code&gt; ones. For example, it can reverse the history, or limit it by date instead of the number of messages. It's fun to play with and you can adjust your own bot in any way you'd love to.&lt;/p&gt;

&lt;p&gt;Well, we're almost done. The final touch is to add a summarization option to the webhook handler. This is what getting an answer looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# process "summarize" command
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/summarize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_chat_history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openai_helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please, briefly summarize the following conversation history:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;\
                                                  &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openai_helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see it blooming!&lt;/p&gt;

&lt;p&gt;After you run the application for the first time, it will ask you to log in to Telegram. That's ok: it's required to get access to message history and other private data the Core API has to offer us. Enter the same phone number you used to get access to Telegram Core API. You will receive a verification code inside your app, and after that you're good to go.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjctn0wyfbrwmlnlddy9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjctn0wyfbrwmlnlddy9m.png" alt="Image description" width="800" height="97"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the bot to a conversation with friends and ask for a summary:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F208g8h5fqyd5k2bmajnd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F208g8h5fqyd5k2bmajnd.png" alt="Image description" width="800" height="845"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! There's an endless list of things you can continue with: add processing other types of messages besides text, configure a number of messages to summarize from the chat, etc. Go for it and don't forget to push your code onto GitHub. Happy coding! :)&lt;/p&gt;

&lt;p&gt;Don't forget to jump onto &lt;a href="https://hyperskill.org/tracks?utm_source=medium_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=chatgpt&amp;amp;utm_term=20.04.2023" rel="noopener noreferrer"&gt;Hyperskill&lt;/a&gt; website to keep learning about developing web applications with Python and Flask. Here are links to some topics that you might find useful exactly for this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://hyperskill.org/learn/step/17366?utm_source=medium_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=chatgpt&amp;amp;utm_term=20.04.2023" rel="noopener noreferrer"&gt;Error handlers&lt;/a&gt;: If you don't handle errors properly, there is a high chance of your application failing in the runtime or showing ugly tracebacks to the user. To avoid that, read about types of errors and how it's best to handle them in a Flask app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hyperskill.org/learn/step/17609?utm_source=medium_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=chatgpt&amp;amp;utm_term=20.04.2023" rel="noopener noreferrer"&gt;Logging&lt;/a&gt;: That's one of the most important things when it comes to testing and debugging your application. Writing meaningful and readable logs is a must for a software developer. Check this topic to learn how to perform logging in Python.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hyperskill.org/learn/step/12935?utm_source=medium_hs&amp;amp;utm_medium=social&amp;amp;utm_campaign=chatgpt&amp;amp;utm_term=20.04.2023" rel="noopener noreferrer"&gt;Intro to SQLAlchemy&lt;/a&gt;: When you decide you want to store some application data, whether it be any user info or conversation history, you will need to communicate to the database. This topic introduces you to the basics of SQLAlchemy which makes working with databases easy and convenient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hyperskill is a project-based learning platform that offers a personalized curriculum and a variety of tracks to help people from different backgrounds gain market-relevant skills through online education. It's not only giving you solid pieces of theory but allows you to practice the skills right away - and practice makes learning perfect.&lt;/p&gt;




&lt;p&gt;Did you find this post helpful? Hit clap and follow Hyperskill and me to read more of them later :)&lt;/p&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
