<?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: farez</title>
    <description>The latest articles on DEV Community by farez (@farez).</description>
    <link>https://dev.to/farez</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%2Fuser%2Fprofile_image%2F388388%2F6533849c-88fd-4da7-9f18-9a8539b255df.jpg</url>
      <title>DEV Community: farez</title>
      <link>https://dev.to/farez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/farez"/>
    <language>en</language>
    <item>
      <title>Ship Indie Projects Fast, and Securely</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Thu, 24 Oct 2024 17:36:12 +0000</pubDate>
      <link>https://dev.to/farez/ship-indie-projects-fast-and-securely-25ag</link>
      <guid>https://dev.to/farez/ship-indie-projects-fast-and-securely-25ag</guid>
      <description>&lt;p&gt;[This post has a &lt;a href="https://www.youtube.com/watch?v=tr4EUqZTLDM" rel="noopener noreferrer"&gt;video&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;If you’ve been keeping up with indie hacking goings on, you’d be aware of the Shipfast and Marc Louvion &lt;a href="https://www.indiehackers.com/post/tech/security-bugs-engulf-shipfast-a-popular-indie-hackers-product-in-drama-y2VgBkHu7b91rSCEEUSO" rel="noopener noreferrer"&gt;drama&lt;/a&gt;. I’m not here to analyse or take sides. And Marc has already &lt;a href="https://x.com/marc/_louvion/status/1849422073250365499" rel="noopener noreferrer"&gt;responded gallantly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But I want to say a few words about our responsibility as entrepreneurs and service providers. (BTW this is coming from over 20 years of professional software engineering experience, 5 years of building startups and a PhD in computer network security, so I’m not talking our of my arse).&lt;/p&gt;

&lt;h2&gt;
  
  
  Security is important
&lt;/h2&gt;

&lt;p&gt;If you’re running a restaurant, would you want to make your customers sick from your food? If you’re selling cars, would you sell cars without locks?&lt;/p&gt;

&lt;p&gt;It's the same with software. If you're building something that handles customer data, there’s a responsibility to ensure it’s safe. The good news is, you don’t need to be a security expert to do that.&lt;/p&gt;

&lt;p&gt;"But you need to ship fast, fail fast, get traction…" Yes, solid advice. But security often gets left behind in the rush, especially when you’re a solo founder. Security seems like a huge, overwhelming topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s not Difficult
&lt;/h2&gt;

&lt;p&gt;Securing your app doesn’t have to be hard. In fact, with modern frameworks, security is baked in.&lt;/p&gt;

&lt;p&gt;Thousands of developers hours have gone into building, and securing, popular open source frameworks like Laravel, Django and Express. And these have been battle tested in the field against numerous attack attempts. Security holes are constantly being discovered and patched.&lt;/p&gt;

&lt;p&gt;With modern frameworks, you don’t even have to think about security because they are often a core component of the framework.&lt;/p&gt;

&lt;p&gt;With Laravel, for example, you get these security features out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Form security&lt;/strong&gt;: Laravel adds tokens to forms to Cross Site Request Forgeries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password hashing&lt;/strong&gt;: Even if a hacker gets into your database, they can’t see the passwords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party logins&lt;/strong&gt;: Want users to log in with Google or Facebook? Just enable it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL Injection protection&lt;/strong&gt;: Laravel uses parameterized queries by default, protecting your database from SQL injection attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Token authentication&lt;/strong&gt;: If you’re exposing an API, authentication using tokens is already taken care of.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of these are things you don’t even have to spend a second setting up, but they save you a ton of headaches down the road.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starter Kits and Security
&lt;/h2&gt;

&lt;p&gt;A lot of indie hackers start with pre-built starter kits. And these can be great—they help you launch faster and focus on what matters. But one thing many of us don’t think about is whether these starter kits are secure. And honestly, it’s not your fault. Most of us aren’t security specialists, and neither are many of the people building these kits.&lt;/p&gt;

&lt;p&gt;The truth is, security hasn’t always been front and center in our community. Many high-profile indie hackers have said they don’t even worry about it until they’ve gained traction. That makes sense—time is short, and the pressure to ship is real.&lt;/p&gt;

&lt;h2&gt;
  
  
  "But Pieter Levels said..."
&lt;/h2&gt;

&lt;p&gt;You’ve probably heard stories like Pieter Levels’s—building entire businesses with just a single index.php file.&lt;/p&gt;

&lt;p&gt;It’s inspiring, and it shows how much you can achieve with minimal resources. But here’s the catch: even those single-file setups need to be secure. Don't be fooled—Pieter secures his scripts.&lt;/p&gt;

&lt;p&gt;And you're not Pieter Levels.&lt;/p&gt;

&lt;p&gt;For my projects, I use Laravel, Tailwind, MySQL, and Nginx. It allows me to ship fast and have security built in. And it’s free.&lt;/p&gt;

&lt;p&gt;But this is just my preference. And there are plenty of other great options out there.&lt;/p&gt;

&lt;p&gt;For example, if you're more into JavaScript, you could use, Node.js, Express, and SQLite. Or if you're more comfortable with Python, you could use Django, FastAPI, PostgreSQL, and Gunicorn.&lt;/p&gt;

&lt;p&gt;These tools are also widely used, secure, and have strong community support. The key is to pick the stack that works best for you and your skillset, while ensuring that security is a priority.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways for Indie Hackers
&lt;/h2&gt;

&lt;p&gt;Buy starter kits if you want. But don’t overlook open source frameworks. It’s secure, it allows you to ship just as fast, and it’s free.&lt;/p&gt;

&lt;p&gt;As indie hackers, we have a lot on our plates. We’re trying to build, launch, and grow—all with limited time and resources. Security can feel like a huge burden, but it doesn’t have to be.&lt;/p&gt;

&lt;p&gt;No need to be an expert, no need to reinvent the wheel. Just use the tools that are already out there, and focus on shipping without drama.&lt;/p&gt;

&lt;p&gt;Let’s keep pushing forward, moving fast, and yes, staying secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Have questions?
&lt;/h2&gt;

&lt;p&gt;Want to know more about securing your app? Or have a question? You can reach me on &lt;a href="https://x.com/farez" rel="noopener noreferrer"&gt;X&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/farez/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>startup</category>
    </item>
    <item>
      <title>What OpenAI’s latest updates mean for AI builders</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Tue, 07 Nov 2023 04:09:46 +0000</pubDate>
      <link>https://dev.to/farez/what-openais-latest-updates-mean-for-ai-builders-19go</link>
      <guid>https://dev.to/farez/what-openais-latest-updates-mean-for-ai-builders-19go</guid>
      <description>&lt;p&gt;&lt;strong&gt;Do we still need embeddings?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GPT-4 now has a 128K context or “more than 300 pages of text in a single prompt”. And you can now upload files with the API. This means for most “chat with document” cases, you can just upload the file wholesale and ask questions.&lt;/p&gt;

&lt;p&gt;Or you can feed all your data to the new Assistants API and let it do the retrieval. You just give it your file and it can do its own vector search on it, if required. Furthermore, it remembers all the chat history, so you don’t need to save that either.&lt;/p&gt;

&lt;p&gt;This also simplifies your architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better math&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assistant API can now run sandboxed Python. Math hasn’t been GPT’s strong point until now.&lt;/p&gt;

&lt;p&gt;Combine this with retrieval, and you have a really powerful data analysis tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multimodal&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can start building true multimodal apps with new Vision, DALL-E, Text-to-speech endpoints.&lt;/p&gt;

&lt;p&gt;Read a table then output a chart. Read an image and read a summary of it out loud. Brainstorm design ideas verbally and have it iterate on a design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheaper&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GPT-3.5 and GPT-4 are 3x cheaper. Fine tuning is 4x cheaper.&lt;/p&gt;

&lt;p&gt;If you’re a SaaS competing on prices, I think this is the time to reconsider your business model.&lt;/p&gt;

&lt;p&gt;But this is great news for bespoke builds. The ongoing maintenance cost for your clients will be much more attractive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Faster&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Multiple function calling in a single message means less round trips to the API. This is great for the user’s experience.&lt;/p&gt;

&lt;p&gt;And the rate limits have doubled GPT-4.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More accuracy, more reproducible&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There’s a new “JSON mode” that will instruct the API to always return valid JSON. This is really useful for returning structured output in a chat session. JSON mode is available in GPT-3.5 too.&lt;/p&gt;

&lt;p&gt;And there is a new “seed” parameter to make outputs reproducible. Useful if you’re integrating your data into a workflow that requires a high level of repeatability.&lt;/p&gt;




&lt;p&gt;What this means for our own AI app, &lt;a href="http://bunni.ai/" rel="noopener noreferrer"&gt;bunni.ai&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's harder to build and grow general-purpose AI tools now. We've started to focus on a niche (researchers) and a specific use case ("summarisation").&lt;/li&gt;
&lt;li&gt;We'll continue to innovate on pricing and UX.&lt;/li&gt;
&lt;li&gt;The new OpenAI API updates will give us so much more to work with. Especially for our custom-build clients.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Follow me on X for comments on AI, development and SaaS: &lt;a href="https://twitter.com/farez" rel="noopener noreferrer"&gt;https://twitter.com/farez&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>chatgpt</category>
      <category>saas</category>
    </item>
    <item>
      <title>I built and launched an AI SaaS: lessons, observations, and metrics.</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Mon, 25 Sep 2023 10:37:36 +0000</pubDate>
      <link>https://dev.to/farez/i-built-and-launched-an-ai-saas-lessons-observations-and-metrics-hci</link>
      <guid>https://dev.to/farez/i-built-and-launched-an-ai-saas-lessons-observations-and-metrics-hci</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL;DR? Chat with this article instead:&lt;br&gt;
&lt;a href="https://app.clarifypdf.com/ask/6d7fb711-23de-428a-95b0-acab7c9f0249" rel="noopener noreferrer"&gt;https://app.clarifypdf.com/ask/6d7fb711-23de-428a-95b0-acab7c9f0249&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just over 3 months ago I &lt;a href="https://twitter.com/farez/status/1665036409277644801" rel="noopener noreferrer"&gt;launched&lt;/a&gt; ClarifyPDF, an AI SaaS to “chat with your PDF”. One of about hundreds out there.&lt;/p&gt;

&lt;p&gt;Against all conventional startup or indie-hacking wisdom, I launched without a problem to solve, without a customer segment to serve, and without even a need for it myself.&lt;/p&gt;

&lt;p&gt;So why did I do it?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I knew that as a developer, I couldn’t ignore AI anymore. I had to up-skill.&lt;/li&gt;
&lt;li&gt;It seemed like anyone launching an AI app is making tonnes of $$$. Yep - I had huge FOMO.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, I will share this journey and some lessons and observations. Hopefully, it’ll be a useful insight for anyone thinking about starting an AI app.&lt;/p&gt;

&lt;p&gt;For context: I’m a web developer with 20 years of commercial dev experience. 3 years ago I started indie hacking. I don’t have any practical experience with AI - just the theories I learned at uni.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building, Launching, Results
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How I came up with the idea
&lt;/h3&gt;

&lt;p&gt;I started this journey by learning the basics: prompt engineering, large language models, and the OpenAI API. ClarifyPDF &lt;a href="https://twitter.com/farez/status/1659652247502966784" rel="noopener noreferrer"&gt;evolved&lt;/a&gt; out of the code I was writing to learn all this. It was my “school project”!&lt;/p&gt;

&lt;p&gt;My primary goal was to learn and then to launch something. Anything. I didn’t want to overthink it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning about building for AI
&lt;/h3&gt;

&lt;p&gt;As I mentioned above, I didn’t have any practical AI development experience. So I had to learn.&lt;/p&gt;

&lt;p&gt;I shared my learnings &lt;a href="https://twitter.com/farez/status/1654942532223086592" rel="noopener noreferrer"&gt;publicly on Twitter,&lt;/a&gt; but this was the basic sequence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://t.co/HZpuUsTA3R" rel="noopener noreferrer"&gt;Learning prompt engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.openai.com/docs/quickstart" rel="noopener noreferrer"&gt;Building with OpenAI API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/blog/topics/developers-practitioners/meet-ais-multitool-vector-embeddings" rel="noopener noreferrer"&gt;Creating embeddings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/farez/status/1656372795259908117" rel="noopener noreferrer"&gt;Building a chatbot app from scratch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://farez.me/how-to-create-a-chatbot-with-openais-api-a-general-architecture/" rel="noopener noreferrer"&gt;Digested and summarised what I learned&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How I validated the idea
&lt;/h3&gt;

&lt;p&gt;The first “validation” was actually by observation. The growth of products like ChatPDF, SiteGPT, and Typing Mind was phenomenal. At least in the short term, the demand for a “better ChatGPT” was clear.&lt;/p&gt;

&lt;p&gt;I didn’t try to do any other validation. I was going to let my launch bring in the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;I didn’t want to overthink it and I knew I had to move fast. It felt like everything was (and still is) changing so quickly in this space anyway, and the only sane approach was to &lt;a href="https://twitter.com/damengchen/status/1671946089266831360%5C" rel="noopener noreferrer"&gt;launch and iterate&lt;/a&gt;. I used what I already knew (Laravel / PHP / Tailwind).&lt;/p&gt;

&lt;p&gt;I did wonder if I should learn Python first because most of the open-source AI code examples and libraries out there are built with Python. But that felt like procrastination and a distraction. If the app takes off I can learn Python later.&lt;/p&gt;

&lt;p&gt;For the database, I went with PostgreSQL because it’s the closest to MySQL, which I am already familiar with. I would have preferred to use a cloud vector database to save time, and I did look into various options. But they all required more time to learn. Again, speed to market was &lt;strong&gt;the&lt;/strong&gt; priority.&lt;/p&gt;

&lt;p&gt;For payments, I strayed from what I knew (Paddle) and went with Lemon Squeezy.&lt;/p&gt;

&lt;p&gt;Mistake.&lt;/p&gt;

&lt;p&gt;Although it was easy to integrate Lemon Squeezy, at the time it was still a bit buggy. I lost time trying to debug it. I was going to go back to Paddle when they fixed the bugs. So I stayed. This cost me some time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;I went with a one-time purchase model. Simply because this was easier to implement than subscriptions!&lt;/p&gt;

&lt;p&gt;I launched with $4.99 per PDF. Which, in hindsight, is insanely expensive for what most competing products allow people to do for free! Well, I didn’t know, did I?&lt;/p&gt;

&lt;p&gt;The price evolved after the launch. Through feedback and usage data, it evolved to $1.99 then finally to $0.99 per PDF now.&lt;/p&gt;

&lt;p&gt;Interestingly, when I halved the price from $1.99 to $0.99, the number of purchases doubled. So halving it got me the same total revenue.&lt;/p&gt;

&lt;p&gt;But, crucially, it got me double the number of customers, which is awesome for feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I launched it
&lt;/h3&gt;

&lt;p&gt;Posted on &lt;a href="https://twitter.com/farez/status/1665036409277644801" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; (1,500 followers), &lt;a href="https://news.ycombinator.com/item?id=36179038" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt;, and &lt;a href="https://www.indiehackers.com/post/building-a-basic-chat-with-a-pdf-app-as-my-ai-learning-project-7c0a3bee90" rel="noopener noreferrer"&gt;Indie Hackers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then it got picked up by some of the larger listing sites, the biggest source of traffic being &lt;a href="https://theresanaiforthat.com/" rel="noopener noreferrer"&gt;There’s An AI For That&lt;/a&gt;. And they listed ClarifyPDF for free.&lt;/p&gt;

&lt;p&gt;This is just a guess but I think it got picked up because I was building in public and, at that time, these sites wanted to grow fast so they were sucking up any AI app they can find. I was lucky to launch within the GPT hype window. Most of these listing sites are not free anymore.&lt;/p&gt;

&lt;p&gt;Customer feedback was priority #1 at this time. From a previous SaaS, I learned that a chatbox is great for this, so I launched ClarifyPDF with a &lt;a href="http://crisp.io/" rel="noopener noreferrer"&gt;Crisp.io&lt;/a&gt; chatbox from day 1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;First week:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visitors: 1,000&lt;/li&gt;
&lt;li&gt;Revenue: $45.42&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First month:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visitors: 2,800&lt;/li&gt;
&lt;li&gt;Revenue: $115.02&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To date:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visitors: 11,600&lt;/li&gt;
&lt;li&gt;Revenue: $320.83&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons
&lt;/h2&gt;

&lt;p&gt;Compared to how much the “big” indie AI apps out there are making, ClarifyPDF is tiny! It didn’t make a tonne of money. But I did learn a tonne. I share some lessons and observations below.&lt;/p&gt;

&lt;p&gt;Please note that this is based on my narrow experience of building a small, very specific type of AI SaaS - a “chat with document” GPT app. I can’t speak for all of the AI landscape!&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Did Right
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Not overthinking it.&lt;/li&gt;
&lt;li&gt;Using what I already know.&lt;/li&gt;
&lt;li&gt;Moving as fast as I could in this competitive space.&lt;/li&gt;
&lt;li&gt;Focusing on learning.&lt;/li&gt;
&lt;li&gt;Building in public.&lt;/li&gt;
&lt;li&gt;Getting in early.&lt;/li&gt;
&lt;li&gt;Automated follow-up emails.&lt;/li&gt;
&lt;li&gt;Crisp chatbox.&lt;/li&gt;
&lt;li&gt;Talking to customers.&lt;/li&gt;
&lt;li&gt;Having analytics in from day 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What I Did Wrong
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Treating it as a “side project”, even after seeing positive signals. I was working on this about 1 day a week. This is a fast-moving sector. It should have dropped everything and worked on this full-time to give it a chance to grow fast.&lt;/li&gt;
&lt;li&gt;Assumed I could mimic the success of others, just by building it. Nope.&lt;/li&gt;
&lt;li&gt;Not doing enough marketing. IMHO, to move fast in this market, your time needs to be at least 50% on marketing.&lt;/li&gt;
&lt;li&gt;Giving in to distractions: other projects, starting new product ideas, starting to work on a course.&lt;/li&gt;
&lt;li&gt;Didn’t offer alternative pricing models. By charging a one-time fee that’s on the ‘expensive’ end of the spectrum, I drove away customers with a need to process lots of documents. A potentially more lucrative market.&lt;/li&gt;
&lt;li&gt;I stopped building in public. My initial efforts of building in public brought some visibility to what I was working on, and I think helped with initial traction. But after the launch, I stalled. I used “need to build fast” as an excuse to not communicate regularly about what I’m working on. This killed off the momentum from earlier efforts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  General observations - market
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New innovative platforms create opportunities we can ride on&lt;/strong&gt;. I saw this with Notion when they released templates and their API. And then with OpenAI when they released their API. Mass adoption and mass platform growth are market makers. Building and launching quickly on these platforms can really bring in a lot of early traffic. But it doesn’t last long. Catch the wave early and ride it to the beach, before it’s gone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I was too late&lt;/strong&gt;. Those who launched early this year saw runaway success because they were first and they caught the wave created by ChatGPT. That wave is now gone.&lt;/li&gt;
&lt;li&gt;But &lt;strong&gt;I’m still early&lt;/strong&gt;. That first wave is responsible for creating a huge amount of awareness. This has made it easier for anyone launching now to explain the benefits of AI. It’s an easier sell. Provided you are solving a real problem. And it has opened up a huge market, which indie makers can jump in now and still be early in.&lt;/li&gt;
&lt;li&gt;It WAS about who’s first. Now, it’s about &lt;strong&gt;who’s better&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Students, teachers, and researchers&lt;/strong&gt; form one early adopter group for GPT. They are the ones that have to consume and generate lots of documents on a day-to-day basis. Lots of boring manual repeated tasks. This is a market that’s craving AI tools to help them do their work faster and better.&lt;/li&gt;
&lt;li&gt;Businesses want &lt;strong&gt;automation&lt;/strong&gt;. Not just a chatbot. “Which manual process can we streamline? Who can we replace?” are questions they ask. The AI solution needs to solve these.&lt;/li&gt;
&lt;li&gt;There is a massive &lt;strong&gt;non-English-speaking market&lt;/strong&gt;. AI makes it easy now to handle documents in almost any language, so your customers will be expecting your app to do that. Anyway, there’s no excuse not to because the barrier to supporting multi-language has been lowered by AI.&lt;/li&gt;
&lt;li&gt;I see lots of &lt;strong&gt;opportunities right now in 4&lt;/strong&gt; areas: 1) selling “picks and shovels” to other AI builders, 2) selling a focused solution to specific problems, 3) selling training, and 4) selling consulting. I think (3) and (4) are growing and easiest to get into right now for indie makers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  General observations - product
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;fundamentals still matter&lt;/strong&gt;: start by solving a real problem for a small group of people.&lt;/li&gt;
&lt;li&gt;In the early stages, &lt;strong&gt;user feedback is more valuable than revenue&lt;/strong&gt;. I halved my price and got double the number of customers. Same revenue, but more user feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A chatbot is not a solution&lt;/strong&gt;. It’s just part of the overall solution to a customer’s problem. People need to do something with the answer they get out of a chatbot. Were they lazy and didn’t like reading? Were they overwhelmed with so many documents? Do they need to create other types of content or feed it into their process?&lt;/li&gt;
&lt;li&gt;OpenAI’s API is still the &lt;strong&gt;quickest engineering route to market&lt;/strong&gt; so far. And one of the cheapest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use open-source projects&lt;/strong&gt;. They’ll save you time. Most of the backend work I’ve done on ClarifyPDF can now be done in 5 lines of code with &lt;a href="https://github.com/embedchain/embedchain" rel="noopener noreferrer"&gt;Embedchain&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Costing is tricky&lt;/strong&gt;. LLM providers typically price by tokens used. But this is not the most convenient model for your customers. You’ll need to work out the arbitrage. But you do need to work out your costs properly as they could get out of hand.&lt;/li&gt;
&lt;li&gt;Your &lt;strong&gt;pricing model picks your customers&lt;/strong&gt;. ClarifyPDF’s one-time purchase model is fine for single documents. But drove away those with lots of documents to process. This can skew your analytics.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  General observations - engineering
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Building a chatbot is easy&lt;/strong&gt;. You now have all the tools and open-source AI packages you need. Pick one, build a SaaS wrapper around it, launch early and sell like hell.&lt;/li&gt;
&lt;li&gt;Building a &lt;strong&gt;good&lt;/strong&gt; chatbot is &lt;strong&gt;hard.&lt;/strong&gt; There are so many parameters. So many knobs to turn. And LLMs are black boxes. One size does not fit all - a summarising prompt is different from a data extraction prompt and is different from a content generation prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data extraction is challenging&lt;/strong&gt;. You need to deal with this before you can even start using the data with the AI. These include extracting text from PDFs, creating embeddings, strategy for retrieving embeddings and content, database architecture, and metadata.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompting is an art&lt;/strong&gt;. And you’ll never stop tweaking it. Don’t underestimate the need for good prompt engineering skills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summarisation&lt;/strong&gt; is a separate problem to chat. Token limits will force you to be creative with how you summarise large amounts of text.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;The signals are good and I will continue to develop ClarifyPDF. These are our focus for the next phase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flexible pricing&lt;/strong&gt;. We need to move away from one-time pricing to a model that’s friendlier to large quantities of documents. The first step is to move to &lt;a href="https://clarifypdf.com/?utm_campaign=blog_lessons_learned_3_months&amp;amp;utm_source=blog&amp;amp;utm_medium=content#pricing" rel="noopener noreferrer"&gt;credit-based pricing&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Beyond PDFs&lt;/strong&gt;. The internet is more than just PDFs. We’re building support for all types of content sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serving small businesses&lt;/strong&gt;. We will start paying more attention to problems we can solve for small businesses. We have also started offering &lt;a href="https://clarifypdf.com/custom-build?utm_campaign=blog_lessons_learned_3_months&amp;amp;utm_source=blog&amp;amp;utm_medium=content" rel="noopener noreferrer"&gt;consulting and custom solutions&lt;/a&gt;, with the goal of learning more about our customers’ needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expand distribution&lt;/strong&gt;. Starting with an attractive affiliate programme. We will then experiment with a few more channels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope my lessons help you in building your own indie AI app.&lt;/p&gt;

&lt;p&gt;As always, I’ll be sharing my updates on my &lt;strong&gt;&lt;a href="https://farez.substack.com/" rel="noopener noreferrer"&gt;newsletter on building an indie AI software business&lt;/a&gt;&lt;/strong&gt;. You can also follow me on &lt;a href="https://twitter.com/farez" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/farez/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>gpt3</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>Is there a way to hide classes in Jetbrains?</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Wed, 13 Sep 2023 04:08:51 +0000</pubDate>
      <link>https://dev.to/farez/is-there-a-way-to-hide-classes-in-jetbrains-30io</link>
      <guid>https://dev.to/farez/is-there-a-way-to-hide-classes-in-jetbrains-30io</guid>
      <description>&lt;p&gt;When editing HTML, is there a way to hide classes (or toggle it on and off) in Jetbrains editors? I'm using PHPStorm.&lt;/p&gt;

&lt;p&gt;Sometimes I just want to see the markup and work on structure without seeing all the class names. Especially when using Tailwind where there are typically a long list of class names on a div, for example.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Installing PostgreSQL + pgvector on Debian</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Sun, 20 Aug 2023 09:32:37 +0000</pubDate>
      <link>https://dev.to/farez/installing-postgresql-pgvector-on-debian-fcf</link>
      <guid>https://dev.to/farez/installing-postgresql-pgvector-on-debian-fcf</guid>
      <description>&lt;p&gt;If you're building any kind of AI app that requires storage of vectors for embeddings, and you need an open source storage solution, it's hard to go wrong with PostgreSQL + the &lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;pgvector&lt;/a&gt; extension.&lt;/p&gt;

&lt;p&gt;You could go with a hosted solution, such as Supabase's &lt;a href="https://supabase.com/vector" rel="noopener noreferrer"&gt;vector storage&lt;/a&gt;. You can also host it yourself. &lt;/p&gt;

&lt;p&gt;It's easy and I show you how to do it for the Debian OS below, which would allow you to add this to a Debian hosted website. This is also the exact setup I'm using for &lt;a href="https://clarifypdf.com/?utm_campaign=content-marketing&amp;amp;utm_source=dev.to&amp;amp;utm_medium=website"&gt;clarifypdf.com&lt;/a&gt;, a "Chat with PDF" AI app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisities
&lt;/h2&gt;

&lt;p&gt;You'll need root access to your Debian environment. &lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;SSH into your server, with your username and server's IP address&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ssh user@ip.add.re.ss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install &lt;a href="https://github.com/pgvector/pgvector#installation-notes" rel="noopener noreferrer"&gt;pgvector&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install postgresql-15-pgvector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Login to PostgreSQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ psql -U db-username db-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable pgvector&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# CREATE EXTENSION vector;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that it's enabled&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# \dx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the extensions list, with pgvector in it.&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%2Fk7u4obsg51b8ssdbp2fo.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%2Fk7u4obsg51b8ssdbp2fo.png" alt="Screen shot of PostgreSQL extensions list showing that pgvector is enabled." width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! You're ready to create embeddings with PostgreSQL!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Weekend challenge: Building a ChatGPT bot with Laravel</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Fri, 28 Jul 2023 07:50:40 +0000</pubDate>
      <link>https://dev.to/farez/weekend-challenge-building-a-chatgpt-bot-with-laravel-3776</link>
      <guid>https://dev.to/farez/weekend-challenge-building-a-chatgpt-bot-with-laravel-3776</guid>
      <description>&lt;p&gt;Half asleep, with my brain not completely switched off, thoughts of all the new cool things announced at Laracon US last week swirled round in my head.&lt;/p&gt;

&lt;p&gt;But being a busy startup developer/founder, finding time to play with these new toys is always a challenge. Even though I know that some of these new advances will only help me build better products.&lt;/p&gt;

&lt;p&gt;So I thought, why not do the learning on top of what I already know! Which is why this weekend I'm going to re-build a small part of my &lt;a href="https://clarify.pdf" rel="noopener noreferrer"&gt;own product&lt;/a&gt; with the latest and greatest from Laravel.&lt;/p&gt;

&lt;p&gt;I'll be building a video summariser and chatbot for all of the Laracon videos.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1684714891947765760-610" src="https://platform.twitter.com/embed/Tweet.html?id=1684714891947765760"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1684714891947765760-610');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1684714891947765760&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I only have a weekend. Let's see where this thing goes!&lt;/p&gt;

&lt;p&gt;As always, I'll be building in public. If you want to follow along, &lt;a href="https://twitter.com/farez" rel="noopener noreferrer"&gt;follow me on Twitter&lt;/a&gt; for the play-by-play, or just read the summary and results in &lt;a href="https://https://farez.substack.com/" rel="noopener noreferrer"&gt;my newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Simplify your Laravel &amp; Blade ifs: @pro, @free and @guest</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Tue, 30 May 2023 11:49:23 +0000</pubDate>
      <link>https://dev.to/farez/simplify-your-laravel-blade-ifs-pro-free-and-guest-4fdl</link>
      <guid>https://dev.to/farez/simplify-your-laravel-blade-ifs-pro-free-and-guest-4fdl</guid>
      <description>&lt;p&gt;Custom if tags to clean up your Blade templates.&lt;/p&gt;

&lt;p&gt;If you're building a SaaS, you'll eventually start accumulating a lot of &lt;code&gt;if&lt;/code&gt; statements that display one version of content for pro users (your paying subscribers), your free uses (if you have a free tier), and your guest users (those not logged in).&lt;/p&gt;

&lt;p&gt;You can use &lt;code&gt;@if&lt;/code&gt; directives in your Blade templates for this, but eventually it starts getting ugly, especially if the conditions are long and complex.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @if (auth()-&amp;gt;user()-&amp;gt;isProUser())
        &amp;lt;button&amp;gt;Click here&amp;lt;/button&amp;gt;
    @endif

    @if (auth()-&amp;gt;user()-&amp;gt;isFreeUser())
        &amp;lt;button&amp;gt;Upgrade&amp;lt;/button&amp;gt;
    @endif

    @guest
        &amp;lt;button&amp;gt;Sign up&amp;lt;/button&amp;gt;
    @endif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It'll be better if it can look like this instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @pro
        &amp;lt;button&amp;gt;Click here&amp;lt;/button&amp;gt;
    @endpro

    @free
        &amp;lt;button&amp;gt;Upgrade&amp;lt;/button&amp;gt;
    @endfree

    @guest
        &amp;lt;button&amp;gt;Sign up&amp;lt;/button&amp;gt;
    @endguest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well you can do that with Blade's &lt;a href="https://laravel.com/docs/10.x/blade#custom-if-statements" rel="noopener noreferrer"&gt;custom if statements&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Just add the following to your &lt;code&gt;AppServiceProvider&lt;/code&gt;'s boot method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public function boot()
    {
        Blade::if('pro', function () {
            if (auth()-&amp;gt;guest()) {
                return false;
            }
            return auth()-&amp;gt;user()-&amp;gt;isPro();
        });

        Blade::if('free', function () {
            if (auth()-&amp;gt;guest()) {
                return false;
            }
            return auth()-&amp;gt;user()-&amp;gt;isOnFreeTier();
        });
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;More on growing my indie SaaS business at &lt;a href="https://farez.substack.com" rel="noopener noreferrer"&gt;https://farez.substack.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>blade</category>
      <category>saas</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a basic "chat with a PDF" app with Laravel and OpenAI</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Sat, 27 May 2023 12:03:00 +0000</pubDate>
      <link>https://dev.to/farez/building-a-basic-chat-with-a-pdfapp-with-laravel-and-openai-4ncm</link>
      <guid>https://dev.to/farez/building-a-basic-chat-with-a-pdfapp-with-laravel-and-openai-4ncm</guid>
      <description>&lt;p&gt;Earlier this month I decided to start learning how to build AI products in my free time.&lt;/p&gt;

&lt;p&gt;It's been quite a satisfying journey. Based on what I've learned, I even wrote up a sort of &lt;a href="https://farez.substack.com/p/how-to-create-a-chatbot-with-openais" rel="noopener noreferrer"&gt;cheat sheet for building chatbots&lt;/a&gt;. And once you've learned the new ideas and components of an AI app, it's not that hard.&lt;/p&gt;

&lt;p&gt;The app uses OpenAI's API and I'm using their GPT-3.5-turbo model. I'm using their embeddings endpoint to create embeddings for the uploaded PDF content, and using the chat endpoint to ask the AI questions about the document.&lt;/p&gt;

&lt;p&gt;In the requests to the API, I asked it to assume the role of "an explanation bot that explains complex information in simple everyday English".&lt;/p&gt;

&lt;p&gt;The learning project actually turned into a half-decent app for interrogating PDFs. Even I myself was impressed with how useful a simple AI integration can be.&lt;/p&gt;

&lt;p&gt;To test it out, I uploaded a &lt;a href="https://www.gov.uk/government/publications/form-an-guidance" rel="noopener noreferrer"&gt;long PDF from the UK Home Office&lt;/a&gt;. It's a document explaining how to apply for UK citizenship. Basically, a long and tedious document to read. Then I asked it a few questions.&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%2Fo86m7v8884j1agby33qm.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%2Fo86m7v8884j1agby33qm.png" alt="Image description" width="800" height="703"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I liked how it summarised the answers and explained them back to me in simple English. Actually, I'm more of a bullet-point kinda guy so I would actually have preferred shorter answers in bullets. But this still saved me a tonne of time trying to read through the document.&lt;/p&gt;

&lt;p&gt;Once I had the basic functionality working, then I tidied the frontend up a bit with some simple Tailwind classes. Instead of the usual chat box at the bottom, I decided to put it at the top and have the AI's responses appear below it.&lt;/p&gt;

&lt;p&gt;Here's the tech stack for this simple app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend: Laravel + Nginx&lt;/li&gt;
&lt;li&gt;Database: PostgresQL + pgvector extension&lt;/li&gt;
&lt;li&gt;Frontend: Livewire + Tailwind&lt;/li&gt;
&lt;li&gt;AI API: OpenAI / GPT-3.5&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I go into more detail about the above in a &lt;a href="https://twitter.com/farez/status/1654942532223086592" rel="noopener noreferrer"&gt;Twitter thread&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For us indie businesses, building is just half the story. To turn this into a money-making project, I'll need to launch this and have people pay to use it.&lt;/p&gt;

&lt;p&gt;This is my task this weekend - polish and launch this learning project as an actual product. And yes, I have bought the domain name: clarifypdf.com :)&lt;/p&gt;

&lt;p&gt;As always I'll be sharing all the details as I go on Twitter &lt;a href="https://twitter.com/farez" rel="noopener noreferrer"&gt;@farez&lt;/a&gt;. Or you can just sign up to &lt;a href="https://farez.substack.com/" rel="noopener noreferrer"&gt;my newsletter&lt;/a&gt; and get posts like this one on my AI SaaS journey.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>laravel</category>
    </item>
    <item>
      <title>How to create a chatbot with OpenAI's API: a conceptual cheat sheet</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Fri, 19 May 2023 16:27:07 +0000</pubDate>
      <link>https://dev.to/farez/how-to-create-a-chatbot-with-openais-api-a-conceptual-cheat-sheet-2o5p</link>
      <guid>https://dev.to/farez/how-to-create-a-chatbot-with-openais-api-a-conceptual-cheat-sheet-2o5p</guid>
      <description>&lt;p&gt;I spent the last couple of weeks diving into AI and I've been learning how to build a chatbot that uses my own content.&lt;/p&gt;

&lt;p&gt;I've outlined the general steps for creating one, as a "cheat sheet" to myself, so I'm sharing it here.&lt;/p&gt;

&lt;p&gt;So if you want to build a chatbot with your own content, here are the general steps you would take.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create an &lt;a href="https://platform.openai.com/" rel="noopener noreferrer"&gt;OpenAI account&lt;/a&gt; and get your API key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a vector database, e.g. &lt;a href="https://supabase.com/blog/openai-embeddings-postgres-vector" rel="noopener noreferrer"&gt;PostgreSQL with pgvector&lt;/a&gt; or &lt;a href="https://redis.com/blog/rediscover-redis-for-vector-similarity-search/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a table to hold all your embeddings (OpenAI's vectors require 1536 dimensions).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Process your documents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gather all your documents ad convert them into text. Convert line breaks and tabs to spaces (OpenAI’s recommendation).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Break the document content into chunks. Each chunk should be small-ish, e.g. 2,000 words (look up OpenAI's &lt;a href="https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them" rel="noopener noreferrer"&gt;tokens&lt;/a&gt; for more specific settings).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use OpenAI’s &lt;a href="https://platform.openai.com/docs/api-reference/embeddings" rel="noopener noreferrer"&gt;API to create embeddings&lt;/a&gt; for each chunk.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save each chunk into the vector database.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a similarity search function
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use a similarity search function to retrieve the correct chunk, based on a question. OpenAI recommends the &lt;a href="https://www.youtube.com/watch?v=e9U0QAFbfLI" rel="noopener noreferrer"&gt;cosine similarity calculation&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test it out and tweak the parameters.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create your user-facing app
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a form to ask questions and display responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Write your prompts
&lt;/h2&gt;

&lt;p&gt;There are 3 types of prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Information gathering prompt: A prompt for OpenAI to keep asking questions until it has all the information it needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Summarise question prompt: Another prompt to summarise the question.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Answer prompt: A prompt that combines the final form of the question along with the relevant chunk of information.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get chatting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Host your code and database somewhere.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When someone asks a question, send the question and the Information gathering prompt to the &lt;a href="https://platform.openai.com/docs/api-reference/chat" rel="noopener noreferrer"&gt;OpenAI Chat API&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repeat until OpenAI responds that it has enough info.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send the chat transcript to OpenAI with the Summarise question prompt.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Answer the question
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use the OpenAI API to convert the summarised question into an embedding.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Search the vector database for the chunk that would most likely contain the answer, using the similarity search function you created earlier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the Answer prompt to send the summarised question and the chunk to the &lt;a href="https://platform.openai.com/docs/api-reference/completions" rel="noopener noreferrer"&gt;OpenAI Completion API&lt;/a&gt; to get the answer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wait for OpenAI to respond and display the answer to the user.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's generally it!&lt;/p&gt;

&lt;p&gt;Would love your feedback, especially from those who have already been building chatbots. Especially if you have a different method or process for building it.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;




&lt;p&gt;I'm sharing a lot more as I learn and build a new AI SaaS, so if you want more, you can find it on &lt;a href="https://farez.substack.com/" rel="noopener noreferrer"&gt;my newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>development</category>
    </item>
    <item>
      <title>My customer found a bug, but I fixed that last</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Mon, 31 May 2021 09:57:41 +0000</pubDate>
      <link>https://dev.to/farez/my-customer-found-a-bug-but-i-fixed-that-last-4g90</link>
      <guid>https://dev.to/farez/my-customer-found-a-bug-but-i-fixed-that-last-4g90</guid>
      <description>&lt;p&gt;For most non-trivial applications, fixing a technical bug could take hours or days. In this case, fixing the actual bug should probably come last.&lt;/p&gt;

&lt;p&gt;First, fix the customer's confidence, followed by the customer's experience.&lt;/p&gt;

&lt;p&gt;Then the bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix the customer's confidence
&lt;/h2&gt;

&lt;p&gt;When something breaks, the first thing that happens is doubt being cast in the customer's mind. Perhaps followed by worry and annoyance, especially if they are relying on our product to get their job done.&lt;/p&gt;

&lt;p&gt;When doubt, worry and annoyance mix, confidence erodes. Our customers will start to question whether this poor experience is going to happen again. And of course it will - you're innovating, and innovation contains bugs.&lt;/p&gt;

&lt;p&gt;So the first job is to fix that loss of confidence.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reply&lt;/em&gt; to the customer as soon as possible, acknowledge the problem, and apologise. Take full ownership and responsibility of it, even if it's someone else's job to do the actual fix. If you've been on one of those "customer service" calls where they pass you around different departments like a hot potato, you know how annoying that experience is. Be the one single contact point for your customers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt; the customer constantly on progress, so they know you're taking this seriously, and they feel taken care of. It is better to over-communicate than to have the customer wondering what's happening. Being informed also helps them plan for any delays or issues caused by the bug in your product. It empowers them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Find out&lt;/em&gt; how this bug is impacting their experience. Is it blocking their workday? Is it causing them stress? Is it impacting their revenue? This information will allow you to fix the customer's experience, next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix the customer's experience
&lt;/h2&gt;

&lt;p&gt;For some products, a bug can have a real impact on the customer's day. It could prevent them from doing their work, make them look bad or cause revenue loss.&lt;/p&gt;

&lt;p&gt;When this happens, our customer is having a really bad experience. So our job is to fix that experience.&lt;/p&gt;

&lt;p&gt;What is the bug really preventing them from doing? And how can we help them overcome that right now? Is there a workaround that we can release quickly so they can carry on with their work, while we fix the actual bug?&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix the bug
&lt;/h2&gt;

&lt;p&gt;Once we've fixed the experience as best as we can, we can then go ahead and fix the bug. We're not going to go into the details of technical bug fixing here, but usually this involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Getting a bug report from the customer.&lt;/li&gt;
&lt;li&gt;Reproducing the bug locally.&lt;/li&gt;
&lt;li&gt;Fixing it.&lt;/li&gt;
&lt;li&gt;Testing it.&lt;/li&gt;
&lt;li&gt;And finally, releasing it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember to keep the customer updated along the way to maintain their confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;I'll illustrate with an actual bug from &lt;a href="https://markfolder.com" rel="noopener noreferrer"&gt;my SaaS product&lt;/a&gt;, a Twitter bookmarker and organiser.&lt;/p&gt;

&lt;p&gt;One customer reported that they were seeing a "500 error" when trying to load a folder to view their bookmarked tweets.&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%2Fd0888humkxav6ktn4jl3.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%2Fd0888humkxav6ktn4jl3.png" alt="Customer bug report email" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clearly, this error is preventing them from doing their work!&lt;/p&gt;

&lt;p&gt;So, step 1: fix the customer's confidence. I emailed this back to them 1 minute later:&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%2F58qp61lsd5fnf3toygqn.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%2F58qp61lsd5fnf3toygqn.png" alt="Bug report customer support email" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had a look at the problem and basically, the site was crashing because for some reason, the app didn't save the content of one of the customer's bookmarked tweet, and I failed to include a check for empty content before trying to display it.&lt;/p&gt;

&lt;p&gt;I could go ahead and fix the bug, but what they really needed is to access their bookmarks so they can get on with their work.&lt;/p&gt;

&lt;p&gt;So step 2: fix the experience. What's the quickest thing I could do to unblock the customer's progress with work? Well, the website still contained a link to the original tweet, so for these "empty" bookmarks, I could just include an error message and a link to view the original tweet. This would be quick to do and they can continue with their work. Which is what I did.&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%2Fwdz2fj0o77dozhzxv78d.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%2Fwdz2fj0o77dozhzxv78d.png" alt="Bug quick fix" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And of course, I'm keeping the customer updated while I'm doing the fixing...&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%2F3qz9l1yd8pn0aszw1fxi.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%2F3qz9l1yd8pn0aszw1fxi.png" alt="Bug report customer support email" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I have tested and released the "experience fix", I communicated it to the customer and asked them to test it. Thankfully, it worked, and that seemed to allow them to continue with their day.&lt;/p&gt;

&lt;p&gt;The fix was released within an hour of the bug report. If I had tried to do a full technical fix of the original bug, it may have taken me a day, and not to mention the pressure I would have had to do it all quickly.&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%2Foqb1i4znx6i80kox5ve7.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%2Foqb1i4znx6i80kox5ve7.png" alt="Alt Text" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 3 is to fix the actual bug. But even here, there's an opportunity to keep improving the customer's experience before the full bug fix.&lt;/p&gt;

&lt;p&gt;For the bug above, I release a second interim fix, which allowed the customer to manually re-fetch the empty bookmark's content from Twitter, should they encounter the problem again. Not a full fix, but a slight improvement to the first one.&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%2F0w8kql5a29me0geq2060.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%2F0w8kql5a29me0geq2060.png" alt="Twitter API error fix" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, this was communicated to the customer that reported the problem and was received positively.&lt;/p&gt;

&lt;p&gt;Throughout this process, I was also updating the product's &lt;a href="https://twitter.com/markfolder" rel="noopener noreferrer"&gt;Twitter account&lt;/a&gt; so other customers are made aware of the bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the customer happy
&lt;/h2&gt;

&lt;p&gt;At the end of the day, our goal is to make the customer happy. &lt;/p&gt;

&lt;p&gt;So here's my framework for dealing with bugs reported by my customers:&lt;/p&gt;

&lt;p&gt;Step 1: Fix the customer's confidence.&lt;/p&gt;

&lt;p&gt;Step 2: Fix the customer's experience.&lt;/p&gt;

&lt;p&gt;Step 3: Fix the damned bug.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>testing</category>
      <category>projectmanagement</category>
    </item>
    <item>
      <title>Where do you store all your project/client details?</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Wed, 21 Apr 2021 04:31:36 +0000</pubDate>
      <link>https://dev.to/farez/where-do-you-store-all-your-project-client-details-16p</link>
      <guid>https://dev.to/farez/where-do-you-store-all-your-project-client-details-16p</guid>
      <description>&lt;p&gt;As a freelancer, I work on lots of different client projects. This means lots of different server environments, workflows, tools, keys, logins, and documentation.&lt;/p&gt;

&lt;p&gt;Over the years I've been putting all this info into various note-taking apps, filed under the client name and the project name for the client. &lt;/p&gt;

&lt;p&gt;Sometimes this is enough, but at times this can also get messy, especially when there's information shared across different projects. &lt;/p&gt;

&lt;p&gt;And sometimes there's information that you just forget to note down and then a year later when the client comes back to me again for some new work, I would have forgotten that info and it's a pain.&lt;/p&gt;

&lt;p&gt;So I'm wondering if any of you folks have a good system for this. &lt;/p&gt;

&lt;p&gt;How do you store important client and project related info that you need for your work?&lt;/p&gt;

</description>
      <category>programming</category>
      <category>systems</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Idea to sale in 2 hours</title>
      <dc:creator>farez</dc:creator>
      <pubDate>Mon, 12 Apr 2021 15:52:36 +0000</pubDate>
      <link>https://dev.to/farez/idea-to-sale-in-2-hours-3jh3</link>
      <guid>https://dev.to/farez/idea-to-sale-in-2-hours-3jh3</guid>
      <description>&lt;p&gt;On 7 April 2021, Gumroad promoted their GumroadDay. It's one day when sellers on gumroad.com get to keep 100% of sales revenue. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/search?q=%23GumroadDay&amp;amp;src=typeahead_click" rel="noopener noreferrer"&gt;GumroadDay&lt;/a&gt; looked like a success because it got a lot of exposure on Twitter and it drove sellers to promote their product on Gumroad, usually with a &lt;a href="https://twitter.com/farez/status/1379742789768896516" rel="noopener noreferrer"&gt;one day discount&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While it looked like a great opportunity for sellers, some lamented that they didn't have anything to sell to take advantage of it. &lt;/p&gt;

&lt;p&gt;So I wondered, would it be possible to create something to sell in an hour? &lt;a href="https://twitter.com/farez/status/1379744692963696641" rel="noopener noreferrer"&gt;That thought&lt;/a&gt; turned into a personal challenge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deciding what to sell
&lt;/h2&gt;

&lt;p&gt;First step: what to sell?&lt;/p&gt;

&lt;p&gt;I only had an hour, so I needed something I could create easily and quickly. And for customers I'm familiar with. &lt;/p&gt;

&lt;p&gt;These came to mind:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Photos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the last few months, I've been playing around with taking stock photos and uploading them for sale on EyeEm. I have a lot of photos and it would have been easy to pick a few, edit them, and sell them. &lt;/p&gt;

&lt;p&gt;Problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I don't know the customer segment well and don't have an existing audience or channel for it.&lt;/li&gt;
&lt;li&gt;I don't think Gumroad is known for selling stock photos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;My time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I could sell my time. I'm a freelancer after all, and I know how to sell this well.&lt;/p&gt;

&lt;p&gt;Problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's not a scalable product.&lt;/li&gt;
&lt;li&gt;I wanted to sell something that's cheap enough, and my time isn't cheap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Documents&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm a freelance web developer, and over the years I've built and refined various processes and documents I use for my day-to-day. &lt;/p&gt;

&lt;p&gt;One of the documents is a "Standard Terms and Conditions" document I include in every client contract. I could repackage this easily and it can be sold at a cheap enough price. And freelancers are constantly looking for legal document templates to reuse for their own projects. &lt;/p&gt;

&lt;p&gt;So a "Terms and Conditions document template for freelancers" seems to be the best option, because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is a clear &lt;strong&gt;problem&lt;/strong&gt;: creating a legally binding contract document is expensive, difficult, and boring. &lt;/li&gt;
&lt;li&gt;There is a clear &lt;strong&gt;target&lt;/strong&gt; segment: freelance web developers, like me.&lt;/li&gt;
&lt;li&gt;There is an obvious &lt;strong&gt;solution&lt;/strong&gt;: a template document that's quick to use. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution&lt;/strong&gt; is easy and obvious: just take what I've been using and refining for so many years and repurpose it into a template.&lt;/li&gt;
&lt;li&gt;There is a ready &lt;strong&gt;distribution&lt;/strong&gt; channel: the small audience that I have and taking advantage of the #GumroadDay hashtag on Twitter for discovery.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating the product
&lt;/h2&gt;

&lt;p&gt;This was easy. &lt;/p&gt;

&lt;p&gt;All I had to do was take the document, and replace all mention of my business name with this placeholder: [[ YOUR BUSINESS NAME ]].&lt;/p&gt;

&lt;p&gt;I assumed that potential customers for this document template would be freelancers who are less experienced. So I needed to include a simple "user guide". &lt;/p&gt;

&lt;p&gt;In doing so, I realised that Terms and Conditions document on its own is half the solution, because there's usually another document that accompanies it: a Proposal document. So I decided to also add a simple Proposal template into the package. &lt;/p&gt;

&lt;p&gt;Again, this is easy because I already have one I've been using for my own client projects.&lt;/p&gt;

&lt;p&gt;The result is a package consisting of a &lt;a href="https://gumroad.com/l/freelance_docs" rel="noopener noreferrer"&gt;Proposal template and a Terms and Conditions template for freelance web developers&lt;/a&gt;, in Google Docs format.&lt;/p&gt;

&lt;p&gt;Total time: 1 hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Packaging and sales copy
&lt;/h2&gt;

&lt;p&gt;Next, I had to sell it on Gumroad. And this actually took a bit of time. &lt;/p&gt;

&lt;p&gt;First I had to write the sales copy. Next I had to include a couple of screen grabs to show what the documents look like. And finally, I needed a cover image for the product.&lt;/p&gt;

&lt;p&gt;For the sales copy, luckily I already had a prior product on Gumroad (an eBook) which I can refer to. I just used the sale copy structure from that product and tweaked it.&lt;/p&gt;

&lt;p&gt;For the cover image, I went on Canva and looked for some ready made templates I can use. I did find one that I like, and spent 10 minutes just changing the copy. &lt;/p&gt;

&lt;h2&gt;
  
  
  Promotion
&lt;/h2&gt;

&lt;p&gt;Once I've created the product on Gumroad and published it, I tweeted it out with the #GumroadDay tag for visibility.&lt;/p&gt;

&lt;p&gt;I also shared it with a handful of forums and groups I'm a part of, on Slack and Telegram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;Only 7 copies sold, but, the first sale came in within 5 minutes! &lt;/p&gt;

&lt;p&gt;I wasn't actually expecting to sell any as the challenge was mainly to see if I could create and sell in an hour. &lt;/p&gt;

&lt;p&gt;But the beauty of creating a digital product is that you can keep selling it many times. &lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learnt
&lt;/h2&gt;

&lt;p&gt;The whole process from idea to sale took 2 hours. I didn't quite meet the 1-hour challenge I gave myself, but 2 hours is still quick. &lt;/p&gt;

&lt;p&gt;What I underestimated was the time required for packaging and sales. This took about an hour.&lt;/p&gt;

&lt;p&gt;Giving myself a very tight time constraint was fantastic for focus. There was no time to waste time on "research" and there was no time for perfectionism. There was only one goal: ship.&lt;/p&gt;

&lt;p&gt;This meant I had to work with what I had and what I knew, and this is something a lot of founders lose sight of, me included. &lt;/p&gt;

&lt;p&gt;Using what you know and selling it to people you already have access to can save you months of time. &lt;/p&gt;

&lt;p&gt;Riding on a trend is also a great way to get exposure. In the case of this product, it was #GumroadDay in Twitter. I could also look out for other trends in future, for example #FreelanceDay and create a promotion for it.&lt;/p&gt;

&lt;p&gt;So, in the end, 7 sales isn't much. But I can reinvest that money into ads and more marketing to try and sell more. &lt;/p&gt;

&lt;p&gt;To me, the main lesson is this: &lt;/p&gt;

&lt;p&gt;Building and launching requires less time than you think.&lt;/p&gt;

&lt;p&gt;Here's the end result: &lt;a href="https://gumroad.com/l/freelance_docs" rel="noopener noreferrer"&gt;Freelance Web Dev Proposal and T&amp;amp;C Templates&lt;/a&gt;&lt;/p&gt;

</description>
      <category>freelance</category>
      <category>templates</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
