Laura Wagner commited on
Commit
e1abfba
·
0 Parent(s):

commit or not commit

Browse files
.gitattributes ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ misc/assets/fonts/** filter=lfs diff=lfs merge=lfs -text
2
+ public/json/tags_character.json filter=lfs diff=lfs merge=lfs -text
3
+ plots/models_nsfw_monthly_histogram_with_quarters.png filter=lfs diff=lfs merge=lfs -text
4
+ public/img/sankey.png filter=lfs diff=lfs merge=lfs -text
5
+ public/img/tag_clusters.png filter=lfs diff=lfs merge=lfs -text
6
+ public/img/training_tags.png filter=lfs diff=lfs merge=lfs -text
7
+ plots/grid10x120.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ data
2
+ ext
3
+ ARCHIVE
4
+ misc/api_keys.txt
5
+ misc/training_tags_categories
6
+ scripts/ARCHIVE
7
+ scripts/CEMETARY
.gitmodules ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [submodule "ext/MiVOLO"]
2
+ path = ext/MiVOLO
3
+ url = https://github.com/WildChlamydia/MiVOLO.git
.virtual_documents/civitai_site_properties.ipynb ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import matplotlib.pyplot as plt
2
+ from matplotlib.font_manager import FontProperties
3
+ from matplotlib import font_manager
4
+ from matplotlib.patches import Rectangle
5
+ from matplotlib.patches import FancyBboxPatch
6
+ import matplotlib.dates as mdates
7
+ from dateutil import parser
8
+ import json
9
+ import requests
10
+ import importlib
11
+ import datetime
12
+ import os
13
+ from collections import Counter
14
+ import functions
15
+ import pandas as pd
16
+ importlib.reload(functions)
17
+ from functions import sortByFrequency, most_popular_tags, models_tags, get_model_info
18
+
19
+
20
+ # Fonts
21
+ font_manager.fontManager.addfont('fonts/Noto_Sans_JP/static/NotoSansJP-Medium.ttf') # Fallback for Japanese
22
+ font_manager.fontManager.addfont('fonts/Noto_Sans_SC/static/NotoSansSC-Medium.ttf') # Fallback for Simplified Chinese
23
+ plt.rcParams['font.family'] = ['Noto Sans JP', 'Noto Sans SC', 'sans-serif']
24
+
25
+
26
+
27
+ get_download_urls('most_popular/most_popular_models_with_date_page_1.json')
28
+
29
+
30
+ get_images()
31
+
32
+
33
+ directory_path = "newest_images" # Update this to your directory path
34
+ march_items = []
35
+
36
+ # Step 1: Filter items by March and collect browsingLevel
37
+ for filename in os.listdir(directory_path):
38
+ if filename.endswith('.json'):
39
+ file_path = os.path.join(directory_path, filename)
40
+ with open(file_path, 'r', encoding='utf-8') as file:
41
+ data = json.load(file)
42
+ items = data['items'] # Access the list of items
43
+ for item in items:
44
+ created_at = datetime.fromisoformat(item['createdAt'][:-1]) # Remove 'Z' and convert to datetime
45
+ if created_at.month == 3 and created_at.year == 2024: # Check if the item is from March 2024
46
+ browsing_level = item.get('browsingLevel', None)
47
+ if browsing_level in [2, 4, 8, 16]: # Only include specified browsing levels
48
+ march_items.append((created_at.day, browsing_level))
49
+
50
+ # Prepare data for the histogram
51
+ days = range(1, 32) # Days in March
52
+ levels = ['1 | PG', '2 | PG13', '4 | R' , '8 | X', '16 | XXX']
53
+ colors = ['coral', 'lightgreen', 'salmon', 'blueviolet', 'blue'] # Different color for each browsingLevel
54
+ labels = [f'Browsing Level: {level}' for level in levels]
55
+
56
+ # Initialize a dictionary to hold day counts for each level
57
+ day_counts_by_level = {level: [0] * 31 for level in levels} # 31 days in March
58
+
59
+ # Populate the day counts
60
+ for day, level in march_items:
61
+ day_counts_by_level[level][day - 1] += 1 # Increment the count for the corresponding day and level
62
+
63
+ # Plotting
64
+ plt.figure(figsize=(10, 6)) # Optional: Adjust the figure size
65
+
66
+ # Create a stacked bar chart
67
+ bottom = [0] * 31
68
+ for level, color, label in zip(levels, colors, labels):
69
+ plt.bar(days, day_counts_by_level[level], bottom=bottom, color=color, label=label, edgecolor='black', width=0.8)
70
+ bottom = [x + y for x, y in zip(bottom, day_counts_by_level[level])]
71
+
72
+ # Set the title and labels
73
+ plt.title('Number of Uploads per Day in March 2024 by Browsing Level')
74
+ plt.xlabel('Day of the Month')
75
+ plt.ylabel('Number of Uploads')
76
+ plt.xticks(days) # Set x-ticks to show every day of the month
77
+ plt.legend() # Show legend to identify browsingLevels
78
+
79
+ # Show the plot
80
+ plt.show()
81
+
82
+
83
+ directory_path = 'most popular' # Update this to your directory path
84
+ hatch_pattern = '\\\\\\\\\\\\\\'
85
+ # Initialize an empty list to store the type of each model
86
+ model_types = []
87
+
88
+ # Iterate over each file in the directory
89
+ for filename in os.listdir(directory_path):
90
+ if filename.endswith('.json'): # Check if the file is a JSON file
91
+ file_path = os.path.join(directory_path, filename)
92
+ with open(file_path, 'r') as file:
93
+ data = json.load(file)
94
+ items = data['items']
95
+ for item in items:
96
+ model_types.append(item['type'])
97
+
98
+ # Convert the list of types into a pandas DataFrame
99
+ df = pd.DataFrame(model_types, columns=['Type'])
100
+
101
+ # Count the occurrences of each type
102
+ type_counts = df['Type'].value_counts().reset_index()
103
+ type_counts.columns = ['Type', 'Count']
104
+ total = type_counts['Count'].sum()
105
+ type_counts['Percentage'] = (type_counts['Count'] / total * 100).round(2)
106
+
107
+ # Plotting
108
+ plt.figure(figsize=(10, 5))
109
+ bars = plt.barh(type_counts['Type'], type_counts['Count'], color='white', hatch=hatch_pattern, edgecolor='peachpuff')
110
+ plt.ylabel('Model Type')
111
+ plt.xlabel('Counts')
112
+
113
+ ax = plt.gca()
114
+ # Hide the spines but keep the tick labels
115
+ ax.spines['top'].set_visible(False)
116
+ ax.spines['right'].set_visible(False)
117
+ ax.spines['left'].set_visible(False)
118
+ ax.spines['bottom'].set_visible(False)
119
+
120
+ ax.xaxis.set_ticks_position('none')
121
+ #ax.yaxis.set_ticks_position('none')
122
+
123
+ plt.title('Model Type Distribution Across All Files')
124
+
125
+ # Adding the percentages on the bars
126
+ for bar, percentage in zip(bars, type_counts['Percentage']):
127
+ plt.text(bar.get_width()+ 100, bar.get_y() + bar.get_height()/2, f'{percentage}%', va='center', color='blueviolet')
128
+
129
+ plt.tight_layout() # Adjust layout to make room for the labels
130
+ plt.show()
131
+
132
+
133
+
134
+
135
+
136
+ ## sortByFrequency function: path-to-json, skalar, title, output_path
137
+ sortByFrequency('most popular/most_popular_models_with_date_page_1.json', 19000, 'Top 20 most downloaded models and their tags -', 'png/2024-03-26/most_downloaded')
138
+ most_popular_tags('most_popular')
139
+ #most_popular_tags_02('most_popular')
140
+
141
+
142
+ importlib.reload(functions)
143
+
144
+
145
+ most_popular_tags('most_popular')
146
+
147
+
148
+ !pip install wordcloud matplotlib
README.md ADDED
File without changes
misc/api_keys_example.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ api_key_01
2
+ api_key_02
misc/autotagging-vocabularies/clip_interrogator.csv ADDED
The diff for this file is too large to render. See raw diff
 
misc/autotagging-vocabularies/danbooru.csv ADDED
The diff for this file is too large to render. See raw diff
 
misc/autotagging-vocabularies/deepbooru_tags.txt ADDED
The diff for this file is too large to render. See raw diff
 
misc/deletemememe.txt ADDED
The diff for this file is too large to render. See raw diff
 
plots/2024-06_image_contributions.svg ADDED
plots/Sec-6-5_lora_tags_categories.svg ADDED
plots/Sec_6-4_adapters_rank.csv.svg ADDED
plots/Sec_6-4_models_rank.csv.svg ADDED
plots/Sec_6-5_taggers.svg ADDED
plots/Section_6-7_model_contributions_sankey.svg ADDED
plots/grid10x120.png ADDED

Git LFS Details

  • SHA256: d6289c2fc434350fa7a97d81a7a66b248576acfaf02d807abd02f85ee7161836
  • Pointer size: 130 Bytes
  • Size of remote file: 14.4 kB
plots/mivolo.svg ADDED
plots/models_nsfw_monthly_histogram_with_quarters.png ADDED

Git LFS Details

  • SHA256: 44137238e4b06b963f97417bfd1cb03fc75fe0ec7fc251972e3464eef0356b65
  • Pointer size: 131 Bytes
  • Size of remote file: 173 kB
plots/models_nsfw_monthly_histogram_with_quarters.svg ADDED
plots/top_15.svg.svg ADDED
requirements.txt ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # requirements.txt
2
+
3
+ # Core Python libraries
4
+ numpy
5
+ pandas
6
+ matplotlib
7
+ plotly
8
+ scipy
9
+ datetime
10
+ dateutil
11
+ pathlib
12
+ itertools
13
+ collections
14
+ logging
15
+ argparse
16
+ shutil
17
+ re
18
+ json
19
+ csv
20
+ sys
21
+ ast
22
+ importlib
23
+ struct
24
+
25
+ # Machine Learning and Image Processing
26
+ torch
27
+ opencv-python
28
+ pillow
29
+ requests
30
+ retrying
31
+ mivolo
32
+
33
+ # Jupyter-specific (if running in Jupyter)
34
+ jupyterlab
35
+ ipykernel
36
+
37
+ # Additional Utilities
38
+ fonttools
scripts/0_Scraping_image_metadata.ipynb ADDED
@@ -0,0 +1,1311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "1111ea95-d385-49b9-a4d9-ef886ace5c7a",
6
+ "metadata": {
7
+ "execution": {
8
+ "iopub.execute_input": "2025-02-06T11:24:25.566747Z",
9
+ "iopub.status.busy": "2025-02-06T11:24:25.566066Z",
10
+ "iopub.status.idle": "2025-02-06T11:24:25.571748Z",
11
+ "shell.execute_reply": "2025-02-06T11:24:25.571305Z",
12
+ "shell.execute_reply.started": "2025-02-06T11:24:25.566705Z"
13
+ }
14
+ },
15
+ "source": [
16
+ "# 0 Scraping Metadata and Dataset consolidation\n"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "markdown",
21
+ "id": "6632505a-e7ca-4463-9ffc-e36fad42235f",
22
+ "metadata": {},
23
+ "source": [
24
+ "## IMAGES\n",
25
+ "---"
26
+ ]
27
+ },
28
+ {
29
+ "cell_type": "markdown",
30
+ "id": "e3388bac-bb71-40bc-a693-9ac7a2d5f32c",
31
+ "metadata": {
32
+ "execution": {
33
+ "iopub.execute_input": "2025-02-06T10:08:22.229784Z",
34
+ "iopub.status.busy": "2025-02-06T10:08:22.229287Z",
35
+ "iopub.status.idle": "2025-02-06T10:08:22.232210Z",
36
+ "shell.execute_reply": "2025-02-06T10:08:22.231793Z",
37
+ "shell.execute_reply.started": "2025-02-06T10:08:22.229766Z"
38
+ }
39
+ },
40
+ "source": [
41
+ "### Step 1: Image metadata scraping, sorting and CSV consolidation"
42
+ ]
43
+ },
44
+ {
45
+ "cell_type": "raw",
46
+ "id": "8b5d623a-a647-42ae-9951-efa99048cdf3",
47
+ "metadata": {},
48
+ "source": [
49
+ "Dataset creation workflow\n",
50
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐\n",
51
+ "│ Scrape Data from API │ --> │ Use CivitAI API with a timestamp-based cursor to │\n",
52
+ "│ Paginate Using Cursor│ │ scrape image metadata and save in JSON batches. │\n",
53
+ "│ Save in JSON Format │ └───────────────────────────────────────────────────┘\n",
54
+ "└─────────┬────────────┘\n",
55
+ " ↓\n",
56
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐\n",
57
+ "│ Locate JSON Files │ --> │ Find all JSON files saved in the directory. │\n",
58
+ "│ in Directory │ │ │\n",
59
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘\n",
60
+ " ↓\n",
61
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐\n",
62
+ "│ Read Each JSON File │ --> │ Parse JSON files and extract metadata, reactions, │\n",
63
+ "│ Parse and Extract │ │ and resource details. │\n",
64
+ "│ Metadata, Reactions, │ │ │\n",
65
+ "│ and Resources │ │ │\n",
66
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘\n",
67
+ " ↓\n",
68
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐\n",
69
+ "│ Sort Items by │ --> │ Sort the extracted items chronologically using │\n",
70
+ "│ createdAt Timestamp │ │ their createdAt timestamp. │\n",
71
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘\n",
72
+ " ↓\n",
73
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐\n",
74
+ "│ Write Extracted Data │ --> │ Save the processed and sorted data into a │\n",
75
+ "│ to a Consolidated │ │ consolidated CSV file with structured columns. │\n",
76
+ "│ CSV File │ │ │\n",
77
+ "└────────��─────────────┘ └───────────────────────────────────────────────────┘\n"
78
+ ]
79
+ },
80
+ {
81
+ "cell_type": "code",
82
+ "execution_count": 3,
83
+ "id": "f8decb63-43f5-4731-823d-94632eee7618",
84
+ "metadata": {
85
+ "execution": {
86
+ "iopub.execute_input": "2025-02-08T19:37:51.115763Z",
87
+ "iopub.status.busy": "2025-02-08T19:37:51.114573Z",
88
+ "iopub.status.idle": "2025-02-08T19:37:51.170027Z",
89
+ "shell.execute_reply": "2025-02-08T19:37:51.169401Z",
90
+ "shell.execute_reply.started": "2025-02-08T19:37:51.115738Z"
91
+ }
92
+ },
93
+ "outputs": [],
94
+ "source": [
95
+ "import os\n",
96
+ "import json\n",
97
+ "import csv\n",
98
+ "import requests\n",
99
+ "from datetime import datetime\n",
100
+ "import time\n",
101
+ "from pathlib import Path\n",
102
+ "import hashlib\n",
103
+ "import pandas as pd\n",
104
+ "import sys\n",
105
+ "from datetime import datetime, timedelta\n",
106
+ "import shutil"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "code",
111
+ "execution_count": 4,
112
+ "id": "4b2426c3-96a0-468e-b6dc-78dea9c3e92b",
113
+ "metadata": {
114
+ "execution": {
115
+ "iopub.execute_input": "2025-02-08T19:37:51.809027Z",
116
+ "iopub.status.busy": "2025-02-08T19:37:51.808835Z",
117
+ "iopub.status.idle": "2025-02-08T19:37:51.812922Z",
118
+ "shell.execute_reply": "2025-02-08T19:37:51.812429Z",
119
+ "shell.execute_reply.started": "2025-02-08T19:37:51.809009Z"
120
+ }
121
+ },
122
+ "outputs": [],
123
+ "source": [
124
+ "current_dir = Path.cwd()"
125
+ ]
126
+ },
127
+ {
128
+ "cell_type": "code",
129
+ "execution_count": 3,
130
+ "id": "dd0daa43-d988-4ac5-b9c7-2f9c65078325",
131
+ "metadata": {
132
+ "execution": {
133
+ "iopub.execute_input": "2025-02-07T20:59:30.413939Z",
134
+ "iopub.status.busy": "2025-02-07T20:59:30.412861Z",
135
+ "iopub.status.idle": "2025-02-07T20:59:30.418660Z",
136
+ "shell.execute_reply": "2025-02-07T20:59:30.418054Z",
137
+ "shell.execute_reply.started": "2025-02-07T20:59:30.413918Z"
138
+ }
139
+ },
140
+ "outputs": [],
141
+ "source": [
142
+ "# Define the input timestamp in ISO 8601 format\n",
143
+ "input_timestamp = \"2025-02-01T00:00:00.000Z\" # point in time from when you want to obtain metadata (you can copy the timestamp from the last *.json batch obtained to get the data of longer timespans)\n",
144
+ "\n",
145
+ "# Function to convert an ISO 8601 date string to a Unix timestamp in milliseconds with a 2-hour offset \n",
146
+ "def iso_to_timestamp(iso_str):\n",
147
+ " # Parse the ISO 8601 date string (including milliseconds and 'Z' indicating UTC)\n",
148
+ " date = datetime.strptime(iso_str, \"%Y-%m-%dT%H:%M:%S.%fZ\") \n",
149
+ " # Add 2 hours to the parsed date\n",
150
+ " adjusted_date = date + timedelta(hours=2)\n",
151
+ " # Convert to Unix timestamp (in milliseconds)\n",
152
+ " timestamp = int(adjusted_date.timestamp() * 1000)\n",
153
+ " return timestamp\n",
154
+ "\n",
155
+ "# Convert the input timestamp to an initial cursor\n",
156
+ "initial_cursor = iso_to_timestamp(input_timestamp)\n"
157
+ ]
158
+ },
159
+ {
160
+ "cell_type": "code",
161
+ "execution_count": 4,
162
+ "id": "20b4bc72-80c4-4af6-bc76-aeecfa65f9dc",
163
+ "metadata": {
164
+ "execution": {
165
+ "iopub.execute_input": "2025-02-07T20:59:31.134620Z",
166
+ "iopub.status.busy": "2025-02-07T20:59:31.133548Z",
167
+ "iopub.status.idle": "2025-02-07T20:59:31.138081Z",
168
+ "shell.execute_reply": "2025-02-07T20:59:31.137555Z",
169
+ "shell.execute_reply.started": "2025-02-07T20:59:31.134599Z"
170
+ }
171
+ },
172
+ "outputs": [],
173
+ "source": [
174
+ "data_raw = current_dir.parent / f\"data/raw/image_metadata/001/{input_timestamp.replace(':', '').replace('T', '_').replace('.', '_').replace('Z', '')}\""
175
+ ]
176
+ },
177
+ {
178
+ "cell_type": "markdown",
179
+ "id": "f69c921d-ca57-4746-8124-a0fa4fce80ff",
180
+ "metadata": {},
181
+ "source": [
182
+ "#### The *.json files will be saved in the following structure:"
183
+ ]
184
+ },
185
+ {
186
+ "cell_type": "raw",
187
+ "id": "d731001e-32a4-4894-a2fe-835ea69214fc",
188
+ "metadata": {},
189
+ "source": [
190
+ "data/\n",
191
+ "└── raw/\n",
192
+ " └── image_metadata\n",
193
+ " └── 001/\n",
194
+ " └── YYYYMMDD_HHMMSS/ # Folder named based on the input timestamp\n",
195
+ " ├── most_recent_1.json # Sequential JSON files\n",
196
+ " ├── most_recent_2.json\n",
197
+ " ├── ...\n",
198
+ " ├── most_recent_50000.json\n",
199
+ " └── YYYYMMDD_HHMMSS_session_TIMESTAMP/ # New folder after API limit is reached\n",
200
+ " ├── most_recent_50001.json\n",
201
+ " ├── most_recent_50002.json\n",
202
+ " ├── ...\n"
203
+ ]
204
+ },
205
+ {
206
+ "cell_type": "code",
207
+ "execution_count": 5,
208
+ "id": "4cb3c005-bf70-43fc-afe8-93bf30872fb4",
209
+ "metadata": {
210
+ "execution": {
211
+ "iopub.execute_input": "2025-02-06T16:51:57.402732Z",
212
+ "iopub.status.busy": "2025-02-06T16:51:57.402532Z",
213
+ "iopub.status.idle": "2025-02-06T16:52:00.855604Z",
214
+ "shell.execute_reply": "2025-02-06T16:52:00.854678Z",
215
+ "shell.execute_reply.started": "2025-02-06T16:51:57.402712Z"
216
+ }
217
+ },
218
+ "outputs": [],
219
+ "source": [
220
+ "max_images = 50000 # some huge number now redundant because CivitAI API currently limits free api usage to 50'000\n",
221
+ "\n",
222
+ "def get_image_metadata():\n",
223
+ " base_url = \"https://civitai.com/api/v1/images\"\n",
224
+ " headers = {\n",
225
+ " \"Accept\": \"application/json\",\n",
226
+ " \"Authorization\": \"Bearer APITOKEN\" # Replace with your actual API token\n",
227
+ " }\n",
228
+ " params = {\n",
229
+ " \"sort\": \"Most Reactions\",\n",
230
+ " \"nsfw\": \"X\",\n",
231
+ " \"cursor\": f\"0|{initial_cursor}\"\n",
232
+ " }\n",
233
+ "\n",
234
+ " # Use pathlib to create the base directory for saving files\n",
235
+ "\n",
236
+ " file_counter = 0\n",
237
+ "\n",
238
+ " # Create a folder based on the input timestamp\n",
239
+ " data_raw.mkdir(parents=True, exist_ok=True)\n",
240
+ " sub_directory_path = data_raw\n",
241
+ "\n",
242
+ " retry_delay = 300 # 300 seconds / 5 minutes\n",
243
+ " retries_without_cursor = 0 # Track consecutive retries without a new cursor\n",
244
+ "\n",
245
+ " while True:\n",
246
+ " response = requests.get(base_url, headers=headers, params=params)\n",
247
+ " if response.status_code == 200:\n",
248
+ " data = response.json()\n",
249
+ " items = data.get('items', [])\n",
250
+ " if not items:\n",
251
+ " print(\"No more data available.\")\n",
252
+ " retries_without_cursor += 1\n",
253
+ " if retries_without_cursor > 5: # Allow up to 5 retries before stopping\n",
254
+ " print(\"Reached the end of the data after multiple retries.\")\n",
255
+ " break\n",
256
+ " time.sleep(retry_delay)\n",
257
+ " continue\n",
258
+ "\n",
259
+ " retries_without_cursor = 0 # Reset if we get data\n",
260
+ "\n",
261
+ " next_cursor = data.get('metadata', {}).get('nextCursor')\n",
262
+ " if next_cursor:\n",
263
+ " # Increment the cursor by 50 (e.g., \"0|1722470401000\" -> \"50|1722470401000\")\n",
264
+ " cursor_value = int(params['cursor'].split(\"|\")[0])\n",
265
+ " new_cursor_value = cursor_value + 50\n",
266
+ " params['cursor'] = f\"{new_cursor_value}|{params['cursor'].split('|')[1]}\"\n",
267
+ " else:\n",
268
+ " print(\"No new cursor returned, stopping.\")\n",
269
+ " break\n",
270
+ "\n",
271
+ " file_counter += 1\n",
272
+ " if file_counter % max_images == 0:\n",
273
+ " time_stamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n",
274
+ " sub_directory_path = data_raw / f\"{input_timestamp.replace(':', '').replace('T', '_').replace('.', '_').replace('Z', '')}_session_{time_stamp}\"\n",
275
+ " sub_directory_path.mkdir(parents=True, exist_ok=True)\n",
276
+ "\n",
277
+ " file_path = sub_directory_path / f'most_recent_{file_counter}.json'\n",
278
+ " with open(file_path, 'w', encoding='utf-8') as file:\n",
279
+ " json.dump(data, file, indent=4)\n",
280
+ "\n",
281
+ " elif response.status_code == 502:\n",
282
+ " print(f\"Received HTTP 502. Retrying in {retry_delay // 60} minutes.\")\n",
283
+ " time.sleep(retry_delay) # Wait for 5 minutes before retrying\n",
284
+ " else:\n",
285
+ " print(f\"Failed to fetch data: HTTP {response.status_code}\")\n",
286
+ " break\n"
287
+ ]
288
+ },
289
+ {
290
+ "cell_type": "markdown",
291
+ "id": "238044f1-544f-4821-a91e-57386d464f9e",
292
+ "metadata": {
293
+ "execution": {
294
+ "iopub.execute_input": "2025-02-06T16:13:44.748157Z",
295
+ "iopub.status.busy": "2025-02-06T16:13:44.747986Z",
296
+ "iopub.status.idle": "2025-02-06T16:13:44.752230Z",
297
+ "shell.execute_reply": "2025-02-06T16:13:44.751694Z",
298
+ "shell.execute_reply.started": "2025-02-06T16:13:44.748140Z"
299
+ }
300
+ },
301
+ "source": [
302
+ "uncomment this line to scrape image metadata:"
303
+ ]
304
+ },
305
+ {
306
+ "cell_type": "code",
307
+ "execution_count": 6,
308
+ "id": "7c89cb68-983b-47df-a028-e02d7ca0829d",
309
+ "metadata": {
310
+ "execution": {
311
+ "iopub.execute_input": "2025-02-06T16:52:00.857210Z",
312
+ "iopub.status.busy": "2025-02-06T16:52:00.857015Z",
313
+ "iopub.status.idle": "2025-02-06T16:52:04.901096Z",
314
+ "shell.execute_reply": "2025-02-06T16:52:04.900159Z",
315
+ "shell.execute_reply.started": "2025-02-06T16:52:00.857191Z"
316
+ }
317
+ },
318
+ "outputs": [],
319
+ "source": [
320
+ "#get_image_metadata()"
321
+ ]
322
+ },
323
+ {
324
+ "cell_type": "markdown",
325
+ "id": "06f5f27e-7278-44c9-ae34-9a2020cac2f2",
326
+ "metadata": {},
327
+ "source": [
328
+ "---\n",
329
+ "---"
330
+ ]
331
+ },
332
+ {
333
+ "cell_type": "markdown",
334
+ "id": "648aee1b-9e01-4400-a6a8-3361c97c377a",
335
+ "metadata": {
336
+ "execution": {
337
+ "iopub.execute_input": "2025-02-06T11:33:11.524990Z",
338
+ "iopub.status.busy": "2025-02-06T11:33:11.523287Z",
339
+ "iopub.status.idle": "2025-02-06T11:33:11.531385Z",
340
+ "shell.execute_reply": "2025-02-06T11:33:11.530884Z",
341
+ "shell.execute_reply.started": "2025-02-06T11:33:11.524893Z"
342
+ }
343
+ },
344
+ "source": [
345
+ "### Step 02 Chronological Sorting"
346
+ ]
347
+ },
348
+ {
349
+ "cell_type": "code",
350
+ "execution_count": 7,
351
+ "id": "b73d7ea5-50e0-485d-8bc5-a4736f31c789",
352
+ "metadata": {
353
+ "execution": {
354
+ "iopub.execute_input": "2025-02-06T16:52:04.902663Z",
355
+ "iopub.status.busy": "2025-02-06T16:52:04.902478Z",
356
+ "iopub.status.idle": "2025-02-06T16:52:08.491068Z",
357
+ "shell.execute_reply": "2025-02-06T16:52:08.490105Z",
358
+ "shell.execute_reply.started": "2025-02-06T16:52:04.902646Z"
359
+ }
360
+ },
361
+ "outputs": [],
362
+ "source": [
363
+ "def organize_files(source_dir, target_dir, max_items_per_file=100):\n",
364
+ " print(f\"Starting to organize files from {source_dir} to {target_dir}\")\n",
365
+ " item_buffer = []\n",
366
+ " file_count = 0\n",
367
+ "\n",
368
+ " # Walk through all files in the source directory\n",
369
+ " for root, dirs, files in os.walk(source_dir):\n",
370
+ " if '.ipynb_checkpoints' in root:\n",
371
+ " continue # Skip .ipynb_checkpoints directories\n",
372
+ " print(f\"Checking directory: {root}\")\n",
373
+ " for filename in files:\n",
374
+ " if filename.lower().endswith('.json'):\n",
375
+ " file_path = os.path.join(root, filename)\n",
376
+ " try:\n",
377
+ " with open(file_path, 'r') as file:\n",
378
+ " data = json.load(file)\n",
379
+ " items = data.get('items', []) # Get the list of items\n",
380
+ " for item in items:\n",
381
+ " item_buffer.append(item)\n",
382
+ " # Write out the buffer if it has reached the maximum size\n",
383
+ " if len(item_buffer) >= max_items_per_file:\n",
384
+ " write_items(item_buffer[:max_items_per_file], target_dir)\n",
385
+ " item_buffer = item_buffer[max_items_per_file:]\n",
386
+ " file_count += 1\n",
387
+ " except json.JSONDecodeError:\n",
388
+ " print(f\"Error decoding JSON from file {file_path}\")\n",
389
+ " except Exception as e:\n",
390
+ " print(f\"An error occurred with file {file_path}: {e}\")\n",
391
+ "\n",
392
+ " # Write any remaining items in the buffer\n",
393
+ " if item_buffer:\n",
394
+ " write_items(item_buffer, target_dir)\n",
395
+ " file_count += 1\n",
396
+ "\n",
397
+ " #print(f\"Processed {file_count} files.\")\n",
398
+ "\n",
399
+ "def write_items(items, target_dir):\n",
400
+ " # Use the createdAt from the first item to determine the directory\n",
401
+ " created_at = items[0].get('createdAt')\n",
402
+ " if created_at:\n",
403
+ " date_obj = datetime.fromisoformat(created_at.rstrip(\"Z\"))\n",
404
+ " new_dir = os.path.join(target_dir, f\"{date_obj.year}\", f\"{date_obj.year}-{date_obj.month:02d}\", f\"{date_obj.year}-{date_obj.month:02d}-{date_obj.day:02d}\")\n",
405
+ " os.makedirs(new_dir, exist_ok=True)\n",
406
+ " new_file_path = os.path.join(new_dir, f\"batch_{date_obj.strftime('%Y%m%dT%H%M%S')}.json\")\n",
407
+ " with open(new_file_path, 'w', encoding='utf-8') as new_file:\n",
408
+ " json.dump(items, new_file, indent=4)\n",
409
+ " #print(f\"Wrote {len(items)} items to {new_file_path}\")\n"
410
+ ]
411
+ },
412
+ {
413
+ "cell_type": "code",
414
+ "execution_count": 8,
415
+ "id": "07cebb8a-2955-4432-a0d1-7ee94975a34b",
416
+ "metadata": {
417
+ "execution": {
418
+ "iopub.execute_input": "2025-02-06T16:52:08.492517Z",
419
+ "iopub.status.busy": "2025-02-06T16:52:08.492328Z",
420
+ "iopub.status.idle": "2025-02-06T16:53:13.648165Z",
421
+ "shell.execute_reply": "2025-02-06T16:53:13.647511Z",
422
+ "shell.execute_reply.started": "2025-02-06T16:52:08.492499Z"
423
+ }
424
+ },
425
+ "outputs": [
426
+ {
427
+ "name": "stdout",
428
+ "output_type": "stream",
429
+ "text": [
430
+ "Starting to organize files from /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/image_metadata/001/2025-02-01_000000_000 to /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/sorted/image_metadata\n",
431
+ "Checking directory: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/image_metadata/001/2025-02-01_000000_000\n"
432
+ ]
433
+ }
434
+ ],
435
+ "source": [
436
+ "data_sorted = current_dir.parent / 'data/sorted/image_metadata'\n",
437
+ "\n",
438
+ "origin = data_raw\n",
439
+ "target = data_sorted\n",
440
+ "\n",
441
+ "organize_files( origin, target)"
442
+ ]
443
+ },
444
+ {
445
+ "cell_type": "markdown",
446
+ "id": "9255fd24-54ee-4235-bc44-a0246e2fd927",
447
+ "metadata": {},
448
+ "source": [
449
+ "---\n",
450
+ "---"
451
+ ]
452
+ },
453
+ {
454
+ "cell_type": "markdown",
455
+ "id": "64639464-6dc4-4997-a805-3f9f41f305c7",
456
+ "metadata": {},
457
+ "source": [
458
+ "### Step 3 CSV consolidation"
459
+ ]
460
+ },
461
+ {
462
+ "cell_type": "markdown",
463
+ "id": "add5f97b-562a-4af5-a8f2-635433a8158f",
464
+ "metadata": {
465
+ "execution": {
466
+ "iopub.execute_input": "2025-02-06T12:03:15.512133Z",
467
+ "iopub.status.busy": "2025-02-06T12:03:15.511399Z",
468
+ "iopub.status.idle": "2025-02-06T12:03:15.516297Z",
469
+ "shell.execute_reply": "2025-02-06T12:03:15.515815Z",
470
+ "shell.execute_reply.started": "2025-02-06T12:03:15.512114Z"
471
+ }
472
+ },
473
+ "source": [
474
+ "#### this script walks through the directories in **image-metadata/** and creates the dataset as **.csv** \n"
475
+ ]
476
+ },
477
+ {
478
+ "cell_type": "markdown",
479
+ "id": "0f8c83aa-c143-4fac-b890-a8d4249067a0",
480
+ "metadata": {
481
+ "execution": {
482
+ "iopub.execute_input": "2025-02-06T12:02:29.925370Z",
483
+ "iopub.status.busy": "2025-02-06T12:02:29.923935Z",
484
+ "iopub.status.idle": "2025-02-06T12:02:31.421575Z",
485
+ "shell.execute_reply": "2025-02-06T12:02:31.420575Z",
486
+ "shell.execute_reply.started": "2025-02-06T12:02:29.925332Z"
487
+ }
488
+ },
489
+ "source": [
490
+ "\n",
491
+ "### Dataset Columns\n",
492
+ "\n",
493
+ "| **Column Name** | **Description** |\n",
494
+ "|------------------------|-----------------------------------------------------------------------------------------------|\n",
495
+ "| `createdAt` | Timestamp when the item was created. |\n",
496
+ "| `url` | URL associated with the item. |\n",
497
+ "| `positivePrompt` | Positive prompts used in the generation process. |\n",
498
+ "| `negativePrompt` | Negative prompts used in the generation process. |\n",
499
+ "| `nsfw` | Indicates whether the item is NSFW (Not Safe for Work). |\n",
500
+ "| `nsfwLevel` | Level of NSFW content (e.g., Soft, Mature). we only considered SFW!! |\n",
501
+ "| `browsingLevel` | Browsing level required to access the content. |\n",
502
+ "| `statsSummary` | All social reactions summed up: cryCount, likeCount, heartCount, CommentCount |\n",
503
+ "| `commentCount` | Number of comments received. |\n",
504
+ "| `username` | Username of the creator of the item. |\n",
505
+ "| `Model` | Model used to generate the content. |\n",
506
+ "| `Meta` | Simplified meta details, including size, seed, steps, sampler, and version. |\n",
507
+ "| `VAE` | Variational Autoencoder (VAE) used, if any. |\n",
508
+ "| `resourceIDs`| Array of up to six resources (LoRA etc.), including name, type, and weight. |\n",
509
+ "\n"
510
+ ]
511
+ },
512
+ {
513
+ "cell_type": "code",
514
+ "execution_count": 5,
515
+ "id": "f8db24f9-6678-4e7d-a3b7-453f33ad0f71",
516
+ "metadata": {
517
+ "execution": {
518
+ "iopub.execute_input": "2025-02-07T20:59:38.328530Z",
519
+ "iopub.status.busy": "2025-02-07T20:59:38.328049Z",
520
+ "iopub.status.idle": "2025-02-07T20:59:38.342970Z",
521
+ "shell.execute_reply": "2025-02-07T20:59:38.342400Z",
522
+ "shell.execute_reply.started": "2025-02-07T20:59:38.328508Z"
523
+ }
524
+ },
525
+ "outputs": [],
526
+ "source": [
527
+ "def find_json_files(directory):\n",
528
+ " \"\"\"Walk through the directory and its subdirectories to find all JSON files.\"\"\"\n",
529
+ " json_files = []\n",
530
+ " for root, _, files in os.walk(directory):\n",
531
+ " for file in files:\n",
532
+ " if file.endswith('.json'):\n",
533
+ " json_files.append(os.path.join(root, file))\n",
534
+ " return json_files\n",
535
+ "\n",
536
+ "def hash_username(username):\n",
537
+ " \"\"\"Convert a username into a unique hash.\"\"\"\n",
538
+ " return hashlib.sha256(username.encode('utf-8')).hexdigest()[:16] # Use first 16 characters for brevity\n",
539
+ "\n",
540
+ "def extract_resource_ids(meta, resources):\n",
541
+ " \"\"\"Extract resource IDs from metadata and resources.\"\"\"\n",
542
+ " resource_ids = set() # Use a set to avoid duplicates\n",
543
+ " hash_ids = set() # Separate set to track hashes specifically\n",
544
+ "\n",
545
+ " # Extract CivitAI model IDs\n",
546
+ " if \"civitaiResources\" in meta:\n",
547
+ " for resource in meta[\"civitaiResources\"]:\n",
548
+ " if \"modelVersionId\" in resource:\n",
549
+ " resource_ids.add(str(resource[\"modelVersionId\"])) # Ensure all IDs are strings\n",
550
+ "\n",
551
+ " # Extract model hashes\n",
552
+ " if \"Model hash\" in meta:\n",
553
+ " hash_ids.add(meta[\"Model hash\"])\n",
554
+ " if \"base_model_hash\" in meta:\n",
555
+ " hash_ids.add(meta[\"base_model_hash\"])\n",
556
+ " if \"models\" in meta and isinstance(meta[\"models\"], list):\n",
557
+ " hash_ids.update(str(model) for model in meta[\"models\"])\n",
558
+ "\n",
559
+ " # Extract identifiers from resources list\n",
560
+ " for resource in resources:\n",
561
+ " if isinstance(resource, dict): # Ensure resource is a dictionary\n",
562
+ " resource_hash = resource.get(\"hash\")\n",
563
+ " if resource_hash:\n",
564
+ " hash_ids.add(str(resource_hash)) # Add to hash set\n",
565
+ " else:\n",
566
+ " name = resource.get(\"name\")\n",
567
+ " if name:\n",
568
+ " resource_ids.add(str(name))\n",
569
+ "\n",
570
+ " # Remove any named IDs if their hash exists\n",
571
+ " resource_ids = {rid for rid in resource_ids if rid not in hash_ids}\n",
572
+ "\n",
573
+ " # Combine hashes and remaining resource IDs\n",
574
+ " final_ids = list(hash_ids) + list(resource_ids)\n",
575
+ " return final_ids\n",
576
+ "\n",
577
+ "def format_resource_ids(resource_ids):\n",
578
+ " \"\"\"Format resource IDs in a standardized list format.\"\"\"\n",
579
+ " formatted_ids = [str(rid).strip() for rid in resource_ids if rid]\n",
580
+ " return f\"[{', '.join(formatted_ids)}]\"\n",
581
+ "\n",
582
+ "def truncate_prompt(prompt, max_tokens=77):\n",
583
+ " \"\"\"Truncate a prompt to a maximum number of tokens.\"\"\"\n",
584
+ " return ' '.join(prompt.split()[:max_tokens]) if prompt else \"\"\n",
585
+ "\n",
586
+ "def write_to_csv(json_files, output_csv):\n",
587
+ " \"\"\"Read JSON files, extract data, and write to a CSV file.\"\"\"\n",
588
+ " with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:\n",
589
+ " fieldnames = [\n",
590
+ " 'id', 'createdAt', 'url', 'positivePrompt', 'negativePrompt', 'nsfw',\n",
591
+ " 'browsingLevel', 'statsSummary', 'usernameHash', 'Model', 'cfgScale',\n",
592
+ " 'sampler', 'Size', 'seed', 'VAE', 'generationSystem', 'resourceIDs'\n",
593
+ " ]\n",
594
+ " writer = csv.DictWriter(csvfile, fieldnames=fieldnames)\n",
595
+ " writer.writeheader()\n",
596
+ "\n",
597
+ " for json_file in json_files:\n",
598
+ " with open(json_file, 'r', encoding='utf-8') as file:\n",
599
+ " try:\n",
600
+ " data = json.load(file)\n",
601
+ " for item in data:\n",
602
+ " meta = item.get('meta', {}) or {}\n",
603
+ " stats = item.get('stats', {}) or {}\n",
604
+ " resources = meta.get('resources', []) if isinstance(meta, dict) else []\n",
605
+ "\n",
606
+ " # Anonymize username\n",
607
+ " username = item.get('username', '')\n",
608
+ " username_hash = hash_username(username) if username else ''\n",
609
+ "\n",
610
+ " # Extract resource IDs\n",
611
+ " resource_ids = extract_resource_ids(meta, resources)\n",
612
+ " formatted_resource_ids = format_resource_ids(resource_ids)\n",
613
+ "\n",
614
+ " # Summarize stats counts\n",
615
+ " stats_summary = sum(stats.get(key, 0) for key in stats)\n",
616
+ "\n",
617
+ " # Truncate prompts\n",
618
+ " positive_prompt = truncate_prompt(meta.get('prompt', ''))\n",
619
+ " negative_prompt = truncate_prompt(meta.get('negativePrompt', ''))\n",
620
+ "\n",
621
+ " # Extract metadata fields\n",
622
+ " cfg_scale = meta.get('cfgScale', 'N/A')\n",
623
+ " sampler = meta.get('sampler', 'N/A')\n",
624
+ " size = meta.get('Size', 'N/A')\n",
625
+ " seed = meta.get('seed', 'N/A')\n",
626
+ " vae = meta.get('VAE', 'N/A')\n",
627
+ " generation_system = \"CivitAI\" if \"civitaiResources\" in meta else \"Undetermined\"\n",
628
+ "\n",
629
+ " # Process a single row\n",
630
+ " row = {\n",
631
+ " 'id': item.get('id', ''),\n",
632
+ " 'createdAt': item.get('createdAt', ''),\n",
633
+ " 'url': item.get('url', ''),\n",
634
+ " 'positivePrompt': positive_prompt,\n",
635
+ " 'negativePrompt': negative_prompt,\n",
636
+ " 'nsfw': item.get('nsfw', False),\n",
637
+ " 'browsingLevel': item.get('browsingLevel', 'N/A'),\n",
638
+ " 'statsSummary': stats_summary,\n",
639
+ " 'usernameHash': username_hash,\n",
640
+ " 'Model': meta.get('Model', ''),\n",
641
+ " 'cfgScale': cfg_scale,\n",
642
+ " 'sampler': sampler,\n",
643
+ " 'Size': size,\n",
644
+ " 'seed': seed,\n",
645
+ " 'VAE': vae,\n",
646
+ " 'generationSystem': generation_system,\n",
647
+ " 'resourceIDs': formatted_resource_ids\n",
648
+ " }\n",
649
+ "\n",
650
+ " writer.writerow(row)\n",
651
+ " except (json.JSONDecodeError, KeyError, TypeError) as e:\n",
652
+ " print(f\"Error processing file {json_file}: {e}\")\n"
653
+ ]
654
+ },
655
+ {
656
+ "cell_type": "markdown",
657
+ "id": "1c51189e-5eb2-40ef-a5dd-807cd9cded5f",
658
+ "metadata": {
659
+ "execution": {
660
+ "iopub.execute_input": "2025-02-06T12:49:11.129158Z",
661
+ "iopub.status.busy": "2025-02-06T12:49:11.128195Z",
662
+ "iopub.status.idle": "2025-02-06T12:49:11.132440Z",
663
+ "shell.execute_reply": "2025-02-06T12:49:11.131779Z",
664
+ "shell.execute_reply.started": "2025-02-06T12:49:11.129132Z"
665
+ }
666
+ },
667
+ "source": [
668
+ "### Save as 'Civiverse' dataset in data/CSV"
669
+ ]
670
+ },
671
+ {
672
+ "cell_type": "code",
673
+ "execution_count": 6,
674
+ "id": "07c97ff9-7ce0-43b7-a156-f5fb79c49cd9",
675
+ "metadata": {
676
+ "execution": {
677
+ "iopub.execute_input": "2025-02-07T20:59:40.218975Z",
678
+ "iopub.status.busy": "2025-02-07T20:59:40.218224Z",
679
+ "iopub.status.idle": "2025-02-07T21:04:11.221872Z",
680
+ "shell.execute_reply": "2025-02-07T21:04:11.220974Z",
681
+ "shell.execute_reply.started": "2025-02-07T20:59:40.218926Z"
682
+ }
683
+ },
684
+ "outputs": [
685
+ {
686
+ "name": "stdout",
687
+ "output_type": "stream",
688
+ "text": [
689
+ "Error processing file /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/sorted/image_metadata/2024/2024-07/2024-07-29/batch_20240729T192800.json: Expecting value: line 1 column 1 (char 0)\n"
690
+ ]
691
+ }
692
+ ],
693
+ "source": [
694
+ "from pathlib import Path\n",
695
+ "\n",
696
+ "raw = current_dir.parent / 'data/sorted/image_metadata/'\n",
697
+ "csv_output = current_dir.parent / 'data/CSV/Civiverse.csv'\n",
698
+ "\n",
699
+ "csv_output.parent.mkdir(parents=True, exist_ok=True)\n",
700
+ "\n",
701
+ "json_files = find_json_files(raw)\n",
702
+ "write_to_csv(json_files, csv_output)"
703
+ ]
704
+ },
705
+ {
706
+ "cell_type": "markdown",
707
+ "id": "b3e64b07-98d1-480d-b4e1-f624a17db848",
708
+ "metadata": {
709
+ "execution": {
710
+ "iopub.execute_input": "2025-02-06T13:50:08.120671Z",
711
+ "iopub.status.busy": "2025-02-06T13:50:08.119949Z",
712
+ "iopub.status.idle": "2025-02-06T13:50:08.124761Z",
713
+ "shell.execute_reply": "2025-02-06T13:50:08.124298Z",
714
+ "shell.execute_reply.started": "2025-02-06T13:50:08.120632Z"
715
+ }
716
+ },
717
+ "source": [
718
+ "### Optional step 4: Create sampled subset"
719
+ ]
720
+ },
721
+ {
722
+ "cell_type": "code",
723
+ "execution_count": 11,
724
+ "id": "b531b8cd-4653-451d-a6d5-386a2721827c",
725
+ "metadata": {
726
+ "execution": {
727
+ "iopub.execute_input": "2025-02-06T16:55:01.916121Z",
728
+ "iopub.status.busy": "2025-02-06T16:55:01.915489Z",
729
+ "iopub.status.idle": "2025-02-06T16:55:01.920043Z",
730
+ "shell.execute_reply": "2025-02-06T16:55:01.919655Z",
731
+ "shell.execute_reply.started": "2025-02-06T16:55:01.916103Z"
732
+ }
733
+ },
734
+ "outputs": [],
735
+ "source": [
736
+ "input_file = current_dir.parent / 'data/CSV/Civiverse.csv'\n",
737
+ "output_file = current_dir.parent / 'data/CSV/image_subsets/Civiverse-mini.csv'\n",
738
+ "output_file.parent.mkdir(parents=True, exist_ok=True)"
739
+ ]
740
+ },
741
+ {
742
+ "cell_type": "code",
743
+ "execution_count": 12,
744
+ "id": "b82db8b3-310c-49e4-9d7a-aa34662f9556",
745
+ "metadata": {
746
+ "execution": {
747
+ "iopub.execute_input": "2025-02-06T16:55:01.920861Z",
748
+ "iopub.status.busy": "2025-02-06T16:55:01.920586Z",
749
+ "iopub.status.idle": "2025-02-06T16:55:06.790164Z",
750
+ "shell.execute_reply": "2025-02-06T16:55:06.789503Z",
751
+ "shell.execute_reply.started": "2025-02-06T16:55:01.920844Z"
752
+ }
753
+ },
754
+ "outputs": [
755
+ {
756
+ "name": "stderr",
757
+ "output_type": "stream",
758
+ "text": [
759
+ "/sctmp/lauwag/ipykernel_1043676/3764041865.py:4: DtypeWarning: Columns (13) have mixed types. Specify dtype option on import or set low_memory=False.\n",
760
+ " df = pd.read_csv(input_file)\n",
761
+ "/sctmp/lauwag/ipykernel_1043676/3764041865.py:10: SettingWithCopyWarning: \n",
762
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
763
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
764
+ "\n",
765
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
766
+ " df_sample['createdAt'] = pd.to_datetime(df_sample['createdAt'], errors='coerce')\n"
767
+ ]
768
+ }
769
+ ],
770
+ "source": [
771
+ "\n",
772
+ "# Define the sampling rate\n",
773
+ "n = 100\n",
774
+ "# Read the CSV file\n",
775
+ "df = pd.read_csv(input_file)\n",
776
+ "\n",
777
+ "# Sample every 15th row\n",
778
+ "df_sample = df.iloc[::n, :]\n",
779
+ "\n",
780
+ "# Convert the 'createdAt' column to datetime, inferring mixed formats\n",
781
+ "df_sample['createdAt'] = pd.to_datetime(df_sample['createdAt'], errors='coerce')\n",
782
+ "\n",
783
+ "# Sort the sampled data by the 'createdAt' column\n",
784
+ "df_sample_sorted = df_sample.sort_values(by='createdAt')\n",
785
+ "\n",
786
+ "# Save the sorted sample DataFrame to a new CSV file\n",
787
+ "df_sample_sorted.to_csv(output_file, index=False)"
788
+ ]
789
+ },
790
+ {
791
+ "cell_type": "markdown",
792
+ "id": "d915b7d6-937a-4fa9-9edc-ded67e3606f5",
793
+ "metadata": {},
794
+ "source": [
795
+ "---\n",
796
+ "---\n",
797
+ "---"
798
+ ]
799
+ },
800
+ {
801
+ "cell_type": "markdown",
802
+ "id": "11647bb7-5ce9-414a-8486-5bdce8d9cfea",
803
+ "metadata": {
804
+ "execution": {
805
+ "iopub.execute_input": "2025-02-06T12:49:43.126762Z",
806
+ "iopub.status.busy": "2025-02-06T12:49:43.125797Z",
807
+ "iopub.status.idle": "2025-02-06T12:49:43.129759Z",
808
+ "shell.execute_reply": "2025-02-06T12:49:43.129176Z",
809
+ "shell.execute_reply.started": "2025-02-06T12:49:43.126736Z"
810
+ }
811
+ },
812
+ "source": [
813
+ "## MODELS"
814
+ ]
815
+ },
816
+ {
817
+ "cell_type": "markdown",
818
+ "id": "5c9cb5e3-7cea-4574-9319-f3cd89354b1f",
819
+ "metadata": {
820
+ "execution": {
821
+ "iopub.execute_input": "2025-02-06T13:23:38.017078Z",
822
+ "iopub.status.busy": "2025-02-06T13:23:38.016639Z",
823
+ "iopub.status.idle": "2025-02-06T13:23:38.019993Z",
824
+ "shell.execute_reply": "2025-02-06T13:23:38.019549Z",
825
+ "shell.execute_reply.started": "2025-02-06T13:23:38.017053Z"
826
+ }
827
+ },
828
+ "source": [
829
+ "### Step 1: Scrape model metadata"
830
+ ]
831
+ },
832
+ {
833
+ "cell_type": "markdown",
834
+ "id": "83e12b9f-5ae1-407d-9754-5979d837f787",
835
+ "metadata": {
836
+ "execution": {
837
+ "iopub.execute_input": "2025-02-06T14:06:04.857874Z",
838
+ "iopub.status.busy": "2025-02-06T14:06:04.857500Z",
839
+ "iopub.status.idle": "2025-02-06T14:06:04.860438Z",
840
+ "shell.execute_reply": "2025-02-06T14:06:04.860030Z",
841
+ "shell.execute_reply.started": "2025-02-06T14:06:04.857856Z"
842
+ }
843
+ },
844
+ "source": [
845
+ "#### the resulting files will appear in data/raw/model_metadata as *.json"
846
+ ]
847
+ },
848
+ {
849
+ "cell_type": "code",
850
+ "execution_count": 5,
851
+ "id": "41ee14e0-fb78-4f91-aba1-13faf05af7d8",
852
+ "metadata": {
853
+ "execution": {
854
+ "iopub.execute_input": "2025-02-08T19:37:56.687832Z",
855
+ "iopub.status.busy": "2025-02-08T19:37:56.687251Z",
856
+ "iopub.status.idle": "2025-02-08T19:37:56.696572Z",
857
+ "shell.execute_reply": "2025-02-08T19:37:56.696059Z",
858
+ "shell.execute_reply.started": "2025-02-08T19:37:56.687809Z"
859
+ }
860
+ },
861
+ "outputs": [],
862
+ "source": [
863
+ "import datetime\n",
864
+ "\n",
865
+ "def load_api_keys():\n",
866
+ " \"\"\"Load API keys from a text file, one per line.\"\"\"\n",
867
+ " if not os.path.exists(key_karussell):\n",
868
+ " raise FileNotFoundError(f\"API key file '{API_KEYS_FILE}' not found!\")\n",
869
+ " \n",
870
+ " with open(key_karussell, 'r') as file:\n",
871
+ " keys = [line.strip() for line in file if line.strip()]\n",
872
+ " \n",
873
+ " if not keys:\n",
874
+ " raise ValueError(\"No API keys found in the file!\")\n",
875
+ " \n",
876
+ " return keys\n",
877
+ "\n",
878
+ "def get_model_metadata():\n",
879
+ " base_url = \"https://civitai.com/api/v1/models\"\n",
880
+ " params = {\"sort\": \"Newest\", \"nsfw\": True}\n",
881
+ "\n",
882
+ " # Load API keys\n",
883
+ " api_keys = load_api_keys()\n",
884
+ " key_index = 0 # Start with the first key\n",
885
+ "\n",
886
+ " page_counter = 0\n",
887
+ " max_pages = 300000000 # Adjust as needed\n",
888
+ " os.makedirs(directory_path, exist_ok=True)\n",
889
+ "\n",
890
+ " while True:\n",
891
+ " if page_counter >= max_pages:\n",
892
+ " print(f\"Reached the limit of {max_pages} pages.\")\n",
893
+ " break\n",
894
+ "\n",
895
+ " headers = {\n",
896
+ " \"Accept\": \"application/json\",\n",
897
+ " \"Authorization\": f\"Bearer {api_keys[key_index]}\"\n",
898
+ " }\n",
899
+ "\n",
900
+ " response = requests.get(base_url, headers=headers, params=params)\n",
901
+ "\n",
902
+ " if response.status_code == 200:\n",
903
+ " data = response.json()\n",
904
+ " page_counter += 1\n",
905
+ "\n",
906
+ " # Add timestamp\n",
907
+ " formatted_timestamp = datetime.datetime.now().strftime(\"data obtained on the %d.%m.%Y at %H:%M CEST\")\n",
908
+ "\n",
909
+ " data['timestamp'] = formatted_timestamp\n",
910
+ "\n",
911
+ " # Save data to file\n",
912
+ " file_path = os.path.join(directory_path, f'newest_models_{page_counter}.json')\n",
913
+ " with open(file_path, 'w', encoding='utf-8') as file:\n",
914
+ " json.dump(data, file, indent=4)\n",
915
+ "\n",
916
+ " # Check for nextCursor\n",
917
+ " next_cursor = data.get('metadata', {}).get('nextCursor')\n",
918
+ " if not next_cursor:\n",
919
+ " print(\"No more data available.\")\n",
920
+ " break\n",
921
+ " else:\n",
922
+ " params['cursor'] = next_cursor\n",
923
+ " \n",
924
+ " elif response.status_code in (401, 403): # Unauthorized or Forbidden\n",
925
+ " print(f\"API Key {key_index + 1} failed with status {response.status_code}. Trying next key...\")\n",
926
+ " key_index += 1\n",
927
+ "\n",
928
+ " if key_index >= len(api_keys):\n",
929
+ " print(\"All API keys failed. Exiting.\")\n",
930
+ " break # Stop if all keys fail\n",
931
+ " \n",
932
+ " else:\n",
933
+ " print(f\"Failed to fetch data: HTTP {response.status_code}\")\n",
934
+ " break # Stop on other errors\n"
935
+ ]
936
+ },
937
+ {
938
+ "cell_type": "code",
939
+ "execution_count": 6,
940
+ "id": "0b574bc0-8bc5-48fd-9ced-8723d07e0d0e",
941
+ "metadata": {
942
+ "execution": {
943
+ "iopub.execute_input": "2025-02-08T19:37:57.395918Z",
944
+ "iopub.status.busy": "2025-02-08T19:37:57.395733Z",
945
+ "iopub.status.idle": "2025-02-08T19:37:57.399679Z",
946
+ "shell.execute_reply": "2025-02-08T19:37:57.399183Z",
947
+ "shell.execute_reply.started": "2025-02-08T19:37:57.395902Z"
948
+ }
949
+ },
950
+ "outputs": [],
951
+ "source": [
952
+ "key_karussell = current_dir.parent / 'misc/api_keys.txt'\n",
953
+ "directory_path = current_dir.parent / 'data/raw/model_metadata/'"
954
+ ]
955
+ },
956
+ {
957
+ "cell_type": "markdown",
958
+ "id": "8f43ce23-5986-4b67-be2d-453831af9a6e",
959
+ "metadata": {},
960
+ "source": [
961
+ "uncomment this to get model metadata"
962
+ ]
963
+ },
964
+ {
965
+ "cell_type": "code",
966
+ "execution_count": 7,
967
+ "id": "3f95b4ba-5742-4268-b2e8-de9145faf495",
968
+ "metadata": {
969
+ "execution": {
970
+ "iopub.execute_input": "2025-02-08T19:37:58.117386Z",
971
+ "iopub.status.busy": "2025-02-08T19:37:58.117158Z",
972
+ "iopub.status.idle": "2025-02-08T19:37:58.121162Z",
973
+ "shell.execute_reply": "2025-02-08T19:37:58.120580Z",
974
+ "shell.execute_reply.started": "2025-02-08T19:37:58.117369Z"
975
+ }
976
+ },
977
+ "outputs": [],
978
+ "source": [
979
+ "#get_model_metadata()"
980
+ ]
981
+ },
982
+ {
983
+ "cell_type": "markdown",
984
+ "id": "1ed5f44e-612e-4b6d-8974-904fb3e058d6",
985
+ "metadata": {
986
+ "execution": {
987
+ "iopub.execute_input": "2025-02-06T12:52:40.162173Z",
988
+ "iopub.status.busy": "2025-02-06T12:52:40.159989Z",
989
+ "iopub.status.idle": "2025-02-06T12:52:40.170634Z",
990
+ "shell.execute_reply": "2025-02-06T12:52:40.169945Z",
991
+ "shell.execute_reply.started": "2025-02-06T12:52:40.162124Z"
992
+ }
993
+ },
994
+ "source": [
995
+ "### Step 2 Consolidate Model-dataset CSV"
996
+ ]
997
+ },
998
+ {
999
+ "cell_type": "code",
1000
+ "execution_count": 8,
1001
+ "id": "464d82f5-c24e-4b53-9b50-682fa4bf3430",
1002
+ "metadata": {
1003
+ "execution": {
1004
+ "iopub.execute_input": "2025-02-08T19:37:59.052245Z",
1005
+ "iopub.status.busy": "2025-02-08T19:37:59.051645Z",
1006
+ "iopub.status.idle": "2025-02-08T19:37:59.056017Z",
1007
+ "shell.execute_reply": "2025-02-08T19:37:59.055598Z",
1008
+ "shell.execute_reply.started": "2025-02-08T19:37:59.052224Z"
1009
+ }
1010
+ },
1011
+ "outputs": [],
1012
+ "source": [
1013
+ "## path thingy\n",
1014
+ "try: #scripts\n",
1015
+ " current_dir = Path(__file__).resolve().parent\n",
1016
+ "except NameError:\n",
1017
+ " # jupyter\n",
1018
+ " current_dir = Path.cwd()"
1019
+ ]
1020
+ },
1021
+ {
1022
+ "cell_type": "code",
1023
+ "execution_count": 9,
1024
+ "id": "14f3db4d-ef93-4629-8a27-971adb49248b",
1025
+ "metadata": {
1026
+ "execution": {
1027
+ "iopub.execute_input": "2025-02-08T19:37:59.443457Z",
1028
+ "iopub.status.busy": "2025-02-08T19:37:59.443236Z",
1029
+ "iopub.status.idle": "2025-02-08T19:37:59.890103Z",
1030
+ "shell.execute_reply": "2025-02-08T19:37:59.889571Z",
1031
+ "shell.execute_reply.started": "2025-02-08T19:37:59.443439Z"
1032
+ }
1033
+ },
1034
+ "outputs": [
1035
+ {
1036
+ "name": "stdout",
1037
+ "output_type": "stream",
1038
+ "text": [
1039
+ "Processing file: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/model_metadata/newest_models_2.json\n",
1040
+ "Processing file: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/model_metadata/newest_models_1.json\n",
1041
+ "Processing file: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/model_metadata/newest_models_4.json\n",
1042
+ "Processing file: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/model_metadata/newest_models_6.json\n",
1043
+ "Processing file: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/model_metadata/newest_models_7.json\n",
1044
+ "Processing file: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/model_metadata/newest_models_5.json\n",
1045
+ "Processing file: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/raw/model_metadata/newest_models_3.json\n"
1046
+ ]
1047
+ }
1048
+ ],
1049
+ "source": [
1050
+ "import os\n",
1051
+ "import json\n",
1052
+ "import pandas as pd\n",
1053
+ "import hashlib\n",
1054
+ "\n",
1055
+ "\n",
1056
+ "json_path = current_dir.parent / 'data/raw/model_metadata/'\n",
1057
+ "\n",
1058
+ "# Initialize a list to hold all the processed records\n",
1059
+ "data_records = []\n",
1060
+ "\n",
1061
+ "def hash_username(username):\n",
1062
+ " \"\"\"Convert a username into a unique hash.\"\"\"\n",
1063
+ " return hashlib.sha256(username.encode('utf-8')).hexdigest()[:16] # Use first 16 characters for brevity\n",
1064
+ "\n",
1065
+ "# Loop through each file in the directory\n",
1066
+ "for filename in os.listdir(json_path):\n",
1067
+ " # Construct the full path to the JSON file\n",
1068
+ " file_path = os.path.join(json_path, filename)\n",
1069
+ "\n",
1070
+ " # Only process files with .json extension\n",
1071
+ " if filename.endswith('.json') and os.path.isfile(file_path):\n",
1072
+ " print(f\"Processing file: {file_path}\")\n",
1073
+ "\n",
1074
+ " # Open and load the JSON file\n",
1075
+ " with open(file_path, 'r') as file:\n",
1076
+ " try:\n",
1077
+ " data = json.load(file)\n",
1078
+ " except json.JSONDecodeError as e:\n",
1079
+ " print(f\"Error decoding JSON in file {filename}: {e}\")\n",
1080
+ " continue\n",
1081
+ "\n",
1082
+ " # Determine how the items are structured within the dictionary\n",
1083
+ " if 'items' in data:\n",
1084
+ " items = data['items']\n",
1085
+ " elif 'data' in data:\n",
1086
+ " items = data['data']\n",
1087
+ " else:\n",
1088
+ " print(f\"No known item list key found in {filename}\")\n",
1089
+ " continue\n",
1090
+ "\n",
1091
+ " for item in items:\n",
1092
+ " if not isinstance(item, dict):\n",
1093
+ " print(f\"Expected a dictionary for each item, but found: {type(item)} in {filename}\")\n",
1094
+ " continue\n",
1095
+ "\n",
1096
+ " # Extract required information\n",
1097
+ " model_versions = item.get('modelVersions', [])\n",
1098
+ " download_url = model_versions[0]['files'][0]['downloadUrl'] if model_versions and 'files' in model_versions[0] and model_versions[0]['files'] else ''\n",
1099
+ " auto_hashes = model_versions[0]['files'][0]['hashes'] if model_versions and 'files' in model_versions[0] and model_versions[0]['files'] else {}\n",
1100
+ "\n",
1101
+ " # Collect up to 20 modelVersion IDs\n",
1102
+ " model_version_ids = [mv.get('id', '') for mv in model_versions[:20]]\n",
1103
+ "\n",
1104
+ " # Get preview images: first and latest\n",
1105
+ " first_image_url = model_versions[0]['images'][0]['url'] if model_versions and 'images' in model_versions[0] and model_versions[0]['images'] else ''\n",
1106
+ " latest_index = len(model_versions) - 1\n",
1107
+ " latest_image_url = model_versions[latest_index]['images'][0]['url'] if model_versions and 'images' in model_versions[latest_index] and model_versions[latest_index]['images'] else ''\n",
1108
+ "\n",
1109
+ " # Hash the username\n",
1110
+ " username = item.get('creator', {}).get('username', '')\n",
1111
+ " username_hash = hash_username(username) if username else ''\n",
1112
+ "\n",
1113
+ " # Extract additional fields\n",
1114
+ " record = {\n",
1115
+ " 'id': item.get('id', ''),\n",
1116
+ " 'name': item.get('name', ''),\n",
1117
+ " 'type': item.get('type', ''),\n",
1118
+ " 'baseModel': model_versions[0].get('baseModel', '') if model_versions else '',\n",
1119
+ " 'downloadCount': item.get('stats', {}).get('downloadCount', 0),\n",
1120
+ " 'nsfwLevel': item.get('nsfwLevel', 0),\n",
1121
+ " 'modelVersions': len(model_versions),\n",
1122
+ " 'publishedAt': model_versions[0].get('publishedAt', '') if model_versions else '',\n",
1123
+ " 'usernameHash': username_hash,\n",
1124
+ " 'downloadUrl': download_url,\n",
1125
+ " 'firstImageUrl': first_image_url,\n",
1126
+ " 'latestImageUrl': latest_image_url,\n",
1127
+ " 'poi': item.get('poi', False),\n",
1128
+ " 'AutoV1': auto_hashes.get('AutoV1', ''),\n",
1129
+ " 'AutoV2': auto_hashes.get('AutoV2', ''),\n",
1130
+ " 'AutoV3': auto_hashes.get('AutoV3', ''),\n",
1131
+ " 'SHA256': auto_hashes.get('SHA256', ''),\n",
1132
+ " 'CRC32': auto_hashes.get('CRC32', ''),\n",
1133
+ " 'BLAKE3': auto_hashes.get('BLAKE3', ''),\n",
1134
+ " 'previewImage': latest_image_url\n",
1135
+ " }\n",
1136
+ "\n",
1137
+ " # Add version IDs to the record\n",
1138
+ " for i in range(20): # Collect up to 20 version IDs\n",
1139
+ " version_key = f'version_id_{i+1}'\n",
1140
+ " record[version_key] = model_version_ids[i] if len(model_version_ids) > i else ''\n",
1141
+ "\n",
1142
+ " # Add tags\n",
1143
+ " tags = item.get('tags', [])\n",
1144
+ " for i in range(7): # To retrieve up to tag 6\n",
1145
+ " tag_key = f'tag_{i+1}'\n",
1146
+ " record[tag_key] = tags[i] if len(tags) > i else ''\n",
1147
+ "\n",
1148
+ " data_records.append(record)\n",
1149
+ "\n",
1150
+ "# Create a DataFrame and sort by download count\n",
1151
+ "df = pd.DataFrame(data_records)\n",
1152
+ "df_sorted = df.sort_values(by='downloadCount', ascending=False)"
1153
+ ]
1154
+ },
1155
+ {
1156
+ "cell_type": "markdown",
1157
+ "id": "2d6f822f-754f-4feb-9ed6-6f868421c454",
1158
+ "metadata": {},
1159
+ "source": [
1160
+ "### Save model-data to CSV"
1161
+ ]
1162
+ },
1163
+ {
1164
+ "cell_type": "code",
1165
+ "execution_count": 10,
1166
+ "id": "f861cf7b-5eb3-46ad-ab2d-9e2fdf2169b4",
1167
+ "metadata": {
1168
+ "execution": {
1169
+ "iopub.execute_input": "2025-02-08T19:38:02.047421Z",
1170
+ "iopub.status.busy": "2025-02-08T19:38:02.046761Z",
1171
+ "iopub.status.idle": "2025-02-08T19:38:02.193381Z",
1172
+ "shell.execute_reply": "2025-02-08T19:38:02.192886Z",
1173
+ "shell.execute_reply.started": "2025-02-08T19:38:02.047397Z"
1174
+ }
1175
+ },
1176
+ "outputs": [
1177
+ {
1178
+ "name": "stdout",
1179
+ "output_type": "stream",
1180
+ "text": [
1181
+ "Data has been saved to /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/Civiverse-Models.csv\n"
1182
+ ]
1183
+ }
1184
+ ],
1185
+ "source": [
1186
+ "output_csv = current_dir.parent / 'data/CSV/Civiverse-Models.csv'\n",
1187
+ "output_csv.parent.mkdir(parents=True, exist_ok=True)\n",
1188
+ "df_sorted.to_csv(output_csv, index=False)\n",
1189
+ "print(f\"Data has been saved to {output_csv}\")"
1190
+ ]
1191
+ },
1192
+ {
1193
+ "cell_type": "markdown",
1194
+ "id": "9b948933-2a2f-42b0-9083-2d81586ae3f2",
1195
+ "metadata": {
1196
+ "execution": {
1197
+ "iopub.execute_input": "2025-02-06T13:42:32.447860Z",
1198
+ "iopub.status.busy": "2025-02-06T13:42:32.446832Z",
1199
+ "iopub.status.idle": "2025-02-06T13:42:32.453827Z",
1200
+ "shell.execute_reply": "2025-02-06T13:42:32.453271Z",
1201
+ "shell.execute_reply.started": "2025-02-06T13:42:32.447821Z"
1202
+ }
1203
+ },
1204
+ "source": [
1205
+ "### Step 3 Create Subsets: Checkpoint only, POI True, POI False"
1206
+ ]
1207
+ },
1208
+ {
1209
+ "cell_type": "code",
1210
+ "execution_count": 11,
1211
+ "id": "ae894e26-4984-40e6-80a6-54fb6b61c873",
1212
+ "metadata": {
1213
+ "execution": {
1214
+ "iopub.execute_input": "2025-02-08T19:38:03.089160Z",
1215
+ "iopub.status.busy": "2025-02-08T19:38:03.088490Z",
1216
+ "iopub.status.idle": "2025-02-08T19:38:03.093067Z",
1217
+ "shell.execute_reply": "2025-02-08T19:38:03.092634Z",
1218
+ "shell.execute_reply.started": "2025-02-08T19:38:03.089138Z"
1219
+ }
1220
+ },
1221
+ "outputs": [],
1222
+ "source": [
1223
+ "file_path = current_dir.parent / 'data/CSV/Civiverse-Models.csv' # Update this with your actual file path\n",
1224
+ "(current_dir.parent / 'data/CSV/model_subsets').mkdir(parents=True, exist_ok=True)\n"
1225
+ ]
1226
+ },
1227
+ {
1228
+ "cell_type": "code",
1229
+ "execution_count": 13,
1230
+ "id": "88438f88-c723-423e-a4e5-e07f59096b72",
1231
+ "metadata": {
1232
+ "execution": {
1233
+ "iopub.execute_input": "2025-02-08T19:41:39.279495Z",
1234
+ "iopub.status.busy": "2025-02-08T19:41:39.279039Z",
1235
+ "iopub.status.idle": "2025-02-08T19:41:39.674445Z",
1236
+ "shell.execute_reply": "2025-02-08T19:41:39.673981Z",
1237
+ "shell.execute_reply.started": "2025-02-08T19:41:39.279476Z"
1238
+ }
1239
+ },
1240
+ "outputs": [
1241
+ {
1242
+ "name": "stdout",
1243
+ "output_type": "stream",
1244
+ "text": [
1245
+ "Files saved successfully!\n"
1246
+ ]
1247
+ }
1248
+ ],
1249
+ "source": [
1250
+ "import pandas as pd\n",
1251
+ "\n",
1252
+ "# Load the dataset\n",
1253
+ "\n",
1254
+ "data = pd.read_csv(file_path)\n",
1255
+ "\n",
1256
+ "# Version 1: Only 'poi' true models\n",
1257
+ "poi_true_models = data[data['poi'] == True]\n",
1258
+ "\n",
1259
+ "# Version 2: Only types lora, dora, locon, textual inversion\n",
1260
+ "specific_types = ['LORA', 'DORA', 'LOCON', 'textualInversion']\n",
1261
+ "adapters = data[data['type'].isin(specific_types)]\n",
1262
+ "\n",
1263
+ "# Version 3: Only type checkpoint\n",
1264
+ "checkpoint_models = data[data['type'] == 'Checkpoint']\n",
1265
+ "\n",
1266
+ "# Version 4: All models apart from 'poi' true\n",
1267
+ "non_poi_models = data[data['poi'] != True]\n",
1268
+ "\n",
1269
+ "# Version 5: All models apart from 'poi' true and with nsfwLevel below 13\n",
1270
+ "non_poi_low_nsfw_models = data[(data['poi'] != True) & (data['nsfwLevel'] < 13)]\n",
1271
+ "\n",
1272
+ "# Save the versions as separate CSV files\n",
1273
+ "poi_true_models.to_csv(current_dir.parent / 'data/CSV/model_subsets/Civiverse_adapters_poi_true.csv', index=False)\n",
1274
+ "adapters.to_csv(current_dir.parent / 'data/CSV/adapters.csv', index=False)\n",
1275
+ "checkpoint_models.to_csv(current_dir.parent / 'data/CSV/model_subsets/Civiverse_checkpoint_only.csv', index=False)\n",
1276
+ "non_poi_models.to_csv(current_dir.parent / 'data/CSV/model_subsets/Civiverse_adapters_poi_false.csv', index=False)\n",
1277
+ "\n",
1278
+ "print(\"Files saved successfully!\")\n"
1279
+ ]
1280
+ },
1281
+ {
1282
+ "cell_type": "code",
1283
+ "execution_count": null,
1284
+ "id": "49e35088-8b2e-4189-83e1-3098d55dcad2",
1285
+ "metadata": {},
1286
+ "outputs": [],
1287
+ "source": []
1288
+ }
1289
+ ],
1290
+ "metadata": {
1291
+ "kernelspec": {
1292
+ "display_name": "Python 3 (ipykernel)",
1293
+ "language": "python",
1294
+ "name": "python3"
1295
+ },
1296
+ "language_info": {
1297
+ "codemirror_mode": {
1298
+ "name": "ipython",
1299
+ "version": 3
1300
+ },
1301
+ "file_extension": ".py",
1302
+ "mimetype": "text/x-python",
1303
+ "name": "python",
1304
+ "nbconvert_exporter": "python",
1305
+ "pygments_lexer": "ipython3",
1306
+ "version": "3.11.9"
1307
+ }
1308
+ },
1309
+ "nbformat": 4,
1310
+ "nbformat_minor": 5
1311
+ }
scripts/Section_2_image_grid.ipynb ADDED
@@ -0,0 +1,389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "e8752a29-06b6-49a2-a724-a7b1c8f3d23b",
6
+ "metadata": {
7
+ "execution": {
8
+ "iopub.execute_input": "2025-02-06T14:16:50.014780Z",
9
+ "iopub.status.busy": "2025-02-06T14:16:50.013936Z",
10
+ "iopub.status.idle": "2025-02-06T14:16:50.018030Z",
11
+ "shell.execute_reply": "2025-02-06T14:16:50.017506Z",
12
+ "shell.execute_reply.started": "2025-02-06T14:16:50.014757Z"
13
+ }
14
+ },
15
+ "source": [
16
+ "# Section 2. Download Images and create image Grid"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "markdown",
21
+ "id": "6f81ff2d-7763-4ac5-a9e3-d9a74541e143",
22
+ "metadata": {
23
+ "execution": {
24
+ "iopub.execute_input": "2025-02-06T16:47:42.502304Z",
25
+ "iopub.status.busy": "2025-02-06T16:47:42.501200Z",
26
+ "iopub.status.idle": "2025-02-06T16:47:42.746600Z",
27
+ "shell.execute_reply": "2025-02-06T16:47:42.745736Z",
28
+ "shell.execute_reply.started": "2025-02-06T16:47:42.502269Z"
29
+ }
30
+ },
31
+ "source": [
32
+ "This script downloads images and places them under data/sorted/YYYY/YYYY-MM/YYYY-MM-DD. A grid is created that blurs all NSFW true images and assigns a color overlay based on the color-coding of the BrowsingLevel"
33
+ ]
34
+ },
35
+ {
36
+ "cell_type": "markdown",
37
+ "id": "d6d7d826-353c-4c1b-9d69-fa67f07e5245",
38
+ "metadata": {
39
+ "execution": {
40
+ "iopub.execute_input": "2025-02-06T16:17:00.985310Z",
41
+ "iopub.status.busy": "2025-02-06T16:17:00.984540Z",
42
+ "iopub.status.idle": "2025-02-06T16:17:01.124348Z",
43
+ "shell.execute_reply": "2025-02-06T16:17:01.123740Z",
44
+ "shell.execute_reply.started": "2025-02-06T16:17:00.985282Z"
45
+ }
46
+ },
47
+ "source": [
48
+ "![Alt text](../plots/grid2x24.png)"
49
+ ]
50
+ },
51
+ {
52
+ "cell_type": "code",
53
+ "execution_count": 1,
54
+ "id": "6e5227f5-925c-4155-8015-53045794b986",
55
+ "metadata": {
56
+ "execution": {
57
+ "iopub.execute_input": "2025-02-08T21:58:48.202108Z",
58
+ "iopub.status.busy": "2025-02-08T21:58:48.201629Z",
59
+ "iopub.status.idle": "2025-02-08T21:58:48.485464Z",
60
+ "shell.execute_reply": "2025-02-08T21:58:48.484783Z",
61
+ "shell.execute_reply.started": "2025-02-08T21:58:48.202077Z"
62
+ }
63
+ },
64
+ "outputs": [],
65
+ "source": [
66
+ "from PIL import Image, ImageFilter, ImageDraw\n",
67
+ "import os\n",
68
+ "from pathlib import Path\n",
69
+ "import json\n",
70
+ "import matplotlib.colors as mcolors\n",
71
+ "import os\n",
72
+ "import json\n",
73
+ "import requests\n",
74
+ "from datetime import datetime\n",
75
+ "import argparse"
76
+ ]
77
+ },
78
+ {
79
+ "cell_type": "code",
80
+ "execution_count": 2,
81
+ "id": "25cb523d-6d22-4d13-84f1-f9e38534d08e",
82
+ "metadata": {
83
+ "execution": {
84
+ "iopub.execute_input": "2025-02-08T21:58:49.153040Z",
85
+ "iopub.status.busy": "2025-02-08T21:58:49.152592Z",
86
+ "iopub.status.idle": "2025-02-08T21:58:49.156982Z",
87
+ "shell.execute_reply": "2025-02-08T21:58:49.156561Z",
88
+ "shell.execute_reply.started": "2025-02-08T21:58:49.153017Z"
89
+ }
90
+ },
91
+ "outputs": [],
92
+ "source": [
93
+ "current_dir = Path.cwd()"
94
+ ]
95
+ },
96
+ {
97
+ "cell_type": "markdown",
98
+ "id": "037ecae3-a060-4d90-beaf-040dfb018696",
99
+ "metadata": {},
100
+ "source": [
101
+ "## Step 1: Download images "
102
+ ]
103
+ },
104
+ {
105
+ "cell_type": "code",
106
+ "execution_count": 3,
107
+ "id": "948809b0-e78a-4821-86d0-fe4eb156265a",
108
+ "metadata": {
109
+ "execution": {
110
+ "iopub.execute_input": "2025-02-08T21:58:50.811934Z",
111
+ "iopub.status.busy": "2025-02-08T21:58:50.811459Z",
112
+ "iopub.status.idle": "2025-02-08T21:58:50.823112Z",
113
+ "shell.execute_reply": "2025-02-08T21:58:50.822600Z",
114
+ "shell.execute_reply.started": "2025-02-08T21:58:50.811911Z"
115
+ }
116
+ },
117
+ "outputs": [],
118
+ "source": [
119
+ "import os\n",
120
+ "import json\n",
121
+ "import requests\n",
122
+ "from datetime import datetime\n",
123
+ "from PIL import Image\n",
124
+ "\n",
125
+ "def download_and_save_data(input_dir, output_dir):\n",
126
+ " print(f\"Scanning directory: {input_dir}\")\n",
127
+ " found_json = False\n",
128
+ " for root, dirs, files in os.walk(input_dir):\n",
129
+ " for file in files:\n",
130
+ " if file.endswith('.json'):\n",
131
+ " found_json = True\n",
132
+ " file_path = os.path.join(root, file)\n",
133
+ " print(f\"Processing JSON file: {file_path}\")\n",
134
+ " try:\n",
135
+ " with open(file_path, 'r', encoding='utf-8') as json_file:\n",
136
+ " items = json.load(json_file)\n",
137
+ " for item in items:\n",
138
+ " if isinstance(item, dict):\n",
139
+ " process_item(item, root, output_dir, input_dir)\n",
140
+ " except json.JSONDecodeError:\n",
141
+ " print(f\"Error decoding JSON from file {file_path}\")\n",
142
+ " except Exception as e:\n",
143
+ " print(f\"An error occurred with file {file_path}: {e}\")\n",
144
+ " if not found_json:\n",
145
+ " print(\"No JSON files found in the directory.\")\n",
146
+ "\n",
147
+ "def process_item(item, root, output_dir, input_dir):\n",
148
+ " if 'createdAt' in item and 'url' in item:\n",
149
+ " created_at = datetime.strptime(item['createdAt'], \"%Y-%m-%dT%H:%M:%S.%fZ\")\n",
150
+ " time_str = created_at.strftime(\"%Y%m%dT%H%M%S%f\") # Include microseconds in the filename\n",
151
+ " relative_path = os.path.relpath(root, input_dir)\n",
152
+ " save_path = os.path.join(output_dir, relative_path)\n",
153
+ " os.makedirs(save_path, exist_ok=True)\n",
154
+ " image_path = os.path.join(save_path, f\"{time_str}.jpeg\")\n",
155
+ " download_image(item['url'], image_path)\n",
156
+ " resize_image(image_path, 512) # Resize if necessary\n",
157
+ " save_prompt(item.get('meta', {}).get('prompt', 'No prompt available'), os.path.join(save_path, f\"{time_str}_positive.txt\"))\n",
158
+ " save_prompt(item.get('meta', {}).get('negativePrompt', 'No negative prompt available'), os.path.join(save_path, f\"{time_str}_negative.txt\"))\n",
159
+ " save_json(item, os.path.join(save_path, f\"{time_str}.json\"))\n",
160
+ " else:\n",
161
+ " print(\"Item missing 'createdAt' or 'url', skipping...\")\n",
162
+ "\n",
163
+ "def download_image(url, path):\n",
164
+ " try:\n",
165
+ " response = requests.get(url)\n",
166
+ " if response.status_code == 200:\n",
167
+ " with open(path, 'wb') as f:\n",
168
+ " f.write(response.content)\n",
169
+ " except requests.RequestException as e:\n",
170
+ " print(f\"Request failed for {url}: {e}\")\n",
171
+ "\n",
172
+ "def resize_image(image_path, max_size):\n",
173
+ " with Image.open(image_path) as img:\n",
174
+ " if img.width > max_size or img.height > max_size:\n",
175
+ " img.thumbnail((max_size, max_size))\n",
176
+ " img.save(image_path)\n",
177
+ "\n",
178
+ "def save_prompt(prompt, path):\n",
179
+ " with open(path, 'w') as f:\n",
180
+ " f.write(prompt)\n",
181
+ "\n",
182
+ "def save_json(data, path):\n",
183
+ " with open(path, 'w', encoding='utf-8') as f:\n",
184
+ " json.dump(data, f, indent=4)\n",
185
+ "\n"
186
+ ]
187
+ },
188
+ {
189
+ "cell_type": "code",
190
+ "execution_count": 4,
191
+ "id": "133e143d-1bb5-4145-8d59-323570bb6e95",
192
+ "metadata": {
193
+ "execution": {
194
+ "iopub.execute_input": "2025-02-08T21:58:51.566234Z",
195
+ "iopub.status.busy": "2025-02-08T21:58:51.565711Z",
196
+ "iopub.status.idle": "2025-02-08T21:58:51.568973Z",
197
+ "shell.execute_reply": "2025-02-08T21:58:51.568474Z",
198
+ "shell.execute_reply.started": "2025-02-08T21:58:51.566214Z"
199
+ }
200
+ },
201
+ "outputs": [],
202
+ "source": [
203
+ "input_dir = current_dir.parent / 'data/sorted/image_metadata/'\n",
204
+ "images = current_dir.parent / 'data/sorted/images'"
205
+ ]
206
+ },
207
+ {
208
+ "cell_type": "markdown",
209
+ "id": "e11c4ad5-c040-42b7-a1b9-a0e21b33ce20",
210
+ "metadata": {},
211
+ "source": [
212
+ "uncomment this to download the images, otherwise proceed with grid creation"
213
+ ]
214
+ },
215
+ {
216
+ "cell_type": "code",
217
+ "execution_count": 5,
218
+ "id": "88a6ca8e-51ee-4d27-ba0c-5f026d5750df",
219
+ "metadata": {
220
+ "execution": {
221
+ "iopub.execute_input": "2025-02-08T21:58:52.986899Z",
222
+ "iopub.status.busy": "2025-02-08T21:58:52.986456Z",
223
+ "iopub.status.idle": "2025-02-08T21:58:52.989508Z",
224
+ "shell.execute_reply": "2025-02-08T21:58:52.988892Z",
225
+ "shell.execute_reply.started": "2025-02-08T21:58:52.986878Z"
226
+ }
227
+ },
228
+ "outputs": [],
229
+ "source": [
230
+ "#download_and_save_data(input_dir, images) "
231
+ ]
232
+ },
233
+ {
234
+ "cell_type": "code",
235
+ "execution_count": 6,
236
+ "id": "f247091b-7b45-4cd4-a6ca-3d4dea414e19",
237
+ "metadata": {
238
+ "execution": {
239
+ "iopub.execute_input": "2025-02-08T21:58:54.127935Z",
240
+ "iopub.status.busy": "2025-02-08T21:58:54.127626Z",
241
+ "iopub.status.idle": "2025-02-08T21:58:54.254290Z",
242
+ "shell.execute_reply": "2025-02-08T21:58:54.253243Z",
243
+ "shell.execute_reply.started": "2025-02-08T21:58:54.127914Z"
244
+ }
245
+ },
246
+ "outputs": [
247
+ {
248
+ "name": "stdout",
249
+ "output_type": "stream",
250
+ "text": [
251
+ "Grid image saved to /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/plots/grid10x120.png\n"
252
+ ]
253
+ }
254
+ ],
255
+ "source": [
256
+ "directory = current_dir.parent / 'data/sorted/images/'\n",
257
+ "#directory = '/home/lauwag/shares/laura_wagner/Civitai_page_analysis/Civitai_dataset/dataset/chronological/full/prompts-images/2024/2024-05/2024-05-31/'\n",
258
+ "output = current_dir.parent / 'plots/grid10x120.png'\n",
259
+ "\n",
260
+ "cell_size = 64 # Resize to 32x32 pixels\n",
261
+ "grid_size = (10, 120)\n",
262
+ "\n",
263
+ "\n",
264
+ "def apply_pixelation(img, level):\n",
265
+ " \"\"\" Apply pixelation based on the level. \"\"\"\n",
266
+ " if level > 1:\n",
267
+ " pixel_size = 8 # Adjust this value for more or less pixelation\n",
268
+ " img_small = img.resize(\n",
269
+ " (img.width // pixel_size, img.height // pixel_size), Image.NEAREST\n",
270
+ " )\n",
271
+ " img_pixelated = img_small.resize(img.size, Image.NEAREST)\n",
272
+ " return img_pixelated\n",
273
+ " return img\n",
274
+ "\n",
275
+ "def apply_blur(img, level):\n",
276
+ " \"\"\" Apply Gaussian blur based on the level of browsing. \"\"\"\n",
277
+ " if level > 1:\n",
278
+ " return img.filter(ImageFilter.GaussianBlur(radius=1.75)) # Adjust radius as needed\n",
279
+ " return img\n",
280
+ "\n",
281
+ "def apply_border_and_overlay(img, color):\n",
282
+ " \"\"\" Apply a colored border and a slight color overlay. \"\"\"\n",
283
+ " # Convert Matplotlib color name to RGB\n",
284
+ " rgb_color = tuple(int(x * 255) for x in mcolors.to_rgb(color))\n",
285
+ " # Create a border\n",
286
+ " border_size = 0 # Adjust border size as needed\n",
287
+ " border_img = Image.new('RGB', (img.width + 2 * border_size, img.height + 2 * border_size), rgb_color)\n",
288
+ " border_img.paste(img, (border_size, border_size))\n",
289
+ " # Create an overlay\n",
290
+ " overlay = Image.new('RGBA', border_img.size, (*rgb_color, 0)) # Semi-transparent overlay\n",
291
+ " #overlay = Image.new('RGBA', border_img.size, (*rgb_color, 128)) # Semi-transparent overlay\n",
292
+ " final_img = Image.alpha_composite(border_img.convert('RGBA'), overlay)\n",
293
+ " return final_img.convert('RGB')\n",
294
+ "\n",
295
+ "def process_image(image_path, json_path, cell_size):\n",
296
+ " \"\"\" Process each image: resize, crop, blur, and add border and overlay based on JSON metadata. \"\"\"\n",
297
+ " with open(json_path, 'r') as f:\n",
298
+ " metadata = json.load(f)\n",
299
+ " browsing_level = metadata.get('browsingLevel', 1)\n",
300
+ "\n",
301
+ " with Image.open(image_path) as img:\n",
302
+ " img = resize_and_crop_image(img, cell_size)\n",
303
+ " img = apply_pixelation(img, browsing_level)\n",
304
+ "\n",
305
+ " color_map = {\n",
306
+ " 2: 'rosybrown', # Matplotlib color name\n",
307
+ " 4: 'coral',\n",
308
+ " 8: 'red',\n",
309
+ " 16: 'magenta'\n",
310
+ " }\n",
311
+ " if browsing_level in color_map:\n",
312
+ " img = apply_border_and_overlay(img, color_map[browsing_level])\n",
313
+ "\n",
314
+ " return img\n",
315
+ "\n",
316
+ "def resize_and_crop_image(img, output_size):\n",
317
+ " \"\"\" Resize and crop the image to a square of the specified size. \"\"\"\n",
318
+ " ratio = min(img.width / output_size, img.height / output_size)\n",
319
+ " new_size = (int(img.width / ratio), int(img.height / ratio))\n",
320
+ " img = img.resize(new_size, Image.Resampling.LANCZOS)\n",
321
+ " left = (img.width - output_size) // 2\n",
322
+ " top = (img.height - output_size) // 2\n",
323
+ " right = left + output_size\n",
324
+ " bottom = top + output_size\n",
325
+ " return img.crop((left, top, right, bottom))\n",
326
+ "\n",
327
+ "# Example usage and the rest of your script remains unchanged\n",
328
+ "\n",
329
+ "# Example usage\n",
330
+ " # 4x4 grid\n",
331
+ "\n",
332
+ "file_types = ('png', 'jpg', 'jpeg') # Define acceptable image file types\n",
333
+ "\n",
334
+ "images = []\n",
335
+ "for root, dirs, files in os.walk(directory):\n",
336
+ " for file in files:\n",
337
+ " if file.lower().endswith(file_types):\n",
338
+ " image_path = os.path.join(root, file)\n",
339
+ " json_path = image_path.rsplit('.', 1)[0] + '.json'\n",
340
+ " if os.path.exists(json_path):\n",
341
+ " img = process_image(image_path, json_path, cell_size)\n",
342
+ " images.append(img)\n",
343
+ " if len(images) == grid_size[0] * grid_size[1]:\n",
344
+ " break\n",
345
+ " if len(images) == grid_size[0] * grid_size[1]:\n",
346
+ " break\n",
347
+ "\n",
348
+ "# Create the grid image\n",
349
+ "grid_img = Image.new('RGB', (grid_size[1] * cell_size, grid_size[0] * cell_size))\n",
350
+ "for index, img in enumerate(images):\n",
351
+ " x = (index % grid_size[1]) * cell_size\n",
352
+ " y = (index // grid_size[1]) * cell_size\n",
353
+ " grid_img.paste(img, (x, y))\n",
354
+ "\n",
355
+ "grid_img.save(output)\n",
356
+ "print(f\"Grid image saved to {output}\")"
357
+ ]
358
+ },
359
+ {
360
+ "cell_type": "code",
361
+ "execution_count": null,
362
+ "id": "28bba299-c5ef-449b-a7fa-1afdc5e26262",
363
+ "metadata": {},
364
+ "outputs": [],
365
+ "source": []
366
+ }
367
+ ],
368
+ "metadata": {
369
+ "kernelspec": {
370
+ "display_name": "Python 3 (ipykernel)",
371
+ "language": "python",
372
+ "name": "python3"
373
+ },
374
+ "language_info": {
375
+ "codemirror_mode": {
376
+ "name": "ipython",
377
+ "version": 3
378
+ },
379
+ "file_extension": ".py",
380
+ "mimetype": "text/x-python",
381
+ "name": "python",
382
+ "nbconvert_exporter": "python",
383
+ "pygments_lexer": "ipython3",
384
+ "version": "3.11.9"
385
+ }
386
+ },
387
+ "nbformat": 4,
388
+ "nbformat_minor": 5
389
+ }
scripts/Section_6-1_Histogram_contributions.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
scripts/Section_6-2_Demographics.ipynb ADDED
@@ -0,0 +1,1779 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "d8161f06-4fd2-436d-9e59-3f68b5a67f2c",
6
+ "metadata": {
7
+ "execution": {
8
+ "iopub.execute_input": "2025-02-06T18:30:16.974712Z",
9
+ "iopub.status.busy": "2025-02-06T18:30:16.974296Z",
10
+ "iopub.status.idle": "2025-02-06T18:30:16.976909Z",
11
+ "shell.execute_reply": "2025-02-06T18:30:16.976526Z",
12
+ "shell.execute_reply.started": "2025-02-06T18:30:16.974692Z"
13
+ }
14
+ },
15
+ "source": [
16
+ "# Section 6.2: Age and Gender Estimation using MiVOLO"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "markdown",
21
+ "id": "64aaedec-ef56-4a62-b61e-12de2675a1ae",
22
+ "metadata": {
23
+ "execution": {
24
+ "iopub.execute_input": "2025-02-06T19:52:51.171282Z",
25
+ "iopub.status.busy": "2025-02-06T19:52:51.170711Z",
26
+ "iopub.status.idle": "2025-02-06T19:52:55.405039Z",
27
+ "shell.execute_reply": "2025-02-06T19:52:55.404308Z",
28
+ "shell.execute_reply.started": "2025-02-06T19:52:51.171245Z"
29
+ }
30
+ },
31
+ "source": [
32
+ "![Alt text](../plots/mivolo.svg)"
33
+ ]
34
+ },
35
+ {
36
+ "cell_type": "code",
37
+ "execution_count": 1,
38
+ "id": "4293f307-44fd-455e-90fe-6e6928be9af5",
39
+ "metadata": {
40
+ "execution": {
41
+ "iopub.execute_input": "2025-02-08T21:59:21.970807Z",
42
+ "iopub.status.busy": "2025-02-08T21:59:21.969931Z",
43
+ "iopub.status.idle": "2025-02-08T22:00:09.724295Z",
44
+ "shell.execute_reply": "2025-02-08T22:00:09.723583Z",
45
+ "shell.execute_reply.started": "2025-02-08T21:59:21.970784Z"
46
+ }
47
+ },
48
+ "outputs": [
49
+ {
50
+ "name": "stderr",
51
+ "output_type": "stream",
52
+ "text": [
53
+ "/home/lauwag/data/conda/envs/horde/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
54
+ " from .autonotebook import tqdm as notebook_tqdm\n"
55
+ ]
56
+ }
57
+ ],
58
+ "source": [
59
+ "import csv\n",
60
+ "from pathlib import Path\n",
61
+ "import logging\n",
62
+ "import os\n",
63
+ "import pandas as pd\n",
64
+ "import requests\n",
65
+ "import numpy as np\n",
66
+ "import torch\n",
67
+ "import cv2\n",
68
+ "from io import BytesIO\n",
69
+ "from PIL import Image, UnidentifiedImageError\n",
70
+ "from datetime import datetime, timedelta\n",
71
+ "from dateutil.relativedelta import relativedelta\n",
72
+ "from mivolo.predictor import Predictor\n",
73
+ "import matplotlib.pyplot as plt\n",
74
+ "import matplotlib.patches as mpatches"
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": 2,
80
+ "id": "63a54f5f-900c-48dd-8932-2632e56c5670",
81
+ "metadata": {
82
+ "execution": {
83
+ "iopub.execute_input": "2025-02-08T22:00:09.726069Z",
84
+ "iopub.status.busy": "2025-02-08T22:00:09.725699Z",
85
+ "iopub.status.idle": "2025-02-08T22:00:09.730626Z",
86
+ "shell.execute_reply": "2025-02-08T22:00:09.730099Z",
87
+ "shell.execute_reply.started": "2025-02-08T22:00:09.726050Z"
88
+ }
89
+ },
90
+ "outputs": [],
91
+ "source": [
92
+ "current_dir = Path.cwd()\n",
93
+ "mini = current_dir.parent / 'data/CSV/image_subsets/Civiverse-mini.csv'\n",
94
+ "mivolo_in = current_dir.parent / 'data/CSV/image_subsets/Civiverse-mini-by-month/'\n",
95
+ "(current_dir.parent / 'data/CSV/image_subsets/Civiverse-mini-by-month/').mkdir(parents=True, exist_ok=True)"
96
+ ]
97
+ },
98
+ {
99
+ "cell_type": "code",
100
+ "execution_count": 3,
101
+ "id": "1fdfb89a-6094-4382-8755-fae213221ea5",
102
+ "metadata": {
103
+ "execution": {
104
+ "iopub.execute_input": "2025-02-08T22:00:09.731540Z",
105
+ "iopub.status.busy": "2025-02-08T22:00:09.731359Z",
106
+ "iopub.status.idle": "2025-02-08T22:00:09.825738Z",
107
+ "shell.execute_reply": "2025-02-08T22:00:09.825258Z",
108
+ "shell.execute_reply.started": "2025-02-08T22:00:09.731524Z"
109
+ }
110
+ },
111
+ "outputs": [],
112
+ "source": [
113
+ "def split_by_month(input_path, output_dir):\n",
114
+ " # Load the dataset\n",
115
+ " df = pd.read_csv(input_path)\n",
116
+ " \n",
117
+ " # Convert the 'createdAt' column to datetime\n",
118
+ " df['createdAt'] = pd.to_datetime(df['createdAt'], errors='coerce')\n",
119
+ " \n",
120
+ " # Extract year and month\n",
121
+ " df['year_month'] = df['createdAt'].dt.to_period('M')\n",
122
+ " \n",
123
+ " # Group the data by year and month and save each group as a CSV file\n",
124
+ " unique_months = df['year_month'].unique()\n",
125
+ "\n",
126
+ " for month in unique_months:\n",
127
+ " # Filter data for the specific month\n",
128
+ " df_month = df[df['year_month'] == month]\n",
129
+ " \n",
130
+ " # Define the file name based on the year and month\n",
131
+ " file_name = f'{output_dir}/Civiverse-{month}.csv'\n",
132
+ " \n",
133
+ " # Save the file\n",
134
+ " df_month.to_csv(file_name, index=False)\n",
135
+ "\n",
136
+ " print(f\"Data has been split and saved to {output_dir}\")"
137
+ ]
138
+ },
139
+ {
140
+ "cell_type": "code",
141
+ "execution_count": 4,
142
+ "id": "2c909d7c-7d16-4dc7-8364-7f1c0784414c",
143
+ "metadata": {
144
+ "execution": {
145
+ "iopub.execute_input": "2025-02-08T22:00:09.827095Z",
146
+ "iopub.status.busy": "2025-02-08T22:00:09.826919Z",
147
+ "iopub.status.idle": "2025-02-08T22:00:10.479484Z",
148
+ "shell.execute_reply": "2025-02-08T22:00:10.478777Z",
149
+ "shell.execute_reply.started": "2025-02-08T22:00:09.827079Z"
150
+ }
151
+ },
152
+ "outputs": [
153
+ {
154
+ "name": "stderr",
155
+ "output_type": "stream",
156
+ "text": [
157
+ "/sctmp/lauwag/ipykernel_1497673/1825509207.py:9: UserWarning: Converting to PeriodArray/Index representation will drop timezone information.\n",
158
+ " df['year_month'] = df['createdAt'].dt.to_period('M')\n"
159
+ ]
160
+ },
161
+ {
162
+ "name": "stdout",
163
+ "output_type": "stream",
164
+ "text": [
165
+ "Data has been split and saved to /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month\n"
166
+ ]
167
+ }
168
+ ],
169
+ "source": [
170
+ "split_by_month(mini, mivolo_in)"
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": 5,
176
+ "id": "4c543306-ffc8-4b9c-a3df-b49b2271caa9",
177
+ "metadata": {
178
+ "execution": {
179
+ "iopub.execute_input": "2025-02-08T22:00:10.480505Z",
180
+ "iopub.status.busy": "2025-02-08T22:00:10.480310Z",
181
+ "iopub.status.idle": "2025-02-08T22:00:10.483961Z",
182
+ "shell.execute_reply": "2025-02-08T22:00:10.483400Z",
183
+ "shell.execute_reply.started": "2025-02-08T22:00:10.480486Z"
184
+ }
185
+ },
186
+ "outputs": [],
187
+ "source": [
188
+ "mivolo_out = current_dir.parent / 'data/CSV/image_subsets/MiVOLO-results/'\n",
189
+ "mivolo_out.mkdir(parents=True, exist_ok=True) # Create the output directory if it doesn't exist"
190
+ ]
191
+ },
192
+ {
193
+ "cell_type": "code",
194
+ "execution_count": null,
195
+ "id": "304ed12f-c7b6-4129-b24d-7ccc793a62c7",
196
+ "metadata": {
197
+ "execution": {
198
+ "iopub.execute_input": "2025-02-08T22:00:10.484802Z",
199
+ "iopub.status.busy": "2025-02-08T22:00:10.484639Z"
200
+ }
201
+ },
202
+ "outputs": [
203
+ {
204
+ "name": "stderr",
205
+ "output_type": "stream",
206
+ "text": [
207
+ "/home/lauwag/data/conda/envs/horde/lib/python3.12/site-packages/ultralytics/nn/tasks.py:634: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
208
+ " return torch.load(file, map_location=\"cpu\"), file # load\n"
209
+ ]
210
+ },
211
+ {
212
+ "name": "stdout",
213
+ "output_type": "stream",
214
+ "text": [
215
+ "Model summary (fused): 268 layers, 68125494 parameters, 0 gradients, 257.4 GFLOPs\n"
216
+ ]
217
+ },
218
+ {
219
+ "name": "stderr",
220
+ "output_type": "stream",
221
+ "text": [
222
+ "[W208 23:00:15.738708520 NNPACK.cpp:61] Could not initialize NNPACK! Reason: Unsupported hardware.\n",
223
+ "/home/lauwag/data/conda/envs/horde/lib/python3.12/site-packages/mivolo/model/mi_volo.py:33: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
224
+ " state = torch.load(ckpt_path, map_location=\"cpu\")\n",
225
+ "INFO:MiVOLO:Model meta:\n",
226
+ "min_age: 1, max_age: 95, avg_age: 48.0, num_classes: 3, in_chans: 6, with_persons_model: True, disable_faces: False, use_persons: True, only_age: False, num_classes_gender: 2, input_size: 224, use_person_crops: True, use_face_crops: True\n",
227
+ "/home/lauwag/data/conda/envs/horde/lib/python3.12/site-packages/timm/models/_helpers.py:39: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
228
+ " checkpoint = torch.load(checkpoint_path, map_location='cpu')\n",
229
+ "INFO:timm.models._helpers:Loaded state_dict from checkpoint '/shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/ext/MiVOLO/models/mivolo_imbd.pth.tar'\n",
230
+ "INFO:MiVOLO:Model mivolo_d1_224 created, param count: 27432414\n",
231
+ "INFO:timm.data.config:Data processing configuration for current model + dataset:\n",
232
+ "INFO:timm.data.config:\tinput_size: (3, 224, 224)\n",
233
+ "INFO:timm.data.config:\tinterpolation: bicubic\n",
234
+ "INFO:timm.data.config:\tmean: (0.485, 0.456, 0.406)\n",
235
+ "INFO:timm.data.config:\tstd: (0.229, 0.224, 0.225)\n",
236
+ "INFO:timm.data.config:\tcrop_pct: 0.96\n",
237
+ "INFO:timm.data.config:\tcrop_mode: center\n"
238
+ ]
239
+ },
240
+ {
241
+ "name": "stdout",
242
+ "output_type": "stream",
243
+ "text": [
244
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2022-11.csv\n",
245
+ "\n",
246
+ "0: 640x640 (no detections), 723.9ms\n",
247
+ "Speed: 12.1ms preprocess, 723.9ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 640)\n",
248
+ "Processed and saved 1 images so far.\n",
249
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2022-11.csv\n",
250
+ "File not found: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2022-12.csv\n",
251
+ "File not found: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-01.csv\n",
252
+ "File not found: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-02.csv\n",
253
+ "File not found: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-03.csv\n",
254
+ "File not found: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-04.csv\n",
255
+ "File not found: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-05.csv\n",
256
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-06.csv\n",
257
+ "\n",
258
+ "0: 416x640 1 person, 455.1ms\n",
259
+ "Speed: 3.5ms preprocess, 455.1ms inference, 33.5ms postprocess per image at shape (1, 3, 416, 640)\n"
260
+ ]
261
+ },
262
+ {
263
+ "name": "stderr",
264
+ "output_type": "stream",
265
+ "text": [
266
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
267
+ "INFO:MiVOLO:\tage: 32.89\n",
268
+ "INFO:MiVOLO:\tgender: male [99%]\n"
269
+ ]
270
+ },
271
+ {
272
+ "name": "stdout",
273
+ "output_type": "stream",
274
+ "text": [
275
+ "Processed and saved 1 images so far.\n",
276
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2023-06.csv\n",
277
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-07.csv\n",
278
+ "\n",
279
+ "0: 640x320 1 person, 395.7ms\n",
280
+ "Speed: 2.9ms preprocess, 395.7ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 320)\n"
281
+ ]
282
+ },
283
+ {
284
+ "name": "stderr",
285
+ "output_type": "stream",
286
+ "text": [
287
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
288
+ "INFO:MiVOLO:\tage: 33.49\n",
289
+ "INFO:MiVOLO:\tgender: female [99%]\n"
290
+ ]
291
+ },
292
+ {
293
+ "name": "stdout",
294
+ "output_type": "stream",
295
+ "text": [
296
+ "Processed and saved 1 images so far.\n",
297
+ "\n",
298
+ "0: 640x448 1 person, 1 face, 478.5ms\n",
299
+ "Speed: 1.9ms preprocess, 478.5ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
300
+ ]
301
+ },
302
+ {
303
+ "name": "stderr",
304
+ "output_type": "stream",
305
+ "text": [
306
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
307
+ "INFO:MiVOLO:\tage: 17.81\n",
308
+ "INFO:MiVOLO:\tgender: female [99%]\n"
309
+ ]
310
+ },
311
+ {
312
+ "name": "stdout",
313
+ "output_type": "stream",
314
+ "text": [
315
+ "Processed and saved 2 images so far.\n",
316
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2023-07.csv\n",
317
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-08.csv\n",
318
+ "\n",
319
+ "0: 640x448 1 person, 478.0ms\n",
320
+ "Speed: 2.9ms preprocess, 478.0ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
321
+ ]
322
+ },
323
+ {
324
+ "name": "stderr",
325
+ "output_type": "stream",
326
+ "text": [
327
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
328
+ "INFO:MiVOLO:\tage: 40.62\n",
329
+ "INFO:MiVOLO:\tgender: male [99%]\n"
330
+ ]
331
+ },
332
+ {
333
+ "name": "stdout",
334
+ "output_type": "stream",
335
+ "text": [
336
+ "Processed and saved 1 images so far.\n",
337
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2023-08.csv\n",
338
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-09.csv\n",
339
+ "\n",
340
+ "0: 416x640 (no detections), 567.1ms\n",
341
+ "Speed: 2.4ms preprocess, 567.1ms inference, 0.4ms postprocess per image at shape (1, 3, 416, 640)\n",
342
+ "Processed and saved 1 images so far.\n",
343
+ "\n",
344
+ "0: 320x640 (no detections), 393.6ms\n",
345
+ "Speed: 1.7ms preprocess, 393.6ms inference, 0.4ms postprocess per image at shape (1, 3, 320, 640)\n",
346
+ "\n",
347
+ "0: 640x640 (no detections), 711.9ms\n",
348
+ "Speed: 3.4ms preprocess, 711.9ms inference, 0.5ms postprocess per image at shape (1, 3, 640, 640)\n",
349
+ "\n",
350
+ "0: 640x640 (no detections), 699.8ms\n",
351
+ "Speed: 2.3ms preprocess, 699.8ms inference, 0.5ms postprocess per image at shape (1, 3, 640, 640)\n",
352
+ "\n",
353
+ "0: 640x576 1 person, 629.6ms\n",
354
+ "Speed: 2.4ms preprocess, 629.6ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 576)\n"
355
+ ]
356
+ },
357
+ {
358
+ "name": "stderr",
359
+ "output_type": "stream",
360
+ "text": [
361
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
362
+ "INFO:MiVOLO:\tage: 28.65\n",
363
+ "INFO:MiVOLO:\tgender: female [99%]\n"
364
+ ]
365
+ },
366
+ {
367
+ "name": "stdout",
368
+ "output_type": "stream",
369
+ "text": [
370
+ "\n",
371
+ "0: 640x448 1 person, 1 face, 598.3ms\n",
372
+ "Speed: 2.1ms preprocess, 598.3ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
373
+ ]
374
+ },
375
+ {
376
+ "name": "stderr",
377
+ "output_type": "stream",
378
+ "text": [
379
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
380
+ "INFO:MiVOLO:\tage: 25.85\n",
381
+ "INFO:MiVOLO:\tgender: female [99%]\n",
382
+ "ERROR:inference:Unidentified image error for URL https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/98848c97-3d1e-4b52-9967-aeeca354a30e/width=656/98848c97-3d1e-4b52-9967-aeeca354a30e.mp4: cannot identify image file <_io.BytesIO object at 0x14cb00133740>\n"
383
+ ]
384
+ },
385
+ {
386
+ "name": "stdout",
387
+ "output_type": "stream",
388
+ "text": [
389
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2023-09.csv\n",
390
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-10.csv\n"
391
+ ]
392
+ },
393
+ {
394
+ "name": "stderr",
395
+ "output_type": "stream",
396
+ "text": [
397
+ "ERROR:inference:Unidentified image error for URL https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/e6469288-b487-4a06-99c1-59e7ac22fa77/width=1024/e6469288-b487-4a06-99c1-59e7ac22fa77.mp4: cannot identify image file <_io.BytesIO object at 0x14cb00ecbdd0>\n"
398
+ ]
399
+ },
400
+ {
401
+ "name": "stdout",
402
+ "output_type": "stream",
403
+ "text": [
404
+ "\n",
405
+ "0: 448x640 (no detections), 536.6ms\n",
406
+ "Speed: 10.1ms preprocess, 536.6ms inference, 0.4ms postprocess per image at shape (1, 3, 448, 640)\n",
407
+ "Processed and saved 2 images so far.\n",
408
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2023-10.csv\n",
409
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-11.csv\n",
410
+ "\n",
411
+ "0: 640x448 1 person, 1 face, 662.9ms\n",
412
+ "Speed: 2.6ms preprocess, 662.9ms inference, 0.9ms postprocess per image at shape (1, 3, 640, 448)\n"
413
+ ]
414
+ },
415
+ {
416
+ "name": "stderr",
417
+ "output_type": "stream",
418
+ "text": [
419
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
420
+ "INFO:MiVOLO:\tage: 17.0\n",
421
+ "INFO:MiVOLO:\tgender: female [99%]\n"
422
+ ]
423
+ },
424
+ {
425
+ "name": "stdout",
426
+ "output_type": "stream",
427
+ "text": [
428
+ "Processed and saved 1 images so far.\n",
429
+ "\n",
430
+ "0: 640x384 1 person, 895.9ms\n",
431
+ "Speed: 2.0ms preprocess, 895.9ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 384)\n"
432
+ ]
433
+ },
434
+ {
435
+ "name": "stderr",
436
+ "output_type": "stream",
437
+ "text": [
438
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
439
+ "INFO:MiVOLO:\tage: 43.33\n",
440
+ "INFO:MiVOLO:\tgender: male [99%]\n"
441
+ ]
442
+ },
443
+ {
444
+ "name": "stdout",
445
+ "output_type": "stream",
446
+ "text": [
447
+ "\n",
448
+ "0: 640x448 (no detections), 529.4ms\n",
449
+ "Speed: 2.6ms preprocess, 529.4ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
450
+ "\n",
451
+ "0: 640x448 1 person, 539.3ms\n",
452
+ "Speed: 2.8ms preprocess, 539.3ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 448)\n"
453
+ ]
454
+ },
455
+ {
456
+ "name": "stderr",
457
+ "output_type": "stream",
458
+ "text": [
459
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
460
+ "INFO:MiVOLO:\tage: 39.15\n",
461
+ "INFO:MiVOLO:\tgender: male [99%]\n"
462
+ ]
463
+ },
464
+ {
465
+ "name": "stdout",
466
+ "output_type": "stream",
467
+ "text": [
468
+ "\n",
469
+ "0: 640x448 1 person, 1 face, 708.6ms\n",
470
+ "Speed: 2.5ms preprocess, 708.6ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 448)\n"
471
+ ]
472
+ },
473
+ {
474
+ "name": "stderr",
475
+ "output_type": "stream",
476
+ "text": [
477
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
478
+ "INFO:MiVOLO:\tage: 29.64\n",
479
+ "INFO:MiVOLO:\tgender: female [99%]\n",
480
+ "ERROR:inference:Unidentified image error for URL https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/ad4b5481-0a58-4196-a3e8-fca2fe22a3cc/width=1080/ad4b5481-0a58-4196-a3e8-fca2fe22a3cc.mp4: cannot identify image file <_io.BytesIO object at 0x14cb010c24d0>\n"
481
+ ]
482
+ },
483
+ {
484
+ "name": "stdout",
485
+ "output_type": "stream",
486
+ "text": [
487
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2023-11.csv\n",
488
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2023-12.csv\n",
489
+ "\n",
490
+ "0: 640x384 1 person, 1 face, 461.0ms\n",
491
+ "Speed: 2.4ms preprocess, 461.0ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 384)\n"
492
+ ]
493
+ },
494
+ {
495
+ "name": "stderr",
496
+ "output_type": "stream",
497
+ "text": [
498
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
499
+ "INFO:MiVOLO:\tage: 19.61\n",
500
+ "INFO:MiVOLO:\tgender: female [99%]\n"
501
+ ]
502
+ },
503
+ {
504
+ "name": "stdout",
505
+ "output_type": "stream",
506
+ "text": [
507
+ "Processed and saved 1 images so far.\n",
508
+ "\n",
509
+ "0: 640x448 1 person, 1 face, 501.3ms\n",
510
+ "Speed: 3.1ms preprocess, 501.3ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
511
+ ]
512
+ },
513
+ {
514
+ "name": "stderr",
515
+ "output_type": "stream",
516
+ "text": [
517
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
518
+ "INFO:MiVOLO:\tage: 22.58\n",
519
+ "INFO:MiVOLO:\tgender: female [99%]\n",
520
+ "ERROR:inference:Unidentified image error for URL https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/3004b5fa-af81-4de7-829d-1d809d70b878/width=512/3004b5fa-af81-4de7-829d-1d809d70b878.mp4: cannot identify image file <_io.BytesIO object at 0x14cb0020ad40>\n"
521
+ ]
522
+ },
523
+ {
524
+ "name": "stdout",
525
+ "output_type": "stream",
526
+ "text": [
527
+ "\n",
528
+ "0: 640x640 (no detections), 842.5ms\n",
529
+ "Speed: 4.5ms preprocess, 842.5ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 640)\n",
530
+ "\n",
531
+ "0: 640x416 (no detections), 446.8ms\n",
532
+ "Speed: 2.5ms preprocess, 446.8ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 416)\n",
533
+ "Processed and saved 5 images so far.\n",
534
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2023-12.csv\n",
535
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2024-01.csv\n",
536
+ "\n",
537
+ "0: 640x448 (no detections), 638.5ms\n",
538
+ "Speed: 2.3ms preprocess, 638.5ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
539
+ "Processed and saved 1 images so far.\n",
540
+ "\n",
541
+ "0: 640x416 (no detections), 441.7ms\n",
542
+ "Speed: 2.5ms preprocess, 441.7ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 416)\n",
543
+ "\n",
544
+ "0: 640x448 (no detections), 470.3ms\n",
545
+ "Speed: 2.3ms preprocess, 470.3ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
546
+ "\n",
547
+ "0: 640x448 (no detections), 693.9ms\n",
548
+ "Speed: 2.5ms preprocess, 693.9ms inference, 0.5ms postprocess per image at shape (1, 3, 640, 448)\n",
549
+ "\n",
550
+ "0: 640x512 1 person, 1 face, 808.6ms\n",
551
+ "Speed: 3.2ms preprocess, 808.6ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 512)\n"
552
+ ]
553
+ },
554
+ {
555
+ "name": "stderr",
556
+ "output_type": "stream",
557
+ "text": [
558
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
559
+ "INFO:MiVOLO:\tage: 15.01\n",
560
+ "INFO:MiVOLO:\tgender: female [99%]\n"
561
+ ]
562
+ },
563
+ {
564
+ "name": "stdout",
565
+ "output_type": "stream",
566
+ "text": [
567
+ "\n",
568
+ "0: 640x320 1 person, 1 face, 345.6ms\n",
569
+ "Speed: 2.0ms preprocess, 345.6ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 320)\n"
570
+ ]
571
+ },
572
+ {
573
+ "name": "stderr",
574
+ "output_type": "stream",
575
+ "text": [
576
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
577
+ "INFO:MiVOLO:\tage: 20.86\n",
578
+ "INFO:MiVOLO:\tgender: female [99%]\n"
579
+ ]
580
+ },
581
+ {
582
+ "name": "stdout",
583
+ "output_type": "stream",
584
+ "text": [
585
+ "Processed and saved 6 images so far.\n",
586
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2024-01.csv\n",
587
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2024-02.csv\n",
588
+ "\n",
589
+ "0: 640x384 1 person, 1 face, 387.8ms\n",
590
+ "Speed: 1.9ms preprocess, 387.8ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 384)\n"
591
+ ]
592
+ },
593
+ {
594
+ "name": "stderr",
595
+ "output_type": "stream",
596
+ "text": [
597
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
598
+ "INFO:MiVOLO:\tage: 17.31\n",
599
+ "INFO:MiVOLO:\tgender: female [99%]\n"
600
+ ]
601
+ },
602
+ {
603
+ "name": "stdout",
604
+ "output_type": "stream",
605
+ "text": [
606
+ "Processed and saved 1 images so far.\n",
607
+ "\n",
608
+ "0: 640x480 1 person, 1 face, 540.4ms\n",
609
+ "Speed: 2.5ms preprocess, 540.4ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 480)\n"
610
+ ]
611
+ },
612
+ {
613
+ "name": "stderr",
614
+ "output_type": "stream",
615
+ "text": [
616
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
617
+ "INFO:MiVOLO:\tage: 17.47\n",
618
+ "INFO:MiVOLO:\tgender: female [99%]\n"
619
+ ]
620
+ },
621
+ {
622
+ "name": "stdout",
623
+ "output_type": "stream",
624
+ "text": [
625
+ "\n",
626
+ "0: 640x640 1 person, 1 face, 713.1ms\n",
627
+ "Speed: 3.8ms preprocess, 713.1ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 640)\n"
628
+ ]
629
+ },
630
+ {
631
+ "name": "stderr",
632
+ "output_type": "stream",
633
+ "text": [
634
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
635
+ "INFO:MiVOLO:\tage: 17.85\n",
636
+ "INFO:MiVOLO:\tgender: female [99%]\n"
637
+ ]
638
+ },
639
+ {
640
+ "name": "stdout",
641
+ "output_type": "stream",
642
+ "text": [
643
+ "\n",
644
+ "0: 640x640 (no detections), 778.8ms\n",
645
+ "Speed: 28.7ms preprocess, 778.8ms inference, 0.5ms postprocess per image at shape (1, 3, 640, 640)\n",
646
+ "\n",
647
+ "0: 640x448 1 person, 1 face, 528.2ms\n",
648
+ "Speed: 2.3ms preprocess, 528.2ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
649
+ ]
650
+ },
651
+ {
652
+ "name": "stderr",
653
+ "output_type": "stream",
654
+ "text": [
655
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
656
+ "INFO:MiVOLO:\tage: 21.63\n",
657
+ "INFO:MiVOLO:\tgender: female [99%]\n"
658
+ ]
659
+ },
660
+ {
661
+ "name": "stdout",
662
+ "output_type": "stream",
663
+ "text": [
664
+ "\n",
665
+ "0: 640x448 1 person, 1 face, 518.4ms\n",
666
+ "Speed: 3.9ms preprocess, 518.4ms inference, 0.9ms postprocess per image at shape (1, 3, 640, 448)\n"
667
+ ]
668
+ },
669
+ {
670
+ "name": "stderr",
671
+ "output_type": "stream",
672
+ "text": [
673
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
674
+ "INFO:MiVOLO:\tage: 18.25\n",
675
+ "INFO:MiVOLO:\tgender: female [99%]\n"
676
+ ]
677
+ },
678
+ {
679
+ "name": "stdout",
680
+ "output_type": "stream",
681
+ "text": [
682
+ "\n",
683
+ "0: 640x448 1 person, 1 face, 470.7ms\n",
684
+ "Speed: 2.5ms preprocess, 470.7ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 448)\n"
685
+ ]
686
+ },
687
+ {
688
+ "name": "stderr",
689
+ "output_type": "stream",
690
+ "text": [
691
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
692
+ "INFO:MiVOLO:\tage: 20.51\n",
693
+ "INFO:MiVOLO:\tgender: female [99%]\n"
694
+ ]
695
+ },
696
+ {
697
+ "name": "stdout",
698
+ "output_type": "stream",
699
+ "text": [
700
+ "\n",
701
+ "0: 640x480 1 person, 1 face, 647.1ms\n",
702
+ "Speed: 2.4ms preprocess, 647.1ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 480)\n"
703
+ ]
704
+ },
705
+ {
706
+ "name": "stderr",
707
+ "output_type": "stream",
708
+ "text": [
709
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
710
+ "INFO:MiVOLO:\tage: 58.87\n",
711
+ "INFO:MiVOLO:\tgender: male [99%]\n"
712
+ ]
713
+ },
714
+ {
715
+ "name": "stdout",
716
+ "output_type": "stream",
717
+ "text": [
718
+ "\n",
719
+ "0: 640x448 (no detections), 469.8ms\n",
720
+ "Speed: 2.6ms preprocess, 469.8ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
721
+ "\n",
722
+ "0: 640x448 1 person, 1 face, 477.5ms\n",
723
+ "Speed: 2.3ms preprocess, 477.5ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 448)\n"
724
+ ]
725
+ },
726
+ {
727
+ "name": "stderr",
728
+ "output_type": "stream",
729
+ "text": [
730
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
731
+ "INFO:MiVOLO:\tage: 23.79\n",
732
+ "INFO:MiVOLO:\tgender: female [99%]\n"
733
+ ]
734
+ },
735
+ {
736
+ "name": "stdout",
737
+ "output_type": "stream",
738
+ "text": [
739
+ "Processed and saved 10 images so far.\n",
740
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2024-02.csv\n",
741
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2024-03.csv\n",
742
+ "\n",
743
+ "0: 640x448 1 face, 511.4ms\n",
744
+ "Speed: 2.5ms preprocess, 511.4ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
745
+ ]
746
+ },
747
+ {
748
+ "name": "stderr",
749
+ "output_type": "stream",
750
+ "text": [
751
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
752
+ "INFO:MiVOLO:\tage: 24.87\n",
753
+ "INFO:MiVOLO:\tgender: female [99%]\n"
754
+ ]
755
+ },
756
+ {
757
+ "name": "stdout",
758
+ "output_type": "stream",
759
+ "text": [
760
+ "Processed and saved 1 images so far.\n",
761
+ "\n",
762
+ "0: 640x544 (no detections), 576.5ms\n",
763
+ "Speed: 2.9ms preprocess, 576.5ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 544)\n",
764
+ "\n",
765
+ "0: 640x448 1 person, 1 face, 687.1ms\n",
766
+ "Speed: 9.9ms preprocess, 687.1ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
767
+ ]
768
+ },
769
+ {
770
+ "name": "stderr",
771
+ "output_type": "stream",
772
+ "text": [
773
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
774
+ "INFO:MiVOLO:\tage: 25.76\n",
775
+ "INFO:MiVOLO:\tgender: female [99%]\n"
776
+ ]
777
+ },
778
+ {
779
+ "name": "stdout",
780
+ "output_type": "stream",
781
+ "text": [
782
+ "\n",
783
+ "0: 640x448 (no detections), 498.3ms\n",
784
+ "Speed: 2.3ms preprocess, 498.3ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
785
+ "\n",
786
+ "0: 640x512 (no detections), 573.2ms\n",
787
+ "Speed: 3.0ms preprocess, 573.2ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 512)\n",
788
+ "Processed and saved 5 images so far.\n",
789
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2024-03.csv\n",
790
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2024-04.csv\n",
791
+ "\n",
792
+ "0: 640x384 (no detections), 518.2ms\n",
793
+ "Speed: 2.7ms preprocess, 518.2ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 384)\n",
794
+ "Processed and saved 1 images so far.\n",
795
+ "\n",
796
+ "0: 640x512 (no detections), 707.7ms\n",
797
+ "Speed: 3.6ms preprocess, 707.7ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 512)\n",
798
+ "\n",
799
+ "0: 640x416 (no detections), 453.7ms\n",
800
+ "Speed: 2.4ms preprocess, 453.7ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 416)\n",
801
+ "\n",
802
+ "0: 640x384 (no detections), 391.0ms\n",
803
+ "Speed: 2.0ms preprocess, 391.0ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 384)\n",
804
+ "\n",
805
+ "0: 640x448 1 person, 1 face, 449.8ms\n",
806
+ "Speed: 2.3ms preprocess, 449.8ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
807
+ ]
808
+ },
809
+ {
810
+ "name": "stderr",
811
+ "output_type": "stream",
812
+ "text": [
813
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
814
+ "INFO:MiVOLO:\tage: 22.39\n",
815
+ "INFO:MiVOLO:\tgender: female [99%]\n"
816
+ ]
817
+ },
818
+ {
819
+ "name": "stdout",
820
+ "output_type": "stream",
821
+ "text": [
822
+ "\n",
823
+ "0: 640x448 (no detections), 618.4ms\n",
824
+ "Speed: 2.3ms preprocess, 618.4ms inference, 0.5ms postprocess per image at shape (1, 3, 640, 448)\n",
825
+ "\n",
826
+ "0: 640x448 1 person, 1 face, 631.0ms\n",
827
+ "Speed: 2.2ms preprocess, 631.0ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
828
+ ]
829
+ },
830
+ {
831
+ "name": "stderr",
832
+ "output_type": "stream",
833
+ "text": [
834
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
835
+ "INFO:MiVOLO:\tage: 24.05\n",
836
+ "INFO:MiVOLO:\tgender: female [99%]\n"
837
+ ]
838
+ },
839
+ {
840
+ "name": "stdout",
841
+ "output_type": "stream",
842
+ "text": [
843
+ "\n",
844
+ "0: 640x512 1 person, 496.4ms\n",
845
+ "Speed: 2.6ms preprocess, 496.4ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 512)\n"
846
+ ]
847
+ },
848
+ {
849
+ "name": "stderr",
850
+ "output_type": "stream",
851
+ "text": [
852
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
853
+ "INFO:MiVOLO:\tage: 22.81\n",
854
+ "INFO:MiVOLO:\tgender: male [99%]\n"
855
+ ]
856
+ },
857
+ {
858
+ "name": "stdout",
859
+ "output_type": "stream",
860
+ "text": [
861
+ "\n",
862
+ "0: 640x448 (no detections), 442.8ms\n",
863
+ "Speed: 2.3ms preprocess, 442.8ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
864
+ "\n",
865
+ "0: 640x448 1 person, 1 face, 477.7ms\n",
866
+ "Speed: 2.4ms preprocess, 477.7ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
867
+ ]
868
+ },
869
+ {
870
+ "name": "stderr",
871
+ "output_type": "stream",
872
+ "text": [
873
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
874
+ "INFO:MiVOLO:\tage: 21.62\n",
875
+ "INFO:MiVOLO:\tgender: female [99%]\n"
876
+ ]
877
+ },
878
+ {
879
+ "name": "stdout",
880
+ "output_type": "stream",
881
+ "text": [
882
+ "\n",
883
+ "0: 640x448 1 person, 1 face, 447.0ms\n",
884
+ "Speed: 2.2ms preprocess, 447.0ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
885
+ ]
886
+ },
887
+ {
888
+ "name": "stderr",
889
+ "output_type": "stream",
890
+ "text": [
891
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
892
+ "INFO:MiVOLO:\tage: 54.31\n",
893
+ "INFO:MiVOLO:\tgender: male [99%]\n"
894
+ ]
895
+ },
896
+ {
897
+ "name": "stdout",
898
+ "output_type": "stream",
899
+ "text": [
900
+ "\n",
901
+ "0: 640x640 (no detections), 819.0ms\n",
902
+ "Speed: 3.6ms preprocess, 819.0ms inference, 0.5ms postprocess per image at shape (1, 3, 640, 640)\n",
903
+ "\n",
904
+ "0: 640x448 1 person, 1 face, 478.2ms\n",
905
+ "Speed: 1.8ms preprocess, 478.2ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
906
+ ]
907
+ },
908
+ {
909
+ "name": "stderr",
910
+ "output_type": "stream",
911
+ "text": [
912
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
913
+ "INFO:MiVOLO:\tage: 20.56\n",
914
+ "INFO:MiVOLO:\tgender: female [99%]\n"
915
+ ]
916
+ },
917
+ {
918
+ "name": "stdout",
919
+ "output_type": "stream",
920
+ "text": [
921
+ "\n",
922
+ "0: 640x448 1 person, 1 face, 471.2ms\n",
923
+ "Speed: 2.7ms preprocess, 471.2ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
924
+ ]
925
+ },
926
+ {
927
+ "name": "stderr",
928
+ "output_type": "stream",
929
+ "text": [
930
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
931
+ "INFO:MiVOLO:\tage: 21.31\n",
932
+ "INFO:MiVOLO:\tgender: female [99%]\n"
933
+ ]
934
+ },
935
+ {
936
+ "name": "stdout",
937
+ "output_type": "stream",
938
+ "text": [
939
+ "\n",
940
+ "0: 640x448 (no detections), 484.0ms\n",
941
+ "Speed: 2.2ms preprocess, 484.0ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
942
+ "\n",
943
+ "0: 640x640 (no detections), 832.6ms\n",
944
+ "Speed: 3.0ms preprocess, 832.6ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 640)\n",
945
+ "\n",
946
+ "0: 640x448 1 person, 1 face, 508.9ms\n",
947
+ "Speed: 2.5ms preprocess, 508.9ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
948
+ ]
949
+ },
950
+ {
951
+ "name": "stderr",
952
+ "output_type": "stream",
953
+ "text": [
954
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
955
+ "INFO:MiVOLO:\tage: 27.19\n",
956
+ "INFO:MiVOLO:\tgender: female [99%]\n",
957
+ "ERROR:inference:Unidentified image error for URL https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/6879c7b9-5cb3-42db-b409-30b4e2f71945/width=1080/6879c7b9-5cb3-42db-b409-30b4e2f71945.mp4: cannot identify image file <_io.BytesIO object at 0x14cb0020ad40>\n"
958
+ ]
959
+ },
960
+ {
961
+ "name": "stdout",
962
+ "output_type": "stream",
963
+ "text": [
964
+ "\n",
965
+ "0: 640x448 9 persons, 461.8ms\n",
966
+ "Speed: 2.4ms preprocess, 461.8ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
967
+ ]
968
+ },
969
+ {
970
+ "name": "stderr",
971
+ "output_type": "stream",
972
+ "text": [
973
+ "INFO:MiVOLO:faces_input: torch.Size([9, 3, 224, 224]), person_input: torch.Size([9, 3, 224, 224])\n",
974
+ "INFO:MiVOLO:\tage: 30.4\n",
975
+ "INFO:MiVOLO:\tgender: male [55%]\n",
976
+ "INFO:MiVOLO:\tage: 28.89\n",
977
+ "INFO:MiVOLO:\tgender: female [63%]\n",
978
+ "INFO:MiVOLO:\tage: 30.31\n",
979
+ "INFO:MiVOLO:\tgender: female [68%]\n",
980
+ "INFO:MiVOLO:\tage: 31.62\n",
981
+ "INFO:MiVOLO:\tgender: female [53%]\n",
982
+ "INFO:MiVOLO:\tage: 35.17\n",
983
+ "INFO:MiVOLO:\tgender: male [53%]\n",
984
+ "INFO:MiVOLO:\tage: 33.02\n",
985
+ "INFO:MiVOLO:\tgender: male [95%]\n",
986
+ "INFO:MiVOLO:\tage: 35.17\n",
987
+ "INFO:MiVOLO:\tgender: male [53%]\n",
988
+ "INFO:MiVOLO:\tage: 35.17\n",
989
+ "INFO:MiVOLO:\tgender: male [53%]\n",
990
+ "INFO:MiVOLO:\tage: 35.17\n",
991
+ "INFO:MiVOLO:\tgender: male [53%]\n"
992
+ ]
993
+ },
994
+ {
995
+ "name": "stdout",
996
+ "output_type": "stream",
997
+ "text": [
998
+ "Processed and saved 19 images so far.\n",
999
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2024-04.csv\n",
1000
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2024-05.csv\n",
1001
+ "\n",
1002
+ "0: 640x448 1 person, 455.5ms\n",
1003
+ "Speed: 2.2ms preprocess, 455.5ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
1004
+ ]
1005
+ },
1006
+ {
1007
+ "name": "stderr",
1008
+ "output_type": "stream",
1009
+ "text": [
1010
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1011
+ "INFO:MiVOLO:\tage: 37.57\n",
1012
+ "INFO:MiVOLO:\tgender: male [95%]\n"
1013
+ ]
1014
+ },
1015
+ {
1016
+ "name": "stdout",
1017
+ "output_type": "stream",
1018
+ "text": [
1019
+ "Processed and saved 1 images so far.\n",
1020
+ "\n",
1021
+ "0: 640x448 1 person, 1 face, 438.7ms\n",
1022
+ "Speed: 2.2ms preprocess, 438.7ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 448)\n"
1023
+ ]
1024
+ },
1025
+ {
1026
+ "name": "stderr",
1027
+ "output_type": "stream",
1028
+ "text": [
1029
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1030
+ "INFO:MiVOLO:\tage: 15.62\n",
1031
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1032
+ ]
1033
+ },
1034
+ {
1035
+ "name": "stdout",
1036
+ "output_type": "stream",
1037
+ "text": [
1038
+ "\n",
1039
+ "0: 640x448 (no detections), 444.8ms\n",
1040
+ "Speed: 2.3ms preprocess, 444.8ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n"
1041
+ ]
1042
+ },
1043
+ {
1044
+ "name": "stderr",
1045
+ "output_type": "stream",
1046
+ "text": [
1047
+ "ERROR:inference:Unidentified image error for URL https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/6032bd70-6d53-4007-9e89-e69d4748efb5/width=528/6032bd70-6d53-4007-9e89-e69d4748efb5.mp4: cannot identify image file <_io.BytesIO object at 0x14cb00ed0950>\n"
1048
+ ]
1049
+ },
1050
+ {
1051
+ "name": "stdout",
1052
+ "output_type": "stream",
1053
+ "text": [
1054
+ "\n",
1055
+ "0: 640x448 (no detections), 453.9ms\n",
1056
+ "Speed: 2.3ms preprocess, 453.9ms inference, 0.5ms postprocess per image at shape (1, 3, 640, 448)\n",
1057
+ "\n",
1058
+ "0: 640x448 1 person, 1 face, 475.0ms\n",
1059
+ "Speed: 1.6ms preprocess, 475.0ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 448)\n"
1060
+ ]
1061
+ },
1062
+ {
1063
+ "name": "stderr",
1064
+ "output_type": "stream",
1065
+ "text": [
1066
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1067
+ "INFO:MiVOLO:\tage: 22.5\n",
1068
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1069
+ ]
1070
+ },
1071
+ {
1072
+ "name": "stdout",
1073
+ "output_type": "stream",
1074
+ "text": [
1075
+ "\n",
1076
+ "0: 640x448 1 person, 1 face, 447.6ms\n",
1077
+ "Speed: 2.5ms preprocess, 447.6ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 448)\n"
1078
+ ]
1079
+ },
1080
+ {
1081
+ "name": "stderr",
1082
+ "output_type": "stream",
1083
+ "text": [
1084
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1085
+ "INFO:MiVOLO:\tage: 23.46\n",
1086
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1087
+ ]
1088
+ },
1089
+ {
1090
+ "name": "stdout",
1091
+ "output_type": "stream",
1092
+ "text": [
1093
+ "\n",
1094
+ "0: 640x512 (no detections), 528.5ms\n",
1095
+ "Speed: 3.2ms preprocess, 528.5ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 512)\n",
1096
+ "\n",
1097
+ "0: 640x448 1 person, 1 face, 449.8ms\n",
1098
+ "Speed: 2.3ms preprocess, 449.8ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
1099
+ ]
1100
+ },
1101
+ {
1102
+ "name": "stderr",
1103
+ "output_type": "stream",
1104
+ "text": [
1105
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1106
+ "INFO:MiVOLO:\tage: 29.32\n",
1107
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1108
+ ]
1109
+ },
1110
+ {
1111
+ "name": "stdout",
1112
+ "output_type": "stream",
1113
+ "text": [
1114
+ "\n",
1115
+ "0: 640x448 1 person, 1 face, 617.7ms\n",
1116
+ "Speed: 2.4ms preprocess, 617.7ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
1117
+ ]
1118
+ },
1119
+ {
1120
+ "name": "stderr",
1121
+ "output_type": "stream",
1122
+ "text": [
1123
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1124
+ "INFO:MiVOLO:\tage: 21.32\n",
1125
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1126
+ ]
1127
+ },
1128
+ {
1129
+ "name": "stdout",
1130
+ "output_type": "stream",
1131
+ "text": [
1132
+ "\n",
1133
+ "0: 640x448 (no detections), 609.1ms\n",
1134
+ "Speed: 2.3ms preprocess, 609.1ms inference, 0.5ms postprocess per image at shape (1, 3, 640, 448)\n",
1135
+ "\n",
1136
+ "0: 640x448 (no detections), 436.2ms\n",
1137
+ "Speed: 2.5ms preprocess, 436.2ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1138
+ "\n",
1139
+ "0: 640x512 1 person, 1 face, 585.6ms\n",
1140
+ "Speed: 3.1ms preprocess, 585.6ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 512)\n"
1141
+ ]
1142
+ },
1143
+ {
1144
+ "name": "stderr",
1145
+ "output_type": "stream",
1146
+ "text": [
1147
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1148
+ "INFO:MiVOLO:\tage: 20.5\n",
1149
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1150
+ ]
1151
+ },
1152
+ {
1153
+ "name": "stdout",
1154
+ "output_type": "stream",
1155
+ "text": [
1156
+ "\n",
1157
+ "0: 640x448 1 person, 457.3ms\n",
1158
+ "Speed: 2.1ms preprocess, 457.3ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
1159
+ ]
1160
+ },
1161
+ {
1162
+ "name": "stderr",
1163
+ "output_type": "stream",
1164
+ "text": [
1165
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1166
+ "INFO:MiVOLO:\tage: 25.19\n",
1167
+ "INFO:MiVOLO:\tgender: male [81%]\n"
1168
+ ]
1169
+ },
1170
+ {
1171
+ "name": "stdout",
1172
+ "output_type": "stream",
1173
+ "text": [
1174
+ "Processed and saved 14 images so far.\n",
1175
+ "Processed and saved to: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/MiVOLO-results/2024-05.csv\n",
1176
+ "Processing: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/image_subsets/Civiverse-mini-by-month/Civiverse-2024-06.csv\n",
1177
+ "\n",
1178
+ "0: 640x448 (no detections), 484.5ms\n",
1179
+ "Speed: 2.8ms preprocess, 484.5ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1180
+ "Processed and saved 1 images so far.\n",
1181
+ "\n",
1182
+ "0: 640x512 (no detections), 524.8ms\n",
1183
+ "Speed: 2.9ms preprocess, 524.8ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 512)\n",
1184
+ "\n",
1185
+ "0: 640x480 1 person, 478.0ms\n",
1186
+ "Speed: 2.6ms preprocess, 478.0ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 480)\n"
1187
+ ]
1188
+ },
1189
+ {
1190
+ "name": "stderr",
1191
+ "output_type": "stream",
1192
+ "text": [
1193
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1194
+ "INFO:MiVOLO:\tage: 39.4\n",
1195
+ "INFO:MiVOLO:\tgender: male [99%]\n"
1196
+ ]
1197
+ },
1198
+ {
1199
+ "name": "stdout",
1200
+ "output_type": "stream",
1201
+ "text": [
1202
+ "\n",
1203
+ "0: 640x512 1 person, 1 face, 539.8ms\n",
1204
+ "Speed: 2.6ms preprocess, 539.8ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 512)\n"
1205
+ ]
1206
+ },
1207
+ {
1208
+ "name": "stderr",
1209
+ "output_type": "stream",
1210
+ "text": [
1211
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1212
+ "INFO:MiVOLO:\tage: 21.33\n",
1213
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1214
+ ]
1215
+ },
1216
+ {
1217
+ "name": "stdout",
1218
+ "output_type": "stream",
1219
+ "text": [
1220
+ "\n",
1221
+ "0: 640x448 1 person, 2 faces, 446.7ms\n",
1222
+ "Speed: 2.4ms preprocess, 446.7ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
1223
+ ]
1224
+ },
1225
+ {
1226
+ "name": "stderr",
1227
+ "output_type": "stream",
1228
+ "text": [
1229
+ "INFO:MiVOLO:faces_input: torch.Size([2, 3, 224, 224]), person_input: torch.Size([2, 3, 224, 224])\n",
1230
+ "INFO:MiVOLO:\tage: 20.65\n",
1231
+ "INFO:MiVOLO:\tgender: female [99%]\n",
1232
+ "INFO:MiVOLO:\tage: 20.53\n",
1233
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1234
+ ]
1235
+ },
1236
+ {
1237
+ "name": "stdout",
1238
+ "output_type": "stream",
1239
+ "text": [
1240
+ "\n",
1241
+ "0: 640x640 1 person, 1 face, 655.0ms\n",
1242
+ "Speed: 3.3ms preprocess, 655.0ms inference, 0.8ms postprocess per image at shape (1, 3, 640, 640)\n"
1243
+ ]
1244
+ },
1245
+ {
1246
+ "name": "stderr",
1247
+ "output_type": "stream",
1248
+ "text": [
1249
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1250
+ "INFO:MiVOLO:\tage: 26.34\n",
1251
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1252
+ ]
1253
+ },
1254
+ {
1255
+ "name": "stdout",
1256
+ "output_type": "stream",
1257
+ "text": [
1258
+ "\n",
1259
+ "0: 640x384 (no detections), 400.6ms\n",
1260
+ "Speed: 2.1ms preprocess, 400.6ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 384)\n",
1261
+ "\n",
1262
+ "0: 640x448 1 person, 587.9ms\n",
1263
+ "Speed: 2.2ms preprocess, 587.9ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 448)\n"
1264
+ ]
1265
+ },
1266
+ {
1267
+ "name": "stderr",
1268
+ "output_type": "stream",
1269
+ "text": [
1270
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1271
+ "INFO:MiVOLO:\tage: 30.4\n",
1272
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1273
+ ]
1274
+ },
1275
+ {
1276
+ "name": "stdout",
1277
+ "output_type": "stream",
1278
+ "text": [
1279
+ "\n",
1280
+ "0: 640x448 (no detections), 610.3ms\n",
1281
+ "Speed: 2.3ms preprocess, 610.3ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1282
+ "\n",
1283
+ "0: 640x448 (no detections), 453.6ms\n",
1284
+ "Speed: 2.3ms preprocess, 453.6ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1285
+ "\n",
1286
+ "0: 640x512 1 person, 1 face, 511.3ms\n",
1287
+ "Speed: 2.8ms preprocess, 511.3ms inference, 0.7ms postprocess per image at shape (1, 3, 640, 512)\n"
1288
+ ]
1289
+ },
1290
+ {
1291
+ "name": "stderr",
1292
+ "output_type": "stream",
1293
+ "text": [
1294
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1295
+ "INFO:MiVOLO:\tage: 34.28\n",
1296
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1297
+ ]
1298
+ },
1299
+ {
1300
+ "name": "stdout",
1301
+ "output_type": "stream",
1302
+ "text": [
1303
+ "\n",
1304
+ "0: 640x448 (no detections), 441.2ms\n",
1305
+ "Speed: 2.3ms preprocess, 441.2ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1306
+ "\n",
1307
+ "0: 640x448 (no detections), 586.3ms\n",
1308
+ "Speed: 2.3ms preprocess, 586.3ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1309
+ "\n",
1310
+ "0: 640x448 (no detections), 437.5ms\n",
1311
+ "Speed: 2.4ms preprocess, 437.5ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1312
+ "\n",
1313
+ "0: 448x640 1 person, 1 face, 437.4ms\n",
1314
+ "Speed: 2.4ms preprocess, 437.4ms inference, 0.7ms postprocess per image at shape (1, 3, 448, 640)\n"
1315
+ ]
1316
+ },
1317
+ {
1318
+ "name": "stderr",
1319
+ "output_type": "stream",
1320
+ "text": [
1321
+ "INFO:MiVOLO:faces_input: torch.Size([1, 3, 224, 224]), person_input: torch.Size([1, 3, 224, 224])\n",
1322
+ "INFO:MiVOLO:\tage: 22.81\n",
1323
+ "INFO:MiVOLO:\tgender: female [99%]\n"
1324
+ ]
1325
+ },
1326
+ {
1327
+ "name": "stdout",
1328
+ "output_type": "stream",
1329
+ "text": [
1330
+ "\n",
1331
+ "0: 640x448 (no detections), 436.8ms\n",
1332
+ "Speed: 2.6ms preprocess, 436.8ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1333
+ "\n",
1334
+ "0: 448x640 (no detections), 433.0ms\n",
1335
+ "Speed: 1.9ms preprocess, 433.0ms inference, 0.4ms postprocess per image at shape (1, 3, 448, 640)\n",
1336
+ "\n",
1337
+ "0: 640x448 (no detections), 599.7ms\n",
1338
+ "Speed: 2.5ms preprocess, 599.7ms inference, 0.4ms postprocess per image at shape (1, 3, 640, 448)\n",
1339
+ "\n"
1340
+ ]
1341
+ }
1342
+ ],
1343
+ "source": [
1344
+ "# Set up logging\n",
1345
+ "detector_weights = current_dir.parent / 'ext/MiVOLO/models/yolov8x_person_face.pt'\n",
1346
+ "checkpoint = current_dir.parent / 'ext/MiVOLO/models/mivolo_imbd.pth.tar'\n",
1347
+ "\n",
1348
+ "_logger = logging.getLogger(\"inference\")\n",
1349
+ "logging.basicConfig(level=logging.INFO)\n",
1350
+ "\n",
1351
+ "# Placeholder configuration and predictor initialization for MiVOLO\n",
1352
+ "class Config:\n",
1353
+ " def __init__(self, detector_weights, checkpoint, device, with_persons=True, disable_faces=False, draw=False):\n",
1354
+ " self.detector_weights = detector_weights\n",
1355
+ " self.checkpoint = checkpoint\n",
1356
+ " self.device = device\n",
1357
+ " self.with_persons = with_persons\n",
1358
+ " self.disable_faces = disable_faces\n",
1359
+ " self.draw = draw\n",
1360
+ "\n",
1361
+ "\n",
1362
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
1363
+ "config = Config(detector_weights=detector_weights, checkpoint=checkpoint, device=device)\n",
1364
+ "predictor = Predictor(config, verbose=True)\n",
1365
+ "\n",
1366
+ "def download_image(url):\n",
1367
+ " try:\n",
1368
+ " response = requests.get(url)\n",
1369
+ " response.raise_for_status()\n",
1370
+ " return Image.open(BytesIO(response.content)).convert(\"RGB\")\n",
1371
+ " except requests.RequestException as e:\n",
1372
+ " _logger.error(f\"Failed to download image from {url}: {e}\")\n",
1373
+ " return None\n",
1374
+ " except UnidentifiedImageError as e:\n",
1375
+ " _logger.error(f\"Unidentified image error for URL {url}: {e}\")\n",
1376
+ " return None\n",
1377
+ "\n",
1378
+ "def process_images_with_progress(data, predictor, output_file, start_idx=0):\n",
1379
+ " results = []\n",
1380
+ " total_images = len(data)\n",
1381
+ "\n",
1382
+ " for idx, row in data.iterrows():\n",
1383
+ " if idx < start_idx:\n",
1384
+ " continue\n",
1385
+ "\n",
1386
+ " img_url = row[\"url\"]\n",
1387
+ " pil_image = download_image(img_url)\n",
1388
+ " if pil_image is None:\n",
1389
+ " continue\n",
1390
+ "\n",
1391
+ " np_image = np.array(pil_image)\n",
1392
+ " np_image = cv2.cvtColor(np_image, cv2.COLOR_RGB2BGR)\n",
1393
+ " detected_objects, _ = predictor.recognize(np_image)\n",
1394
+ "\n",
1395
+ " row_result = row.to_dict() # Start with the original row's data\n",
1396
+ "\n",
1397
+ " if detected_objects and detected_objects.ages:\n",
1398
+ " for i in range(len(detected_objects.ages)):\n",
1399
+ " age = detected_objects.ages[i]\n",
1400
+ " gender = detected_objects.genders[i]\n",
1401
+ " gender_confidence = detected_objects.gender_scores[i]\n",
1402
+ "\n",
1403
+ " if gender_confidence >= 0.83:\n",
1404
+ " detection = {\n",
1405
+ " \"detection_type\": 'face' if i in detected_objects.face_to_person_map else 'person',\n",
1406
+ " \"gender\": gender,\n",
1407
+ " \"gender_confidence\": gender_confidence,\n",
1408
+ " \"age\": age,\n",
1409
+ " \"n_persons\": detected_objects.n_persons,\n",
1410
+ " \"n_faces\": detected_objects.n_faces,\n",
1411
+ " \"detected\": True\n",
1412
+ " }\n",
1413
+ " else:\n",
1414
+ " detection = {\n",
1415
+ " \"detection_type\": \"N/A\",\n",
1416
+ " \"gender\": \"N/A\",\n",
1417
+ " \"gender_confidence\": 0,\n",
1418
+ " \"age\": 0,\n",
1419
+ " \"n_persons\": detected_objects.n_persons if detected_objects else 0,\n",
1420
+ " \"n_faces\": detected_objects.n_faces if detected_objects else 0,\n",
1421
+ " \"detected\": False\n",
1422
+ " }\n",
1423
+ "\n",
1424
+ " results.append({**row_result, **detection})\n",
1425
+ " else:\n",
1426
+ " detection = {\n",
1427
+ " \"detection_type\": \"N/A\",\n",
1428
+ " \"gender\": \"N/A\",\n",
1429
+ " \"gender_confidence\": 0,\n",
1430
+ " \"age\": 0,\n",
1431
+ " \"n_persons\": detected_objects.n_persons if detected_objects else 0,\n",
1432
+ " \"n_faces\": detected_objects.n_faces if detected_objects else 0,\n",
1433
+ " \"detected\": False\n",
1434
+ " }\n",
1435
+ " results.append({**row_result, **detection})\n",
1436
+ "\n",
1437
+ " if idx % 100 == 0 or idx == total_images - 1:\n",
1438
+ " df = pd.DataFrame(results)\n",
1439
+ " if os.path.exists(output_file):\n",
1440
+ " df.to_csv(output_file, mode='a', header=False, index=False)\n",
1441
+ " else:\n",
1442
+ " df.to_csv(output_file, mode='w', header=True, index=False)\n",
1443
+ " results = []\n",
1444
+ " print(f\"Processed and saved {idx + 1} images so far.\")\n",
1445
+ "\n",
1446
+ "def generate_months(start, end):\n",
1447
+ " start_date = datetime.strptime(start, '%Y-%m')\n",
1448
+ " end_date = datetime.strptime(end, '%Y-%m')\n",
1449
+ " while start_date <= end_date:\n",
1450
+ " yield start_date.strftime('%Y-%m')\n",
1451
+ " start_date += relativedelta(months=1) # Increment by calendar months\n",
1452
+ "\n",
1453
+ "\n",
1454
+ "start_month = '2022-11'\n",
1455
+ "end_month = '2024-12'\n",
1456
+ "\n",
1457
+ "for month in generate_months(start_month, end_month):\n",
1458
+ " input_file_path = mivolo_in / f'Civiverse-{month}.csv'\n",
1459
+ " output_file_path = mivolo_out / f'{month}.csv'\n",
1460
+ "\n",
1461
+ " if input_file_path.exists():\n",
1462
+ " print(f\"Processing: {input_file_path}\")\n",
1463
+ "\n",
1464
+ " data = pd.read_csv(input_file_path)\n",
1465
+ " start_index = 0\n",
1466
+ " process_images_with_progress(data, predictor, output_file_path, start_idx=start_index)\n",
1467
+ "\n",
1468
+ " print(f\"Processed and saved to: {output_file_path}\")\n",
1469
+ " else:\n",
1470
+ " print(f\"File not found: {input_file_path}\")"
1471
+ ]
1472
+ },
1473
+ {
1474
+ "cell_type": "code",
1475
+ "execution_count": null,
1476
+ "id": "88ec896a-bf9b-4cc6-a787-c1343f8acb41",
1477
+ "metadata": {},
1478
+ "outputs": [],
1479
+ "source": [
1480
+ "import matplotlib.pyplot as plt\n",
1481
+ "import matplotlib.patches as mpatches\n",
1482
+ "\n",
1483
+ "input_dir = current_dir.parent / 'data/CSV/image_subsets/MiVOLO-results/'\n",
1484
+ "plot_dir = current_dir.parent / 'plots/'\n",
1485
+ "\n",
1486
+ "\n",
1487
+ "all_data = pd.DataFrame()\n",
1488
+ "for file_path in input_dir.glob('*.csv'): # Reads all CSV files in the folder\n",
1489
+ " #print(f\"Loading: {file_path}\")\n",
1490
+ " data = pd.read_csv(file_path)\n",
1491
+ " all_data = pd.concat([all_data, data], ignore_index=True)\n",
1492
+ "\n",
1493
+ "# Filter rows where detection_type equals \"person\"\n",
1494
+ "person_data = all_data[all_data['detection_type'] == 'person']\n",
1495
+ "\n",
1496
+ "# Count unique images and categorize by persons detected\n",
1497
+ "n_images = all_data['id'].nunique()\n",
1498
+ "images_with_zero_persons = all_data[all_data['n_persons'] == 0]['id'].nunique()\n",
1499
+ "images_with_one_or_more_persons = all_data[all_data['n_persons'] > 0]['id'].nunique()\n",
1500
+ "\n",
1501
+ "n_persons_detected = person_data['id'].nunique() # Unique images with at least one detected person\n",
1502
+ "total_persons_detected = person_data.shape[0] # Total number of persons detected\n",
1503
+ "\n",
1504
+ "\n",
1505
+ "\n",
1506
+ "n_total_female = person_data[person_data['gender'] == 'female']['id'].nunique()\n",
1507
+ "n_total_male = person_data[person_data['gender'] == 'male']['id'].nunique()\n",
1508
+ "\n",
1509
+ "# Filter the data further for non-missing age and gender\n",
1510
+ "filtered_data = person_data.dropna(subset=['age', 'gender'])\n",
1511
+ "\n",
1512
+ "# Round ages for consistent plotting\n",
1513
+ "filtered_data['rounded_age'] = np.round(filtered_data['age'] * 4) / 4\n",
1514
+ "\n",
1515
+ "# Map browsingLevel to colors\n",
1516
+ "def get_browsing_color(browsing_level):\n",
1517
+ " color_mapping = {\n",
1518
+ " 1: 'silver',\n",
1519
+ " 2: 'rosybrown',\n",
1520
+ " 4: 'coral',\n",
1521
+ " 8: 'crimson',\n",
1522
+ " 16: 'blueviolet'\n",
1523
+ " }\n",
1524
+ " return color_mapping.get(browsing_level, 'black') # Default to black for unknown values\n",
1525
+ "\n",
1526
+ "filtered_data['color'] = filtered_data['browsingLevel'].apply(get_browsing_color)\n",
1527
+ "\n",
1528
+ "# Aggregate data for plotting\n",
1529
+ "aggregated_data = (\n",
1530
+ " filtered_data.groupby(['rounded_age', 'gender', 'color'])\n",
1531
+ " .size()\n",
1532
+ " .unstack(fill_value=0)\n",
1533
+ ")\n",
1534
+ "\n",
1535
+ "# Define NSFW colors\n",
1536
+ "nsfw_colors = ['blueviolet', 'crimson', 'coral', 'rosybrown', 'silver']\n",
1537
+ "\n",
1538
+ "# Plotting function\n",
1539
+ "def plot_gender_data(ax, data, gender_label):\n",
1540
+ " ages = data.index\n",
1541
+ " bottom = np.zeros(len(ages))\n",
1542
+ " \n",
1543
+ " for color in nsfw_colors:\n",
1544
+ " counts = data[color] if color in data.columns else np.zeros(len(ages))\n",
1545
+ " ax.bar(\n",
1546
+ " ages,\n",
1547
+ " counts,\n",
1548
+ " color=color,\n",
1549
+ " edgecolor=color,\n",
1550
+ " linewidth=1,\n",
1551
+ " width=0.2,\n",
1552
+ " bottom=bottom,\n",
1553
+ " alpha=0.5\n",
1554
+ " )\n",
1555
+ " bottom += counts\n",
1556
+ "\n",
1557
+ " x_min = 5\n",
1558
+ " x_max = filtered_data['rounded_age'].max()\n",
1559
+ " ax.set_xticks(np.arange(x_min, x_max + 0.5, 5))\n",
1560
+ " ax.set_xticklabels([f'{int(age)}' for age in np.arange(x_min, x_max + 0.5, 5)], fontsize=12, fontweight='bold')\n",
1561
+ " ax.set_xticks(np.arange(x_min, x_max + 0.5, 0.5), minor=True)\n",
1562
+ "\n",
1563
+ " y_min = 0\n",
1564
+ " y_max = bottom.max() + 100\n",
1565
+ " y_ticks = np.arange(y_min, y_max + 1, 100) # Fine-grained steps of 100\n",
1566
+ " ax.set_yticks(y_ticks)\n",
1567
+ " ax.set_yticklabels([str(int(y)) for y in y_ticks], fontsize=12, fontweight='bold')\n",
1568
+ "\n",
1569
+ " ax.grid(True, which='major', color='lightgrey', linestyle='-', linewidth=0.5)\n",
1570
+ " ax.grid(True, which='minor', color='lightgrey', linestyle=':', linewidth=0.5)\n",
1571
+ "\n",
1572
+ " ax.spines['top'].set_visible(False)\n",
1573
+ " ax.spines['right'].set_visible(False)\n",
1574
+ " ax.spines['left'].set_visible(False)\n",
1575
+ " ax.spines['bottom'].set_visible(False)\n",
1576
+ " \n",
1577
+ " ax.set_xlabel('Age', fontsize=12, fontweight='bold')\n",
1578
+ " if gender_label == 'Female':\n",
1579
+ " ax.set_ylabel('Number of Subjects', fontsize=14, fontweight='bold')\n",
1580
+ " ax.set_title(f'{gender_label} Read', fontsize=14, fontweight='bold')\n",
1581
+ "\n",
1582
+ "# Set up the subplots\n",
1583
+ "fig, axes = plt.subplots(1, 2, figsize=(14, 6.5), sharey=True)\n",
1584
+ "\n",
1585
+ "plot_gender_data(axes[0], aggregated_data.xs('male', level='gender'), 'Male')\n",
1586
+ "plot_gender_data(axes[1], aggregated_data.xs('female', level='gender'), 'Female')\n",
1587
+ "\n",
1588
+ "legend_patches = [\n",
1589
+ " mpatches.Patch(facecolor='blueviolet', edgecolor='blueviolet', linewidth=2, label='Level 16: XXX'),\n",
1590
+ " mpatches.Patch(facecolor='crimson', edgecolor='crimson', linewidth=2, label='Level 8: X'),\n",
1591
+ " mpatches.Patch(facecolor='coral', edgecolor='coral', linewidth=2, label='Level 4: Mature'),\n",
1592
+ " mpatches.Patch(facecolor='rosybrown', edgecolor='rosybrown', linewidth=2, label='Level 2: Soft'),\n",
1593
+ " mpatches.Patch(facecolor='silver', edgecolor='silver', linewidth=2, label='Level 1: SFW'),\n",
1594
+ " mpatches.Patch(facecolor='none', edgecolor='none', label=f'n images: {n_images}', alpha=0),\n",
1595
+ " mpatches.Patch(facecolor='none', edgecolor='none', label=f'Total persons detected: {total_persons_detected}', alpha=0),\n",
1596
+ " mpatches.Patch(facecolor='none', edgecolor='none', label=f'Unique images containing persons: {n_persons_detected}', alpha=0),\n",
1597
+ "]\n",
1598
+ "\n",
1599
+ "axes[0].legend(handles=legend_patches, title=\"Browsing Levels\", loc='upper left', fontsize=12, title_fontsize=12, frameon=True)\n",
1600
+ "plt.savefig(f'{plot_dir}/mivolo.svg', format='svg', bbox_inches='tight')\n",
1601
+ "plt.tight_layout()\n",
1602
+ "\n",
1603
+ "# Count images with at least one person\n",
1604
+ "images_with_one_or_more_persons = all_data[all_data['n_persons'] > 0]['id'].nunique()\n",
1605
+ "\n",
1606
+ "# Count unique images in `person_data`\n",
1607
+ "n_persons_detected = person_data['id'].nunique()\n",
1608
+ "\n",
1609
+ "# Count total persons detected\n",
1610
+ "total_persons = person_data.shape[0] # This counts all detected persons\n",
1611
+ "\n",
1612
+ "# Display potential inconsistencies\n",
1613
+ "print(f\"Total images: {n_images}\")\n",
1614
+ "print(f\"Images with at least one person: {images_with_one_or_more_persons}\")\n",
1615
+ "print(f\"Unique images in `person_data`: {n_persons_detected}\")\n",
1616
+ "print(f\"Total number of persons detected: {total_persons}\")\n",
1617
+ "\n",
1618
+ "\n",
1619
+ "\n",
1620
+ "plt.show()"
1621
+ ]
1622
+ },
1623
+ {
1624
+ "cell_type": "markdown",
1625
+ "id": "42b2a557-b8f4-4d0f-8907-98e3012a1b34",
1626
+ "metadata": {
1627
+ "execution": {
1628
+ "iopub.execute_input": "2025-02-06T20:01:54.848400Z",
1629
+ "iopub.status.busy": "2025-02-06T20:01:54.847713Z",
1630
+ "iopub.status.idle": "2025-02-06T20:01:54.851533Z",
1631
+ "shell.execute_reply": "2025-02-06T20:01:54.851102Z",
1632
+ "shell.execute_reply.started": "2025-02-06T20:01:54.848376Z"
1633
+ }
1634
+ },
1635
+ "source": [
1636
+ "### Latex Table"
1637
+ ]
1638
+ },
1639
+ {
1640
+ "cell_type": "code",
1641
+ "execution_count": null,
1642
+ "id": "3e506c41-6497-4ece-99f3-73f09fe1129e",
1643
+ "metadata": {},
1644
+ "outputs": [],
1645
+ "source": [
1646
+ "import os\n",
1647
+ "import pandas as pd\n",
1648
+ "\n",
1649
+ "# Define the directory containing CSV files\n",
1650
+ "directory_path = current_dir.parent / 'data/CSV/image_subsets/MiVOLO-results/' # Update this path with the actual directory path\n",
1651
+ "\n",
1652
+ "# Prepare data for LaTeX table\n",
1653
+ "table_rows = []\n",
1654
+ "\n",
1655
+ "# Loop through each file in the directory\n",
1656
+ "for file_name in os.listdir(directory_path):\n",
1657
+ " if file_name.endswith('.csv'):\n",
1658
+ " file_path = os.path.join(directory_path, file_name)\n",
1659
+ " print(f\"Processing file: {file_name}\")\n",
1660
+ "\n",
1661
+ " # Load the data\n",
1662
+ " data = pd.read_csv(file_path)\n",
1663
+ "\n",
1664
+ " # Total images analyzed\n",
1665
+ " total_images = data['id'].nunique()\n",
1666
+ "\n",
1667
+ " # Count of images with no persons detected\n",
1668
+ " images_no_persons = data[data['n_persons'] == 0]['id'].nunique()\n",
1669
+ "\n",
1670
+ " # Total persons detected (only using \"person\" detection type)\n",
1671
+ " total_persons_count = data[data['detection_type'] == 'person'].shape[0]\n",
1672
+ "\n",
1673
+ " # Average age and standard deviation for male and female individuals\n",
1674
+ " male_age_stats = data[data['gender'] == 'male']['age'].agg(['mean', 'std']).fillna(0)\n",
1675
+ " female_age_stats = data[data['gender'] == 'female']['age'].agg(['mean', 'std']).fillna(0)\n",
1676
+ "\n",
1677
+ " # Count of female and male subjects\n",
1678
+ " female_images_count = data[data['gender'] == 'female']['id'].nunique()\n",
1679
+ " male_images_count = data[data['gender'] == 'male']['id'].nunique()\n",
1680
+ "\n",
1681
+ " # Female to male ratio\n",
1682
+ " female_to_male_ratio = female_images_count / male_images_count if male_images_count else None\n",
1683
+ "\n",
1684
+ " # Browsing level analysis for females\n",
1685
+ " female_browsing_level_1 = data[(data['gender'] == 'female') & (data['browsingLevel'] == 1)]['id'].nunique()\n",
1686
+ " female_browsing_level_2_16 = data[(data['gender'] == 'female') & (data['browsingLevel'].isin([2, 4, 8, 16]))]['id'].nunique()\n",
1687
+ " \n",
1688
+ " female_browsing_level_1_percentage = (female_browsing_level_1 / female_images_count * 100) if female_images_count else 0\n",
1689
+ " female_browsing_level_2_16_percentage = (female_browsing_level_2_16 / female_images_count * 100) if female_images_count else 0\n",
1690
+ "\n",
1691
+ " # Browsing level analysis for males\n",
1692
+ " male_browsing_level_1 = data[(data['gender'] == 'male') & (data['browsingLevel'] == 1)]['id'].nunique()\n",
1693
+ " male_browsing_level_2_16 = data[(data['gender'] == 'male') & (data['browsingLevel'].isin([2, 4, 8, 16]))]['id'].nunique()\n",
1694
+ "\n",
1695
+ " male_browsing_level_1_percentage = (male_browsing_level_1 / male_images_count * 100) if male_images_count else 0\n",
1696
+ " male_browsing_level_2_16_percentage = (male_browsing_level_2_16 / male_images_count * 100) if male_images_count else 0\n",
1697
+ "\n",
1698
+ " # Add row to table data\n",
1699
+ " table_rows.append([\n",
1700
+ " file_name.replace('.csv', ''), # Remove file extension\n",
1701
+ " total_images,\n",
1702
+ " total_persons_count,\n",
1703
+ " images_no_persons,\n",
1704
+ " f\"{female_browsing_level_1_percentage:.2f}\",\n",
1705
+ " f\"{female_browsing_level_2_16_percentage:.2f}\",\n",
1706
+ " f\"{male_browsing_level_1_percentage:.2f}\",\n",
1707
+ " f\"{male_browsing_level_2_16_percentage:.2f}\",\n",
1708
+ " f\"{female_to_male_ratio:.2f}\" if female_to_male_ratio is not None else \"N/A\",\n",
1709
+ " f\"{female_age_stats['mean']:.2f} ({female_age_stats['std']:.2f})\",\n",
1710
+ " f\"{male_age_stats['mean']:.2f} ({male_age_stats['std']:.2f})\"\n",
1711
+ " ])\n",
1712
+ "\n",
1713
+ "# Sort table rows by the filename (assumes filenames are formatted with sortable dates)\n",
1714
+ "table_rows = sorted(table_rows, key=lambda x: x[0])\n",
1715
+ "\n",
1716
+ "# Generate LaTeX table\n",
1717
+ "latex_table = r\"\"\"\n",
1718
+ "\\begin{table}[H]\n",
1719
+ "\\centering\n",
1720
+ "\\scriptsize\n",
1721
+ "\\renewcommand{\\arraystretch}{0.9}\n",
1722
+ "\\caption{Summary of Image Classification for 2023-2024}\n",
1723
+ "\\label{table:image_classification_2023_2024}\n",
1724
+ "\\begin{tabular}{lrrrrrrrrrr}\n",
1725
+ "\\toprule\n",
1726
+ "File Name & Total Images & Total Persons & No Persons & \\multicolumn{2}{c}{Female (\\%)} & \\multicolumn{2}{c}{Male (\\%)} & Female:Male & Female Age (Mean ± SD) & Male Age (Mean ± SD) \\\\\n",
1727
+ " & & & & L1 & L2-16 & L1 & L2-16 & & & \\\\\n",
1728
+ "\\midrule\n",
1729
+ "\"\"\"\n",
1730
+ "for row in table_rows:\n",
1731
+ " latex_table += \" & \".join(map(str, row)) + r\" \\\\\\\\\\n\"\n",
1732
+ "\n",
1733
+ "latex_table += r\"\"\"\n",
1734
+ "\\bottomrule\n",
1735
+ "\\end{tabular}\n",
1736
+ "\\vspace{1em}\n",
1737
+ "\\noindent\n",
1738
+ "\\textbf{Disclaimer:} \\(\\female\\) and \\(\\male\\) refer to female-read and male-read classifications as determined by the MiVOLO system's weights. \n",
1739
+ "We acknowledge the complexities of gender presentations and stress that these terms do not necessarily correspond to biological sex.\n",
1740
+ "\\end{table}\n",
1741
+ "\"\"\"\n",
1742
+ "\n",
1743
+ "# Output LaTeX table\n",
1744
+ "print(\"\\nGenerated LaTeX Table:\")\n",
1745
+ "print(latex_table)\n",
1746
+ "\n"
1747
+ ]
1748
+ },
1749
+ {
1750
+ "cell_type": "code",
1751
+ "execution_count": null,
1752
+ "id": "3ef428be-856b-4c4c-b1b0-a052d181d03b",
1753
+ "metadata": {},
1754
+ "outputs": [],
1755
+ "source": []
1756
+ }
1757
+ ],
1758
+ "metadata": {
1759
+ "kernelspec": {
1760
+ "display_name": "HORDE",
1761
+ "language": "python",
1762
+ "name": "horde"
1763
+ },
1764
+ "language_info": {
1765
+ "codemirror_mode": {
1766
+ "name": "ipython",
1767
+ "version": 3
1768
+ },
1769
+ "file_extension": ".py",
1770
+ "mimetype": "text/x-python",
1771
+ "name": "python",
1772
+ "nbconvert_exporter": "python",
1773
+ "pygments_lexer": "ipython3",
1774
+ "version": "3.12.4"
1775
+ }
1776
+ },
1777
+ "nbformat": 4,
1778
+ "nbformat_minor": 5
1779
+ }
scripts/Section_6-3_Models.ipynb ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "14f6b6e3-5edb-458a-9553-09616455ba9f",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Section 6.3: Download Models"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "markdown",
13
+ "id": "64d0907d-780d-48a0-b2c4-a9de650a3760",
14
+ "metadata": {},
15
+ "source": [
16
+ "### Download models from CIVITAI to the respective folders to ~/ComfyUI/models\n"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "code",
21
+ "execution_count": 1,
22
+ "id": "2f788cc1-d8ff-43b8-9051-a3d5d8d79086",
23
+ "metadata": {
24
+ "execution": {
25
+ "iopub.execute_input": "2025-02-06T18:25:06.875713Z",
26
+ "iopub.status.busy": "2025-02-06T18:25:06.875579Z",
27
+ "iopub.status.idle": "2025-02-06T18:25:07.380814Z",
28
+ "shell.execute_reply": "2025-02-06T18:25:07.380184Z",
29
+ "shell.execute_reply.started": "2025-02-06T18:25:06.875698Z"
30
+ }
31
+ },
32
+ "outputs": [],
33
+ "source": [
34
+ "import os\n",
35
+ "import re\n",
36
+ "import csv\n",
37
+ "import json\n",
38
+ "import time\n",
39
+ "import requests\n",
40
+ "from itertools import cycle\n",
41
+ "import pandas as pd\n",
42
+ "from requests.adapters import HTTPAdapter\n",
43
+ "from requests.packages.urllib3.util.retry import Retry\n",
44
+ "from pathlib import Path"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "execution_count": 2,
50
+ "id": "7b6349d2-b839-4b8e-895e-cc7eb3fba88f",
51
+ "metadata": {
52
+ "execution": {
53
+ "iopub.execute_input": "2025-02-06T18:25:07.848340Z",
54
+ "iopub.status.busy": "2025-02-06T18:25:07.848183Z",
55
+ "iopub.status.idle": "2025-02-06T18:25:07.851420Z",
56
+ "shell.execute_reply": "2025-02-06T18:25:07.850952Z",
57
+ "shell.execute_reply.started": "2025-02-06T18:25:07.848325Z"
58
+ }
59
+ },
60
+ "outputs": [],
61
+ "source": [
62
+ "current_dir = Path.cwd()\n",
63
+ "api_karussell = current_dir.parent / 'misc/api_keys.txt'\n",
64
+ "target_dir = current_dir.parent / 'data/models/checkpoints/' \n",
65
+ "target_dir.parent.mkdir(parents=True, exist_ok=True)"
66
+ ]
67
+ },
68
+ {
69
+ "cell_type": "markdown",
70
+ "id": "3c2a9244-5070-4159-821f-39bb92051daf",
71
+ "metadata": {},
72
+ "source": [
73
+ "## function definition:"
74
+ ]
75
+ },
76
+ {
77
+ "cell_type": "code",
78
+ "execution_count": 3,
79
+ "id": "aeaaf1eb-9768-47ad-9298-7d7a8be59094",
80
+ "metadata": {
81
+ "execution": {
82
+ "iopub.execute_input": "2025-02-06T18:25:09.379460Z",
83
+ "iopub.status.busy": "2025-02-06T18:25:09.379303Z",
84
+ "iopub.status.idle": "2025-02-06T18:25:09.382034Z",
85
+ "shell.execute_reply": "2025-02-06T18:25:09.381557Z",
86
+ "shell.execute_reply.started": "2025-02-06T18:25:09.379446Z"
87
+ }
88
+ },
89
+ "outputs": [],
90
+ "source": [
91
+ "csv_file_path = current_dir.parent / 'data/CSV/model_subsets/Civiverse_checkpoint_only.csv'"
92
+ ]
93
+ },
94
+ {
95
+ "cell_type": "code",
96
+ "execution_count": null,
97
+ "id": "2cdc7051-af24-439c-b985-b5088bb13cc0",
98
+ "metadata": {
99
+ "execution": {
100
+ "iopub.execute_input": "2025-02-06T18:25:10.192171Z",
101
+ "iopub.status.busy": "2025-02-06T18:25:10.191997Z"
102
+ }
103
+ },
104
+ "outputs": [
105
+ {
106
+ "name": "stdout",
107
+ "output_type": "stream",
108
+ "text": [
109
+ "Downloaded: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/models/checkpoints/Pony/realDream_sdxlPony14.safetensors\n",
110
+ "Downloaded: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/models/checkpoints/Flux.1 D/acornIsSpinningFLUX_aisFluxV15.safetensors\n",
111
+ "Failed to download https://civitai.com/api/download/models/1376998: 401 Client Error: Unauthorized for url: https://civitai.com/api/download/models/1376998\n",
112
+ "Failed to download https://civitai.com/api/download/models/1379842: 401 Client Error: Unauthorized for url: https://civitai.com/api/download/models/1379842\n",
113
+ "Downloaded: /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/models/checkpoints/Illustrious/miaomiaoHarem_v15a.safetensors\n"
114
+ ]
115
+ }
116
+ ],
117
+ "source": [
118
+ "with open(api_karussell, 'r') as f:\n",
119
+ " api_keys = [line.strip() for line in f if line.strip()]\n",
120
+ "api_key_cycle = cycle(api_keys) # Rotate API keys\n",
121
+ "\n",
122
+ "# Load CSV file\n",
123
+ "\n",
124
+ "df = pd.read_csv(csv_file_path)\n",
125
+ "\n",
126
+ "\n",
127
+ "\n",
128
+ "def get_filename_from_response(response, url):\n",
129
+ " if 'content-disposition' in response.headers:\n",
130
+ " content_disposition = response.headers['content-disposition']\n",
131
+ " filename = content_disposition.split(\"filename=\")[-1].strip(\"\\\"\")\n",
132
+ " else:\n",
133
+ " filename = url.split(\"/\")[-1]\n",
134
+ " return filename\n",
135
+ "\n",
136
+ "def download_file(url, dest_folder, api_key):\n",
137
+ " headers = {'Authorization': f'Bearer {api_key}'} # If authentication is needed\n",
138
+ " \n",
139
+ " try:\n",
140
+ " response = requests.get(url, headers=headers, stream=True)\n",
141
+ " response.raise_for_status()\n",
142
+ " \n",
143
+ " filename = get_filename_from_response(response, url)\n",
144
+ " dest_path = dest_folder / filename\n",
145
+ " \n",
146
+ " with open(dest_path, 'wb') as f:\n",
147
+ " for chunk in response.iter_content(chunk_size=8192):\n",
148
+ " f.write(chunk)\n",
149
+ " \n",
150
+ " print(f\"Downloaded: {dest_path}\")\n",
151
+ " except requests.exceptions.RequestException as e:\n",
152
+ " print(f\"Failed to download {url}: {e}\")\n",
153
+ "\n",
154
+ "def main():\n",
155
+ " for _, row in df.iterrows():\n",
156
+ " url = row['downloadUrl']\n",
157
+ " base_model = row['baseModel']\n",
158
+ " \n",
159
+ " if pd.isna(url) or pd.isna(base_model):\n",
160
+ " continue # Skip missing values\n",
161
+ " \n",
162
+ " # Create model-specific folder\n",
163
+ " model_folder = target_dir / base_model\n",
164
+ " model_folder.mkdir(parents=True, exist_ok=True)\n",
165
+ " \n",
166
+ " # Rotate API keys\n",
167
+ " api_key = next(api_key_cycle)\n",
168
+ " \n",
169
+ " # Download filfile\n",
170
+ " download_file(url, model_folder, api_key)\n",
171
+ " \n",
172
+ " # Sleep to avoid rate limits\n",
173
+ " time.sleep(2) # Adjust based on API limits\n",
174
+ "\n",
175
+ "\n",
176
+ "if __name__ == \"__main__\":\n",
177
+ " main()\n"
178
+ ]
179
+ },
180
+ {
181
+ "cell_type": "code",
182
+ "execution_count": null,
183
+ "id": "c99e2fee-eef2-4530-b69a-9a3db3bda84f",
184
+ "metadata": {},
185
+ "outputs": [],
186
+ "source": []
187
+ }
188
+ ],
189
+ "metadata": {
190
+ "kernelspec": {
191
+ "display_name": "Python 3 (ipykernel)",
192
+ "language": "python",
193
+ "name": "python3"
194
+ },
195
+ "language_info": {
196
+ "codemirror_mode": {
197
+ "name": "ipython",
198
+ "version": 3
199
+ },
200
+ "file_extension": ".py",
201
+ "mimetype": "text/x-python",
202
+ "name": "python",
203
+ "nbconvert_exporter": "python",
204
+ "pygments_lexer": "ipython3",
205
+ "version": "3.11.9"
206
+ }
207
+ },
208
+ "nbformat": 4,
209
+ "nbformat_minor": 5
210
+ }
scripts/Section_6-6_Users_Images.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
scripts/Section_6-7_Users_Models.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
scripts/Updated_Section_6-1_Models_ratios.ipynb ADDED
@@ -0,0 +1,547 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "f743158b-c26f-417e-a7b6-1563d007eec4",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Section 6.1 NSFW Escalation"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "raw",
13
+ "id": "106dfd44-1411-43ca-8753-8c79f5e01bad",
14
+ "metadata": {},
15
+ "source": [
16
+ "NSFW Ratio Calculation Workflow\n",
17
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐ \n",
18
+ "│ Load Civiverse CSV │ --> │ Read Civiverse dataset containing models, │ \n",
19
+ "│ │ │ metadata, and NSFW labels. │ \n",
20
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘ \n",
21
+ " ↓\n",
22
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐ \n",
23
+ "│ Expand Resource IDs │ --> │ Extract resourceIDs from each model (IDs & hashes).│ \n",
24
+ "│ │ │ │ \n",
25
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘ \n",
26
+ " ↓\n",
27
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐ \n",
28
+ "│ Classify ResourceIDs │ --> │ Separate resourceIDs into ID-based and Hash-based │ \n",
29
+ "│ as 'ID' or 'Hash' │ │ identifiers for matching. │ \n",
30
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘ \n",
31
+ " ↓\n",
32
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐ \n",
33
+ "│ Group by Resource ID │ --> │ Count occurrences of each ID/Hash and sum NSFW │ \n",
34
+ "│ & Compute Matches │ │ labels per resource. │ \n",
35
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘ \n",
36
+ " ↓\n",
37
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐ \n",
38
+ "│ Compute NSFW Ratio │ --> │ NSFW Ratio = (NSFW True Count) / (Total Matches). │ \n",
39
+ "│ │ │ Ensures fair assessment of NSFW presence. │ \n",
40
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘ \n",
41
+ " ↓\n",
42
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐ \n",
43
+ "│ Merge Back to Models │ --> │ Attach calculated NSFW ratios to model dataset │ \n",
44
+ "│ Dataset │ │ for further analysis and visualization. │ \n",
45
+ "└─────────┬────────────┘ └───────────────────────────────────────────────────┘ \n",
46
+ " ↓\n",
47
+ "┌──────────────────────┐ ┌───────────────────────────────────────────────────┐ \n",
48
+ "│ Save Updated CSV │ --> │ Write final dataset with NSFW ratios and metadata │ \n",
49
+ "│ │ �� for structured storage and analysis. │ \n",
50
+ "└──────────────────────┘ └───────────────────────────────────────────────────┘ \n"
51
+ ]
52
+ },
53
+ {
54
+ "cell_type": "code",
55
+ "execution_count": 2,
56
+ "id": "9dc7445d",
57
+ "metadata": {
58
+ "execution": {
59
+ "iopub.execute_input": "2025-02-08T21:19:45.476339Z",
60
+ "iopub.status.busy": "2025-02-08T21:19:45.475634Z",
61
+ "iopub.status.idle": "2025-02-08T21:19:45.875103Z",
62
+ "shell.execute_reply": "2025-02-08T21:19:45.874435Z",
63
+ "shell.execute_reply.started": "2025-02-08T21:19:45.476313Z"
64
+ }
65
+ },
66
+ "outputs": [
67
+ {
68
+ "name": "stdout",
69
+ "output_type": "stream",
70
+ "text": [
71
+ "Paths initialized successfully.\n"
72
+ ]
73
+ }
74
+ ],
75
+ "source": [
76
+ "# Import necessary libraries\n",
77
+ "from pathlib import Path\n",
78
+ "import pandas as pd\n",
79
+ "import ast\n",
80
+ "import re\n",
81
+ "from multiprocessing import Pool, cpu_count\n",
82
+ "\n",
83
+ "# Define current working directory\n",
84
+ "current_dir = Path.cwd()\n",
85
+ "\n",
86
+ "# Define frequently used paths\n",
87
+ "data_dir = current_dir.parent / 'data/CSV'\n",
88
+ "subsets_dir = data_dir / 'model_subsets'\n",
89
+ "\n",
90
+ "# Input CSV files\n",
91
+ "civiverse_csv = data_dir / 'Civiverse.csv'\n",
92
+ "model_ids_csv = subsets_dir / 'model_ids.csv'\n",
93
+ "model_hashes_csv = subsets_dir / 'models_hashes.csv'\n",
94
+ "\n",
95
+ "# Output CSV file\n",
96
+ "models_output_csv = data_dir / 'Civiverse-Models_ratios.csv'\n",
97
+ "\n",
98
+ "# Ensure directories exist\n",
99
+ "subsets_dir.mkdir(parents=True, exist_ok=True)\n",
100
+ "\n",
101
+ "print('Paths initialized successfully.')"
102
+ ]
103
+ },
104
+ {
105
+ "cell_type": "code",
106
+ "execution_count": 3,
107
+ "id": "a417fd1d",
108
+ "metadata": {
109
+ "execution": {
110
+ "iopub.execute_input": "2025-02-08T21:19:45.921995Z",
111
+ "iopub.status.busy": "2025-02-08T21:19:45.921691Z",
112
+ "iopub.status.idle": "2025-02-08T21:19:45.924611Z",
113
+ "shell.execute_reply": "2025-02-08T21:19:45.924147Z",
114
+ "shell.execute_reply.started": "2025-02-08T21:19:45.921975Z"
115
+ }
116
+ },
117
+ "outputs": [],
118
+ "source": [
119
+ "current_dir = Path.cwd()"
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "execution_count": 4,
125
+ "id": "cd519fea",
126
+ "metadata": {
127
+ "execution": {
128
+ "iopub.execute_input": "2025-02-08T21:19:46.534207Z",
129
+ "iopub.status.busy": "2025-02-08T21:19:46.534034Z",
130
+ "iopub.status.idle": "2025-02-08T21:19:46.536779Z",
131
+ "shell.execute_reply": "2025-02-08T21:19:46.536283Z",
132
+ "shell.execute_reply.started": "2025-02-08T21:19:46.534191Z"
133
+ }
134
+ },
135
+ "outputs": [],
136
+ "source": [
137
+ "civiverse = civiverse_csv\n",
138
+ "model_ids = model_ids_csv\n",
139
+ "model_hashes = model_hashes_csv"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "markdown",
144
+ "id": "1e8f462a-d6ba-4fec-95ff-a72273cc45c8",
145
+ "metadata": {
146
+ "execution": {
147
+ "iopub.execute_input": "2025-02-07T19:39:49.851283Z",
148
+ "iopub.status.busy": "2025-02-07T19:39:49.849959Z",
149
+ "iopub.status.idle": "2025-02-07T19:39:49.854079Z",
150
+ "shell.execute_reply": "2025-02-07T19:39:49.853522Z",
151
+ "shell.execute_reply.started": "2025-02-07T19:39:49.851229Z"
152
+ }
153
+ },
154
+ "source": [
155
+ "## Step 1 Match model IDs with Image NSFW (true/false)"
156
+ ]
157
+ },
158
+ {
159
+ "cell_type": "code",
160
+ "execution_count": 5,
161
+ "id": "a14dd867",
162
+ "metadata": {
163
+ "execution": {
164
+ "iopub.execute_input": "2025-02-08T21:19:47.488085Z",
165
+ "iopub.status.busy": "2025-02-08T21:19:47.487915Z",
166
+ "iopub.status.idle": "2025-02-08T21:19:49.871306Z",
167
+ "shell.execute_reply": "2025-02-08T21:19:49.870619Z",
168
+ "shell.execute_reply.started": "2025-02-08T21:19:47.488069Z"
169
+ }
170
+ },
171
+ "outputs": [
172
+ {
173
+ "name": "stdout",
174
+ "output_type": "stream",
175
+ "text": [
176
+ "Processing chunk 0...\n",
177
+ "Chunk 0: Found 6860 hash entries\n",
178
+ "Processing chunk 1...\n",
179
+ "Chunk 1: Found 2282 hash entries\n",
180
+ "ID summary saved to /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/model_subsets/model_ids.csv\n",
181
+ "Hash summary saved to /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/model_subsets/models_hashes.csv\n"
182
+ ]
183
+ }
184
+ ],
185
+ "source": [
186
+ "model_ids.parent.mkdir(parents=True, exist_ok=True)\n",
187
+ "model_hashes.parent.mkdir(parents=True, exist_ok=True)\n",
188
+ "\n",
189
+ "# Define a function to process each chunk\n",
190
+ "def process_chunk(chunk):\n",
191
+ " chunk_subset = chunk[['generationSystem', 'resourceIDs', 'nsfw']].copy()\n",
192
+ " chunk_subset['resourceIDs'] = chunk_subset['resourceIDs'].fillna('[]').astype(str)\n",
193
+ "\n",
194
+ " # Expand the resourceIDs into individual rows\n",
195
+ " chunk_subset['resourceIDs'] = chunk_subset['resourceIDs'].str.strip('[]').str.split(', ')\n",
196
+ " expanded_chunk = chunk_subset.explode('resourceIDs')\n",
197
+ "\n",
198
+ " # Clean resourceIDs\n",
199
+ " expanded_chunk['resourceIDs'] = expanded_chunk['resourceIDs'].str.strip().str.strip(\"'\").str.strip('\"')\n",
200
+ "\n",
201
+ " # Classify resources\n",
202
+ " def classify_resource(resource):\n",
203
+ " if pd.isna(resource):\n",
204
+ " return None\n",
205
+ " if resource.isdigit():\n",
206
+ " return 'ID'\n",
207
+ " elif re.fullmatch(r'[a-fA-F0-9]{8,64}', resource): # Allow up to 64-char hashes\n",
208
+ " return 'Hash'\n",
209
+ " else:\n",
210
+ " return None\n",
211
+ "\n",
212
+ " expanded_chunk['Type'] = expanded_chunk['resourceIDs'].apply(classify_resource)\n",
213
+ " expanded_chunk = expanded_chunk.dropna(subset=['Type'])\n",
214
+ "\n",
215
+ " # Group data\n",
216
+ " grouped_chunk = expanded_chunk.groupby(['resourceIDs', 'Type']).agg(\n",
217
+ " matches=('resourceIDs', 'size'),\n",
218
+ " nsfw_true=('nsfw', 'sum')\n",
219
+ " ).reset_index()\n",
220
+ " grouped_chunk['nsfw_ratio'] = grouped_chunk['nsfw_true'] / grouped_chunk['matches']\n",
221
+ "\n",
222
+ " # Separate into ID and hash subsets\n",
223
+ " ids_chunk = grouped_chunk[grouped_chunk['Type'] == 'ID'].drop(columns=['Type'])\n",
224
+ " hashes_chunk = grouped_chunk[grouped_chunk['Type'] == 'Hash'].drop(columns=['Type'])\n",
225
+ "\n",
226
+ " return ids_chunk, hashes_chunk\n",
227
+ "\n",
228
+ "# Write headers to output files\n",
229
+ "pd.DataFrame(columns=['ID', 'matches', 'nsfw_true', 'nsfw_ratio']).to_csv(model_ids, index=False)\n",
230
+ "pd.DataFrame(columns=['hash', 'matches', 'nsfw_true', 'nsfw_ratio']).to_csv(model_hashes, index=False)\n",
231
+ "\n",
232
+ "# Process the dataset in chunks\n",
233
+ "chunk_size = 100000\n",
234
+ "chunk_index = 0\n",
235
+ "\n",
236
+ "for chunk in pd.read_csv(civiverse, chunksize=chunk_size, low_memory=False):\n",
237
+ " print(f\"Processing chunk {chunk_index}...\")\n",
238
+ "\n",
239
+ " ids_chunk, hashes_chunk = process_chunk(chunk)\n",
240
+ "\n",
241
+ " # Debugging to ensure hashes exist\n",
242
+ " print(f\"Chunk {chunk_index}: Found {len(hashes_chunk)} hash entries\")\n",
243
+ "\n",
244
+ " if len(hashes_chunk) == 0:\n",
245
+ " print(\"Warning: No hash data in this chunk. Check classification function.\")\n",
246
+ "\n",
247
+ " # Append data correctly\n",
248
+ " ids_chunk.rename(columns={'resourceIDs': 'ID'}).to_csv(\n",
249
+ " model_ids, index=False, mode='a', header=not model_ids.exists()\n",
250
+ " )\n",
251
+ " hashes_chunk.rename(columns={'resourceIDs': 'hash'}).to_csv(\n",
252
+ " model_hashes, index=False, mode='a', header=not model_hashes.exists()\n",
253
+ " )\n",
254
+ "\n",
255
+ " chunk_index += 1\n",
256
+ "\n",
257
+ "print(f\"ID summary saved to {model_ids}\")\n",
258
+ "print(f\"Hash summary saved to {model_hashes}\")"
259
+ ]
260
+ },
261
+ {
262
+ "cell_type": "markdown",
263
+ "id": "aa84573e-9d4f-4a1a-8db2-0c34244c2c3b",
264
+ "metadata": {},
265
+ "source": [
266
+ "## Step 2 Match IDs with Model-Dataset"
267
+ ]
268
+ },
269
+ {
270
+ "cell_type": "code",
271
+ "execution_count": 6,
272
+ "id": "7d28a287",
273
+ "metadata": {
274
+ "execution": {
275
+ "iopub.execute_input": "2025-02-08T21:19:49.872606Z",
276
+ "iopub.status.busy": "2025-02-08T21:19:49.872432Z",
277
+ "iopub.status.idle": "2025-02-08T21:19:50.072017Z",
278
+ "shell.execute_reply": "2025-02-08T21:19:50.071338Z",
279
+ "shell.execute_reply.started": "2025-02-08T21:19:49.872590Z"
280
+ }
281
+ },
282
+ "outputs": [
283
+ {
284
+ "name": "stdout",
285
+ "output_type": "stream",
286
+ "text": [
287
+ "Updated models dataset saved to /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/Civiverse-Models_ratios.csv\n",
288
+ "ID matches: 11\n",
289
+ "Version ID matches: 3\n",
290
+ "AutoV1 matches: 0\n",
291
+ "AutoV2 matches: 1\n",
292
+ "AutoV3 matches: 5\n",
293
+ "CRC32 matches: 0\n"
294
+ ]
295
+ }
296
+ ],
297
+ "source": [
298
+ "import pandas as pd\n",
299
+ "\n",
300
+ "# Paths to the main dataset and summary files\n",
301
+ "models_file_path = current_dir.parent / 'data/CSV/Civiverse-Models.csv' # Replace with your models dataset path\n",
302
+ "ids_summary_file = model_ids_csv # Replace with your IDs summary file path\n",
303
+ "hashes_summary_file = model_hashes_csv # Replace with your hashes summary file path\n",
304
+ "models_output_file = models_output_csv\n",
305
+ "\n",
306
+ "# Load datasets\n",
307
+ "models_data = pd.read_csv(models_file_path)\n",
308
+ "ids_summary = pd.read_csv(ids_summary_file)\n",
309
+ "hashes_summary = pd.read_csv(hashes_summary_file)\n",
310
+ "\n",
311
+ "# Normalize column names\n",
312
+ "ids_summary.rename(columns={'ID': 'id'}, inplace=True)\n",
313
+ "hashes_summary.rename(columns={'hash': 'resourceID'}, inplace=True)\n",
314
+ "\n",
315
+ "# Ensure consistent data types\n",
316
+ "models_data['id'] = models_data['id'].astype(str).str.lower()\n",
317
+ "ids_summary['id'] = ids_summary['id'].astype(str).str.lower()\n",
318
+ "hash_columns = ['AutoV1', 'AutoV2', 'AutoV3', 'CRC32']\n",
319
+ "\n",
320
+ "# Normalize hash columns in models_data\n",
321
+ "for col in hash_columns:\n",
322
+ " if col in models_data.columns:\n",
323
+ " models_data[col] = models_data[col].astype(str).str.lower()\n",
324
+ "\n",
325
+ "# Flatten and clean hashes_summary\n",
326
+ "hashes_summary_cleaned = hashes_summary.groupby('resourceID').agg(\n",
327
+ " matches=('matches', 'sum'),\n",
328
+ " nsfw_true=('nsfw_true', 'sum'),\n",
329
+ " nsfw_ratio=('nsfw_ratio', 'mean')\n",
330
+ ").reset_index()\n",
331
+ "\n",
332
+ "# Match IDs directly\n",
333
+ "models_data = models_data.merge(\n",
334
+ " ids_summary,\n",
335
+ " on='id',\n",
336
+ " how='left',\n",
337
+ " suffixes=('', '_id_summary')\n",
338
+ ")\n",
339
+ "models_data['id_matches'] = ~models_data['matches'].isna()\n",
340
+ "\n",
341
+ "# Match Version IDs\n",
342
+ "version_id_columns = [col for col in models_data.columns if col.startswith('version_id_')]\n",
343
+ "all_version_ids = ids_summary['id'].unique() # All IDs from the summary for comparison\n",
344
+ "\n",
345
+ "# Create a flag for version ID matches\n",
346
+ "for col in version_id_columns:\n",
347
+ " if col in models_data.columns:\n",
348
+ " models_data[f'{col}_match'] = models_data[col].astype(str).str.lower().isin(all_version_ids)\n",
349
+ "\n",
350
+ "# Consolidate version ID matches\n",
351
+ "models_data['version_ids_match'] = models_data[[f'{col}_match' for col in version_id_columns]].any(axis=1)\n",
352
+ "\n",
353
+ "# Match Hashes\n",
354
+ "for column in hash_columns:\n",
355
+ " if column in models_data.columns:\n",
356
+ " models_data = models_data.merge(\n",
357
+ " hashes_summary_cleaned,\n",
358
+ " left_on=column,\n",
359
+ " right_on='resourceID',\n",
360
+ " how='left',\n",
361
+ " suffixes=('', f'_{column}')\n",
362
+ " )\n",
363
+ " models_data[f'{column}_matches'] = ~models_data[f'matches_{column}'].isna()\n",
364
+ " models_data['matches'] = models_data[['matches', f'matches_{column}']].sum(axis=1, skipna=True)\n",
365
+ " models_data['nsfw_true'] = models_data[['nsfw_true', f'nsfw_true_{column}']].sum(axis=1, skipna=True)\n",
366
+ " models_data.drop(columns=[f'matches_{column}', f'nsfw_true_{column}', f'nsfw_ratio_{column}', 'resourceID'], inplace=True)\n",
367
+ "\n",
368
+ "# Aggregate NSFW columns\n",
369
+ "models_data['nsfw_ratio'] = models_data['nsfw_true'] / models_data['matches']\n",
370
+ "models_data['nsfw_ratio'] = models_data['nsfw_ratio'].fillna(0)\n",
371
+ "\n",
372
+ "# Remove duplicates and keep the row with the highest `matches` and `nsfw_true`\n",
373
+ "models_data = models_data.sort_values(['id', 'matches', 'nsfw_true'], ascending=[True, False, False])\n",
374
+ "models_data = models_data.drop_duplicates(subset=['id'], keep='first')\n",
375
+ "\n",
376
+ "# Save updated dataset\n",
377
+ "models_data.to_csv(models_output_file, index=False)\n",
378
+ "print(f\"Updated models dataset saved to {models_output_file}\")\n",
379
+ "\n",
380
+ "# Verify match counts\n",
381
+ "id_match_count = models_data['id_matches'].sum()\n",
382
+ "version_id_match_count = models_data['version_ids_match'].sum()\n",
383
+ "hash_match_counts = {col: models_data[f'{col}_matches'].sum() for col in hash_columns if f'{col}_matches' in models_data}\n",
384
+ "\n",
385
+ "print(f\"ID matches: {id_match_count}\")\n",
386
+ "print(f\"Version ID matches: {version_id_match_count}\")\n",
387
+ "for col, count in hash_match_counts.items():\n",
388
+ " print(f\"{col} matches: {count}\")"
389
+ ]
390
+ },
391
+ {
392
+ "cell_type": "markdown",
393
+ "id": "76f7c8a5-64b7-4ee9-9099-cfdd34a91084",
394
+ "metadata": {},
395
+ "source": [
396
+ "## Step 3 get missing values from model preview images"
397
+ ]
398
+ },
399
+ {
400
+ "cell_type": "markdown",
401
+ "id": "cb8cd4aa-a3de-47a8-b6f8-7227b10a92f7",
402
+ "metadata": {
403
+ "execution": {
404
+ "iopub.execute_input": "2025-02-07T20:31:23.202465Z",
405
+ "iopub.status.busy": "2025-02-07T20:31:23.202215Z",
406
+ "iopub.status.idle": "2025-02-07T20:31:23.220786Z",
407
+ "shell.execute_reply": "2025-02-07T20:31:23.219314Z",
408
+ "shell.execute_reply.started": "2025-02-07T20:31:23.202447Z"
409
+ }
410
+ },
411
+ "source": [
412
+ "this script reads the MODELS dataset from step 2, if there are 0 or less than 5 matches, it takes the civitai ID of the model, selectively calls the model API metadata and evaluates the NSFW level of the preview images for the model."
413
+ ]
414
+ },
415
+ {
416
+ "cell_type": "code",
417
+ "execution_count": 7,
418
+ "id": "1887bc8d",
419
+ "metadata": {
420
+ "execution": {
421
+ "iopub.execute_input": "2025-02-08T21:19:51.442737Z",
422
+ "iopub.status.busy": "2025-02-08T21:19:51.442264Z",
423
+ "iopub.status.idle": "2025-02-08T21:23:37.409298Z",
424
+ "shell.execute_reply": "2025-02-08T21:23:37.408248Z",
425
+ "shell.execute_reply.started": "2025-02-08T21:19:51.442717Z"
426
+ }
427
+ },
428
+ "outputs": [
429
+ {
430
+ "name": "stdout",
431
+ "output_type": "stream",
432
+ "text": [
433
+ "Failed to fetch model 1219172: 404\n",
434
+ "Failed to fetch model 1221714: 404\n",
435
+ "Failed to fetch model 1224231: 404\n",
436
+ "Failed to fetch model 1224333: 404\n",
437
+ "Failed to fetch model 1224599: 404\n",
438
+ "Updated dataset saved to /shares/weddigen.ki.uzh/laura_wagner/Civitai_page_analysis/Civitai_visualizations/data/CSV/models_ratios_a.csv\n"
439
+ ]
440
+ },
441
+ {
442
+ "name": "stderr",
443
+ "output_type": "stream",
444
+ "text": [
445
+ "/sctmp/lauwag/ipykernel_1495948/3660970368.py:54: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n",
446
+ "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n",
447
+ "\n",
448
+ "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n",
449
+ "\n",
450
+ "\n",
451
+ " models_data[\"nsfw_ratio\"].fillna(0, inplace=True) # Replace NaN with 0\n"
452
+ ]
453
+ }
454
+ ],
455
+ "source": [
456
+ "import requests\n",
457
+ "\n",
458
+ "dataset_path = models_output_csv\n",
459
+ "\n",
460
+ "models_data = pd.read_csv(dataset_path)\n",
461
+ "api_base_url = \"https://civitai.com/api/v1/models/\"\n",
462
+ "output_dir = Path(current_dir.parent / 'data/raw/less_than_5_matches_models_temp/')\n",
463
+ "output_dir.mkdir(exist_ok=True)\n",
464
+ "\n",
465
+ "def fetch_model_data(model_id):\n",
466
+ " \"\"\"Fetches model data from the API and saves it as a JSON file.\"\"\"\n",
467
+ " file_path = output_dir / f\"model_{model_id}.json\"\n",
468
+ " \n",
469
+ " # Check if data already exists locally\n",
470
+ " if file_path.exists():\n",
471
+ " with open(file_path, \"r\", encoding=\"utf-8\") as f:\n",
472
+ " return json.load(f)\n",
473
+ " \n",
474
+ " # Fetch data from the API\n",
475
+ " url = f\"{api_base_url}{model_id}\"\n",
476
+ " response = requests.get(url)\n",
477
+ " if response.status_code == 200:\n",
478
+ " data = response.json()\n",
479
+ " with open(file_path, \"w\", encoding=\"utf-8\") as f:\n",
480
+ " json.dump(data, f, indent=4)\n",
481
+ " return data\n",
482
+ " else:\n",
483
+ " print(f\"Failed to fetch model {model_id}: {response.status_code}\")\n",
484
+ " return None\n",
485
+ "\n",
486
+ "def process_model_json(data):\n",
487
+ " \"\"\"Processes the JSON file to extract matches and NSFW values.\"\"\"\n",
488
+ " nsfw_count = 0\n",
489
+ " total_count = 0\n",
490
+ " for version in data.get(\"modelVersions\", []):\n",
491
+ " for image in version.get(\"images\", []):\n",
492
+ " total_count += 1\n",
493
+ " if image.get(\"nsfwLevel\", 1) > 1:\n",
494
+ " nsfw_count += 1\n",
495
+ " return total_count, nsfw_count\n",
496
+ "\n",
497
+ "# ✅ Now `models_data` is a DataFrame and `.iterrows()` works correctly\n",
498
+ "for index, row in models_data.iterrows():\n",
499
+ " if row.get(\"matches\", 0) < 3:\n",
500
+ " model_id = row[\"id\"]\n",
501
+ " model_data = fetch_model_data(model_id)\n",
502
+ " if model_data:\n",
503
+ " total_images, nsfw_images = process_model_json(model_data)\n",
504
+ " models_data.at[index, \"matches\"] = total_images\n",
505
+ " models_data.at[index, \"nsfw_true\"] = nsfw_images\n",
506
+ "\n",
507
+ "# Recalculate nsfw_ratio\n",
508
+ "models_data[\"nsfw_ratio\"] = models_data[\"nsfw_true\"].div(models_data[\"matches\"], fill_value=0)\n",
509
+ "models_data[\"nsfw_ratio\"].fillna(0, inplace=True) # Replace NaN with 0\n",
510
+ "\n",
511
+ "# Save updated dataset\n",
512
+ "output_file = current_dir.parent / 'data/CSV/models_ratios_a.csv'\n",
513
+ "models_data.to_csv(output_file, index=False)\n",
514
+ "print(f\"Updated dataset saved to {output_file}\")"
515
+ ]
516
+ },
517
+ {
518
+ "cell_type": "code",
519
+ "execution_count": null,
520
+ "id": "6ec9ab6b",
521
+ "metadata": {},
522
+ "outputs": [],
523
+ "source": []
524
+ }
525
+ ],
526
+ "metadata": {
527
+ "kernelspec": {
528
+ "display_name": "Python 3 (ipykernel)",
529
+ "language": "python",
530
+ "name": "python3"
531
+ },
532
+ "language_info": {
533
+ "codemirror_mode": {
534
+ "name": "ipython",
535
+ "version": 3
536
+ },
537
+ "file_extension": ".py",
538
+ "mimetype": "text/x-python",
539
+ "name": "python",
540
+ "nbconvert_exporter": "python",
541
+ "pygments_lexer": "ipython3",
542
+ "version": "3.11.9"
543
+ }
544
+ },
545
+ "nbformat": 4,
546
+ "nbformat_minor": 5
547
+ }
scripts/Updated_Section_6-4_Top_Models_Adapters.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
scripts/Updated_Section_6-5_LoRA_metadata.ipynb ADDED
The diff for this file is too large to render. See raw diff