Cobbling together my first tech stack


[03-2021 / English / 701 words]

Lately I’ve got several questions by technically-minded users, and colleagues from AustrianStartups regarding the details of how MechanicalQuill works. I’m of course always happy to talk about my startup, and in this blog post I will shine some light on what I am using as my tech stack. For that, I will be going from the ground up, moving from the infrastructure layer to the backend, and then the frontend of the application.



MQL is written in Flask and hosted on Pythonanywhere. I chose Pythonanywhere because of its full commitment to Python webhosting, its fair pricing and its good UI. Flask is a lightweight Python framework to create dynamic websites and -apps. The reason that I chose Flask over the more popular Django is that Flask is more decision-agnostic and gives me more configuration choices instead of having strong defaults. So far, this has worked great for me, and has taught me a lot about how a responsive website actually processes requests, and how it interacts with a database. For the database side of the application, I am using the Flask-SQLAlchemy package to run SQLite. I chose SQLite since it works from a single file, and doesn’t need an extra database server to run.

MechanicalQuill’s text generation model is hosted on Google Cloud Run in a Docker container. The Flask app communicates via a stateless JSON-based API with the GCR environment, and provides it with submitted user text over an encrypted connection. This is where the heavy lifting is done, and new text is generated based on pre-trained machine-learning models. The freshly created text is then sent back to the user’s web session, where it shows up as suggestions on how the user can continue their story.

GCR is a great cloud service that allows me to pack my whole textual generation (inference) model, including the Tensorflow code to run it, into one container that is only spun up when a request is made. With GCR I do not have to manage a full server with all its dependencies. Even more importantly, I am billed per request, not per time the service is available. For my early-stage startup this is a difference of day and night. Currently, I am paying only a few cents per day to host several machine-learning models. With a very large increase in user count (which I hope to reach someday) it will probably be cheaper to serve requests from a dedicated webserver, but this depends on a lot of variables, like whether the requests are spread out evenly during the day, or occur all in the same few hours.

MQL’s frontend consists of several static pages, and a dynamic login system with basic user management. A logged-in user can write text and submit the text via a button to receive several suggestions on how to continue the story. It was surprisingly difficult for me to create a bare-bones text field in the browser that behaves like a user would expect it to work (e.g. like Microsoft Word). I first tried using a content-editable <div>, since it expands and shrinks by default when text is added or deleted. However, hacking a <div> for this purpose had many disadvantages, and was not treated the same way by different browsers. This is why I chose to use the html <textarea> instead and augmented it with autosize, a script for automatic resizing.

For a lack of a better alternative, I am currently using Google Analytics to understand which audience I am reaching. When I have more time at hand, and a small budget to spend, I plan to migrate to another analytics provider to avoid having my user sessions logged by Google. Right now, however, GA is simply the easiest (and free) analytics solution that works out of the box. For email hosting, I tried Zoho but was disappointed by its chaotic UI – instead, I switched to Migadu, which I recommend. At a later stage, when I have more emails to send, I plan to use an automated email sending service like Sendgrid or Mailchimp.

Thanks for reading! I appreciate any feedback, and I’m always happy to talk. You can reach me via fd (at) fabiandietrich (dot) com