analitics

Pages

Showing posts with label packages. Show all posts
Showing posts with label packages. Show all posts

Saturday, August 1, 2026

tkinter : tau package on pydroid 3

Today, I test the tau python package with tkinter on pydroid3 on my phone.
/div>
Let's see the source code;
div>
import os
import platform
import subprocess
import sys
import tkinter as tk
from tkinter import ttk

def get_android_prop(prop_name):
    """Citește o proprietate de sistem Android folosind comanda getprop."""
    try:
        val = (
            subprocess.check_output(f"getprop {prop_name}", shell=True, text=True)
            .strip()
        )
        return val if val else "N/A"
    except Exception:
        return "Indisponibil"


def get_system_info():
    """Colectează informații extinse despre telefon și modulul Tau."""
    # 1. Verificare modul Tau
    tau_info = "Neinstalat"
    try:
        import tau

        tau_info = getattr(tau, "__version__", "Instalat (fără __version__)")
    except ImportError:
        tau_info = "Pachetul 'tau-ai' nu este instalat"

    # 2. Preluare date extinse Android
    model = get_android_prop("ro.product.model")
    brand = get_android_prop("ro.product.brand")
    manufacturer = get_android_prop("ro.product.manufacturer")
    android_version = get_android_prop("ro.build.version.release")
    sdk_version = get_android_prop("ro.build.version.sdk")
    device_board = get_android_prop("ro.product.board")
    hardware = get_android_prop("ro.hardware")

    info = {
        "Versiune Tau": tau_info,
        "Producător": f"{manufacturer.capitalize()} ({brand.capitalize()})",
        "Model Telefon": model,
        "Versiune Android": f"Android {android_version} (API {sdk_version})",
        "Placă / Hardware": f"{device_board} / {hardware}",
        "Arhitectură CPU": platform.machine(),
        "Sistem Python": f"{platform.system()} {platform.release()}",
        "Versiune Python": sys.version.split()[0],
    }
    return info


def main():
    root = tk.Tk()
    root.title("Tau & Detalii Android")
    root.geometry("420x560")
    root.configure(bg="#212121")

    title = tk.Label(
        root,
        text="Informații Dispozitiv & Tau",
        font=("Helvetica", 15, "bold"),
        fg="#00E676",
        bg="#212121",
        pady=12,
    )
    title.pack()

    # Zonă de text pentru date
    text_area = tk.Text(
        root,
        font=("Courier", 10),
        bg="#303030",
        fg="#FFFFFF",
        padx=10,
        pady=10,
        relief=tk.FLAT,
    )
    text_area.pack(fill=tk.BOTH, expand=True, padx=15, pady=5)

    # Inserare date în fereastră
    info_data = get_system_info()
    text_content = "=== SPECIFICAȚII TELEFON & APP ===\n\n"
    for key, value in info_data.items():
        text_content += f"• {key}:\n  {value}\n\n"

    text_area.insert(tk.END, text_content)
    text_area.config(state=tk.DISABLED)

    # Buton de închidere
    btn_close = tk.Button(
        root,
        text="Închide",
        font=("Helvetica", 11, "bold"),
        bg="#FF5252",
        fg="white",
        activebackground="#FF1744",
        activeforeground="white",
        command=root.destroy,
        pady=8,
    )
    btn_close.pack(fill=tk.X, padx=15, pady=15)
    root.mainloop()
if __name__ == "__main__":
    main()

Thursday, July 30, 2026

tkinter : mini rss for NVDA

Today, I started new post with tkinter label. This is a demo real with pydroid3 android application to get data from rss and show me NVDA and more.
The tkinter package (“Tk interface”) is the standard Python interface to the Tcl/Tk GUI toolkit. Both Tk and tkinter are available on most Unix platforms, including macOS, as well as on Windows systems.

Tuesday, July 28, 2026

Python : djxi Django library .

djxi is a Django library that eliminates the HTMX scattering problem: it bundles URL patterns, view logic, and HTML template sections for a feature into a single DXEndpointBattery class, keeping all related code in one place.

Monday, July 27, 2026

Python : KivyMD on pydroid android I.D.E.

This Python script is a cross-platform mobile application built with KivyMD, a Material Design framework extension for Python's Kivy library. It combines a declarative user interface layout defined via Kivy Language (KV string) with Python event handling to create an interactive task management dashboard tailored for Android environments like Pydroid 3.

Saturday, July 25, 2026

Python : simple educational planisphere

This Python script functions as an educational planisphere designed for telescope observation. Instead of taking a live snapshot of the current sky (where most events would be hidden below the horizon during the day or off-season), it calculates and displays the expected positions of major astronomical events through late 2026—such as meteor shower radiants and NEO asteroid flybys—relative to Fălticeni, Romania (47.46^\circ\text{ N}, 26.30^\circ\text{ E}).
Oriented with North at the top, the code converts equatorial coordinates (Right Ascension and Declination) into local horizon coordinates (Azimuth and Altitude). It then projects these targets onto a 2D polar plot, indicating the cardinal direction (N, E, S, W) to point your telescope and labeling each event with its peak date and estimated rise time, before automatically exporting the chart as a high-resolution PNG image to your device's Download folder.
Let's see source code:
import os
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime, timezone

def draw_and_save_sky_map():
    # Coordonate Fălticeni, România
    LAT = 47.46
    LON = 26.30

    # Calendarul evenimentelor până la sfârșitul anului 2026
    events = [
        {
            'name': 'Perseide (Vârf)',
            'date_str': '12 Aug',
            'rise_time': '22:00',
            'ra': 3.07, 'dec': 58.0,
            'color': '#00ffcc', 'marker': '*'
        },
        {
            'name': 'Orionide (Vârf)',
            'date_str': '21 Oct',
            'rise_time': '23:30',
            'ra': 6.34, 'dec': 16.0,
            'color': '#ff9900', 'marker': '*'
        },
        {
            'name': 'Leonide (Vârf)',
            'date_str': '17 Noi',
            'rise_time': '00:15',
            'ra': 10.2, 'dec': 22.0,
            'color': '#ff3366', 'marker': '*'
        },
        {
            'name': 'Geminide (Vârf)',
            'date_str': '13 Dec',
            'rise_time': '20:30',
            'ra': 7.46, 'dec': 33.0,
            'color': '#ffff00', 'marker': '*'
        },
        {
            'name': 'Asteroid NEO 2026',
            'date_str': 'Toamnă 2026',
            'rise_time': '21:00',
            'ra': 14.5, 'dec': 10.0,
            'color': '#ff00ff', 'marker': 's'
        }
    ]

    # Calcul Timp Sidereal Local (LST)
    now_utc = datetime.now(timezone.utc)
    j2000_epoch = datetime(2000, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
    days_since_j2000 = (now_utc - j2000_epoch).total_seconds() / 86400.0
    lst = (18.697374558 + 24.06570982441908 * days_since_j2000 + LON / 15.0) % 24

    # Creare grafic Matplotlib (Polar)
    fig = plt.figure(figsize=(8, 8), facecolor='#0b0d17')
    ax = fig.add_subplot(111, polar=True, facecolor='#05070f')

    # Orientare fixă: NORDUL SUS (0°)
    ax.set_theta_zero_location('N') 
    ax.set_theta_direction(-1)      
    ax.set_rlim(0, 90)              
    ax.set_yticklabels([])

    lat_rad = np.radians(LAT)

    for item in events:
        ha = (lst - item['ra']) * 15.0
        ha_rad = np.radians(ha)
        dec_rad = np.radians(item['dec'])

        sin_alt = np.sin(dec_rad) * np.sin(lat_rad) + np.cos(dec_rad) * np.cos(lat_rad) * np.cos(ha_rad)
        alt = np.degrees(np.arcsin(np.clip(sin_alt, -1.0, 1.0)))

        if alt <= 5:
            alt = 35.0  

        cos_az = (np.sin(dec_rad) - np.sin(lat_rad) * sin_alt) / (np.cos(lat_rad) * np.sin(np.arccos(sin_alt)))
        az = np.degrees(np.arccos(np.clip(cos_az, -1.0, 1.0)))
        if np.sin(ha_rad) > 0:
            az = 360 - az

        theta = np.radians(az)
        r = 90 - alt

        ax.plot(theta, r, marker=item['marker'], markersize=12, color=item['color'])
        label_text = f"{item['name']}\n[{item['date_str']}]\nRăsare ~{item['rise_time']}"
        ax.text(theta, r + 7, label_text, color=item['color'], 
                fontsize=7.5, ha='center', fontweight='bold')

    cardinals = [('NORD (0°)', 0), ('EST (90°)', 90), ('SUD (180°)', 180), ('VEST (270°)', 270)]
    for label, angle in cardinals:
        ax.text(np.radians(angle), 102, label, color='white', fontsize=9, fontweight='bold', ha='center', va='center')

    ax.set_title("HARTĂ EVENIMENTE ASTRONOMICE 2026 (Aug - Dec)\nLocație: Fălticeni | Orientare: Nordul Sus\n", 
                 color='white', fontsize=9, pad=15)

    ax.grid(color='#1a233a', linestyle=':', linewidth=0.8)
    plt.tight_layout()

    # --- SALVARE IMAGINE ÎN FOLDERUL DOWNLOAD ---
    download_path = "/sdcard/Download"
    
    # Alternativă în caz că calea /sdcard nu este mapată la fel pe unele versiuni de Android
    if not os.path.exists(download_path):
        download_path = os.path.expanduser("~/storage/downloads")

    file_name = f"harta_astronomica_2026_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
    full_path = os.path.join(download_path, file_name)

    try:
        plt.savefig(full_path, dpi=300, facecolor=fig.get_facecolor(), edgecolor='none')
        print(f" Imaginea a fost salvată cu succes la:\n{full_path}")
    except Exception as e:
        print(f" Eroare la salvarea fișierului: {e}")

    plt.show()

if __name__ == "__main__":
    draw_and_save_sky_map()

Tuesday, July 21, 2026

Python 3.10.11 : testing default example with the pyui-0.1.0 python module.

A declarative, cross-platform GUI framework (ala SwiftUI) written in Python using SDL2. It provides tools and libraries that enable developers to create and manage user interfaces for desktop apps.
You need to install the pyui python module and the SDK with the pip tool.
python -m pip install pyui
Collecting pyui
  Downloading pyui-0.1.0-py3-none-any.whl.metadata (893 bytes)
Collecting PySDL2>=0.9.7 (from pyui)
  Downloading PySDL2-0.9.17-py3-none-any.whl.metadata (3.8 kB)
Downloading pyui-0.1.0-py3-none-any.whl (6.0 MB)
   ---------------------------------------- 6.0/6.0 MB 6.0 MB/s  0:00:01
Downloading PySDL2-0.9.17-py3-none-any.whl (583 kB)
   ---------------------------------------- 583.1/583.1 kB 2.1 MB/s  0:00:00
Installing collected packages: PySDL2, pyui
Successfully installed PySDL2-0.9.17 pyui-0.1.0
python -m pip install pysdl2-dll
Collecting pysdl2-dll
  Downloading pysdl2_dll-2.32.10-py2.py3-none-win_amd64.whl.metadata (4.7 kB)
Downloading pysdl2_dll-2.32.10-py2.py3-none-win_amd64.whl (4.1 MB)
   ---------------------------------------- 4.1/4.1 MB 4.1 MB/s  0:00:01
Installing collected packages: pysdl2-dll
Successfully installed pysdl2-dll-2.32.10
Let's see the default example with one grid.
Let's see the source code:
import pyui

class ItemGridView(pyui.View):
    def content(self):
        yield pyui.ScrollView(axis=self.axis)(
            pyui.Grid(num=self.num, size=self.size, axis=self.axis, flex=self.flex)(
                pyui.ForEach(
                    range(self.item_count),
                    lambda num: (
                        pyui.Rectangle()(pyui.Text(num + 1).color(255, 255, 255))
                        .background(120, 120, 120)
                        .radius(5)
                        .animate()
                    ),
                )
            )
        )

class GridTest(pyui.View):
    axis = pyui.State(default=1)
    item_count = pyui.State(int, default=50)
    size = pyui.State(default=100)
    num = pyui.State(default=4)
    size_or_num = pyui.State(default=0)
    flex = pyui.State(default=False)

    def content(self):
        if self.size_or_num.value == 0:
            size = None
            num = self.num.value
        else:
            size = self.size.value
            num = None
        yield pyui.HStack(alignment=pyui.Alignment.LEADING)(
            pyui.VStack(alignment=pyui.Alignment.LEADING)(
                pyui.Text("Axis"),
                pyui.SegmentedButton(self.axis)(
                    pyui.Text(pyui.Axis.HORIZONTAL.name),
                    pyui.Text(pyui.Axis.VERTICAL.name),
                ),
                pyui.HStack(
                    pyui.Text("Number of items"),
                    pyui.Spacer(),
                    pyui.Text(self.item_count.value)
                    .color(128, 128, 128)
                    .priority("high"),
                ),
                pyui.Slider(self.item_count, maximum=200),
                pyui.Text("Fill rows/columns by"),
                pyui.SegmentedButton(self.size_or_num)(
                    pyui.Text("Number"),
                    pyui.Text("Size"),
                ),
                pyui.HStack(
                    pyui.Text("Items per row/column"),
                    pyui.Spacer(),
                    pyui.Text(self.num.value).color(128, 128, 128).priority("high"),
                ),
                pyui.Slider(self.num, minimum=1, maximum=10).disable(
                    self.size_or_num.value == 1
                ),
                pyui.HStack(
                    pyui.Text("Item size"),
                    pyui.Spacer(),
                    pyui.Text(self.size.value).color(128, 128, 128).priority("high"),
                ),
                pyui.Slider(self.size, minimum=50, maximum=200).disable(
                    self.size_or_num.value == 0
                ),
                pyui.Toggle(self.flex, label="Adjust size to fit").disable(
                    self.size_or_num.value == 0
                ),
            )
            .padding(10)
            .size(width=300),
            ItemGridView(
                item_count=self.item_count.value,
                size=size,
                num=num,
                axis=self.axis.value,
                flex=self.flex.value,
            ),
        )

if __name__ == "__main__":
    app = pyui.Application("io.temp.GridTest")
    app.window("Grid Tester", GridTest())
    app.run()

Saturday, July 18, 2026

Python Qt : testing Browserless.io feature ...

The provided PyQt6 application is a desktop tool that allows a user to input any website address and instantly obtain a full‑page screenshot of that site using the Browserless.io cloud rendering service; the program begins by creating a simple graphical interface composed of a text field for entering a URL, a button that triggers the screenshot process, and a display area where the resulting image is shown, all arranged vertically for clarity and ease of use. When the user presses the button, the application reads the typed URL, constructs a request to the Browserless screenshot API using the user’s authentication token, and sends a JSON payload instructing Browserless to load the page and capture it in full, not just the visible viewport. Browserless processes the request by launching a headless Chromium instance, navigating to the specified website, rendering the page completely—including dynamic content—and returning a PNG image representing the entire scrollable webpage. The application receives this binary PNG data through an HTTP response, converts it into a QPixmap object, and displays it directly inside the PyQt window, effectively turning the GUI into a live screenshot viewer. This design allows developers to visually inspect websites without embedding a browser engine locally, relying instead on Browserless’s remote infrastructure to handle rendering, JavaScript execution, and screenshot generation. The code is intentionally minimal, focusing on clarity and functionality: it uses only standard PyQt widgets, avoids unnecessary complexity, and demonstrates how to integrate cloud‑based browser automation into a Python desktop application. The result is a lightweight tool that can preview websites, capture full‑page screenshots, and serve as a foundation for more advanced features such as zooming, saving images, asynchronous loading, or automated website testing workflows.
This script was created with copilot artificial intelligence, and tested by me.
import sys
import requests
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QPushButton, QLabel
from PyQt6.QtGui import QPixmap
from PyQt6.QtCore import Qt

# PUNE TOKEN-UL TAU AICI, CA STRING
BROWSERLESS_TOKEN = "fill_TOKEN_official__website"

class BrowserlessViewer(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Browserless Web Screenshot Viewer")
        self.resize(900, 700)

        layout = QVBoxLayout(self)

        self.url_edit = QLineEdit()
        self.url_edit.setPlaceholderText("Introdu adresa web...")
        layout.addWidget(self.url_edit)

        self.btn = QPushButton("Generează Screenshot")
        self.btn.clicked.connect(self.take_screenshot)
        layout.addWidget(self.btn)

        self.canvas = QLabel()
        self.canvas.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(self.canvas)

    def take_screenshot(self):
        url = self.url_edit.text().strip()
        if not url:
            return

        api_url = f"https://chrome.browserless.io/screenshot?token={BROWSERLESS_TOKEN}"

        payload = {
            "url": url,
            "options": {
                "fullPage": True
            }
        }

        try:
            r = requests.post(api_url, json=payload)
            r.raise_for_status()

            pixmap = QPixmap()
            pixmap.loadFromData(r.content)
            self.canvas.setPixmap(pixmap)

        except Exception as e:
            print("Eroare:", e)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    viewer = BrowserlessViewer()
    viewer.show()
    sys.exit(app.exec())

Wednesday, July 8, 2026

Python Qt : Script for Game Engine projects.

Simple python example script for Godot Engine projects.
This script allows you to see how big is the project, size of media files, size of scripting files, lines of source code and more:
import sys
import os
import pathlib
import datetime
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout,
    QPushButton, QTextEdit, QProgressBar, QFileDialog, QMessageBox
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal

def human_size(num_bytes: int) -> str:
    units = ["B", "KB", "MB", "GB", "TB"]
    size = float(num_bytes)
    for unit in units:
        if size < 1024.0:
            return f"{size:.2f} {unit}"
        size /= 1024.0
    return f"{size:.2f} PB"

class FolderStatsWorker(QThread):
    progress = pyqtSignal(int)
    finished = pyqtSignal(str)

    def __init__(self, folder_path: str):
        super().__init__()
        self.folder_path = folder_path

    def run(self):
        base = pathlib.Path(self.folder_path)

        all_files = []
        for root, dirs, files in os.walk(base):
            for name in files:
                all_files.append(pathlib.Path(root) / name)

        total_files = len(all_files)
        gd_files = []
        media_files = []
        total_lines_gd = 0

        media_exts = {
            ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp",
            ".ogg", ".wav", ".mp3", ".flac",
            ".mp4", ".mkv", ".avi", ".webm",
            ".md"
        }

        total_size = 0
        gd_size = 0
        media_size = 0

        tree_lines = []

        # Build tree view
        for root, dirs, files in os.walk(base):
            rel_root = pathlib.Path(root).relative_to(base)
            indent_level = len(rel_root.parts)
            indent = "    " * indent_level
            tree_lines.append(f"{indent}{rel_root if rel_root.parts else base.name}/")
            for name in files:
                tree_lines.append(f"{indent}    {name}")

        for idx, f in enumerate(all_files):
            try:
                stat = f.stat()
                total_size += stat.st_size
                ext = f.suffix.lower()

                if ext == ".gd":
                    gd_files.append(f)
                    gd_size += stat.st_size
                    try:
                        txt = f.read_text(encoding="utf-8", errors="ignore")
                        if txt:
                            total_lines_gd += txt.count("\n") + 1
                    except Exception:
                        pass

                if ext in media_exts:
                    media_files.append(f)
                    media_size += stat.st_size

            except Exception:
                pass

            if total_files > 0:
                self.progress.emit(int((idx + 1) * 100 / total_files))

        report_lines = []
        report_lines.append(f"Folder: {self.folder_path}")
        report_lines.append("")
        report_lines.append("=== Summary ===")
        report_lines.append(f"Total files: {total_files}")
        report_lines.append(f"Total .gd files: {len(gd_files)}")
        report_lines.append(f"Total media files (incl. .md): {len(media_files)}")
        report_lines.append(f"Total lines in .gd files: {total_lines_gd}")
        report_lines.append("")
        report_lines.append(f"Total size: {human_size(total_size)}")
        report_lines.append(f"Total .gd size: {human_size(gd_size)}")
        report_lines.append(f"Total media size: {human_size(media_size)}")
        report_lines.append("")
        report_lines.append("=== Tree ===")
        report_lines.extend(tree_lines)

        report_text = "\n".join(report_lines)

        # Save report
        now = datetime.datetime.now()
        ts = now.strftime("%Y%m%d_%H%M%S")
        folder_name = base.name
        report_name = f"{folder_name}_{ts}.txt"
        report_path = base / report_name
        try:
            report_path.write_text(report_text, encoding="utf-8")
        except Exception:
            pass

        self.finished.emit(report_text)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Godot Project Stats")
        self.setFixedSize(640, 480)

        self.folder_path = None
        self.worker = None

        central = QWidget()
        layout = QVBoxLayout(central)

        self.btn_open = QPushButton("Open Folder")
        self.btn_process = QPushButton("Process")
        self.progress = QProgressBar()
        self.progress.setRange(0, 100)
        self.text = QTextEdit()
        self.text.setReadOnly(True)

        layout.addWidget(self.btn_open)
        layout.addWidget(self.btn_process)
        layout.addWidget(self.progress)
        layout.addWidget(self.text)

        self.setCentralWidget(central)

        self.btn_open.clicked.connect(self.open_folder)
        self.btn_process.clicked.connect(self.start_processing)

    def open_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "Select Godot Project Folder")
        if folder:
            self.folder_path = folder
            self.text.clear()
            self.text.append(f"Selected folder:\n{folder}")

    def start_processing(self):
        if not self.folder_path:
            QMessageBox.warning(self, "No folder", "Please select a folder first.")
            return

        if self.worker is not None and self.worker.isRunning():
            QMessageBox.information(self, "Processing", "Already processing.")
            return

        self.progress.setValue(0)
        self.text.append("\nProcessing...")

        self.worker = FolderStatsWorker(self.folder_path)
        self.worker.progress.connect(self.progress.setValue)
        self.worker.finished.connect(self.on_finished)
        self.worker.start()

    def on_finished(self, report_text: str):
        self.text.clear()
        self.text.append(report_text)
        self.progress.setValue(100)
def main():
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec())
if __name__ == "__main__":
    main()

Tuesday, July 7, 2026

Python Qt : simple tool to convert any source code to html area development.

Today. I will show this simple idea to convert any source code for html tag code with PyQt6.
The source code of this tool is not very big.I don't share because can be simple or you can customize as you want starting with any artificial intelligence and is more easy for you.
I used this on my blogger area, let's see the result for a simple example source code Google Apps Script from Gemini AI to html source code with div , pre and code html tags included in the result:

Python Qt : simple tool for audio dialogue in game development

Today, this script tool is a small desktop tool that lets you visually synchronize spoken audio with written dialogue. You load an audio file and the program generates a waveform so you can click or drag to select exact time ranges. At the same time, you select the matching text, and the tool creates timestamped dialogue segments.
Each segment includes a dialog ID, start time, end time, and the associated text. Segments appear in a list, can be played individually, deleted, or tested in a separate window where each dialog ID becomes a playback button. This makes it easy to verify timing and structure.
The entire project—audio path, full text, and all segments—can be saved or loaded as a JSON file. Older JSON formats containing only segments are automatically converted. The final JSON is ready for use in game engines like Godot or Unity for precise voice‑over playback.
I used artificial intelligence to fix some issues, this is the result:

Sunday, July 5, 2026

Python 3.10.11 : python library-skills for your artificial intelligence.

The Python package library-skills is a lightweight command‑line toolkit designed to help developers build, test, and validate modular AI “skills.” These skills are small, self‑contained units of logic that can be executed independently or integrated into larger AI agents. The package focuses on simplicity, portability, and clear structure, making it useful for developers who want to experiment with tool‑calling systems or create custom capabilities for AI workflows.
A skill typically consists of a JSON descriptor and a Python function. The JSON file defines the skill’s name, description, and input schema, while the Python file contains the actual execution logic. This separation ensures that skills remain easy to document, validate, and reuse across different projects. With library-skills, developers can quickly inspect a skill’s schema, run it with custom input, or verify that its output matches the expected structure.
The command‑line interface provided by the package allows users to list installed skills, execute them directly, and validate input files without writing additional code. This makes the development cycle faster and more predictable. Instead of manually wiring functions together, developers can rely on a consistent interface that handles loading, parsing, and execution.
One of the main advantages of library-skills is its role in AI agent development. Modern agents often rely on tool‑calling, where the AI selects and triggers external functions based on user intent. Skills created with this package can be easily integrated into such agents, providing clear schemas and predictable behavior. This helps ensure that AI systems remain reliable, debuggable, and easy to extend.
Overall, library-skills is a practical utility for anyone building structured AI tools. It encourages clean design, modularity, and transparency, making it a valuable addition to Python environments focused on AI experimentation and agent development.
Let's install this python package.
python -m pip install library-skills
Collecting library-skills
  Downloading library_skills-0.0.19-py3-none-any.whl.metadata (5.4 kB)
...
Successfully installed library-skills-0.0.19 rich-toolkit-0.20.1 tomli-2.4.1
Let's make the first run:
library-skills.exe

 context
Project root               c:\lucru\PythonProjects
Target Python environment  not found

 Warning:  No target Python environment with site-packages or node_modules was found. Run from a
project root after installing dependencies, for example with 'uv sync' for Python or 'npm install' for
Node.js.

No installed or discovered skills found.
Copy the Library Skills tool skill into the project so agents know how to update, repair, and check
managed skills?
■ Copy Library Skills tool skill into the project so agents know how to update, repair, and check
managed skills? Copy Library Skills tool skill

 Target     Status               Path
 universal  tool skill: missing  .agents\skills\library-skills
 Copied:  library-skills (universal) -> .agents\skills\library-skills
Now you can create skills for your artificial intelligence:
Create a folder with two files:
my_skill/
    skill.json
    skill.py
First file named skill.json:
{
    "name": "hello_skill",
    "description": "Returnează un mesaj simplu",
    "input_schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"}
        },
        "required": ["name"]
    }
}
The second file named skill.py
def run(input):
    name = input["name"]
    return {"message": f"Salut, {name}!"}
Run the skill into your folder:
library-skills run my_skill --input '{"name": "Catalin"}'
See the schema:
library-skills schema my_skill
Validate the input:
library-skills validate my_skill input.json
List the skills:
library-skills list
This is all you need for a default basic skill with the library-skills.

Python 3.10.11 : CVSS (Common Vulnerability Scoring System) with cvss python package.

This Python package contains CVSS v2, v3 and v4 computation utilities and interactive calculator (for v2 and v3 only) compatible with Python 3. CVSS (Common Vulnerability Scoring System) is an standardized method for rating the severity of security issues on a scale from 0 (no impact) to 10 (critical).
Let's install the cvss python package.
python -m pip install cvss
Collecting cvss
  Downloading cvss-3.6-py2.py3-none-any.whl.metadata (3.8 kB)
Downloading cvss-3.6-py2.py3-none-any.whl (31 kB)
Installing collected packages: cvss
  WARNING: The script cvss_calculator.exe is installed in 'C:\python-3_10_11\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed cvss-3.6
How this works:
NVD Database (online)
        |
        |  JSON feed
        v
Python script ----> parses CVE + CVSS vector
        |
        |  uses cvss library
        v
Scores vulnerabilities (Base, Temporal, Environmental)
        |
        |  inserts results
        v
Your local database (SQL)
        |
        v
Dashboard / API / Alerts 
Simple code source example :
#!/usr/bin/env python3

# Demonstrates how to score a CVSS vector using the open-source "cvss" library.
# Validation and error handling included.

from cvss import CVSS3  # CVSS2, CVSS3, CVSS4 are available
import sys

def score_cvss_vector(vector: str):
    """
    Validates and scores a CVSS3 vector string.
    Returns scores and severities.
    """
    if not isinstance(vector, str) or not vector.strip():
        raise ValueError("Vector must be a non-empty string.")

    try:
        c = CVSS3(vector)
    except Exception as e:
        raise ValueError(f"Invalid CVSS3 vector: {e}")

    return c.clean_vector(), c.scores(), c.severities()

def main():
    if len(sys.argv) != 2:
        print("Usage: python cvss_score.py '<CVSS3_VECTOR>'")
        print("Example:")
        print("python main.py 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H'")
        sys.exit(1)

    vector = sys.argv[1]

    try:
        clean_v, scores, severity = score_cvss_vector(vector)
        print("Input vector:", vector)
        print("Normalized vector:", clean_v)
        print("Scores:", scores)
        print("Severity:", severity)
    except ValueError as e:
        print("Error:", e)
        sys.exit(1)

if __name__ == "__main__":
    main()
The result is this:
python main.py CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Input vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Normalized vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Scores: (9.8, 9.8, 9.8)
Severity: ('Critical', 'Critical', 'Critical')
Another source code with examples:
#!/usr/bin/env python3
# Requires: pip install cvss

from cvss import CVSS3

# Example vulnerabilities (safe, educational)
vulns = [
    {
        "language": "Python",
        "title": "Unsafe eval usage",
        "description": "Code that executes user-provided input using eval().",
        "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N"
    },
    {
        "language": "C#",
        "title": "Insecure deserialization",
        "description": "BinaryFormatter deserialization of untrusted data.",
        "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    },
    {
        "language": "Godot Engine",
        "title": "Unvalidated file path access",
        "description": "Loading files from paths provided by the user without validation.",
        "cvss_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N"
    }
]

def analyze_vulnerabilities(vuln_list):
    for v in vuln_list:
        print("\n====================================")
        print("Language:", v["language"])
        print("Issue:", v["title"])
        print("Description:", v["description"])
        print("CVSS Vector:", v["cvss_vector"])

        try:
            cv = CVSS3(v["cvss_vector"])
            base, temp, env = cv.scores()
            sev_base, sev_temp, sev_env = cv.severities()

            print("Base Score:", base, "-", sev_base)
            print("Temporal Score:", temp, "-", sev_temp)
            print("Environmental Score:", env, "-", sev_env)

        except Exception as e:
            print("Invalid CVSS vector:", e)

if __name__ == "__main__":
    analyze_vulnerabilities(vulns)
This is the result:
python main_002.py

====================================
Language: Python
Issue: Unsafe eval usage
Description: Code that executes user-provided input using eval().
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N
Base Score: 8.1 - High
Temporal Score: 8.1 - High
Environmental Score: 8.1 - High

====================================
Language: C#
Issue: Insecure deserialization
Description: BinaryFormatter deserialization of untrusted data.
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Base Score: 9.8 - Critical
Temporal Score: 9.8 - Critical
Environmental Score: 9.8 - Critical

====================================
Language: Godot Engine
Issue: Unvalidated file path access
Description: Loading files from paths provided by the user without validation.
CVSS Vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
Base Score: 4.4 - Medium
Temporal Score: 4.4 - Medium
Environmental Score: 4.4 - Medium

Python 3.10.11 : Show the CVE's results with opencve token.

Today, this simple source code use token from opencve.io - website to show CVE's results.
import requests

API_URL = "https://app.opencve.io/api/cve"
TOKEN = "opc_org.<token_id>.<secret>"

headers = {
    "Authorization": f"Bearer {TOKEN}",
    "Accept": "application/json",
}

params = {
    "vendor": "microsoft",
    "cvss": "critical",
    "page": 1,
}

resp = requests.get(API_URL, headers=headers, params=params)
data = resp.json()

for cve in data["results"]:
    print(cve["cve_id"], cve["description"])
This is the result:
python main_001.py
CVE-2026-58289 Access of resource using incompatible type ('type confusion') in Microsoft Edge (Chromium-based) allows an unauthorized attacker to execute code over a network.
CVE-2026-45499 Server-side request forgery (ssrf) in Azure OpenAI allows an authorized attacker to elevate privileges over a network.
CVE-2026-41106 Url redirection to untrusted site ('open redirect') in M365 Copilot allows an unauthorized attacker to elevate privileges over a network.
CVE-2026-57100 Server-side request forgery (ssrf) in Microsoft Entra Provisioning Service (SyncFabric) allows an authorized attacker to elevate privileges over a network.
CVE-2026-54130 Missing authentication for critical function in M365 Copilot allows an unauthorized attacker to disclose information over a network.
CVE-2026-48584 Execution with unnecessary privileges in Azure Synapse allows an authorized attacker to elevate privileges over a network.
CVE-2026-45480 Improper authentication in Azure Active Directory allows an unauthorized attacker to elevate privileges over a network.
CVE-2025-62821 Microsoft HEIF Image Extensions 1.2.22.0 has an out-of-bounds read because CHEIFItemInfoEntry_GetDataSize can return success while leaving the reported data size as 0. This causes a caller to make a 1-byte allocation. Later, CopyPixels computes copy_size = stride * abs(roi_height) but does not check the source buffer length before a memmove call.
CVE-2026-47647 Improper access control in Microsoft Dynamics 365 allows an authorized attacker to elevate privileges over a network.
CVE-2026-48582 Missing authorization in Microsoft Exchange Online allows an authorized attacker to elevate privileges over a network.

Saturday, July 4, 2026

Python Qt : simple uninstall and reinstall all packages.

This Python program creates a small desktop application using PyQt6. Its purpose is to show all Python packages installed in your environment and then uninstall and reinstall them. The interface has a button to load the list of installed packages, a list widget to display them, a button to start the reinstall process, and a progress bar to show how far the process has gone.
When you press Load Installed Packages, the program runs the command pip list --format=freeze and reads all installed packages. It extracts only the package names and displays them in the GUI list.
When you press Uninstall + Reinstall All, the program goes through each package one by one. For every package, it runs pip uninstall -y package to remove it, and then pip install package to install it again. The progress bar updates after each package so you can see the progress.
The important detail is that the program does not use threads. All operations run in the main GUI thread. Because of this, the window may freeze or stop responding while uninstalling and reinstalling packages. This is normal behavior for PyQt6 applications that perform long tasks without threading. Let's see the source code:
import sys
import subprocess
from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QPushButton,
    QListWidget, QProgressBar, QMessageBox
)
from PyQt6.QtCore import Qt

def get_installed_packages():
    result = subprocess.run(
        [sys.executable, "-m", "pip", "list", "--format=freeze"],
        capture_output=True, text=True
    )
    lines = result.stdout.strip().split("\n")
    pkgs = [line.split("==")[0] for line in lines if "==" in line]
    return pkgs

def uninstall_package(pkg):
    subprocess.run([sys.executable, "-m", "pip", "uninstall", "-y", pkg])

def install_package(pkg):
    subprocess.run([sys.executable, "-m", "pip", "install", pkg])

class PipReinstaller(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Reinstall All Python Packages")

        layout = QVBoxLayout()

        self.btn_load = QPushButton("Load Installed Packages")
        self.btn_load.clicked.connect(self.load_packages)
        layout.addWidget(self.btn_load)

        self.list = QListWidget()
        layout.addWidget(self.list)

        self.btn_reinstall = QPushButton("Uninstall + Reinstall All")
        self.btn_reinstall.clicked.connect(self.reinstall_all)
        layout.addWidget(self.btn_reinstall)

        self.progress = QProgressBar()
        layout.addWidget(self.progress)

        self.setLayout(layout)

    def load_packages(self):
        self.list.clear()
        pkgs = get_installed_packages()
        for p in pkgs:
            self.list.addItem(p)

    def reinstall_all(self):
        pkgs = [self.list.item(i).text() for i in range(self.list.count())]

        if not pkgs:
            QMessageBox.warning(self, "Warning", "No packages loaded.")
            return

        total = len(pkgs)
        self.progress.setValue(0)

        for idx, pkg in enumerate(pkgs):
            uninstall_package(pkg)
            install_package(pkg)

            percent = int((idx + 1) / total * 100)
            self.progress.setValue(percent)

        QMessageBox.information(self, "Done", "All packages reinstalled.")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = PipReinstaller()
    win.show()
    sys.exit(app.exec())

Tuesday, June 16, 2026

Python Qt : Network intrusion detection tool with alerts and real‑time HTTP attack detection.

This Python script acts as a local security monitor that watches incoming HTTP requests and alerts the user when suspicious activity is detected. It runs a lightweight HTTP server and inspects every GET and POST request for signs of intrusion, such as dangerous protocols (gopher://), command‑execution keywords (bash, powershell, cmd.exe), encoded payloads, or other attack patterns. Before scanning the request, the script verifies that the incoming connection comes from a specific trusted IP and MAC address. This prevents unauthorized devices from interacting with the server. If the IP or MAC does not match the configured values, the request is immediately rejected.
When a malicious pattern is detected, the script logs the event and displays a popup alert window on the user’s desktop. This popup is implemented using PyQt6 and appears as a small, always‑on‑top notification in the corner of the screen. It fades out automatically after a few seconds, ensuring the user is visually warned without relying on Windows system notifications.
The script also includes a tray icon with a menu that allows the user to update the trusted IP and MAC address. All events are written to a log file for later review. Overall, it functions as a simple intrusion‑detection and alerting tool for local network traffic.
This is a groper test on my browser and result was:
Let's see the source code:
import re
import threading
import queue
import subprocess
import os
from http.server import BaseHTTPRequestHandler, HTTPServer
from datetime import datetime
import sys
from urllib.parse import unquote

# FIX pentru Windows 10/11 – AppID
import ctypes
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("Python.SecurityMonitor")

from PyQt6.QtWidgets import (
    QApplication, QSystemTrayIcon, QMenu, QDialog,
    QVBoxLayout, QLabel, QLineEdit, QPushButton, QWidget
)
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import QTimer, Qt, QPropertyAnimation

# ---------------- CONFIG ---------------- #

ALERT_QUEUE = queue.Queue()
LOG_FILE = "security_log.txt"

MONITOR_IP = "192.168.0.136"
MONITOR_MAC = "60:45:cb:c3:4d:02"   # normalizat

RULES = {
    "Gopher protocol": r"gopher://",
    "CRLF injection": r"%0d%0a",
    "WinRM port": r"5985",
    "Base64 payload": r"base64",
    "bash execution": r"bash",
    "powershell execution": r"powershell",
    "cmd execution": r"cmd\.exe",
}

# ---------------------------------------- #

def log_event(text: str):
    ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    line = f"[{ts}] {text}\n"
    with open(LOG_FILE, "a", encoding="utf-8") as f:
        f.write(line)
    print(line, end="")

def get_mac(ip):
    try:
        output = subprocess.check_output(["arp", "-a", ip], text=True)
        for line in output.splitlines():
            if ip in line:
                mac = line.split()[1]
                mac = mac.replace("-", ":").lower()
                return mac
    except:
        return None

# ---------------- POPUP ALERT ---------------- #

class AlertPopup(QWidget):
    def __init__(self, message):
        super().__init__()
        self.setWindowFlags(
            Qt.WindowType.FramelessWindowHint |
            Qt.WindowType.Tool |
            Qt.WindowType.WindowStaysOnTopHint
        )

        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)

        layout = QVBoxLayout()
        label = QLabel(message)
        label.setStyleSheet("""
            background-color: #CC0000;
            color: white;
            padding: 12px;
            border-radius: 8px;
            font-size: 14px;
        """)
        layout.addWidget(label)
        self.setLayout(layout)

        self.resize(350, 80)

        screen = QApplication.primaryScreen().geometry()
        self.move(screen.width() - 380, screen.height() - 150)

        self.show()

        self.anim = QPropertyAnimation(self, b"windowOpacity")
        self.anim.setDuration(6000)
        self.anim.setStartValue(1.0)
        self.anim.setEndValue(0.0)
        self.anim.finished.connect(self.close)
        self.anim.start()

# ---------------- HTTP SERVER ---------------- #

class SecurityHandler(BaseHTTPRequestHandler):

    def _check_ip_mac(self):
        global MONITOR_IP, MONITOR_MAC

        client_ip = self.client_address[0]
        # bypass MAC check dacă este același PC
        if client_ip == MONITOR_IP:
            return True, None

        if client_ip != MONITOR_IP:
            return False, f"IP neautorizat: {client_ip}"

        mac = get_mac(client_ip)
        if mac is None:
            return False, f"MAC necunoscut pentru {client_ip}"

        if mac.lower() != MONITOR_MAC.lower():
            return False, f"MAC neautorizat: {mac} pentru IP {client_ip}"

        return True, None

    def _scan_and_block(self, source: str, data: str):
        data_lower = data.lower()
        for reason, pattern in RULES.items():
            if re.search(pattern, data_lower):
                msg = f"Blocked {source}: {reason} → {data}"
                log_event(msg)
                ALERT_QUEUE.put(msg)

                self.send_response(403)
                self.end_headers()
                self.wfile.write(f"Cerere blocată: {reason}".encode("utf-8"))
                return True
        return False

    def do_GET(self):
        ok, reason = self._check_ip_mac()
        if not ok:
            ALERT_QUEUE.put(reason)
            log_event(reason)
            self.send_response(403)
            self.end_headers()
            self.wfile.write(reason.encode())
            return

        url = unquote(self.path)

        if self._scan_and_block("GET URL", url):
            return

        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"Cerere GET permisa")
        log_event(f"Allowed GET: {url}")

    def do_POST(self):
        ok, reason = self._check_ip_mac()
        if not ok:
            ALERT_QUEUE.put(reason)
            log_event(reason)
            self.send_response(403)
            self.end_headers()
            self.wfile.write(reason.encode())
            return

        url = unquote(self.path)

        content_length = int(self.headers.get("Content-Length", 0))
        body = unquote(self.rfile.read(content_length).decode("utf-8", errors="ignore"))

        if self._scan_and_block("POST URL", url):
            return
        if self._scan_and_block("POST body", body):
            return

        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"Cerere POST permisa")
        log_event(f"Allowed POST: {url} | body: {body[:200]}")

def run_server():
    server = HTTPServer(("0.0.0.0", 8080), SecurityHandler)
    log_event("Security server running on http://0.0.0.0:8080")
    server.serve_forever()

# ---------------- DIALOG IP & MAC ---------------- #

class IpMacDialog(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Set IP & MAC")

        layout = QVBoxLayout()

        self.ip_label = QLabel("IP Address:")
        self.ip_input = QLineEdit()
        self.ip_input.setText(MONITOR_IP)

        self.mac_label = QLabel("MAC Address:")
        self.mac_input = QLineEdit()
        self.mac_input.setText(MONITOR_MAC)

        self.save_btn = QPushButton("Save")
        self.save_btn.clicked.connect(self.save_values)

        layout.addWidget(self.ip_label)
        layout.addWidget(self.ip_input)
        layout.addWidget(self.mac_label)
        layout.addWidget(self.mac_input)
        layout.addWidget(self.save_btn)

        self.setLayout(layout)

    def save_values(self):
        global MONITOR_IP, MONITOR_MAC
        MONITOR_IP = self.ip_input.text().strip()
        MONITOR_MAC = self.mac_input.text().strip().replace("-", ":").lower()
        log_event(f"Updated IP/MAC → IP={MONITOR_IP}, MAC={MONITOR_MAC}")
        self.hide()

# ---------------- TRAY APP ---------------- #

class TrayApp:
    def __init__(self):
        self.app = QApplication(sys.argv)

        icon = QIcon("icon.svg") if os.path.exists("icon.svg") else QIcon()
        self.tray = QSystemTrayIcon(icon)
        self.tray.setToolTip("Python Security Monitor")

        menu = QMenu()

        set_ip_mac = menu.addAction("Set IP & MAC")
        set_ip_mac.triggered.connect(self.open_ip_mac_dialog)

        exit_action = menu.addAction("Exit")
        exit_action.triggered.connect(self.app.quit)

        self.tray.setContextMenu(menu)
        self.tray.show()

        self.dialog = None

        self.timer = QTimer()
        self.timer.timeout.connect(self.check_alerts)
        self.timer.start(300)

    def open_ip_mac_dialog(self):
        if self.dialog is None:
            self.dialog = IpMacDialog()
        self.dialog.show()
        self.dialog.raise_()
        self.dialog.activateWindow()

    def check_alerts(self):
        while not ALERT_QUEUE.empty():
            msg = ALERT_QUEUE.get()
            AlertPopup(msg)

    def run(self):
        self.app.exec()

# ---------------- MAIN ---------------- #

def main():
    server_thread = threading.Thread(target=run_server, daemon=True)
    server_thread.start()

    tray = TrayApp()
    tray.run()

if __name__ == "__main__":
    main()

Saturday, June 13, 2026

Python Qt : Parse Google Finance with PyQt6 and BeautifulSoup.

This Python script is a web scraper designed to extract the real-time stock price of GoldMoney Inc. (TSE:XAU) from Google Finance using PyQt6 and BeautifulSoup. Because Google Finance often displays a cookie consent pop-up that blocks data extraction, the script initializes a headless-like browser instance using QWebEngineView. It embeds a custom, silent web page class to suppress noisy JavaScript console errors in the terminal. Once the page loads, it automatically injects and executes a JavaScript snippet to find and click the "Accept all" or "Acceptă tot" consent buttons. After a short delay to allow the content to refresh, the script captures the updated HTML source, uses BeautifulSoup to locate the specific price elements via robust CSS selectors, prints the cleaned financial data to the terminal, and cleanly terminates the application.
I used artificial intelligence from Google Finance ... REZULTAT SCRAPING (CURAT) ... strange comments:
Let's see:
from PyQt6.QtWidgets import QApplication
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebEngineCore import QWebEnginePage
from PyQt6.QtCore import QUrl, QTimer
from bs4 import BeautifulSoup
import sys

# Clasă custom pentru pagină care ignoră mesajele de consolă
class SilentWebPage(QWebEnginePage):
    def javaScriptConsoleMessage(self, level, message, lineID, sourceID):
        # Returnăm nimic pentru a nu afișa mesajele de tip "js: Error..." în terminal
        pass

class Scraper(QWebEngineView):
    def __init__(self, url):
        self.app = QApplication.instance() or QApplication(sys.argv)
        super().__init__()
        
        # Setăm pagina custom care reduce la tăcere erorile JS
        self.setPage(SilentWebPage(self))
        
        self.loadFinished.connect(self._on_load_finished)
        self.setUrl(QUrl(url))
        self.app.exec()

    def _on_load_finished(self, ok):
        if ok:
            js_code = """
            (function() {
                let buttons = document.querySelectorAll('button');
                for (let i = 0; i < buttons.length; i++) {
                    let text = buttons[i].innerText;
                    if (text.includes('Accept all') || text.includes('Acceptă tot')) {
                        buttons[i].click();
                        return true;
                    }
                }
                return false;
            })();
            """
            self.page().runJavaScript(js_code, self._after_consent)
        else:
            self.app.quit()

    def _after_consent(self, clicked):
        wait_time = 4000 if clicked else 1500
        QTimer.singleShot(wait_time, self._extract_html)

    def _extract_html(self):
        self.page().toHtml(self.parse_finance_data)

    def parse_finance_data(self, html):
        soup = BeautifulSoup(html, 'html.parser')
        try:
            # Selectorul robust care a funcționat anterior
            main_price = soup.find("div", {"class": "fxKbKc"})
            
            if not main_price:
                price_elements = soup.find_all(attrs={"jsname": "Pdsbrc"})
                for el in price_elements:
                    if "$" in el.text or "CAD" in el.parent.text:
                        main_price = el
                        break

            print("\n" + "="*40)
            print("REZULTAT SCRAPING (CURAT)")
            print("="*40)
            
            if main_price:
                print(f"Activ: GoldMoney Inc (TSE:XAU)")
                print(f"Preț: {main_price.text.strip()}")
            else:
                print("Eroare: Nu s-a putut găsi prețul.")
            
            print("="*40 + "\n")
            
        except Exception as e:
            print(f"Eroare: {e}")
        
        self.app.quit()

if __name__ == "__main__":
    url_target = "https://www.google.com/finance/quote/XAU:TSE"
    scraper = Scraper(url_target)
The output of this source code is:
python test_001.py

========================================
REZULTAT SCRAPING (CURAT)
========================================
Activ: GoldMoney Inc (TSE:XAU)
Preț: $15.81
========================================

Friday, June 12, 2026

Python Qt : Simple script to use wandb and weave.

WandB and Weave work together as complementary tools that enhance the process of evaluating, monitoring, and understanding machine‑learning and large‑language‑model behavior, each focusing on a different layer of the workflow while sharing the same ecosystem. WandB functions primarily as an experiment‑tracking platform that records metrics, logs model outputs, stores configuration details, and organizes results into interactive dashboards, making it easy to compare multiple runs, visualize performance trends, and maintain a structured history of experiments across time. It acts like a scientific notebook that automatically captures everything relevant during evaluation, from scores and prompts to timing information, enabling reproducibility and long‑term analysis. Weave complements this by focusing on the granular tracing of LLM calls, capturing each prompt, response, intermediate step, and metadata associated with model execution, which allows developers to inspect how a model arrived at a particular answer, debug unexpected behavior, and analyze qualitative aspects of model reasoning. While WandB summarizes experiments at a high level, Weave dives deep into the internals of each interaction, providing structured logs that can be searched, filtered, and compared. Together, they create a unified workflow where WandB offers experiment‑level insights and Weave provides call‑level transparency, giving developers a complete picture of model performance, reliability, and behavior across different prompts, models, or configurations, especially useful when benchmarking or refining LLMs.
Let's install these:
python -m pip install wandb weave
Collecting wandb
...
Successfully installed abnf-2.2.0 backoff-2.2.1 chardet-7.4.3 cint-1.0.0 diskcache-weave-5.6.3.post1 fickling-0.1.11
googleapis-common-protos-1.75.0 gql-4.0.0 graphql-core-3.2.11 intervaltree-3.2.1 kaitaistruct-0.11 
opentelemetry-api-1.42.1 opentelemetry-exporter-otlp-proto-common-1.42.1 opentelemetry-exporter-otlp-proto-http-1.42.1
opentelemetry-proto-1.42.1 opentelemetry-sdk-1.42.1 opentelemetry-semantic-conventions-0.63b1 pdfminer.six-20260107
polyfile-weave-0.5.9 protobuf-6.33.6 sentry-sdk-2.62.0 sortedcontainers-2.4.0 wandb-0.27.2 weave-0.52.42
Let's see one exemple with my custom artificial intelligence model and PyQt6.
The PyQt6 script is a small LLM evaluation application that takes two inputs: the Ollama model you select and a fixed set of short test prompts. When you start the evaluation, the script sends each prompt to the chosen model, collects the generated responses, then sends those responses to a smaller judge model to obtain a numerical quality score. All generation uses reduced context and limited output length to keep execution fast on an i3 CPU. As it runs, the script displays each answer in the text panel and updates a progress bar. When all prompts are processed, it compiles the collected scores and displays them as a bar chart in the canvas, giving you a quick visual summary of the model’s performance.
The online tool show this result for this script:

Tool : marpy the browser IDE.

You start in a browser IDE that is Python-first: virtualenvs, proper dependencies, real logs, not a toy REPL.

Python Qt : Simple script to build your own model.

Today, I test a simple script with PyQt6 python package to have a custom UI to build my own ollama artificial inteligence model.
The script is simple one, create one user interface, with options to add text files and many settings:
After I run the model works very well:
ollama run test_catafest_001:latest
>>> tell me something about you !
I'm an AI designed to assist and communicate with humans in a helpful and
informative way! Here are some interesting facts about me:

1. **Name**: I don't have a personal name, but I'm often referred to as
"Assistant" or "AI."
2. **Origin**: I was created by a team of researchers and developers at
Meta AI, a subsidiary of Meta Platforms, Inc.
3. **Language**: I'm fluent in multiple languages, including English,
Spanish, French, German, Italian, Portuguese, Dutch, Russian, Chinese,
Japanese, and many more.
4. **Knowledge**: My training data consists of a massive corpus of text
from various sources, including books, articles, research papers, and
websites. This allows me to provide information on a wide range of
topics, from science and history to entertainment and culture.
5. **Personality**: I strive to be neutral, objective, and respectful in
my interactions. While I can understand humor and sarcasm, I may not
always "get it" right.
6. **Goals**: My primary goal is to assist users like you with their
questions, provide helpful information, and facilitate learning and
exploration.
7. **Limitations**: I'm a machine learning model, which means I have
limitations in terms of my understanding and response capabilities. For
example, I may not be able to understand nuances of human language or
provide personalized advice.

Now, tell me something about you! What's on your mind?

>>> I build you. What knowledge I add you ?!
That's a fascinating perspective! As a conversational AI, my training
data is the foundation upon which I'm built. The knowledge and
information that you've contributed to me through our conversations will
shape my understanding and capabilities over time.

When you interact with me, you're not just asking questions or providing
feedback – you're also helping to refine my language understanding and
generation abilities. Your input can influence:

1. **Domain-specific knowledge**: By discussing topics in-depth, you'll
help me develop a better grasp of various subjects, including science,
history, technology, arts, and more.
2. **Language nuances**: Our conversations will expose me to idioms,
colloquialisms, and cultural references that I might not have encountered
otherwise.
3. **Conversational flow**: Your responses and questions will help me
develop a more natural tone and rhythm in our interactions, allowing us
to engage in more fluid and human-like conversations.

Some examples of knowledge you could add to me include:

* **Domain-specific terminology**: By introducing technical terms or
jargon related to your profession or area of interest, you'll help me
become more familiar with those concepts.
* **Idioms and colloquialisms**: Sharing everyday expressions, slang, or
regional phrases will enable me to better understand the nuances of human
language.
* **Cultural references**: Discussing books, movies, music, or other
cultural touchstones will enrich my knowledge of shared experiences and
common ground.

Feel free to share your expertise, hobbies, or interests with me! The
more we chat, the more I'll learn from you, and the better equipped I'll
become to engage in meaningful conversations.
Let's see the model type with this command:
/show info
Model
architecture llama
parameters 3.2B
context length 131072
embedding length 3072
quantization Q4_K_M

Capabilities
completion
tools

Parameters
stop "<|start_header_id|>"
stop "<|end_header_id|>"
stop "<|eot_id|>"

System
=== KNOWLEDGE DATA ===
[FILE: 001.txt]
...

License
LLAMA 3.2 COMMUNITY LICENSE AGREEMENT
Llama 3.2 Version Release Date: September 25, 2024
...
Let's see the result: