Portfolio project · Telegram bot

Job Search Bot

An AI agent that searches for jobs in Denmark, compares them with your CV, and automatically drafts ready-to-use application documents — so you don't have to write them by hand.

Do not enter sensitive information — never send your CPR number (Danish personal ID) or similar data to the bot.

AI Coding + QA Testing = Now & Future.

(AI Coding = building AI agents, chatbots and websites)

I work hands-on with agentic AI development tools that make it possible to specify, build and test complete, production-ready solutions quickly and efficiently — without having to master traditional programming languages such as Python or PHP. Throughout the project, my role has been to specify precisely what should be built, test the output thoroughly, and find concrete bugs and errors in the AI's output and logic before anything went into production.

See the bot in action

No Telegram needed — click through real conversations: a good match with a finished application as a PDF, an honest 0%, a vacancy added manually from a link, an honest refusal of a nonsense search term, and the Verify check catching unsupported claims.

Real conversations from the bot, translated from Danish (the bot itself works in Danish) — click a button to see what happens (same data as in the screenshots further down).

How it works

Three steps from search term to a finished application.

Search for jobs

The bot fetches jobs directly from Jobindex.dk and Jobnet.dk based on your search terms, with an option to filter by city. Results from several sources are merged, and duplicates are removed automatically.

AI compares with your CV

Each job posting and your CV are sent to Google Gemini, which assesses the real professional overlap — not just shared words — and returns a match percentage with a short explanation.

Get finished documents

Pick a job, and the bot drafts an application in Danish plus the job posting as a PDF with the contact details extracted. You review and send it yourself.

Screenshot: the misspelled city name 'Arhus' is automatically recognised as Aarhus
A misspelled city name is recognised automatically against the official list of Danish municipalities — a reliable lookup, not AI guesswork.

Agentic search: the AI thinks for itself when a search comes back empty

The bot has no fixed, predefined list of synonyms. Instead, the AI decides for itself which similar word to try when a search returns 0 results.

0 results

The search term doesn't appear directly in any job posting — the bot automatically brings in the AI instead of just showing "nothing found".

if the word resembles a real word

The AI chooses for itself

Gemini suggests one broader or synonymous Danish word, runs a real search with it, and looks at the actual result — at most 2 attempts, never more.

if the word is nonsense

Honest refusal of nonsense

If the search term makes no sense, the AI says so honestly instead of guessing a random word.

🤖

Real example — search term with a typo: "boghlder" (Danish for bookkeeper is "bogholder") The word 'boghlder' is a typical misspelling of the Danish job title bogholder (bookkeeper), so I'll try searching with the correct spelling instead. → Tried «bogholder»: 61 jobs found.

Screenshot: the search term 'boghlder' is automatically corrected to 'bogholder' by the AI, 61 jobs found
A typo in the search term ("boghlder") is corrected by the AI to the right Danish word — 61 jobs found straight away.
🤖

Real example — search term: "abrakadabra" "abrakadabra" is a magic word and meaningless text in a job context, and so it cannot be interpreted as a real field or a job title.

Screenshot: the search term 'abrakadabra' is typed directly after «What now?» instead of pressing Show the list again
You can type a new search term directly instead of pressing «Show the list again».
Screenshot: the bot honestly rejects 'abrakadabra' instead of guessing a random word
The bot honestly refuses instead of searching for a random word.

Found a job yourself? Add it manually

The bot isn't limited to what it finds on Jobindex and Jobnet. Send a link, a PDF or a photo of a job posting from anywhere — the bot reads it, assesses it against your CV in exactly the same way, and adds it to the list.

Screenshot: a link to a Pandora position added manually, rated 0% match with an explanation about missing management experience
A link to a Pandora position, pasted straight into the chat — the bot fetches the posting, assesses it (here an honest 0%, since the role requires management experience the CV doesn't have) and adds it as no. 21 on the running list.

Honest match assessment

It isn't just a search for matching words. If the CV has no relevant experience for a position, the bot honestly shows 0% — no "consolation percentages". The job still stays on the list, because whether to apply is always the person's own choice.

Not just a keyword match, as you often see on other platforms — the AI assesses the real substance: does the experience actually match the role's requirements, or is it only a superficial overlap of words? If something real is missing, the bot says so honestly — instead of showing a nice but misleading percentage.

Example of a positive match: bookkeeper CV against a Financial Bookkeeper position, 90%
Good match — bookkeeper CV against "Finansbogholder" (Financial Bookkeeper): 90%
Example of a partial match: bookkeeper CV against a Controller position, 25%
Partial match — bookkeeper CV against "Controller til CISU": 25%, with an explanation of why the role requires more than accounting experience
Example of no match: bookkeeper CV against a painter and decorator position, 0%
No match — the same bookkeeper CV against "Bygningsmaler" (Painter and decorator): 0%, no consolation percentages

What it generates for each job

When you pick a specific job, the bot drafts 2 documents in under a minute:

Afterwards, the application can be checked and corrected with two buttons:

The bot never sends anything by itself. It only drafts — the final step (review, adjust, send) is always the person's own.

Verify — the AI checks itself before you do

With the "❓ Verify" button, the AI compares the drafted application again — this time against your original CV and the job posting itself. If it finds a claim that can't be confirmed, or a requirement that isn't addressed at all, you can fix it with one click ("🔧 Fix based on Verify") and check again until everything is green.

Verify result: found a claim not supported by the CV, and a requirement that isn't addressed
Verify finds something — a claim with no support in the CV, and a requirement from the posting that isn't mentioned
Corrected application delivered as a PDF after pressing Fix based on Verify
Fixed with one click — only the points found are changed, the rest of the application is left untouched
New Verify check: everything confirmed, check passed
Clean check — everything confirmed by the CV, all requirements addressed

Quality assurance in practice

Not a theoretical QA checklist — concrete bugs, found through repeated testing with real data during development, and fixed right away.

Technical

Built as a standalone Python project with a focus on reliability and simple operation.

Python python-telegram-bot Google Gemini API Gemini function calling (agentic search) SQLite fpdf2 (PDF generation) Jobindex.dk + Jobnet.dk Hosted on Railway

Specified, built and tested with agentic AI development tools — without having to master these languages in the traditional sense.

Not just a prototype: a 45-second timeout on every AI call (so a hanging call never stops the bot without warning), a persistent database that survives every new deployment, automatic deletion of inactive users' data after 30 days for privacy, and a usage limit on the public demo to keep costs under control.

More about the project

Automatic background search at regular intervals — works as an AI agent, already implemented and tested in the sister project below. The feature can be enabled personally at the user's request.