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
Using Flask and vanilla JavaScript, the application accepts a PDF resume, extracts its text, analyzes skills and ATS compatibility, and returns personalized feedback.
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!









Comments
Post a Comment