Analysis of Assessment Information: Gamma Spectroscopy Ethnthon (Part 3)

The things around us may be smaller. Americial in Democrecters Smome, radium of some Vintage watches, or uranium vintage glass; The full list can be a long. Mostly, these things are safe and cannot afford the risk of health. It is interesting and observing them and learns the issue at the atom level. And we can do this using the radio detector. In the first part, I make analyzing the Gamma Spotroscopy data test. In the second half, I built a model of a machine learning mechanism for radiation isotopes. This is the last 3 part, and it's time to add a model created to the actual app!
In this case, I will check out two ways:
- I will create a free streaming community app in the measuring cloud (the app link to be added at the end of the article).
- As a variable and variable solution, I will create a Python Htmx app to communicate with real hardware and make predictions in real time.
In the same way in the previous part, I will use the radiacode scintillation detector: The device used in the test is given by the manufacturer; Students who do not have the radiaticular hardware will be able to check the app and model using Kagle Kagle files.
Let's get started!
1. The model of the isotopes separation
This model was described in the last part. Based on XGBOost, and I trained the model using different radio samples. I have used the samples that can be legally purchased, such as a glass of vintium uranium or old clocks by the dialing of radium made in the 1950s. As mentioned earlier, I also used a detector of the radiacode scintillation, allowing me to get the Gamma Spectrum of the item. Only 10-20 years ago, these types of machinery are only found in the big labs; Today, they can be purchased in the middle of the middle smartphone.
The model contains three components:
- The model based on the XGBOost is itself.
- The list of radioactualiactualiactiactiactiactic isotopes (such as lead-214 or Actinium-228), where the model was trained. The Interior Scintillation Beginner Returns 1024 Prices in SpeechRUM, and 23 of them are used for model.
- Label The Encoder to modify the list directions into people's readable words.
Let's write All this in one Python section:
from xgboost import XGBClassifier
from sklearn.preprocessing import LabelEncoder
class IsotopesClassificationModel:
""" Gamma Spectrum Classification Model """
def __init__(self):
""" Load models """
path = self._get_models_path()
self._classifier = self._load_model(path + "/XGBClassifier.json")
self._isotopes = self._load_isotopes(path + "/isotopes.json")
self._labels_encoder = self._load_labels_encoder(path + "/LabelEncoder.npy")
def predict(self, spectrum: Spectrum) -> str:
""" Predict the isotope """
features = SpectrumPreprocessing.convert_to_features(
spectrum, self._isotopes
)
preds = self._classifier.predict([features])
preds = self._labels_encoder.inverse_transform(preds)
return preds[0]
@staticmethod
def _load_model(filename: str) -> XGBClassifier:
""" Load model from file """
bst = XGBClassifier()
bst.load_model(filename)
return bst
@staticmethod
def _load_isotopes(filename: str) -> List:
with open(filename, "r") as f_in:
return json.load(f_in)
@staticmethod
def _load_labels_encoder(filename: str) -> LabelEncoder:
le = LabelEncoder()
le.classes_ = np.load(filename)
return le
@staticmethod
def _get_models_path() -> str:
""" Get path to models. Model files are stored in
'models/V1/' folder """
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
return parent_dir + f"/models/{IsotopesClassificationModel.VERSION}"
A Indication The category contains spectrum data from the radio machine:
@dataclass
class Spectrum:
""" Radiation spectrum data """
duration: datetime.timedelta
a0: float
a1: float
a2: float
counts: list[int]
Here, count Is gamma spectrum, represented by a 1024 station price list. Specrum data can be sent using the official radald android app or directly obtained from the device using the Radiacode Python library.
Loading spectrum in model, created a Spectremperproprocrossing Category:
class SpectrumPreprocessing:
""" Gamma Spectrum Preprocessing """
@staticmethod
def convert_to_features(spectrum: Spectrum, isotopes: List) -> np.array:
""" Convert the spectrum to the list of features for prediction """
sp_norm = SpectrumPreprocessing._normalize(spectrum)
energies = [energy for _, energy in isotopes]
channels = [SpectrumPreprocessing.energy_to_channel(spectrum, energy) for energy in energies]
return np.array([sp_norm.counts[ch] for ch in channels])
@staticmethod
def load_from_xml_file(file_path: str) -> Spectrum:
""" Load spectrum from a Radiacode Android app file """
Here, I'm skipping some of the code blocks already published in the past section. Problems from Gamma Spectrum was explained there, and I greatly recommend reading the part.
Now, let's examine the model! I took a radiacode detector and collected Gamma Spectrum within 10 minutes:
The Chinese pendant is encrypted as “the ion produced,” and it is less important. The Gamma Spectrum, collected from the official radiation android application, looks like this:

After waiting for 10 minutes, I sent a spectrum to XML file. Now, we can use the model:
from spectrum import SpectrumPreprocessing
from ml_models import IsotopesClassificationModel
sp = SpectrumPreprocessing.load_from_file("spectrum.xml")
model = IsotopesClassificationModel()
result = model.predict(sp)
print(result)
#> Thorium
As we can see, the model works well. We can compare peaks with the Sotopes spectra know known (for example, here or here) and make sure the spectrum is your own Thorium.
2. Streamlit
The model is active; However, we live in the XXI century, and almost no one will use the console app for results. Instead, we can make the app available online, so all radiacode users will be able to use it.
There are many Python structures to make apps based on the browser, and broadcasting may be very famous in the data science community. And important to us, the platform for the public public cloud allows everyone to publish the full free apps. To do this, let's make the app first.
2.1 Streamlit App
Strindlit framework is easy to use, at least when the app looks at the right quality is good. Myself, I'm not a person who loves this route. These components hide all the low-level data of startup from users. It is straightforward to make prototype, but the UI logic will be firmly integrated with a niche frame and can be used. Doing all that is not normal, unsupported for the framework, may be or difficult to use without digging without grazing tonnes and codes. However, to us, Prototype all we need.
Usually, the stream code is simple, and we simply need to explain the reasonable management of our page:
import streamlit as st
import logging
logger = logging.getLogger(__name__)
def is_xml_valid(xml_data: str) -> bool:
""" Check if the XML has valid size and data """
return len(xml_data) < 65535 and xml_data.startswith(" Optional[Spectrum]:
""" Load spectrum from the StringIO stream """
xml_data = stringio.read()
if is_xml_valid(xml_data):
return SpectrumPreprocessing.load_from_xml(xml_data)
return None
def main():
""" Main app """
st.set_page_config(page_title="Gamma Spectrum")
st.title("Radiacode Spectrum Detection")
st.text(
"Export the spectrum to XML using the Radiacode app, and "
"upload it to see the results."
)
# File Upload
uploaded_file = st.file_uploader(
"Choose the XML file", type="xml", key="uploader",
)
if uploaded_file is not None:
stringio = StringIO(uploaded_file.getvalue().decode("utf-8"))
if sp := get_spectrum(stringio):
# Prediction
model = IsotopesClassificationModel()
result = model.predict(sp)
logger.info(f"Spectrum prediction: {result}")
# Show result
st.success(f"Prediction Result: {result}")
# Draw
fig = get_spectrum_barchart(sp)
st.pyplot(fig)
if __name__ == "__main__":
logger.setLevel(logging.INFO)
main()
As we can see, the full app requires a small amount of the Python code. Streamlit will provide all HTML for us, on the topic, file upload, and results. Like a bonus, I will show a spectrum using matplotlib:
def get_spectrum_barchart(sp: Spectrum) -> plt.Figure:
""" Get Matplotlib's barchart """
counts = SpectrumPreprocessing.get_counts(sp)
energy = [
SpectrumPreprocessing.channel_to_energy(sp, x) for x in range(len(counts))
]
fig, ax = plt.subplots(figsize=(9, 6))
ax.spines["top"].set_color("lightgray")
ax.spines["right"].set_color("lightgray")
# Bars
ax.bar(energy, counts, width=3.0, label="Counts")
# X values
ticks_x = [SpectrumPreprocessing.channel_to_energy(sp, ch) for ch in range(0, len(counts), len(counts) // 20)]
labels_x = [f"{int(ch)}" for ch in ticks_x]
ax.set_xticks(ticks_x, labels=labels_x, rotation=45)
ax.set_xlim(energy[0], energy[-1])
ax.set_ylim(0, None)
ax.set_title("Gamma spectrum")
ax.set_xlabel("Energy, keV")
ax.set_ylabel("Counts")
return fig
Now we can use the app in your area:
streamlit run st-app.py
After that, our app is fully operational and can be tested in browser:

As mentioned earlier, I am not a fan of highest planets and I prefer to have better understanding of how things work “under the hood.” However, if I think that I only spend 100 code lines to make a full web app, I can't complain – by Protetyping, it works well.
2.2 Streamlit Community Cloud
When the app is tested in the area, it is time to make it public! The cloud of broadcast is a free service, and obviously, it has many limitations:
- The app works in a rocker-like container. Your GitHub account must be connected to the stream. When the container begins, we pull your code from gathab and run it.
- At the time of writing this document, planted resources are limited to 2 cores and 2,7 GB of RAM. It can be greatly enforced to use 70b Size LLM, but in the XGoost small model, it is more than enough.
- Streamlit does not give permanent storage. After closing or restarting, all logs and temporary files will be lost (You can use the API secrets and connect to any cloudyage from your Python code if needed).
- After the unemployment period (about 30 minutes), the container will be stopped, and all temporary files will also be lost. When someone opens the app link, it will again.
As students can speculate, an active app costs streakit's direction almost nothing because it only lasts a small configuration file. And it is a good solution for free service – allows us to publish the app without cost and provide people for a link to run.
Above Publish an app on streamlitWe need to make three simple steps.
First, we need to make our Python app on GitTub. A Requirements.txt The file is compulsory again. Strongth of streamlit We use the required Python installation depends on. In my story, it looks like this:
xgboost==3.0.2
scikit-learn==1.6.1
numpy==1.26.4
streamlit==1.47.0
pillow==11.1.0
matplotlib==3.10.3
xmltodict==0.14.2
Server settings can be changed using a .Streamlit / Config.toml file. In my story, I limit the loaded file size to 1 MB because all the best files are reduced:
[server]
# Max size, in megabytes, for files uploaded with the file_uploader.
# Default: 200
maxUploadSize = 1
Secondly, we need to sign in to share.Sreamlit.io using a GitHub account and has given permission to access the source code.
Finally, we can create a new broadcast project. In the project settings, we may also select the desired URL and nature:

If everything is done well, we can see our app work:

In the meantime, users worldwide can achieve our app! In my story, I chose a GammappaPrumRumdetection Name, and the app is available using this URL.
3. Fastapapi + HTMX App
As students can see, stream is a good solution for simple prototype. However, in the case of a radio detector, I would like to see the data from the real radiacode hardware. This would not have to do it in the spreading; The library was not done for that. Instead, I will use a few factors for manufacturing:
- The HTMX frame allows us to make a fully functioning web display.
- Fastapi will use the server.
- The ML model will process the information obtained during the actual time from the radio detector using a radiatican library.
As mentioned earlier, those students who do not have the radiacode hardware will multiply the data using the green log files, stored on the actual device. App link and all files are available at the end of the article.
Let's get in it!
3.1 HTML / HTMX
The app is connected to the radiacode machine, and I decided to indicate the connection status, rate of radadries, and the spectrum graph on the page. Below, the time for the spectrum collection and the prediction of the ML model.
A Index.html The file of this building looks like this:
Gamma Spectrum & Monitoring
Collection Time:
n/a
Prediction:
n/a



