This blog post was written specially for DOU.

Hi, DOU!

My name is Andrii BOGDANOVYCH. I once worked as the Deputy Head of Kherson Regional State Administration, and now I am the Deputy Chairman of the State Inspection of Energy Supervision of Ukraine for Digital Development, Digital Transformations and Digitalization (CDTO), and in my free time, I write Python code, create open-source utilities, and experiment with Large Language Models.

Today, I want to share the story of transforming one project that is very important to me — "Crimea is Ukraine". This is a case about how technology helps rescue historical memory, why AI agents are the best helpers for routine migration and translation of large volumes of data, and why complex logic and patriotic "Easter eggs" should still be written solely by hand.

Background: from civil service to Python

Over six years ago, while working at the Kherson Regional State Administration, I initiated the creation of the "Crimea is Ukraine" project. The goal was simple but critical: to collect, organize, and preserve unique archival documents, articles, museum exhibits, and testimonies that prove the Ukrainian identity of Crimea and document the facts of the occupation.

Back then, in times of limited resources and tight deadlines, the website was launched on the Tilda constructor (yes, a Russian one — but at that moment, the choice of quick solutions was crucial for us). Later, I moved it to Weblium — a wonderful Ukrainian constructor. However, over time came the understanding: a historical archive must be completely independent. No closed platforms, no dependency on third-party constructors. Only open text formats, Git, and self-hosting.

This is where the technological evolution of the project began, which split into two entirely different approaches: routine automation using AI, and manual development.

Part 1. Site migration and translation (the triumph of AI agents)

I was faced with a task: to migrate hundreds of pages of content, archival documents, exhibit descriptions, and media files from the builder to the static Markdown format to run on the MkDocs engine.

Doing this manually — copying text, downloading images, rewriting links, aligning HTML grids — would take hundreds of hours of monotonous work.

I decided to run an experiment and delegated this to AI agents.

Migration result:

I didn't write a single line of code for the routine migration. The agent was tasked with exporting all existing content, converting it to clean Markdown, organizing it into folders, configuring the site, and writing custom Python plugins to automatically generate structured HTML card grids and banners based on Markdown files.

Large-scale translation via AI:

In addition to the migration itself, I had the task of creating a full English version of the archive. This meant nearly 300 historical articles and archival documents. Doing this translation manually while preserving specific terminology, proper names, and formatting would take months.

Thanks to AI agents, this process was completely automated. The agent did not just translate the texts, but preserved the entire link structure, formatting, etc. Now the site offers nearly 300 articles in two languages — Ukrainian and English.

Today, the site operates as a super-fast static archive that loads in milliseconds, is fully stored in Git, and is deployed on a self-hosted server.

Lesson #1: If the task is data migration, parsing, translating large volumes of content, or writing standard configurations — give it to AI. It will save you months of your life.

Part 2. Creating a RAG Assistant (the joy of coding by hand)

After the successful launch of the site, a new idea emerged. Reading long archives is useful, but people often want a quick answer to a specific question.

This is how the Crimea RAG (Retrieval-Augmented Generation) project was born — a chat assistant. But this time, I decided to do the opposite: no AI agents, I wrote all the code exclusively by hand.

Why? First, programming is my hobby that brings me pleasure. Second, developing the RAG required designing non-template architecture and fine-tuning.

Architecture and hand-crafted solutions:

I used the LangChain framework and the Chroma DB vector database to search for context across articles. In addition, I used Chainlit for the interface.

For generating vector embeddings, I chose the mxbai-embed-large model, which I deployed locally on my own server running Ollama. This allowed for high speed of text processing and complete independence from third-party paid APIs.

A separate architectural challenge was working with chat memory and semantic search. In real dialogues, users often ask follow-up questions, like: "And when did it happen?" or "Who was in power then?". If you pass such a question to the Chroma DB vector database directly, the search will return irrelevant content because the pronouns "it" or "then" do not carry the necessary semantic load.

To solve this problem, I built a multi-step search:

  1. The system takes the history of previous messages and the current short query of the user.
  2. A special chain via LLM analyzes the conversation context and reformulates the user's remark into an independent, informationally complete question. For example, the query "And when did it happen?" turns into "When did the transfer of Crimea to the Ukrainian SSR take place?".
  3. The resulting autonomous query is sent to the vector database for accurate document retrieval.

As the main LLM provider, I chose Lapathoniia — a Ukrainian inference provider with Mamay and Lapa models. This allowed me to preserve the Ukrainian linguistic and historical context without censorship or Western bias.

When you write code by hand, you fully control the architecture. I implemented fault tolerance myself: if the main model from Lapathoniia is temporarily overloaded or unavailable, the system automatically switches to a backup model without errors appearing to the user.

Also, multi-language localization was configured manually using Project Fluent, providing flexible management of text messages.

Patriotic "Easter eggs" vs Corporate filters

Try asking ChatGPT or Claude to write code with a sharp political subtext — corporate safety filters will immediately block your request. But when you write the code yourself, you are free to implement any ideas.

I integrated an interesting detail into the chat assistant for users with a Russian browser locale. I won't show the code or spoil the prompts in this post. Instead, I suggest you run a small experiment: set Russian as the default interface language in your browser and try talking to the chat.

I promise you will see an interesting patriotic Easter egg reminding of Ukrainians' attitude towards the leadership of the occupying country. The language model will not just talk to such a user in a certain tone, but also harmoniously weave well-known Ukrainian slogans into its answers.

Lesson #2: AI will never write for you what goes beyond the corporate safety rules of big tech companies. Creativity, humor, local patriotic context, and non-standard solutions are the realm of human freedom.

When to use AI agents and when to write code yourself?

Based on this experience, I derived a simple rule of balance:

Use AI agents for:

  • Migrating, parsing, and structuring large datasets.
  • Translating hundreds of historical or technical texts while preserving formatting.
  • Creating standard templates, simple configurations, or writing unit tests.
  • Routine refactoring.

Write code by hand for:

  • Designing architecture and complex application state management.
  • Working on fault tolerance, caching, and system integration.
  • Personal learning (if the agent writes everything, you won't understand how technology works from the inside).
  • Implementing unique creative ideas, humor, and Easter eggs blocked by AI censorship.
  • Experiencing the joy of creation.

Conclusion

AI tools are an incredible accelerator. They allowed me to completely free the site from dependency on constructors in one evening and translate 300 articles into English. But the real joy of programming starts when you close the chat window with AI, open the IDE, and start designing the system yourself.

I invite you to evaluate the results of both approaches:

View the static archive of documents:

Talk to the knowledge base:

The project code is fully open-source, and you can explore it in detail on GitHub: