Today, I worked with art artificial intelligence, to create tool for my game development.
I used python and PyQt6 and this tool help me to remove border, resize, split, rename and save images as PNG file type for Godot game engine.



Is a blog about python programming language. You can see my work with python programming language, tutorials and news.
python catafest_build_package_001.py
🔍 Verificare module standard...
[✓] Modul standard 'json' este disponibil.
[✓] Modul standard 'subprocess' este disponibil.
[✓] Modul standard 'platform' este disponibil.
[✓] Modul standard 'datetime' este disponibil.
[✓] Modul standard 'os' este disponibil.
[✓] Modul standard 'sys' este disponibil.
📦 Verificare și instalare module pip...
[✓] Modulul 'PyQt6' este deja instalat.
[✓] Modulul 'build' este deja instalat.
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
- setuptools
- wheel
...
import os
import subprocess
from PyQt6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QPushButton,
QListWidget, QMessageBox
)
# fisier download : yt-dlp.exe -vU https://www.youtube.com/watch?v=xxxxxx -f bestvideo*+bestaudio/best
FOLDER_PATH = r"D:\Software"
class FFmpegMerger(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Combinare Video + Audio cu FFmpeg")
self.resize(600, 400)
self.layout = QVBoxLayout()
self.file_list = QListWidget()
self.process_button = QPushButton("Prelucrează în MP4")
self.layout.addWidget(self.file_list)
self.layout.addWidget(self.process_button)
self.setLayout(self.layout)
self.process_button.clicked.connect(self.process_files)
self.populate_file_list()
def populate_file_list(self):
files = os.listdir(FOLDER_PATH)
video_files = [f for f in files if f.endswith(".f401.mp4")]
audio_files = [f for f in files if f.endswith(".f251-9.webm")]
base_names = set(f.split(".f401.mp4")[0] for f in video_files)
candidates = []
for base in base_names:
audio_name = f"{base}.f251-9.webm"
output_name = f"{base}.mp4"
if audio_name in audio_files and output_name not in files:
candidates.append(base)
for name in candidates:
self.file_list.addItem(name)
def process_files(self):
for i in range(self.file_list.count()):
base = self.file_list.item(i).text()
video_path = os.path.join(FOLDER_PATH, f"{base}.f401.mp4")
audio_path = os.path.join(FOLDER_PATH, f"{base}.f251-9.webm")
output_path = os.path.join(FOLDER_PATH, f"{base}.mp4")
cmd = [
"ffmpeg",
"-i", video_path,
"-i", audio_path,
"-c:v", "copy",
"-c:a", "aac",
"-strict", "experimental",
output_path
]
try:
subprocess.run(cmd, check=True)
except subprocess.CalledProcessError as e:
QMessageBox.critical(self, "Eroare", f"Eroare la procesarea {base}: {e}")
return
QMessageBox.information(self, "Succes", "Toate fișierele au fost prelucrate cu succes!")
if __name__ == "__main__":
app = QApplication([])
window = FFmpegMerger()
window.show()
app.exec()
pip install geoai-py
Successfully installed Flask-Caching-2.3.1 MarkupSafe-3.0.2 PySocks-1.7.1 PyYAML-6.0.2 absl-py-2.3.1 aenum-3.1.16 affine-2.4.0 aiohappyeyeballs-2.6.1 aiohttp-3.12.14 aiosignal-1.4.0 albucore-0.0.24 albumentations-2.0.8 aniso8601-10.0.1 annotated-types-0.7.0 antlr4-python3-runtime-4.9.3 anyio-4.9.0 anywidget-0.9.18 argon2-cffi-25.1.0 argon2-cffi-bindings-21.2.0 arrow-1.3.0 asttokens-3.0.0 beautifulsoup4-4.13.4 bitsandbytes-0.46.1 bleach-6.2.0 blinker-1.9.0 bqplot-0.12.45 branca-0.8.1 buildingregulariser-0.2.2 cachelib-0.13.0 cachetools-6.1.0 cffi-1.17.1 click-8.2.1 click-plugins-1.1.1.2 cligj-0.7.2 color-operations-0.2.0 comm-0.2.2 contextily-1.6.2 contourpy-1.3.2 cycler-0.12.1 datasets-4.0.0 decorator-5.2.1 defusedxml-0.7.1 dill-0.3.8 docstring-parser-0.17.0 duckdb-1.3.2 einops-0.8.1 eval-type-backport-0.2.2 ever-beta-0.5.1 executing-2.2.0 fastjsonschema-2.21.1 filelock-3.18.0 fiona-1.10.1 flask-3.1.1 flask-cors-6.0.1 flask-restx-1.3.0 folium-0.20.0 fonttools-4.59.0 fqdn-1.5.1 frozenlist-1.7.0 fsspec-2025.3.0 gdown-5.2.0 geoai-py-0.9.0 geographiclib-2.0 geojson-3.2.0 geopandas-1.1.1 geopy-2.4.1 gitdb-4.0.12 gitpython-3.1.44 grpcio-1.73.1 h11-0.16.0 httpcore-1.0.9 httpx-0.28.1 huggingface_hub-0.33.4 hydra-core-1.3.2 importlib-resources-6.5.2 ipyevents-2.0.2 ipyfilechooser-0.6.0 ipyleaflet-0.20.0 ipython-9.4.0 ipython-pygments-lexers-1.1.1 ipytree-0.2.2 ipyvue-1.11.2 ipyvuetify-1.11.3 ipywidgets-8.1.7 isoduration-20.11.0 itsdangerous-2.2.0 jedi-0.19.2 jinja2-3.1.6 joblib-1.5.1 jsonargparse-4.40.0 jsonnet-0.21.0 jsonpointer-3.0.0 jupyter-client-8.6.3 jupyter-core-5.8.1 jupyter-events-0.12.0 jupyter-leaflet-0.20.0 jupyter-server-2.16.0 jupyter-server-proxy-4.4.0 jupyter-server-terminals-0.5.3 jupyterlab-pygments-0.3.0 jupyterlab_widgets-3.0.15 kiwisolver-1.4.8 kornia-0.8.1 kornia_rs-0.1.9 leafmap-0.48.6 lightly-1.5.21 lightly_utils-0.0.2 lightning-2.5.2 lightning-utilities-0.14.3 localtileserver-0.10.6 mapclassify-2.10.0 maplibre-0.3.4 markdown-3.8.2 markdown-it-py-3.0.0 matplotlib-3.10.3 matplotlib-inline-0.1.7 mdurl-0.1.2 mercantile-1.2.1 mistune-3.1.3 morecantile-6.2.0 multidict-6.6.3 multiprocess-0.70.16 narwhals-1.48.0 nbclient-0.10.2 nbconvert-7.16.6 nbformat-5.10.4 numexpr-2.11.0 omegaconf-2.3.0 opencv-python-headless-4.12.0.88 overrides-7.7.0 overturemaps-0.15.0 pandas-2.3.1 pandocfilters-1.5.1 parso-0.8.4 planetary-computer-1.0.0 plotly-6.2.0 prettytable-3.16.0 prometheus-client-0.22.1 prompt_toolkit-3.0.51 propcache-0.3.2 psygnal-0.14.0 pure-eval-0.2.3 pyarrow-21.0.0 pycparser-2.22 pydantic-2.11.7 pydantic-core-2.33.2 pygments-2.19.2 pyogrio-0.11.0 pyparsing-3.2.3 pyproj-3.7.1 pystac-1.13.0 pystac-client-0.9.0 python-box-7.3.2 python-dateutil-2.9.0.post0 python-dotenv-1.1.1 python-json-logger-3.3.0 pytorch_lightning-2.5.2 pytz-2025.2 pywin32-311 pywinpty-2.0.15 pyzmq-27.0.0 rasterio-1.4.3 regex-2024.11.6 rfc3339-validator-0.1.4 rfc3986-validator-0.1.1 rich-14.0.0 rio-cogeo-5.4.2 rio-tiler-7.8.1 rioxarray-0.19.0 rtree-1.4.0 safetensors-0.5.3 scikit-learn-1.7.1 scooby-0.10.1 segmentation-models-pytorch-0.5.0 send2trash-1.8.3 sentry-sdk-2.33.0 server-thread-0.3.0 shapely-2.1.1 simpervisor-1.0.0 simsimd-6.5.0 six-1.17.0 smmap-5.0.2 sniffio-1.3.1 soupsieve-2.7 stack_data-0.6.3 stringzilla-3.12.5 tensorboard-2.20.0 tensorboard-data-server-0.7.2 tensorboardX-2.6.4 terminado-0.18.1 threadpoolctl-3.6.0 timm-1.0.17 tinycss2-1.4.0 tokenizers-0.21.2 torch-2.7.1 torchange-0.0.1 torchgeo-0.7.1 torchinfo-1.8.0 torchmetrics-1.7.4 torchvision-0.22.1 tornado-6.5.1 traitlets-5.14.3 traittypes-0.2.1 transformers-4.53.2 types-python-dateutil-2.9.0.20250708 typeshed-client-2.8.2 typing-inspection-0.4.1 tzdata-2025.2 uri-template-1.3.0 uvicorn-0.35.0 wandb-0.21.0 wcwidth-0.2.13 webcolors-24.11.1 webencodings-0.5.1 websocket-client-1.8.0 werkzeug-3.1.3 whitebox-2.3.6 whiteboxgui-2.3.0 widgetsnbextension-4.0.14 xarray-2025.7.1 xxhash-3.5.0 xyzservices-2025.4.0 yarl-1.20.1
>>> import geoai
>>> dir(geoai)
['AgricultureFieldDelineator', 'Any', 'AutoConfig', 'AutoModelForMaskGeneration',
'AutoModelForMaskedImageModeling', 'AutoProcessor', 'BoundingBox', 'BuildingFootprintExtractor',
'CLIPSegForImageSegmentation', 'CLIPSegProcessor', 'CLIPSegmentation', 'CarDetector',
'ChangeDetection', 'CustomDataset', 'DetectionResult', 'Dict', 'ET', 'GroundedSAM', 'Image',
'Iterable', 'List', 'Map', 'MapLibre', 'MultiPolygon', 'NonGeoDataset', 'ObjectDetector',
'Optional', 'OrderedDict', 'ParkingSplotDetector', 'Path', 'Polygon', 'RandomRotation',
'ShipDetector', 'SolarPanelDetector', 'Tuple', 'Union', 'Window', '__author__',
'__builtins__', '__cached__', '__doc__', '__email__', '__file__', '__loader__', '__name__',
'__package__', '__path__', '__spec__', '__version__', 'adaptive_regularization',
'add_geometric_properties', 'analyze_vector_attributes', 'batch_vector_to_raster', 'bbox_to_xy',
'box', 'boxes_to_vector', 'calc_stats', 'change_detection', 'classify', 'classify_image',
'classify_images', 'clip_raster_by_bbox', 'coords_to_xy', 'create_overview_image',
'create_split_map', 'create_vector_data', 'csv', 'cv2', 'dataclass', 'deeplabv3_resnet50',
'dict_to_image', 'dict_to_rioxarray', 'download', 'download_file', 'download_model_from_hf',
'download_naip', 'download_overture_buildings', 'download_pc_stac_item', 'edit_vector_data',
'export_geotiff_tiles', 'export_geotiff_tiles_batch', 'export_tiles_to_geojson',
'export_training_data', 'extract', 'extract_building_stats', 'fasterrcnn_resnet50_fpn_v2',
'fcn_resnet50', 'features', 'geoai', 'geojson_to_coords', 'geojson_to_xy', 'get_device',
'get_instance_segmentation_model', 'get_model_config', 'get_model_input_channels',
'get_overture_data', 'get_raster_info', 'get_raster_info_gdal', 'get_raster_resolution',
'get_raster_stats', 'get_vector_info', 'get_vector_info_ogr', 'glob', 'gpd', 'hf',
'hf_hub_download', 'hybrid_regularization', 'image_segmentation', 'inspect_pth_file',
'install_package', 'instance_segmentation', 'instance_segmentation_batch',
'instance_segmentation_inference_on_geotiff', 'json', 'leafmap', 'logging', 'maplibregl',
'mapping', 'mask_generation', 'maskrcnn_resnet50_fpn', 'masks_to_vector', 'math',
'mosaic_geotiffs', 'ndimage', 'np', 'object_detection', 'object_detection_batch', 'orthogonalize',
'os', 'pc_collection_list', 'pc_item_asset_list', 'pc_stac_download', 'pc_stac_search', 'pd',
'pipeline', 'plot_batch', 'plot_images', 'plot_masks', 'plot_performance_metrics',
'plot_prediction_comparison', 'plt', 'print_raster_info', 'print_vector_info', 'raster_to_vector',
'raster_to_vector_batch', 'rasterio', 'read_pc_item_asset', 'read_raster', 'read_vector',
'region_groups', 'regularization', 'regularize', 'requests', 'rotate', 'rowcol_to_xy', 'rxr',
'segment', 'semantic_segmentation', 'semantic_segmentation_batch', 'set_proj_lib_path', 'shape',
'show', 'stack_bands', 'subprocess', 'sys', 'temp_file_path', 'time', 'torch', 'torchgeo', 'tqdm',
'train', 'train_MaskRCNN_model', 'train_classifier', 'train_instance_segmentation_model',
'train_segmentation_model', 'transform_bounds', 'try_common_architectures', 'utils',
'vector_to_geojson', 'vector_to_raster', 'view_image', 'view_pc_item', 'view_pc_items',
'view_raster', 'view_vector', 'view_vector_interactive', 'visualize_vector_by_attribute',
'warnings', 'write_colormap', 'xr']
# Generate star polygon vertices
points_cw = []
points_ccw = []
for i in range(steps):
t = 2 * math.pi * i / steps
r = outer_radius if i % 2 == 0 else inner_radius
x_cw = center[0] + r * math.cos(t)
y_cw = center[1] + r * math.sin(t)
x_ccw = center[0] + r * math.cos(-t + math.pi / max(lobes, 1))
y_ccw = center[1] + r * math.sin(-t + math.pi / max(lobes, 1))
points_cw.append((x_cw, y_cw))
points_ccw.append((x_ccw, y_ccw))
import os
import unittest
from PIL import Image, ImageDraw, ImageFont, ImageQt
import shutil
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QFileDialog, QLabel, QVBoxLayout, QWidget, QComboBox
from PyQt6.QtGui import QPixmap
from PyQt6.QtCore import Qt
import sys
def create_test_image(path, size, number):
img = Image.new('RGBA', size, (255, 255, 255, 255))
draw = ImageDraw.Draw(img)
# Simplified to just draw the number with a basic color background
draw.rectangle((0, 0, size[0], size[1]), fill=(0, 100 * number % 255, 0, 255))
try:
font = ImageFont.load_default()
except:
font = None
draw.text((size[0]//2-5, size[1]//2-5), str(number), fill=(255, 255, 255, 255), font=font)
img.save(path, 'PNG')
def merge_sprites(folder_path, output_horizontal, output_vertical):
images = [Image.open(os.path.join(folder_path, f)) for f in os.listdir(folder_path) if f.endswith(('.png', '.jpg', '.jpeg'))]
if not images:
return None, None
width, height = images[0].size
# Horizontal merge
total_width = width * len(images)
horizontal_image = Image.new('RGBA', (total_width, height))
for i, img in enumerate(images):
horizontal_image.paste(img, (i * width, 0))
horizontal_image.save(output_horizontal, 'PNG')
# Vertical merge
total_height = height * len(images)
vertical_image = Image.new('RGBA', (width, total_height))
for i, img in enumerate(images):
vertical_image.paste(img, (0, i * height))
vertical_image.save(output_vertical, 'PNG')
return horizontal_image, vertical_image
class TestSpriteMerger(unittest.TestCase):
def setUp(self):
self.test_folder = 'test_images'
self.size = (50, 20)
os.makedirs(self.test_folder, exist_ok=True)
for i in range(3):
create_test_image(os.path.join(self.test_folder, f'test_{i+1}.png'), self.size, i+1)
def test_merge_horizontal(self):
output_h = 'test_merged_horizontal.png'
output_v = 'test_merged_vertical.png'
h_img, _ = merge_sprites(self.test_folder, output_h, output_v)
self.assertIsNotNone(h_img, "Horizontal merge failed")
self.assertEqual(h_img.size, (self.size[0] * 3, self.size[1]))
def test_merge_vertical(self):
output_h = 'test_merged_horizontal.png'
output_v = 'test_merged_vertical.png'
_, v_img = merge_sprites(self.test_folder, output_h, output_v)
self.assertIsNotNone(v_img, "Vertical merge failed")
self.assertEqual(v_img.size, (self.size[0], self.size[1] * 3))
def tearDown(self):
if os.path.exists(self.test_folder):
shutil.rmtree(self.test_folder)
for f in ['test_merged_horizontal.png', 'test_merged_vertical.png']:
if os.path.exists(f):
os.remove(f)
class SpriteMergerApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Sprite Merger")
self.setGeometry(100, 100, 800, 600)
self.folder_path = ""
layout = QVBoxLayout()
self.select_button = QPushButton("Select Folder")
self.select_button.clicked.connect(self.select_folder)
layout.addWidget(self.select_button)
self.merge_type = QComboBox()
self.merge_type.addItems(["Horizontal", "Vertical"])
layout.addWidget(self.merge_type)
self.process_button = QPushButton("Process Selected Folder")
self.process_button.clicked.connect(self.process_folder)
layout.addWidget(self.process_button)
self.test_button = QPushButton("Run Unit Test")
self.test_button.clicked.connect(self.run_unit_test)
layout.addWidget(self.test_button)
self.result_label = QLabel("No image processed")
layout.addWidget(self.result_label)
self.image_label = QLabel()
layout.addWidget(self.image_label)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def select_folder(self):
self.folder_path = QFileDialog.getExistingDirectory(self, "Select Sprite Folder")
self.result_label.setText(f"Selected: {self.folder_path}")
def process_folder(self):
if not self.folder_path:
self.result_label.setText("Please select a folder first")
return
h_img, v_img = merge_sprites(self.folder_path, 'merged_horizontal.png', 'merged_vertical.png')
selected_type = self.merge_type.currentText()
img = h_img if selected_type == "Horizontal" else v_img
if img:
pixmap = QPixmap.fromImage(ImageQt.ImageQt(img))
self.image_label.setPixmap(pixmap.scaled(700, 500, aspectRatioMode=Qt.AspectRatioMode.KeepAspectRatio))
self.result_label.setText(f"{selected_type} merge completed")
else:
self.result_label.setText(f"{selected_type} merge failed")
def run_unit_test(self):
suite = unittest.TestLoader().loadTestsFromTestCase(TestSpriteMerger)
result = unittest.TextTestRunner().run(suite)
test_folder = 'test_images'
os.makedirs(test_folder, exist_ok=True)
for i in range(3):
create_test_image(os.path.join(test_folder, f'test_{i+1}.png'), (50, 20), i+1)
h_img, v_img = merge_sprites(test_folder, 'test_merged_horizontal.png', 'test_merged_vertical.png')
selected_type = self.merge_type.currentText()
img = h_img if selected_type == "Horizontal" else v_img
if img:
pixmap = QPixmap.fromImage(ImageQt.ImageQt(img))
self.image_label.setPixmap(pixmap.scaled(700, 500, aspectRatioMode=Qt.AspectRatioMode.KeepAspectRatio))
self.result_label.setText(f"Unit tests: {result.testsRun} run, {len(result.failures)} failed, showing {selected_type.lower()} merge")
else:
self.result_label.setText(f"Unit tests: {result.testsRun} run, {len(result.failures)} failed, merge failed")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = SpriteMergerApp()
window.show()
sys.exit(app.exec())
pip install --upgrade keras
Collecting keras
Downloading keras-3.10.0-py3-none-any.whl.metadata (6.0 kB)
...
Successfully installed absl-py-2.3.0 h5py-3.14.0 keras-3.10.0 ml-dtypes-0.5.1 namex-0.1.0 optree-0.16.0
pip install tensorflow
ERROR: Could not find a version that satisfies the requirement tensorflow (from versions: none)
ERROR: No matching distribution found for tensorflow
pip install torch
Collecting torch
...
Successfully installed filelock-3.18.0 fsspec-2025.5.1 mpmath-1.3.0 sympy-1.14.0 torch-2.7.1
import os
from groq import Groq
client = Groq(
api_key="gsk_..."
)
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": "explain what groq is",
}
],
model="llama-3.3-70b-versatile",
)
print(chat_completion.choices[0].message.content)
import sys
import os
from datetime import datetime
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QFileDialog, QLineEdit, QCheckBox, QLabel, QMessageBox
from PyQt6.QtCore import Qt
from PIL import Image
class ResizeApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Image Resizer")
self.setGeometry(100, 100, 400, 200)
layout = QVBoxLayout()
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
self.folder_button = QPushButton("Select Folder")
self.folder_button.clicked.connect(self.select_folder)
layout.addWidget(self.folder_button)
self.width_edit = QLineEdit("800")
self.width_edit.setPlaceholderText("Width (px)")
layout.addWidget(QLabel("Width:"))
layout.addWidget(self.width_edit)
self.height_edit = QLineEdit("600")
self.height_edit.setPlaceholderText("Height (px)")
layout.addWidget(QLabel("Height:"))
layout.addWidget(self.height_edit)
self.aspect_ratio = QCheckBox("Maintain Aspect Ratio")
self.aspect_ratio.setChecked(True)
layout.addWidget(self.aspect_ratio)
self.resize_button = QPushButton("Resize Images")
self.resize_button.clicked.connect(self.resize_images)
layout.addWidget(self.resize_button)
self.folder_path = ""
def select_folder(self):
self.folder_path = QFileDialog.getExistingDirectory(self, "Select Image Folder")
if self.folder_path:
self.folder_button.setText(f"Selected: {os.path.basename(self.folder_path)}")
def resize_images(self):
if not self.folder_path:
QMessageBox.warning(self, "Error", "Please select a folder.")
return
try:
width = int(self.width_edit.text())
height = int(self.height_edit.text())
except ValueError:
QMessageBox.warning(self, "Error", "Please enter valid width and height.")
return
if width <= 0 or height <= 0:
QMessageBox.warning(self, "Error", "Width and height must be positive.")
return
date_str = datetime.now().strftime("%d%m%y_%H%M")
aspect_str = "asp_on" if self.aspect_ratio.isChecked() else "asp_off"
output_folder = os.path.join(self.folder_path, f"resized_{date_str}_{height}_{aspect_str}")
os.makedirs(output_folder, exist_ok=True)
for file_name in os.listdir(self.folder_path):
if file_name.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
image_path = os.path.join(self.folder_path, file_name)
try:
with Image.open(image_path) as img:
if self.aspect_ratio.isChecked():
img.thumbnail((width, height), Image.Resampling.LANCZOS)
else:
img = img.resize((width, height), Image.Resampling.LANCZOS)
output_path = os.path.join(output_folder, f"resized_{date_str}_{height}_{aspect_str}_{file_name}")
img.save(output_path)
except Exception as e:
QMessageBox.warning(self, "Error", f"Failed to process {file_name}: {str(e)}")
QMessageBox.information(self, "Success", f"Images resized and saved to {output_folder}!")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = ResizeApp()
window.show()
sys.exit(app.exec())
pip install jupyterlab
Collecting jupyterlab
...
Successfully installed anyio-4.9.0 argon2-cffi-25.1.0 argon2-cffi-bindings-21.2.0 arrow-1.3.0 asttokens-3.0.0 async-lru-2.0.5
attrs-25.3.0 babel-2.17.0 bleach-6.2.0 cffi-1.17.1 comm-0.2.2 debugpy-1.8.14 defusedxml-0.7.1 executing-2.2.0
fastjsonschema-2.21.1 fqdn-1.5.1 h11-0.16.0 httpcore-1.0.9 httpx-0.28.1 ipykernel-6.29.5 ipython-9.4.0
ipython-pygments-lexers-1.1.1 isoduration-20.11.0 jedi-0.19.2 json5-0.12.0 jsonpointer-3.0.0 jsonschema-4.24.0
jsonschema-specifications-2025.4.1 jupyter-client-8.6.3 jupyter-core-5.8.1 jupyter-events-0.12.0 jupyter-lsp-2.2.5
jupyter-server-2.16.0 jupyter-server-terminals-0.5.3 jupyterlab-4.4.4 jupyterlab-pygments-0.3.0 jupyterlab-server-2.27.3
matplotlib-inline-0.1.7 mistune-3.1.3 nbclient-0.10.2 nbconvert-7.16.6 nbformat-5.10.4 nest-asyncio-1.6.0 notebook-shim-0.2.4
overrides-7.7.0 pandocfilters-1.5.1 parso-0.8.4 platformdirs-4.3.8 prometheus-client-0.22.1 prompt_toolkit-3.0.51
psutil-7.0.0 pure-eval-0.2.3 pycparser-2.22 python-json-logger-3.3.0 pywin32-310 pywinpty-2.0.15 pyyaml-6.0.2 pyzmq-27.0.0
referencing-0.36.2 rfc3339-validator-0.1.4 rfc3986-validator-0.1.1 rpds-py-0.26.0 send2trash-1.8.3 sniffio-1.3.1
stack_data-0.6.3 terminado-0.18.1 tinycss2-1.4.0 tornado-6.5.1 traitlets-5.14.3 types-python-dateutil-2.9.0.20250516
uri-template-1.3.0 wcwidth-0.2.13 webcolors-24.11.1 webencodings-0.5.1 websocket-client-1.8.0
pip install notebook
Collecting notebook
...
Installing collected packages: notebook
Successfully installed notebook-7.4.4
pip install voila
Collecting voila
...
Successfully installed voila-0.5.8 websockets-15.0.1
pip install ipywidgets
Collecting ipywidgets
...
Successfully installed ipywidgets-8.1.7 jupyterlab_widgets-3.0.15 widgetsnbextension-4.0.14
jupyter notebook
import ipywidgets as widgets
from IPython.display import display
slider = widgets.IntSlider(value=5, min=0, max=10)
display(slider)
voila test.ipynb
python.exe -m pip install --upgrade pip
pip install manim
Collecting manim
Downloading manim-0.19.0-py3-none-any.whl.metadata (11 kB)
...
Successfully installed Pillow-11.2.1 Pygments-2.19.1 audioop-lts-0.2.1 av-13.1.0 beautifulsoup4-4.13.4 click-8.2.1 cloup-3.0.7 colorama-0.4.6 decorator-5.2.1 glcontext-3.0.0 isosurfaces-0.1.2 manim-0.19.0 manimpango-0.6.0 mapbox-earcut-1.0.3 markdown-it-py-3.0.0 mdurl-0.1.2 moderngl-5.12.0 moderngl-window-3.1.1 networkx-3.5 numpy-2.3.0 pycairo-1.28.0 pydub-0.25.1 pyglet-2.1.6 pyglm-2.8.2 rich-14.0.0 scipy-1.15.3 screeninfo-0.8.1 skia-pathops-0.8.0.post2 soupsieve-2.7 srt-3.5.3 svgelements-1.9.6 tqdm-4.67.1 typing-extensions-4.14.0 watchdog-6.0.0
python.exe -m manim render --help
Manim Community v0.19.0
Usage: python -m manim render ...
from manim import *
class AdvancedAnimation(Scene):
def construct(self):
# Scene 1: Introduction
title = Text("Advanced Animation with Manim").scale(0.76)
self.play(FadeIn(title))
self.wait(2)
# Scene 2: Custom Animation
circle = Circle().set_fill(color=BLUE, opacity=0.5)
square = Square().set_fill(color=RED, opacity=0.5)
self.add(circle, square)
self.play(
Rotate(circle, angle=TAU),
Rotate(square, angle=-TAU),
run_time=2,
rate_func=linear
)
self.wait()
# Scene 3: Text Animation
text = Text("This is a custom text animation", font_size=40).to_edge(UP)
self.play(Write(text), run_time=2)
self.wait()
# Scene 4: Shapes Manipulation
triangle = Triangle().shift(RIGHT * 2)
self.play(GrowFromCenter(triangle), run_time=1.5)
self.wait()
# Scene 5: Transition to next scene
self.play(Uncreate(triangle), FadeOut(text))
# Scene 6: Final Animation
final_text = Text("This is the end of our animation", font_size=50).to_edge(DOWN)
self.play(FadeIn(final_text), run_time=1.5)
self.wait(2)
# Run the animation
AdvancedAnimation()
python.exe -m manim render manim_test_001.py AdvancedAnimation -p
AdvancedAnimation -p
Manim Community v0.19.0
[06/27/25 19:52:43] INFO Animation 0 : Partial movie file scene_file_writer.py:588
written in
'D:\PythonProjects\manim_projects\med
ia\videos\manim_test_001\1080p60\part
ial_movie_files\AdvancedAnimation\397
7891868_355746014_223132457.mp4'
...
[06/27/25 19:53:56] INFO Previewed File at: file_ops.py:237
'D:\PythonProjects\manim_projects\media\videos
\manim_test_001\1080p60\AdvancedAnimation.mp4'
import sys
import os
import re
import shutil
import zipfile
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QPushButton, QListWidget, QFileDialog, QMessageBox, QDialog, QLabel)
from PyQt6.QtCore import Qt
class CriteriaDialog(QDialog):
def __init__(self, folder, parent=None):
super().__init__(parent)
self.setWindowTitle(f"Processing Folder: {folder}")
self.layout = QVBoxLayout(self)
self.layout.addWidget(QLabel(f"Selected folder: {folder}"))
self.ok_button = QPushButton("OK")
self.ok_button.clicked.connect(self.accept)
self.layout.addWidget(self.ok_button)
class DuplicateFinder(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Duplicate File Finder")
self.setGeometry(100, 100, 600, 400)
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout = QVBoxLayout(self.central_widget)
self.file_list = QListWidget()
self.file_list.setSelectionMode(QListWidget.SelectionMode.MultiSelection)
self.layout.addWidget(self.file_list)
button_layout = QHBoxLayout()
self.select_button = QPushButton("Select Folder")
self.select_button.clicked.connect(self.select_folder)
button_layout.addWidget(self.select_button)
self.copy_button = QPushButton("Copy To")
self.copy_button.clicked.connect(self.copy_files)
button_layout.addWidget(self.copy_button)
self.zip_button = QPushButton("Zip All")
self.zip_button.clicked.connect(self.zip_files)
button_layout.addWidget(self.zip_button)
self.delete_button = QPushButton("Delete All")
self.delete_button.clicked.connect(self.delete_files)
button_layout.addWidget(self.delete_button)
self.layout.addLayout(button_layout)
self.files = []
self.selected_folder = ""
def select_folder(self):
folder = QFileDialog.getExistingDirectory(self, "Select Folder")
if folder:
self.selected_folder = folder
dialog = CriteriaDialog(folder, self)
if dialog.exec():
self.files = []
self.file_list.clear()
self.scan_folder(folder)
self.find_duplicates()
def scan_folder(self, folder):
for root, _, files in os.walk(folder):
for file in files:
file_path = os.path.join(root, file)
self.files.append({
'path': file_path,
'name': os.path.basename(file_path),
'size': os.path.getsize(file_path),
'extension': os.path.splitext(file_path)[1]
})
def find_duplicates(self):
duplicates = self.find_by_similar_name()
self.display_duplicates(duplicates)
def find_by_similar_name(self):
duplicates = []
name_groups = {}
pattern = r'(.+?)(?:[\s_-]*\d{3,}|[\s_-]*\d{1,2}|_)?(?:\.\w+)?$'
for file in self.files:
match = re.match(pattern, file['name'])
if match:
base_name = match.group(1)
if base_name in name_groups:
name_groups[base_name].append(file)
else:
name_groups[base_name] = [file]
for base_name, files in name_groups.items():
if len(files) > 1:
duplicates.extend(files)
return duplicates
def display_duplicates(self, duplicates):
self.file_list.clear()
for file in duplicates:
self.file_list.addItem(file['path'])
def copy_files(self):
if not self.file_list.selectedItems():
QMessageBox.warning(self, "Warning", "No files selected!")
return
dest_folder = QFileDialog.getExistingDirectory(self, "Select Destination Folder")
if dest_folder:
for item in self.file_list.selectedItems():
file_path = item.text()
dest_path = os.path.join(dest_folder, os.path.basename(file_path))
shutil.copy2(file_path, dest_path)
QMessageBox.information(self, "Success", "Files copied!")
def zip_files(self):
if not self.file_list.selectedItems():
QMessageBox.warning(self, "Warning", "No files selected!")
return
zip_path = QFileDialog.getSaveFileName(self, "Save Zip File", "", "Zip Files (*.zip)")[0]
if zip_path:
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for item in self.file_list.selectedItems():
file_path = item.text()
zipf.write(file_path, os.path.basename(file_path))
QMessageBox.information(self, "Success", "Files zipped!")
def delete_files(self):
if not self.file_list.selectedItems():
QMessageBox.warning(self, "Warning", "No files selected!")
return
reply = QMessageBox.question(self, "Confirm", "Delete selected files?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
for item in self.file_list.selectedItems():
os.remove(item.text())
self.file_list.clear()
QMessageBox.information(self, "Success", "Files deleted!")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = DuplicateFinder()
window.show()
sys.exit(app.exec())
import json
from pathlib import Path
bookmark_path = Path.home() / "AppData/Local/Microsoft/Edge/User Data/Default/Bookmarks"
with open(bookmark_path, "r", encoding="utf-8") as f:
data = json.load(f)
# Exemplu: listăm toate titlurile bookmark-urilor
def extract_bookmarks(bookmark_node):
bookmarks = []
if "children" in bookmark_node:
for child in bookmark_node["children"]:
bookmarks.extend(extract_bookmarks(child))
elif bookmark_node.get("type") == "url":
bookmarks.append((bookmark_node["name"], bookmark_node["url"]))
return bookmarks
all_bookmarks = extract_bookmarks(data["roots"]["bookmark_bar"])
for name, url in all_bookmarks:
print(f"{name}: {url}")
pip install flask
Collecting flask
Downloading flask-3.1.1-py3-none-any.whl.metadata (3.0 kB)
...
Installing collected packages: markupsafe, itsdangerous, blinker, werkzeug, jinja2, flask
Successfully installed blinker-1.9.0 flask-3.1.1 itsdangerous-2.2.0 jinja2-3.1.6 markupsafe-3.0.2 werkzeug-3.1.3
pip install requests
...
Installing collected packages: urllib3, idna, charset_normalizer, certifi, requests
Successfully installed certifi-2025.6.15 charset_normalizer-3.4.2 idna-3.10 requests-2.32.4 urllib3-2.5.0
pip install playwright
Collecting playwright
...
Installing collected packages: pyee, greenlet, playwright
Successfully installed greenlet-3.2.3 playwright-1.52.0 pyee-13.0.0
...
playwright install
Downloading Chromium 136.0.7103.25 ...
from flask import Flask, request
app = Flask(__name__)
@app.route("/")
def detecteaza_ipuri():
ip_client = request.headers.get('CF-Connecting-IP', 'Necunoscut')
ip_cloudflare = request.remote_addr
return (
f"IP real vizitator: {ip_client}
"
f"IP Cloudflare (vizibil de server): {ip_cloudflare}"
)
if __name__ == "__main__":
app.run(debug=True)
from flask import Flask, request
import requests
import ipaddress
app = Flask(__name__)
def este_ip_cloudflare(ip):
try:
raspuns = requests.get("https://www.cloudflare.com/ips-v4")
raspuns.raise_for_status()
subneturi = raspuns.text.splitlines()
for subnet in subneturi:
if ipaddress.ip_address(ip) in ipaddress.ip_network(subnet):
return True
return False
except Exception as e:
return f"Eroare la verificarea IP-ului Cloudflare: {e}"
@app.route("/")
def detecteaza_ipuri():
ip_client = request.headers.get('CF-Connecting-IP', 'Necunoscut')
ip_cloudflare = request.remote_addr
rezultat = este_ip_cloudflare(ip_cloudflare)
return (
f"IP real vizitator: {ip_client}
"
f"IP Cloudflare (forwarder): {ip_cloudflare}
"
f"Este IP-ul din rețeaua Cloudflare? {'DA' if rezultat == True else 'NU' if rezultat == False else rezultat}"
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
import requests
url = "https://cobalt.tools"
headers = {
"User-Agent": "Mozilla/5.0", # Simulează un browser real
}
try:
r = requests.get(url, headers=headers, timeout=10)
content = r.text.lower()
print(f"Cod răspuns HTTP: {r.status_code}")
if "cloudflare" in content or "cf-ray" in content or "attention required" in content:
print("Cloudflare a intermediat cererea sau a blocat-o cu o pagină specială.")
else:
print("Cererea a fost servită normal.")
except Exception as e:
print(f"Eroare la conexiune: {e}")
import sys
import re
from urllib.parse import urlparse
from pathlib import Path
from playwright.sync_api import sync_playwright
def converteste_url_in_nume_fisier(url):
parsed = urlparse(url)
host = parsed.netloc.replace('.', '_')
path = parsed.path.strip('/').replace('/', '_')
if not path:
path = 'index'
return f"{host}_{path}.txt"
if len(sys.argv) != 2:
print("Utilizare: python script.py https://exemplu.com")
sys.exit(1)
url = sys.argv[1]
fisier_output = converteste_url_in_nume_fisier(url)
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
pagina = browser.new_page()
pagina.goto(url, wait_until='networkidle')
continut = pagina.content()
Path(fisier_output).write_text(continut, encoding='utf-8')
browser.close()
print(f"Conținutul a fost salvat în: {fisier_output}")
cd uv_projects
uv_projects>uv init hello-world
Initialized project `hello-world` at `D:\PythonProjects\uv_projects\hello-world`
uv_projects>cd hello-world
uv_projects\hello-world>uv run main.py
Using CPython 3.13.5 interpreter at: C:\Python3135\python.exe
Creating virtual environment at: .venv
Hello from hello-world!
import sys
from PyQt6.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout, QMenu
# diff PyQt6 versus old PyQt
from PyQt6.QtGui import QAction
from PyQt6.QtGui import QPixmap, QIcon
from PyQt6.QtCore import QTimer, Qt
class AnimatedWindow(QWidget):
def __init__(self):
super().__init__()
# set window
self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
# build layout
layout = QVBoxLayout()
self.label = QLabel(self)
layout.addWidget(self.label)
self.setLayout(layout)
# load sprite sheet from Camera_256px.png file name
sprite_sheet = QPixmap("Camera_256px.png")
self.frame_width = sprite_sheet.width() // 11 # because I have 11 sprite on image
self.sprites = [sprite_sheet.copy(i * self.frame_width, 0, self.frame_width, sprite_sheet.height()) for i in range(11)]
self.current_frame = 0
#
self.timer = QTimer()
self.timer.timeout.connect(self.update_animation)
self.timer.start(150) # Schimbă frame-ul la fiecare 150 ms
#
self.resize(self.frame_width, sprite_sheet.height())
# left down on screen
screen = QApplication.primaryScreen().geometry()
self.move(10, screen.height() - self.height() - 10)
def update_animation(self):
"""Actualizează sprite-ul în QLabel"""
self.label.setPixmap(self.sprites[self.current_frame])
self.current_frame = (self.current_frame + 1) % len(self.sprites)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = AnimatedWindow()
window.show()
sys.exit(app.exec())
python -m pip install -U nuitka
Collecting nuitka
Downloading Nuitka-2.7.tar.gz (3.9 MB)
...
Successfully built nuitka
Installing collected packages: zstandard, ordered-set, nuitka
Successfully installed nuitka-2.7 ordered-set-4.1.0 zstandard-0.23.0
[notice] A new release of pip is available: 25.0.1 -> 25.1.1
[notice] To update, run: python.exe -m pip install --upgrade pip
python.exe -m pip install --upgrade pip
...
Successfully installed pip-25.1.1
python -m nuitka --version
2.7
Commercial: None
Python: 3.13.0rc1 (tags/v3.13.0rc1:e4a3e78, Jul 31 2024, 20:58:38) [MSC v.1940 64 bit (AMD64)]
Flavor: CPython Official
GIL: yes
Executable: C:\Python313\python.exe
OS: Windows
Arch: x86_64
WindowsRelease: 10
Nuitka-Scons:WARNING: Windows SDK must be installed in Visual Studio for it to be usable
Nuitka-Scons:WARNING: with Nuitka. Use the Visual Studio installer for adding it.
Version C compiler: ~\AppData\Local\Nuitka\Nuitka\Cache\downloads\gcc\x86_64\14.2.0posix-19.1.1-12.0.0-msvcrt-r2\mingw64\bin\gcc.exe (gcc 14.2.0).
python -m nuitka --version
2.7
Commercial: None
Python: 3.13.3 (tags/v3.13.3:6280bb5, Apr 8 2025, 14:47:33) [MSC v.1943 64 bit (AMD64)]
Flavor: CPython Official
GIL: yes
Executable: C:\Python313\python.exe
OS: Windows
Arch: x86_64
WindowsRelease: 10
Nuitka-Scons:WARNING: Windows SDK must be installed in Visual Studio for it to be usable
Nuitka-Scons:WARNING: with Nuitka. Use the Visual Studio installer for adding it.
Version C compiler: ~\AppData\Local\Nuitka\Nuitka\Cache\downloads\gcc\x86_64\14.2.0posix-19.1.1-12.0.0-msvcrt-r2\mingw64\bin\gcc.exe (gcc 14.2.0).
python -m pip install -U nuitka
Collecting nuitka
...
Installing collected packages: zstandard, ordered-set, nuitka
Successfully installed nuitka-2.7 ordered-set-4.1.0 zstandard-0.23.0
[notice] A new release of pip is available: 24.2 -> 25.1.1
[notice] To update, run: python.exe -m pip install --upgrade pip
python.exe -m pip install --upgrade pip
Requirement already satisfied: pip in c:\python_3_13_0\lib\site-packages (24.2)
...
Successfully installed pip-25.1.1
py -3.12 -m pip install -U nuitka
Collecting nuitka
Using cached Nuitka-2.7.tar.gz (3.9 MB)
Installing build dependencies ... done
...
Installing collected packages: zstandard, ordered-set, nuitka
Successfully installed nuitka-2.7 ordered-set-4.1.0 zstandard-0.23.0
[notice] A new release of pip is available: 24.2 -> 25.1.1
[notice] To update, run: C:\Python312\python.exe -m pip install --upgrade pip
py -0
-V:3.13 * Python 3.13 (64-bit)
-V:3.12 Python 3.12 (64-bit)
py -3.12 -m nuitka --mingw64 hello.py
Nuitka-Options: Used command line options:
Nuitka-Options: --mingw64 hello.py
Nuitka-Options:WARNING: You did not specify to follow or include anything but main
Nuitka-Options:WARNING: program. Check options and make sure that is intended.
Nuitka: Starting Python compilation with:
Nuitka: Version '2.7' on Python 3.12 (flavor 'CPython Official')
Nuitka: commercial grade 'not installed'.
Nuitka: Completed Python level compilation and optimization.
Nuitka: Generating source code for C backend compiler.
Nuitka: Running data composer tool for optimal constant value handling.
Nuitka: Running C compilation via Scons.
Nuitka-Scons: Backend C compiler: gcc (gcc 14.2.0).
Nuitka-Scons: Backend C linking with 6 files (no progress information available for
Nuitka-Scons: this stage).
Nuitka-Scons: Compiled 6 C files using ccache.
Nuitka-Scons: Cached C files (using ccache) with result 'cache miss': 6
Nuitka: Keeping build directory 'hello.build'.
Nuitka: Successfully created 'D:\PythonProjects\hello.exe'.
Nuitka: Execute it by launching 'hello.cmd', the batch file needs to set environment.
def talk(message):
return "Talk " + message
def main():
print(talk("Hello World"))
if __name__ == "__main__":
main()
hello.exe
Talk Hello World
system32>setx.exe FAL_KEY "e6fd708c-8065-4c73-ac2a-e3c73c6ff0fe:f70e0adb08362a3073993efa31b6acee"
SUCCESS: Specified value was saved.
import fal_client
response = fal_client.run("fal-ai/fast-sdxl", arguments={"prompt": "a cute cat, realistic, orange"})
print(response["images"][0]["url"])
python test_fal_client_001.py
https://v3.fal.media/files/rabbit/kY2MZG6LLkzjyIT8J3oiI.jpe
from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QMenu
from bs4 import BeautifulSoup
class AgentPy:
"""Clasă pentru procesarea și curățarea HTML-ului."""
@staticmethod
def clean_all_styles(html_content):
soup = BeautifulSoup(html_content, 'html.parser')
for tag in soup.find_all(True):
if tag.name == "a":
attrs_to_keep = {"href": tag.attrs.get("href")} if "href" in tag.attrs else {}
tag.attrs = attrs_to_keep
else:
tag.attrs = {}
return str(soup)
@staticmethod
def clean_empty_tags(html_content):
soup = BeautifulSoup(html_content, 'html.parser')
for tag in soup.find_all(True):
if not tag.contents or all(str(content).strip() == "" for content in tag.contents):
tag.decompose()
return str(soup)
@staticmethod
def clean_duplicate_tags(html_content):
soup = BeautifulSoup(html_content, 'html.parser')
unique_tags = {}
for tag in soup.find_all(True):
tag_key = (tag.name, str(tag.attrs))
if tag_key in unique_tags:
tag.decompose()
else:
unique_tags[tag_key] = tag
return str(soup)
@staticmethod
def convert_to_html(source_code):
"""Convertim caractere speciale din cod sursă în entități HTML."""
# Creăm un dicționar pentru conversia caracterelor
html_entities = {
'<': '<',
'>': '>',
'&': '&',
'"': '"',
"'": ''',
'[': '[',
']': ']',
}
# Înlocuim caracterele în codul sursă
for char, entity in html_entities.items():
source_code = source_code.replace(char, entity)
return source_code
class HtmlEditor(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("catafest-cleaner-HTML")
self.setGeometry(100, 100, 800, 600)
# Editor de text
self.editor = QTextEdit(self)
self.setCentralWidget(self.editor)
# Meniu contextual
self.editor.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.editor.customContextMenuRequested.connect(self.show_context_menu)
def show_context_menu(self, position):
menu = QMenu(self)
clean_styles_action = menu.addAction("Clean basic HTML")
clean_styles_action.triggered.connect(self.clean_all_styles)
clean_empty_tags_action = menu.addAction("Clean Empty Tags")
clean_empty_tags_action.triggered.connect(self.clean_empty_tags)
clean_agentpy_action = menu.addAction("Clean AgentPy")
clean_agentpy_action.triggered.connect(self.clean_duplicate_tags)
convert_to_html_action = menu.addAction("Convert to HTML") # Noua opțiune
convert_to_html_action.triggered.connect(self.convert_to_html)
menu.exec(self.editor.mapToGlobal(position))
def clean_all_styles(self):
html_content = self.editor.toPlainText()
clean_html = AgentPy.clean_all_styles(html_content)
self.editor.setPlainText(clean_html)
def clean_empty_tags(self):
html_content = self.editor.toPlainText()
clean_html = AgentPy.clean_empty_tags(html_content)
self.editor.setPlainText(clean_html)
def clean_duplicate_tags(self):
html_content = self.editor.toPlainText()
clean_html = AgentPy.clean_duplicate_tags(html_content)
self.editor.setPlainText(clean_html)
def convert_to_html(self):
source_code = self.editor.toPlainText()
html_content = AgentPy.convert_to_html(source_code)
self.editor.setPlainText(html_content)
if __name__ == "__main__":
import sys
from PyQt6.QtCore import Qt
app = QApplication(sys.argv)
window = HtmlEditor()
window.show()
sys.exit(app.exec())