Building an AI Resume Analyzer with Flask and Monitoring It with SigNoz


I built a simple AI Resume Analyzer, but instead of focusing only on the UI, I looked into understanding what happened inside the backend when a resume was uploaded. That led me to instrument the application with OpenTelemetry and visualize the complete request flow in SigNoz.

Source Code

If you'd like to explore the code, modify the project, or run it on your own machine, the complete source code is available on GitHub.

GitHub Repository:
https://github.com/Amit-sandhu/Resume-Analyzer-Signoz





Above screenshots are from the AI Resume Analyzer source code and active web browser.
Using Flask and vanilla JavaScript, the application accepts a PDF resume, extracts its text, analyzes skills and ATS compatibility, and returns personalized feedback.




To run SigNoz locally, installed Docker on Xubuntu 24.04 and deployed the complete observability stack on my machine. Running everything locally allowed me to instrument the application, generate traces, and experiment freely without depending on any cloud services or external infrastructure. 

Running SigNoz

After Docker was working, I deployed SigNoz locally. I chose to run it on my own machine instead of using any cloud setup because it made testing much easier while building the project.

The installation itself wasn't completely smooth. I ran into Docker permission issues, PATH problems with foundryctl, and had to restart a few things before all the containers were finally up and running. Once everything started successfully, I could access the SigNoz dashboard from my browser.

At this point, the dashboard was empty because my Flask application wasn't sending any telemetry yet.



Connecting my Flask application


The next step was making my Resume Analyzer talk to SigNoz.

I added OpenTelemetry instrumentation to the Flask application and created spans around the main parts of the request pipeline instead of treating the entire request as one big operation.

The spans I added were:

  • save_upload
  • extract_text
  • analyze_resume
  • calculate_score
  • generate_suggestions

This way I could see exactly where the application was spending time whenever someone uploaded a resume.



First Trace 

This was honestly the coolest part of the project.

I uploaded a resume through my web application and refreshed SigNoz. A few seconds later, my application showed up in the Services page and I could open the trace for the request.

Instead of seeing just one request, I could actually see every processing step inside it.


Looking at the trace

The trace made it pretty obvious where most of the time was being spent.

For one of my test resumes I got something close to this:

  • POST /analyze → around 88 ms
  • extract_text → around 40 ms
  • analyze_resume → around 30 ms
  • calculate_score → less than 1 ms
  • generate_suggestions → almost instant

The biggest surprise was that extracting text from the PDF actually took more time than the resume analysis itself.

Without tracing, I would've probably guessed the opposite.


Service Metrics

After running the application a few more times, the Service Metrics page started showing useful information.

Instead of manually measuring response times, I could quickly see the latency of different operations and compare them.

Even though this is a small project, it gave me a much better idea of how observability tools help while debugging or optimizing backend applications.

Trying something weird

I also wanted to see what would happen if I uploaded something that wasn't actually a resume.

Since the website only accepts PDFs, I uploaded a bill instead.

The application didn't crash.

It still extracted the text, analyzed whatever it found, and gave the document an Overall Resume Score of 2/100 and an ATS Score of 20/100.

That was actually nice to see because it meant the pipeline handled unexpected PDFs gracefully instead of just failing.

                    

( As a sanity check, I uploaded a non-resume PDF (a bill). The application didn't fail it extracted the text, analyzed it, and produced very low resume and ATS scores. This confirmed that the pipeline is resilient to unexpected PDF content. )


Final Thoughts

This project started as a simple AI Resume Analyzer built with Flask, but by the end I had also learned how to instrument a backend application using OpenTelemetry and visualize its behavior with SigNoz.

Instead of only checking whether the application worked, I could actually see what happened behind the scenes whenever a resume was uploaded. The traces and metrics made it much easier to understand which parts of the request took the most time and how the different processing stages worked together.

I also got hands-on experience with Docker, local deployments, OpenTelemetry, and SigNoz, which were all new to me before starting this project.

Overall, this was a really fun project to build, and it gave me a much better understanding of observability than I could have gotten by just reading documentation.

Thanks for reading!

Happy Coding :D 

Comments