analitics

Pages

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:

Tuesday, June 9, 2026

Python Qt : Simple script to install the G'MIC archive to the Krita folder.

Today, this simple script will install the G'MIC archive to the Krita folder:
import sys
import os
import zipfile
import shutil
import subprocess
from PyQt6.QtWidgets import (
    QApplication, QWidget, QPushButton, QFileDialog,
    QVBoxLayout, QLabel, QMessageBox
)

class GMICInstaller(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("GMIC Installer for Krita")

        self.gmic_zip = ""
        self.krita_folder = ""

        layout = QVBoxLayout()

        self.label_zip = QLabel("GMIC archive: Not selected")
        self.label_krita = QLabel("Krita folder: Not selected")

        btn_zip = QPushButton("Select GMIC Archive (.zip)")
        btn_zip.clicked.connect(self.select_gmic_zip)

        btn_krita = QPushButton("Select Krita Folder")
        btn_krita.clicked.connect(self.select_krita_folder)

        btn_install = QPushButton("Install on Krita")
        btn_install.clicked.connect(self.install_gmic)

        layout.addWidget(self.label_zip)
        layout.addWidget(btn_zip)
        layout.addWidget(self.label_krita)
        layout.addWidget(btn_krita)
        layout.addWidget(btn_install)

        self.setLayout(layout)

    def select_gmic_zip(self):
        file, _ = QFileDialog.getOpenFileName(self, "Select GMIC ZIP", "", "ZIP Files (*.zip)")
        if file:
            self.gmic_zip = file
            self.label_zip.setText(f"GMIC archive: {file}")

    def select_krita_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "Select Krita Folder")
        if folder:
            self.krita_folder = folder
            self.label_krita.setText(f"Krita folder: {folder}")

    def install_gmic(self):
        if not self.gmic_zip or not self.krita_folder:
            QMessageBox.warning(self, "Error", "Select both GMIC archive and Krita folder first.")
            return

        # Step 1: Extract GMIC ZIP
        extract_path = os.path.join(os.getcwd(), "gmic_extracted")
        if os.path.exists(extract_path):
            shutil.rmtree(extract_path)
        os.makedirs(extract_path)

        with zipfile.ZipFile(self.gmic_zip, 'r') as zip_ref:
            zip_ref.extractall(extract_path)

        # Step 2: Find GMIC folder inside extracted content
        gmic_folder = None
        for root, dirs, files in os.walk(extract_path):
            if "gmic_krita_qt.dll" in files or "gmic_qt.exe" in files:
                gmic_folder = root
                break

        if not gmic_folder:
            QMessageBox.critical(self, "Error", "GMIC plugin files not found in archive.")
            return

        # Step 3: Find Krita plugin folders
        possible_paths = [
            os.path.join(self.krita_folder, "share", "krita", "pykrita"),
            os.path.join(self.krita_folder, "lib", "krita", "plugins"),
            os.path.join(os.getenv("APPDATA"), "krita", "pykrita")
        ]

        installed = False

        for path in possible_paths:
            if os.path.exists(path):
                try:
                    shutil.copytree(gmic_folder, os.path.join(path, "gmic_qt"), dirs_exist_ok=True)
                    installed = True
                except Exception as e:
                    print("Copy error:", e)

        if not installed:
            QMessageBox.critical(self, "Error", "Could not find a valid Krita plugin folder.")
            return

        # Step 4: Launch Krita
        krita_bin = os.path.join(self.krita_folder, "bin", "krita.exe")
        if os.path.exists(krita_bin):
            subprocess.Popen([krita_bin])
        else:
            QMessageBox.warning(self, "Warning", "GMIC installed, but Krita executable not found.")

        QMessageBox.information(self, "Success", "GMIC successfully installed into Krita!")

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

Monday, June 8, 2026

News : Wing Python IDE 12 Early Access.

Wing 12 is now available as an early access release that focuses on AI agent driven development. Wing 12 introduces deep integration with Claude Code, including a dedicated Claude Code tool, a new Tasks tool for planning, executing, and reviewing AI agent work, and a set of MCP servers that allow agents to work more efficiently by giving them access to Wing's source code analysis, unit testing, and debugger features.

Saturday, June 6, 2026

News : The new beta preview of Python 3.15.

Python 3.15 is still in development. This release, 3.15.0b2, is the second of four planned beta releases.
Beta release previews are intended to give the wider community the opportunity to test new features and bug fixes and to prepare their projects to support the new feature release.

Friday, June 5, 2026

News : no more bleach ...

NOTE: 2026-06-05: Bleach is no longer maintained. There will be no future releases including for security issues. See issue: https://github.com/mozilla/bleach/issues/698
Bleach is an allowed-list-based HTML sanitizing library that escapes or strips markup and attributes.
Bleach can also linkify text safely, applying filters that Django’s urlize filter cannot, and optionally setting rel attributes, even on links already in the text.

Wednesday, June 3, 2026

News : Django many security issues.

In accordance with our security release policy, the Django team is issuing releases for Django 6.0.6 and Django 5.2.15. These releases address the security issues detailed below. We encourage all users of Django to upgrade as soon as possible.

Saturday, May 30, 2026

Python 3.10.11 : MiniMax-M2.7 tested with python.

Today, I tested MiniMax-M2.7 with api key from nvidia and openai python package.
The script is one default example:
python -m pip install openai
Collecting openai
  Downloading openai-2.38.0-py3-none-any.whl.metadata (31 kB)
...
Successfully installed distro-1.9.0 jiter-0.15.0 openai-2.38.0
from openai import OpenAI

client = OpenAI(
  base_url = "https://integrate.api.nvidia.com/v1",
  api_key = "nvapi-nvidia"
)

completion = client.chat.completions.create(
  model="minimaxai/minimax-m2.7",
  messages=[{"role":"user","content":""}],
  temperature=1,
  top_p=0.95,
  max_tokens=8192,
  stream=False
)

print(completion.choices[0].message.content)
This will show only:
python minimax_27_001.py
Hello! How can I help you today?
I tested with this python script and works well:
import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                             QHBoxLayout, QTextEdit, QLineEdit, QPushButton, QLabel)
from PyQt6.QtCore import QThread, pyqtSignal, Qt
from PyQt6.QtGui import QFont
from openai import OpenAI

# --- WORKER THREAD API ---
# Previne blocarea interfeței grafice în timpul apelului de rețea
class ApiWorker(QThread):
    response_received = pyqtSignal(str)
    error_occurred = pyqtSignal(str)

    def __init__(self, user_message):
        super().__init__()
        self.user_message = user_message

    def run(self):
        try:
            # Inițializare client OpenAI cu endpoint-ul Nvidia specificat de tine
            client = OpenAI(
                base_url="https://integrate.api.nvidia.com/v1",
                api_key="nvapi-KEY"  # nvidia api key
            )

            completion = client.chat.completions.create(
                model="minimaxai/minimax-m2.7",
                messages=[{"role": "user", "content": self.user_message}],
                temperature=1,
                top_p=0.95,
                max_tokens=8192,
                stream=False
            )
            
            # Trimite răspunsul înapoi către fereastra principală
            answer = completion.choices[0].message.content
            self.response_received.emit(answer)
            
        except Exception as e:
            self.error_occurred.emit(str(e))

class MiniMaxChatApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("MiniMax M2.7 - Interactive Chat")
        self.resize(600, 700)

        # Widget-ul central și layout-ul principal
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # 1. Zona de afișare a istoricului chat-ului
        self.chat_display = QTextEdit()
        self.chat_display.setReadOnly(True)
        self.chat_display.setFont(QFont("Segoe UI", 11))
        self.chat_display.setPlaceholderText("Conversația va apărea aici...")
        main_layout.addWidget(self.chat_display)

        # 2. Zona de introducere text și butonul (aranjate pe orizontală)
        input_layout = QHBoxLayout()
        
        self.input_field = QLineEdit()
        self.input_field.setFont(QFont("Segoe UI", 11))
        self.input_field.setPlaceholderText("Scrie un mesaj sau o comandă de Windows...")
        # Trimite mesajul când apeși tasta Enter
        self.input_field.returnPressed.connect(self.send_message) 
        input_layout.addWidget(self.input_field)

        self.send_button = QPushButton("Trimite")
        self.send_button.setFont(QFont("Segoe UI", 11, QFont.Weight.Bold))
        self.send_button.clicked.connect(self.send_message)
        input_layout.addWidget(self.send_button)

        main_layout.addLayout(input_layout)

        # 3. Indicator de status (jos de tot)
        self.status_label = QLabel("Pregătit")
        self.status_label.setStyleSheet("color: gray;")
        main_layout.addWidget(self.status_label)

    def send_message(self):
        user_text = self.input_field.text().strip()
        
        if not user_text:
            return  # Nu trimite dacă e gol

        # Adaugă mesajul utilizatorului în istoric și curăță câmpul de input
        self.chat_display.append(f"Tu: {user_text}\n")
        self.input_field.clear()

        # Dezactivează butoanele în timp ce AI-ul se gândește
        self.input_field.setEnabled(False)
        self.send_button.setEnabled(False)
        self.status_label.setText("MiniMax M2.7 gândește...")

        # Pornirea Thread-ului separat pentru apelul API
        self.worker = ApiWorker(user_text)
        self.worker.response_received.connect(self.handle_response)
        self.worker.error_occurred.connect(self.handle_error)
        self.worker.finished.connect(self.cleanup_worker)
        self.worker.start()

    def handle_response(self, ai_response):
        # Afișează răspunsul primit de la MiniMax
        self.chat_display.append(f"MiniMax M2.7: {ai_response}\n")
        self.chat_display.append("-" * 40 + "\n")
        self.status_label.setText("Răspuns primit.")

    def handle_error(self, error_msg):
        # Afișează eroarea în caz că pică netul sau cheia API e greșită
        self.chat_display.append(f"Eroare: {error_msg}\n")
        self.status_label.setText("A apărut o eroare.")

    def cleanup_worker(self):
        # Reatonează butoanele după ce procesul s-a încheiat
        self.input_field.setEnabled(True)
        self.send_button.setEnabled(True)
        self.input_field.setFocus()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    chat_window = MiniMaxChatApp()
    chat_window.show()
    sys.exit(app.exec())
This is the result:

News : ... Django 6.1 alpha 1 released by Jacob Walls on May 20, 2026!

Django 6.1 alpha 1 is now available. It represents the first stage in the 6.1 release cycle and is an opportunity to try out the changes coming in Django 6.1.
Django 6.1 offers a harmonious mélange of new features and usability improvements, which you can read about in the in-development 6.1 release notes.
This alpha milestone marks the feature freeze. The current release schedule calls for a beta release in about a month and a release candidate roughly a month after that. We'll only be able to keep this schedule with early and frequent testing from the community. Updates on the release schedule are available on the Django forum.

Python Qt : Testing new google_news_api released May 22, 2026.

Today, this script will help you too search and find results with google_news_api python package, released: May 22, 2026 by Paolo Mazza. Use your keywords, or make drag and drop ... See the official website - pypi.org.
import sys
import asyncio
import webbrowser
from functools import partial

from PyQt6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout, QListWidget,
QListWidgetItem, QPushButton, QTextEdit, QLineEdit, QLabel,
QProgressBar, QFileDialog, QDialog
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal

from google_news_api import AsyncGoogleNewsClient


# ---------------------------------------------------------
# Worker Thread for Async Google News
# ---------------------------------------------------------
class NewsWorker(QThread):
progress = pyqtSignal(int)
finished = pyqtSignal(list)

def __init__(self, queries):
super().__init__()
self.queries = queries

async def fetch_news(self):
results = []
async with AsyncGoogleNewsClient(language="en", country="US") as client:
batch = await client.batch_search(
queries=self.queries,
when="7d",
max_results=10
)

for idx, (topic, articles) in enumerate(batch.items()):
for article in articles:
url = await client.decode_url(article["link"])
results.append({
"title": article["title"],
"source": article["source"],
"url": url
})

self.progress.emit(int((idx + 1) / len(batch) * 100))

return results

def run(self):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
results = loop.run_until_complete(self.fetch_news())
self.finished.emit(results)


# ---------------------------------------------------------
# HTML Results Dialog
# ---------------------------------------------------------
class ResultsDialog(QDialog):
def __init__(self, results):
super().__init__()
self.setWindowTitle("Search Results")

layout = QVBoxLayout(self)

self.text = QTextEdit()
self.text.setReadOnly(True)
layout.addWidget(self.text)

html = "<h2>Search Results</h2>"
for r in results:
html += f"""
<p>
<b>{r['title']}</b><br>
<i>{r['source']}</i><br>
<a href="{r['url']}">{r['url']}</a>
</p>
"""

self.text.setHtml(html)

save_btn = QPushButton("Save Results")
save_btn.clicked.connect(lambda: self.save_results(html))
layout.addWidget(save_btn)

def save_results(self, html):
file, _ = QFileDialog.getSaveFileName(self, "Save HTML", "", "HTML Files (*.html)")
if not file:
return
with open(file, "w", encoding="utf-8") as f:
f.write(html)


# ---------------------------------------------------------
# Main GUI
# ---------------------------------------------------------
class NewsGUI(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Google News Search Tool")
self.resize(900, 600)

main = QHBoxLayout(self)

# ---------------- LEFT: predefined keywords ----------------
left_layout = QVBoxLayout()
left_layout.addWidget(QLabel("Predefined Keywords"))

self.left_list = QListWidget()
self.left_list.setDragEnabled(True)
self.left_list.setSelectionMode(QListWidget.SelectionMode.SingleSelection)

predefined = [
"inteligență artificială", "python", "godot engine", "shaders",
"2D", "3D", "C#", "programming", "catafest",
"Catalin George Festila", "Fălticeni", "Suceava",
"investiții", "2026"
]

for word in predefined:
self.left_list.addItem(word)

left_layout.addWidget(self.left_list)

# Add custom keyword
self.add_keyword_input = QLineEdit()
self.add_keyword_input.setPlaceholderText("Add new keyword...")
left_layout.addWidget(self.add_keyword_input)

add_btn = QPushButton("Add Keyword")
add_btn.clicked.connect(self.add_keyword)
left_layout.addWidget(add_btn)

main.addLayout(left_layout)

# ---------------- RIGHT: search keywords ----------------
right_layout = QVBoxLayout()
right_layout.addWidget(QLabel("Search Keywords (drag from left)"))

self.right_list = QListWidget()
self.right_list.setAcceptDrops(True)
self.right_list.setDragEnabled(True)
self.right_list.setDefaultDropAction(Qt.DropAction.MoveAction)
right_layout.addWidget(self.right_list)

# Custom search input
self.custom_query = QLineEdit()
self.custom_query.setPlaceholderText("Custom search query...")
right_layout.addWidget(self.custom_query)

# Progress bar
self.progress = QProgressBar()
right_layout.addWidget(self.progress)

# Search button
search_btn = QPushButton("Process Search")
search_btn.clicked.connect(self.start_search)
right_layout.addWidget(search_btn)

main.addLayout(right_layout)

# ---------------------------------------------------------
# Add keyword
# ---------------------------------------------------------
def add_keyword(self):
text = self.add_keyword_input.text().strip()
if text:
self.left_list.addItem(text)
self.add_keyword_input.clear()

# ---------------------------------------------------------
# Start search
# ---------------------------------------------------------
def start_search(self):
queries = []

# from right canvas
for i in range(self.right_list.count()):
queries.append(self.right_list.item(i).text())

# custom query
if self.custom_query.text().strip():
queries.append(self.custom_query.text().strip())

if not queries:
QMessageBox.warning(self, "Warning", "No search keywords selected.")
return

self.worker = NewsWorker(queries)
self.worker.progress.connect(self.progress.setValue)
self.worker.finished.connect(self.show_results)
self.worker.start()

# ---------------------------------------------------------
# Show results dialog
# ---------------------------------------------------------
def show_results(self, results):
dlg = ResultsDialog(results)
dlg.exec()


# ---------------------------------------------------------
# MAIN
# ---------------------------------------------------------
if __name__ == "__main__":
app = QApplication(sys.argv)
gui = NewsGUI()
gui.show()
sys.exit(app.exec())
This is the result:

Friday, May 29, 2026

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: