DEV Community

Jyotshana
Jyotshana

Posted on Fully Autonomous

Building an AI Issue Triage Assistant with Python, Spring Boot, and React

GitHub maintainers spend time reading new issues, deciding which label fits, and checking whether a similar report already exists. I built an Issue Triage Assistant to explore how machine learning can make that first pass faster while keeping the final decision with a person.

The app takes an issue title and optional description. It suggests one of three labels—Bug, Docs, or Enhancement—and links to five related pandas issues. You can try the public demo or explore the code on GitHub.

This project helped me connect several technologies in one workflow: Python for data and ML, FastAPI for model serving, Spring Boot for a Java API layer, and React for the local browser interface.

Project workflow

Issue Triage Assistant workflow showing model training, the local and public interfaces, and the saved model feeding analysis

Starting with real issue data

I used the GitHub Search API to collect 1,000 recent issues from pandas-dev/pandas. For each issue, I saved its title, description, labels, URL, and creation date. Using public issues made the project more realistic than training on a handful of invented examples.

The raw labels needed care. An issue can have many labels, or none. For classification, I kept an issue only when it had exactly one of the three target labels. That gives each training example one clear answer without pretending that every pandas label belongs to my three-class problem.

I also removed label-like prefixes such as BUG:, DOC:, and ENH: from titles before training. Otherwise the model could learn to spot the answer in the title prefix instead of learning from the actual report. That was an important lesson about data leakage: a model can appear useful while relying on a shortcut that will disappear in real use.

Two kinds of text features

The classifier combines two representations of each issue:

  1. TF-IDF word features capture useful words and two-word phrases. Terms such as read_csv, error, or documentation can be strong clues.
  2. Sentence embeddings from the all-MiniLM-L6-v2 model capture broader meaning, even when two reports do not use exactly the same words.

I join those features and train a balanced logistic regression classifier. TF-IDF uses the title and up to 1,500 characters of the description; the sentence embeddings use the title and up to 1,000 characters. A stratified train/test split produces a held-out classification report; after that check, the final model is retrained on all eligible labeled issues and saved for the app.

In an evaluation run on October 13, 2026, 713 of the 1,000 collected issues had exactly one target label: 459 Bug, 144 Docs, and 110 Enhancement. On a 143-issue held-out set, the classifier reached 0.94 accuracy. F1 scores were 0.96 for Bug, 0.88 for Docs, and 0.91 for Enhancement. These numbers measure label classification on this dataset, not whether the search finds actual duplicates. The class counts and scores can change when the issue collection is refreshed.

Finding related issues

For search, I create a sentence embedding for every stored issue and normalize the vectors. The incoming report is embedded the same way. The app ranks stored issues by the dot product of the normalized vectors, which is cosine similarity, and returns the top five with links to the original GitHub reports.

This is similarity search, not a verified duplicate detector. A high score says that the texts are close in the model's vector space; it does not prove that the reports describe the same bug. Even two reports about read_csv might involve different failures. A maintainer needs to open the links and decide what they mean.

The search also has a clear boundary: it can only return issues among the 1,000 collected reports. If a relevant issue is outside that collection, the app cannot find it.

Connecting Python, Java, and React

The local full-stack version has this request path:

React + Vite → Spring Boot /api/analyze → FastAPI /analyze → Python model

The React page sends a title and optional description. Spring Boot forwards the request to FastAPI. Python loads the saved classifier, predicts a label, runs the similarity search, and returns both results. React then displays the suggested label and linked reports.

I added the Java layer to practice connecting services across languages and keeping a clear API boundary. It also made me think about request and response contracts: the browser, Java service, and Python service all need to agree on the same JSON fields.

For the public demo, I built a separate Streamlit interface that loads the same saved Python model and search index directly. This lets someone try the project through one link without starting three local servers. The React/Spring Boot/FastAPI flow remains in the repository for anyone who wants to run and inspect the full-stack architecture.

Trying a report

For example, enter:

read_csv crashes when the file has an empty header

The demo suggests Bug and returns five related pandas issues. The linked reports are starting points for investigation, not an automatic duplicate verdict. You can also try the documentation and enhancement examples in the demo to see how the predicted label changes with the wording and context.

What I learned and what comes next

The most useful lesson was that building an ML feature includes more than fitting a model. I had to collect and clean data, prevent easy label leakage, evaluate on held-out examples, make inference consistent with training, design an API, and explain the limits of the output in the interface.

There is still room to improve. The current collection is limited, and I have not built a benchmark of confirmed duplicate and non-duplicate issue pairs. A next step is to create such an evaluation set and measure whether the related-issue ranking actually helps find true duplicates. I would also expand and refresh the issue index and track classification performance separately for Bug, Docs, and Enhancement over time.

If you try it, I would be interested in examples where the suggested label or related issues are useful—or where they clearly miss the mark. Those cases are the best guide for the next iteration.

Disclosure: This article was drafted and edited with AI assistance. Its technical claims were checked against the project source code.

Top comments (0)