diff --git a/TEST/Tagdataset_print.ipynb b/TEST/Tagdataset_print.ipynb deleted file mode 100644 index 2a604d0..0000000 --- a/TEST/Tagdataset_print.ipynb +++ /dev/null @@ -1,75 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "a3c42dd3", - "metadata": {}, - "source": [ - "# データセットのアップロードを確認するやつ\n", - "Dataset Viewer使えば要らない\n", - "データセットリポジトリからランダムに取り出して情報を表示する" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "from PIL import Image\n", - "from datasets import load_dataset\n", - "\n", - "# データセットをロード\n", - "dataset_dict = load_dataset(\"username/name\")\n", - "train_dataset = dataset_dict['train']\n", - "\n", - "# ランダムにレコードを取り出す\n", - "def show_random_record(dataset):\n", - " index = random.randint(0, len(dataset) - 1)\n", - " record = dataset[index]\n", - " \n", - " # 画像を表示\n", - " image = record['image']\n", - " if isinstance(image, str):\n", - " image = Image.open(image)\n", - " image.show()\n", - "\n", - " # その他の内容を表示\n", - " print(f\"Record {index}:\")\n", - " print(f\"File Name: {record['file_name']}\")\n", - " print(f\"Tags: {record['tags']}\")\n", - " print(f\"Caption: {record['caption']}\")\n", - " print(f\"Width: {record['width']}\")\n", - " print(f\"Height: {record['height']}\")\n", - " print(f\"Pixels: {record['pixels']}\")\n", - " print(f\"LAION Aesthetic: {record['LAION_aesthetic']}\")\n", - " print(f\"Cafe Aesthetic: {record['cafe_aesthetic']}\")\n", - "\n", - "# ランダムなレコードを表示\n", - "show_random_record(train_dataset)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/TEST/TestTagCaptionCleaner.py b/TEST/TestTagCaptionCleaner.py deleted file mode 100644 index a5a4002..0000000 --- a/TEST/TestTagCaptionCleaner.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -タグクリーンナップのテスト -未だにエスケープの処理が甘いかもしれない - """ - -import unittest -from cleanup_txt import clean_tags, clean_format, clean_caption - -class TestTagCaptionCleaner(unittest.TestCase): - - def test_clean_format(self): - text = "**Tags** :Hello, World! (TEST)\naa\u2014aa. " - expected = r"Tags :Hello, World! \(TEST\), aa aa, " - result = clean_format(text) - self.assertEqual(result, expected, "文字の置き換えができてない") - - def test_remove_duplicates(self): - tags = "girl, long hair, long hair, blue eyes, blue eyes, white shirt, shirt" - expected = "girl, long hair, blue eyes, white shirt" - result = clean_tags(tags) - self.assertEqual(result, expected, "重複してるタグをちゃんと消せてない") - - def test_handle_special_chars(self): - tags = "girl, ^_^, long_hair, short hair, ," - expected = "girl, ^_^, long hair, short hair" - result = clean_tags(tags) - self.assertEqual(result, expected, "特殊文字") - - def test_clean_clor_tags(self): - tags = "bleu eyes, eyes, white shirt, shirt, green hair, hair, black kimono, kimono" - expected = "bleu eyes, white shirt, green hair, black kimono" - result = clean_tags(tags) - self.assertEqual(result, expected, "色のタグ") - - def test_multiple_patterns(self): - tags = "2girls, ponytail, braid, braid, red hair, blue eyes, long hair, ," - expected = "2girls, long hair" - result = clean_tags(tags) - self.assertEqual(result, expected, "複数パターン") - - def test_keep_important_tags(self): - tags = "girl, bob cut, bob cut, hime cut, ," - expected = "girl, bob cut, hime cut" - result = clean_tags(tags) - self.assertEqual(result, expected, "重複削除失敗") - - def test_danbooru_tags(self): - tags = "kitasan black (umamusume)" - expected = r"kitasan black \(umamusume\)" - result = clean_tags(tags) - self.assertEqual(result, expected, "意図した結果ではない") - - -class TestCaptionCleaning(unittest.TestCase): - def test_clean_caption(self): - cases = [ - ("Here is an anime anime scene", "Here is an anime scene"), - ("This young girl is playing", "This girl is playing"), - ("The cartoon female is dancing", "The girl is dancing"), - ("A group of cartoon women are here", "A group of girls are here"), - ("There are many people in this scene", "There are many girls in this scene"), - ("Look at this person walking", "Look at this girl walking"), - ("The lady walks her dog", "The girl walks her dog"), - ("a cartoon drawing of a landscape", "a drawing of a landscape") - ] - - for inp, expected in cases: - self.assertEqual(clean_caption(inp), expected) - -if __name__ == '__main__': - unittest.main() diff --git a/TEST/caption_batch.py b/TEST/caption_batch.py deleted file mode 100644 index 7aff4ef..0000000 --- a/TEST/caption_batch.py +++ /dev/null @@ -1,175 +0,0 @@ -""" -ふぉるだ内の画像に対応した.captionがない場合バッチ処理用JSONに追加 -GPT4でバッチ処置を開始 -開始までなので結果は別に確認 - Returns: - _type_: _description_ - """ -import os -import configparser -from pathlib import Path -import base64 -import json -import requests -import math - -# 設定 -input_dir = Path(r'your_imgdir_path') -MODEL = "gpt-4-turbo" -config = configparser.ConfigParser() -config.read('apikey.ini') -api_key = config['KEYS']['openai_api_key'] -sprit_json_uploas = True - -def encode_image(image_path): - '''画像をBase64エンコードして返す''' - with open(image_path, "rb") as image_file: - return base64.b64encode(image_file.read()).decode('utf-8') - -def generate_instructions_json(img_id, model, base64img): - '''バッチ用プロンプトを作成''' - prompt = "As an AI image tagging expert, your role is to provide accurate and specific tags for images to improve the CLIP model's performance. \ - Each image should have tags that accurately capture its main subjects, setting, artistic style, composition, and technical details like image quality and camera settings. \ - For images of people, detail gender, attire, actions, pose, expressions, and any notable accessories. \ - For landscapes or objects, focus on the material, historical context, and any significant features. \ - Always use precise and specific tags—prefer \"Gothic cathedral\" over \"building\" Avoid duplicative tags. \ - Each set of tags should be unique and relevant, separated only by commas, and kept within a 50-150 word count. \ - Also, provide a concise 1-2 sentence caption that captures the image's narrative or essence. \ - High-quality tagging and captioning will be compensated at $10 per image, rewarding exceptional clarity and precision that enhance image recreation" - payload = { - "custom_id": img_id, - "method": "POST", - "url": "/v1/chat/completions", - "body": { - "model": model, - "messages": [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": prompt - }, - { - "type": "image_url", - "image_url": { - "url": f"data:image/webp;base64,{base64img}", - "detail": "high" - } - } - ] - } - ], - "max_tokens": 3000 - } - } - return payload - -def save_jsonline_to_file(batch_payloads, filename): - """データリストをJSON Lines形式でファイルに保存する""" - with open(filename, 'w', encoding='utf-8') as f: - for item in batch_payloads: - json.dump(item, f) - f.write('\n') # 各JSONオブジェクトの後に改行を追加 - print(f"Data saved to {filename}") - return filename - -def upload_json_to_openai(json_path, purpose='batch'): - """JSONファイルをOpenAI APIにアップロードする""" - url = "https://api.openai.com/v1/files" - headers = { - "Authorization": f"Bearer {api_key}" - } - files = { - 'file': open(json_path, 'rb') - } - data = { - 'purpose': purpose - } - response = requests.post(url, headers=headers, files=files, data=data, timeout=500) - if response.status_code == 200: - print("アップロード成功") - file_id = response.json().get('id') - return file_id - else: - print(f"アップロード失敗: {response.status_code}") - print(response.text) - return None - -def start_batch_processing(input_file_id): - """ - OpenAI APIを使用してバッチ処理を開始する。 - - Args: - input_file_id (str): アップロードされたファイルのID。 - Returns: - dict: APIからの応答を含む辞書。 - """ - url = "https://api.openai.com/v1/batches" - headers = { - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json" - } - data = { - "input_file_id": input_file_id, - "endpoint": "/v1/chat/completions", - "completion_window": "24h" - } - - response = requests.post(url, headers=headers, json=data, timeout=30) - if response.status_code == 200: - print("バッチ処理の開始") - return response.json() - else: - print(f"バッチ処理実行失敗 {response.status_code}") - print(response.text) - return None - -def caption_batch(input_dir): - """#フォルダ内の画像に対応した.captionがない場合バッチ処理用JSONに追加 - Args: - input_dir (Path): 入力ディレクトリ - """ - batch_payloads = [] - # ディレクトリを走査してキャプションの生成 - for filename in input_dir.rglob('*'): - # 拡張子を除去したファイル名の取得 - base_filename = os.path.splitext(filename)[0] - if filename.name.lower().endswith(('webp')): #webp以外の画像の場合はリサイズ等の処理がされてないから無視 - image_path = os.path.join(input_dir, filename) - caption_path = os.path.join(input_dir, f'{base_filename}.caption') - # キャプションファイルが存在しない場合のみ処理を行う - if not os.path.exists(caption_path): - print(f'Processing {filename}...') - base64img = encode_image(image_path) - payload = generate_instructions_json(base_filename, MODEL, base64img) - batch_payloads.append(payload) - - jsonl_path = save_jsonline_to_file(batch_payloads, 'instructions.jsonl') - - # サイズチェックしてjsonlが96MB[OpenAIの制限]を超えないようにするために分割する - jsonl_size = os.path.getsize(jsonl_path) - if jsonl_size > 100663296: - print("JSONLファイルが大きすぎます。分割します。") - # jsonl_sizeに基づいてファイルを分割 - split_size = math.ceil(jsonl_size / 100663296) - with open(jsonl_path, 'r', encoding='utf-8') as f: - lines = f.readlines() - lines_per_file = math.ceil(len(lines) / split_size) # 各ファイルに必要な行数 - for i in range(split_size): - split_filename = f'instructions_{i}.jsonl' - split_path = os.path.join(os.path.dirname(jsonl_path), split_filename) - with open(split_path, 'w', encoding='utf-8') as f: - f.writelines(lines[i * lines_per_file:(i + 1) * lines_per_file]) - - if sprit_json_uploas: - upload_file_id = upload_json_to_openai(split_path) - start_batch_processing(upload_file_id) - else: - print(f"分割ファイルを保存しました: {split_path}") - print("分割ファイルをアップロードしてバッチ処理を開始するには、sprit_json_uploasをTrueに設定してください。") - else: - upload_file_id = upload_json_to_openai(jsonl_path) - start_batch_processing(upload_file_id) - -caption_batch(input_dir) \ No newline at end of file diff --git a/TEST/googleai.py b/TEST/googleai.py deleted file mode 100644 index b6954f7..0000000 --- a/TEST/googleai.py +++ /dev/null @@ -1,75 +0,0 @@ -"""goofle AI studioを使用して画像のタグ付けを行うスクリプト -構造化プロンプトの使用 -まだまだ使い方を寝る必要がある -""" - -import toml -from pathlib import Path -import google.generativeai as genai - -img0 = Path(r"your\path\to\img01.webp") -img1 = Path(r"your\path\to\img02.webp") -img2 = Path(r"your\path\to\img03.webp") - -config = toml.load("processing.toml") -api_key = config["APIKEYS"]["google_api_key"] - - -# キーワード引数 api_key を使用して configure() を呼び出す -# キーワード引数しか受け取らない -genai.configure(api_key=api_key) - -# Set up the model -generation_config = { - "temperature": 1, - "top_p": 0.95, - "top_k": 64, - "max_output_tokens": 8192, -} - -safety_settings = [ - { - "category": "HARM_CATEGORY_HARASSMENT", - "threshold": "BLOCK_NONE" - }, - { - "category": "HARM_CATEGORY_HATE_SPEECH", - "threshold": "BLOCK_NONE" - }, - { - "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", - "threshold": "BLOCK_NONE" - }, - { - "category": "HARM_CATEGORY_DANGEROUS_CONTENT", - "threshold": "BLOCK_NONE" - }, -] - -model = genai.GenerativeModel(model_name="gemini-1.5-pro-latest", - generation_config=generation_config, - safety_settings=safety_settings) - -prompt_parts = [ - "As an AI image tagging expert, your role is to provide accurate and specific tags for images to improve the CLIP model's performance. \nEach image should have tags that accurately capture its main subjects, setting, artistic style, composition, and technical details like image quality and camera settings. \nFor images of people, detail gender, attire, actions, pose, expressions, and any notable accessories. \nFor landscapes or objects, focus on the material, historical context, and any significant features. \nAlways use precise and specific tags—prefer \"gothic cathedral\" over \"building.\" Avoid duplicative tags. \nEach set of tags should be unique and relevant, separated only by commas, and kept within a 50-150 word count. \nAlso, provide a concise 1-2 sentence caption that captures the image's narrative or essence.", - "input:img ", - genai.upload_file(img0,mime_type="image/webp"), - "Tags and Caption Tags:\n\nCaption:", - "input:img ", - genai.upload_file(img1,mime_type="image/webp"), - "Tags and Caption Tags:\n\nCaption:", - "input:img ", - genai.upload_file(img2,mime_type="image/webp"), - "Tags and Caption Tags:\n\nCaption:", - "input:img ", -] - -response = model.generate_content(prompt_parts) - -# safety_ratings を出力 -for candidate in response.candidates: - print(f"Safety ratings: {candidate.safety_ratings}") - -with open("Googleoutput.txt", "w") as f: - f.write(response.text) -print(response.text) \ No newline at end of file diff --git a/TEST/test_ImageEditor.py b/TEST/test_ImageEditor.py deleted file mode 100644 index e760fe1..0000000 --- a/TEST/test_ImageEditor.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -リサイズの計算が正しいかどうかをテストするためのユニットテスト -""" -import unittest -from ImageEditor import find_matching_resolution - -class TestImageEditor(unittest.TestCase): - def test_find_matching_resolution(self): - # Test case 1: Matching resolution found - original_width = 2432 - original_height = 1664 - max_dimension = 1024 - expected_resolution = (1216, 832) - self.assertEqual(find_matching_resolution(original_width, original_height, max_dimension), expected_resolution) - - # Test case 2: No matching resolution found - original_width = 1920 - original_height = 1080 - max_dimension = 1024 - expected_resolution = None - self.assertEqual(find_matching_resolution(original_width, original_height, max_dimension), expected_resolution) - - # Test case 3: Multiple matching resolutions, closest to max_dimension**2 - original_width = 2000 - original_height = 2000 - max_dimension = 1024 - expected_resolution = (1024, 1024) - self.assertEqual(find_matching_resolution(original_width, original_height, max_dimension), expected_resolution) - - # Test case 4: Multiple matching resolutions, not closest to max_dimension**2 - original_width = 800 - original_height = 600 - max_dimension = 1024 - expected_resolution = None - self.assertEqual(find_matching_resolution(original_width, original_height, max_dimension), expected_resolution) - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/TEST/test_scorer.py b/TEST/test_scorer.py deleted file mode 100644 index 986622a..0000000 --- a/TEST/test_scorer.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -LIONとCAFEのモデルを用いて評価するスクリプト -""" -# test_scorer.py -from pathlib import Path -from score_module.scorer import AestheticScorer -from PIL import Image -def test_scorer(scorer: AestheticScorer): - image_path = Path("testimg\\1_img\\1-370.jpg") # テスト用の画像パスを指定 - img = Image.open(image_path) - laion_aesthetic = scorer.score(img, model_type="laion") - cafe_aesthetic = scorer.score(img, model_type="cafe") - print(f"LAION Aesthetic score: {laion_aesthetic}") - - print(f"CAFE Aesthetic score: {cafe_aesthetic}") - -if __name__ == "__main__": - score = AestheticScorer() - test_scorer(score) diff --git a/TEST/test_sqlclean.py b/TEST/test_sqlclean.py deleted file mode 100644 index 5321a39..0000000 --- a/TEST/test_sqlclean.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -sqlite3を使って、タグのクリーンナップを行う -非推奨タグを推奨のタグ名に置き換える -""" -import sqlite3 - -def cleanup_tag_sql(db_path, tags): - # SQLite DBに接続する - conn = sqlite3.connect(db_path) - cursor = conn.cursor() - # 結果を格納するリスト - cleaned_tags = [] - # クリーンナップ前のタグを対応する正規のタグ名に置き換えるクエリ - query = """ - SELECT name - FROM tags - WHERE aliases = ? - """ - - for tag_to_cleanup in tags: - cursor.execute(query, (tag_to_cleanup,)) - results = cursor.fetchall() - # 結果があれば、正規のタグ名を返す。なければ元のタグを返す - if results: - #fetchallはタプルのリストを返すので、リスト内包表記でタプルの要素を取り出す - names = [result[0] for result in results] - cleaned_tags.append(','.join(names)) - else: - cleaned_tags.append(tag_to_cleanup) - - conn.close() - return cleaned_tags - -# 使用例 -db_path = 'tags.db' -tag_to_cleanup = 'general, sensitive, looking at viewer, blush, short hair, shirt, blonde hair, multiple girls, holding, 2girls, collarbone, white shirt, upper body, short sleeves, solo focus, indoors, nose blush, embarrassed, wavy mouth, ?, t-shirt, @ @, overalls, spoken question mark, ear blush, general, sensitive, 1girl, solo, blush, short hair, blue eyes, shirt, blonde hair, multiple girls, brown hair, holding, closed mouth, 2girls, collarbone, white shirt, upper body, short sleeves, indoors, embarrassed, wavy mouth, ?, @ @, paper, overalls, spoken question mark, general, sensitive, 1girl, looking at viewer, blush, short hair, shirt, blonde hair, multiple girls, holding, closed mouth, 2girls, collarbone, white shirt, upper body, short sleeves, solo focus, indoors, nose blush, embarrassed, light brown hair, wavy mouth, ?, t-shirt, @ @, paper, full-face blush, overalls, spoken question mark, ear blush, holding paper, female, solo, feral, clothing, clothed, hair, blush, tears, text, crying, anthro, mammal, hi res, ambiguous gender, dagasi, bodily fluids' -#タグを分割 -tags = tag_to_cleanup.split(", ") -cleaned_tags = cleanup_tag_sql(db_path, tags) -cleaned_tags_str = ','.join(cleaned_tags) -print(f'Cleaned tag: {cleaned_tags_str}') - -