見出し画像

Koboldcpp用pngメタデータ編集コード公開しました

 GUI付きでKoboldcppにインポート可能なchub.aiPygmalionAIのダウンロードしたキャラクターのPNGファイルのメタデータを編集できて保存ができるコードを作成しました。

 一応、既存のでないかは探したのですが、長期間メンテされてないソフトしかありませんでしたので、Claude3-Opusと相談しながらコードを生成しました。Koboldcppに編集機能がついていれば、こんなコード不要だったのですが…


必須環境

 前提として、Pythonがインストールされている環境である必要があります。
 また、以下のライブラリをインストールしていない場合はインストールする必要があります。

pip install pillow
pip install pyqt5

 pillowはA1111webuiでも使われるpng用のライブラリです。pyqt5はGUI用のライブラリです。

Pythonコード

import sys
import base64
import json
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QTextEdit, QPushButton, QVBoxLayout, QWidget, QLabel, QSpinBox
from PIL import Image, PngImagePlugin

class PNGMetadataEditor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.current_file = ""
        self.isDarkMode = False

    def initUI(self):
        self.setWindowTitle("PNG Metadata Editor")
        self.setGeometry(100, 100, 600, 400)

        # Create widgets
        self.textEdit = QTextEdit()
        openButton = QPushButton("Open PNG")
        openButton.clicked.connect(self.openFile)
        saveButton = QPushButton("Save PNG")
        saveButton.clicked.connect(self.saveFile)
        saveAsButton = QPushButton("Save As PNG")
        saveAsButton.clicked.connect(self.saveAsFile)

        # Create font size label and spin box
        fontSizeLabel = QLabel("Font Size:")
        self.fontSizeSpinBox = QSpinBox()
        self.fontSizeSpinBox.setMinimum(6)
        self.fontSizeSpinBox.setMaximum(24)
        self.fontSizeSpinBox.setValue(12)
        self.fontSizeSpinBox.valueChanged.connect(self.changeFontSize)

        # Create dark mode toggle button
        self.darkModeButton = QPushButton("Dark Mode")
        self.darkModeButton.clicked.connect(self.toggleDarkMode)

        # Create layout
        layout = QVBoxLayout()
        layout.addWidget(self.textEdit)
        layout.addWidget(openButton)
        layout.addWidget(saveButton)
        layout.addWidget(saveAsButton)
        layout.addWidget(fontSizeLabel)
        layout.addWidget(self.fontSizeSpinBox)
        layout.addWidget(self.darkModeButton)

        # Create central widget and set layout
        centralWidget = QWidget()
        centralWidget.setLayout(layout)
        self.setCentralWidget(centralWidget)

    def openFile(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open PNG File", "", "PNG Files (*.png)")
        if fileName:
            self.current_file = fileName
            with Image.open(fileName) as img:
                metadata = img.text
                json_data = None
                if "chara" in metadata:
                    base64_data = metadata["chara"]
                    json_data = base64.b64decode(base64_data).decode('utf-8')
                elif "data" in metadata:
                    json_data = metadata["data"]
                
                if json_data:
                    self.textEdit.setPlainText(json_data)
                else:
                    self.textEdit.setPlainText("No JSON metadata found in the PNG file.")

    def saveFile(self):
        if self.current_file:
            self.saveMetadata(self.current_file)
        else:
            self.saveAsFile()

    def saveAsFile(self):
        fileName, _ = QFileDialog.getSaveFileName(self, "Save PNG File", "", "PNG Files (*.png)")
        if fileName:
            self.saveMetadata(fileName)

    def saveMetadata(self, fileName):
        try:
            json_data = self.textEdit.toPlainText()
            base64_data = base64.b64encode(json_data.encode('utf-8')).decode('utf-8')
            metadata = PngImagePlugin.PngInfo()
            metadata.add_text("chara", base64_data)
            
            with Image.open(self.current_file) as img:
                img.save(fileName, pnginfo=metadata)
        except json.JSONDecodeError:
            self.textEdit.setPlainText("Invalid JSON format in the text edit.")
        except Exception as e:
            self.textEdit.setPlainText(f"Error saving PNG file: {str(e)}")

    def changeFontSize(self, fontSize):
        font = self.textEdit.font()
        font.setPointSize(fontSize)
        self.textEdit.setFont(font)

    def toggleDarkMode(self):
        self.isDarkMode = not self.isDarkMode
        if self.isDarkMode:
            app.setStyleSheet("""
                QWidget {
                    background-color: #333333;
                    color: #ffffff;
                }
                QTextEdit {
                    background-color: #444444;
                    color: #ffffff;
                }
                QPushButton {
                    background-color: #555555;
                    color: #ffffff;
                }
            """)
        else:
            app.setStyleSheet("")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    editor = PNGMetadataEditor()
    editor.show()
    sys.exit(app.exec_())

 このコード適当なフォルダにPNGMetadataEditor.pyなど適当な名前を付けて保存して、実行すれば以下のような画面が出てきます。

PNGMetadataEditor

 Open PNGで対応したPNGファイルが開けて、JSON形式のメタデータが読み込まれます。
textを直接編集できるので適宜変更してください。ただし、書式を誤って編集してもエラーメッセージを出す機能とかはないので、各自自己責任で編集してください(基本的にミスしてもkoboldcppでの読み込み時にErrorが出るだけです)。

 Save PNGで変更した内容が、直接開いたPNGファイルに書き込まれます。

 Save As PNGで名前を変更してのPNGの保存ができます。
Font Sizeの上下矢印ボタンか、直接入力で6-24の間でフォントサイズを変更できます。

        self.fontSizeSpinBox.setValue(12)

 この部分の数値を書き換えれば、起動時のデフォルトのフォントサイズを変更も可能です。
Dark Modeを押すと、背景が黒く文字が白く出来ます。もう一回押すともとに戻ります。

 何か問題があれば、ツイッターやディスコ(@willlion)までご連絡くださいm(_ _)m
 自分はSillyTavernを使用して(node.jsのインストールが必要)、koboldcppをAPIとして使用していて直接色々編集できるので、基本的に今後のメンテの予定はありませんので、予めご了承ください。また、自由に改変再配布をしてもらって構いませんが、ここにオリジナルがあることを明記してください。

 表紙画像はStableCascadeで「png metadata editing code for Koboldcpp published, masterpiece, best quality」という、表題英訳をそのまま突っ込んでできた画像です。最初は男性の顔のドアップで、集合体恐怖症の人にはアウトなブツブツがある顔だったので2枚目に生成した画像です。

この記事が参加している募集

AIとやってみた

この記事が気に入ったらサポートをしてみませんか?