diff --git a/Assemblies/AIImages.dll b/Assemblies/AIImages.dll
index ee3bb26..3ae3f55 100644
Binary files a/Assemblies/AIImages.dll and b/Assemblies/AIImages.dll differ
diff --git a/Assemblies/Microsoft.Bcl.AsyncInterfaces.dll b/Assemblies/Microsoft.Bcl.AsyncInterfaces.dll
new file mode 100644
index 0000000..476f1b1
Binary files /dev/null and b/Assemblies/Microsoft.Bcl.AsyncInterfaces.dll differ
diff --git a/Assemblies/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/Assemblies/Microsoft.Extensions.DependencyInjection.Abstractions.dll
new file mode 100644
index 0000000..edda9e2
Binary files /dev/null and b/Assemblies/Microsoft.Extensions.DependencyInjection.Abstractions.dll differ
diff --git a/Assemblies/Microsoft.Extensions.DependencyInjection.dll b/Assemblies/Microsoft.Extensions.DependencyInjection.dll
new file mode 100644
index 0000000..d749915
Binary files /dev/null and b/Assemblies/Microsoft.Extensions.DependencyInjection.dll differ
diff --git a/Assemblies/Microsoft.Extensions.Http.Polly.dll b/Assemblies/Microsoft.Extensions.Http.Polly.dll
new file mode 100644
index 0000000..99d38f3
Binary files /dev/null and b/Assemblies/Microsoft.Extensions.Http.Polly.dll differ
diff --git a/Assemblies/Microsoft.Extensions.Http.dll b/Assemblies/Microsoft.Extensions.Http.dll
new file mode 100644
index 0000000..c9bb6b1
Binary files /dev/null and b/Assemblies/Microsoft.Extensions.Http.dll differ
diff --git a/Assemblies/Microsoft.Extensions.Logging.Abstractions.dll b/Assemblies/Microsoft.Extensions.Logging.Abstractions.dll
new file mode 100644
index 0000000..5e6a10f
Binary files /dev/null and b/Assemblies/Microsoft.Extensions.Logging.Abstractions.dll differ
diff --git a/Assemblies/Microsoft.Extensions.Logging.dll b/Assemblies/Microsoft.Extensions.Logging.dll
new file mode 100644
index 0000000..1af1104
Binary files /dev/null and b/Assemblies/Microsoft.Extensions.Logging.dll differ
diff --git a/Assemblies/Microsoft.Extensions.Options.dll b/Assemblies/Microsoft.Extensions.Options.dll
new file mode 100644
index 0000000..1310caa
Binary files /dev/null and b/Assemblies/Microsoft.Extensions.Options.dll differ
diff --git a/Assemblies/Microsoft.Extensions.Primitives.dll b/Assemblies/Microsoft.Extensions.Primitives.dll
new file mode 100644
index 0000000..f6daaab
Binary files /dev/null and b/Assemblies/Microsoft.Extensions.Primitives.dll differ
diff --git a/Assemblies/Newtonsoft.Json.dll b/Assemblies/Newtonsoft.Json.dll
new file mode 100644
index 0000000..3f6541a
Binary files /dev/null and b/Assemblies/Newtonsoft.Json.dll differ
diff --git a/Assemblies/Polly.Extensions.Http.dll b/Assemblies/Polly.Extensions.Http.dll
new file mode 100644
index 0000000..ef47032
Binary files /dev/null and b/Assemblies/Polly.Extensions.Http.dll differ
diff --git a/Assemblies/Polly.dll b/Assemblies/Polly.dll
new file mode 100644
index 0000000..a252caf
Binary files /dev/null and b/Assemblies/Polly.dll differ
diff --git a/Assemblies/StableDiffusionNet.dll b/Assemblies/StableDiffusionNet.dll
new file mode 100644
index 0000000..c3dc3e4
Binary files /dev/null and b/Assemblies/StableDiffusionNet.dll differ
diff --git a/Assemblies/System.Buffers.dll b/Assemblies/System.Buffers.dll
new file mode 100644
index 0000000..f2d83c5
Binary files /dev/null and b/Assemblies/System.Buffers.dll differ
diff --git a/Assemblies/System.Diagnostics.DiagnosticSource.dll b/Assemblies/System.Diagnostics.DiagnosticSource.dll
new file mode 100644
index 0000000..0774d46
Binary files /dev/null and b/Assemblies/System.Diagnostics.DiagnosticSource.dll differ
diff --git a/Assemblies/System.Memory.dll b/Assemblies/System.Memory.dll
new file mode 100644
index 0000000..5d19470
Binary files /dev/null and b/Assemblies/System.Memory.dll differ
diff --git a/Assemblies/System.Numerics.Vectors.dll b/Assemblies/System.Numerics.Vectors.dll
new file mode 100644
index 0000000..0865972
Binary files /dev/null and b/Assemblies/System.Numerics.Vectors.dll differ
diff --git a/Assemblies/System.Runtime.CompilerServices.Unsafe.dll b/Assemblies/System.Runtime.CompilerServices.Unsafe.dll
new file mode 100644
index 0000000..c5ba4e4
Binary files /dev/null and b/Assemblies/System.Runtime.CompilerServices.Unsafe.dll differ
diff --git a/Assemblies/System.Threading.Tasks.Extensions.dll b/Assemblies/System.Threading.Tasks.Extensions.dll
new file mode 100644
index 0000000..eeec928
Binary files /dev/null and b/Assemblies/System.Threading.Tasks.Extensions.dll differ
diff --git a/Assemblies/System.ValueTuple.dll b/Assemblies/System.ValueTuple.dll
new file mode 100644
index 0000000..4ce28fd
Binary files /dev/null and b/Assemblies/System.ValueTuple.dll differ
diff --git a/Languages/English/Keyed/AIImages.xml b/Languages/English/Keyed/AIImages.xml
index 24da3ec..7091f44 100644
--- a/Languages/English/Keyed/AIImages.xml
+++ b/Languages/English/Keyed/AIImages.xml
@@ -25,4 +25,8 @@
Material: {0}
Durability: {0}/{1} ({2}%)
Color: RGB({0}, {1}, {2})
+
+ Stable Diffusion Prompt
+ Copy Prompt
+ Copied!
diff --git a/Languages/Russian/Keyed/AIImages.xml b/Languages/Russian/Keyed/AIImages.xml
index 3a260f5..dc4375d 100644
--- a/Languages/Russian/Keyed/AIImages.xml
+++ b/Languages/Russian/Keyed/AIImages.xml
@@ -25,4 +25,8 @@
Материал: {0}
Прочность: {0}/{1} ({2}%)
Цвет: RGB({0}, {1}, {2})
+
+ Промпт для Stable Diffusion
+ Копировать промпт
+ Скопировано!
diff --git a/Source/AIImages/AIImages.csproj b/Source/AIImages/AIImages.csproj
index 1a9f816..881a33e 100644
--- a/Source/AIImages/AIImages.csproj
+++ b/Source/AIImages/AIImages.csproj
@@ -18,5 +18,6 @@
+
diff --git a/Source/AIImages/Window_AIImage.cs b/Source/AIImages/Window_AIImage.cs
index 544fd82..20a9576 100644
--- a/Source/AIImages/Window_AIImage.cs
+++ b/Source/AIImages/Window_AIImage.cs
@@ -37,9 +37,10 @@ namespace AIImages
this.preventCameraMotion = false; // Не блокируем управление камерой
}
- public override Vector2 InitialSize => new Vector2(700f, 600f);
+ public override Vector2 InitialSize => new Vector2(700f, 700f);
private Vector2 scrollPosition = Vector2.zero;
+ private float copiedMessageTime = 0f;
///
/// Обновляет текущую пешку в окне
@@ -71,6 +72,12 @@ namespace AIImages
{
pawn = selectedPawn;
}
+
+ // Уменьшаем таймер сообщения о копировании
+ if (copiedMessageTime > 0f)
+ {
+ copiedMessageTime -= Time.deltaTime;
+ }
}
///
@@ -209,6 +216,142 @@ namespace AIImages
sb.AppendLine();
}
+ ///
+ /// Генерирует промпт для Stable Diffusion на основе внешности персонажа
+ ///
+ private string GenerateStableDiffusionPrompt()
+ {
+ if (pawn?.story == null)
+ return "portrait of a person";
+
+ StringBuilder prompt = new StringBuilder("portrait of a ");
+
+ prompt.Append(GetAgeAndGenderDescription());
+ prompt.Append(GetBodyTypeDescription());
+ prompt.Append(GetSkinToneDescription());
+ prompt.Append(GetHairDescription());
+ prompt.Append(GetApparelPromptDescription());
+ prompt.Append(
+ "realistic, detailed, high quality, professional lighting, 8k, photorealistic"
+ );
+
+ return prompt.ToString();
+ }
+
+ private string GetAgeAndGenderDescription()
+ {
+ string ageGroup = pawn.ageTracker.AgeBiologicalYears switch
+ {
+ < 18 => "young",
+ < 30 => "young adult",
+ < 50 => "middle-aged",
+ _ => "mature",
+ };
+ return $"{ageGroup} {pawn.gender.GetLabel()}, ";
+ }
+
+ private string GetBodyTypeDescription()
+ {
+ if (pawn.story.bodyType == null)
+ return "";
+
+ string bodyDesc = pawn.story.bodyType.defName.ToLower() switch
+ {
+ "thin" => "slender build",
+ "hulk" => "muscular build",
+ "fat" => "heavyset build",
+ _ => "average build",
+ };
+ return $"{bodyDesc}, ";
+ }
+
+ private string GetSkinToneDescription()
+ {
+ if (pawn.story.SkinColor == null)
+ return "";
+
+ float brightness =
+ (pawn.story.SkinColor.r + pawn.story.SkinColor.g + pawn.story.SkinColor.b) / 3f;
+ string skinTone = brightness switch
+ {
+ >= 0.8f => "fair skin",
+ >= 0.6f => "light skin",
+ >= 0.4f => "olive skin",
+ >= 0.2f => "brown skin",
+ _ => "dark skin",
+ };
+ return $"{skinTone}, ";
+ }
+
+ private string GetHairDescription()
+ {
+ if (pawn.story.hairDef == null)
+ return "";
+
+ string result = $"{pawn.story.hairDef.label.ToLower()} hair";
+ if (pawn.story.HairColor != null)
+ {
+ result += $", {GetColorDescription(pawn.story.HairColor)} hair color";
+ }
+ return result + ", ";
+ }
+
+ private string GetApparelPromptDescription()
+ {
+ if (pawn.apparel?.WornApparel == null || !pawn.apparel.WornApparel.Any())
+ return "";
+
+ List items = pawn
+ .apparel.WornApparel.Take(3)
+ .Select(a =>
+ a.Stuff != null
+ ? $"{a.Stuff.label.ToLower()} {a.def.label.ToLower()}"
+ : a.def.label.ToLower()
+ )
+ .ToList();
+
+ return $"wearing {string.Join(", ", items)}, ";
+ }
+
+ ///
+ /// Получает текстовое описание цвета
+ ///
+ private string GetColorDescription(Color color)
+ {
+ // Определяем доминирующий цвет
+ float max = Mathf.Max(color.r, color.g, color.b);
+ float min = Mathf.Min(color.r, color.g, color.b);
+ float diff = max - min;
+
+ if (diff < 0.1f)
+ {
+ // Оттенки серого
+ return max switch
+ {
+ > 0.8f => "white",
+ > 0.6f => "light gray",
+ > 0.4f => "gray",
+ > 0.2f => "dark gray",
+ _ => "black",
+ };
+ }
+
+ // Цветные
+ const float epsilon = 0.001f;
+ if (Mathf.Abs(color.r - max) < epsilon)
+ {
+ return color.g > color.b ? "orange" : "red";
+ }
+ else if (Mathf.Abs(color.g - max) < epsilon)
+ {
+ return color.r > color.b ? "yellow" : "green";
+ }
+ else
+ {
+ return color.r > color.g ? "purple" : "blue";
+ }
+ }
+
public override void DoWindowContents(Rect inRect)
{
float curY = 0f;
@@ -282,6 +425,47 @@ namespace AIImages
new Rect(20f, contentY, scrollViewRect.width - 30f, apparelHeight),
apparelText
);
+ contentY += apparelHeight + 20f;
+
+ // Разделитель
+ Widgets.DrawLineHorizontal(10f, contentY, scrollViewRect.width - 20f);
+ contentY += 15f;
+
+ // Секция "Stable Diffusion Промпт"
+ Text.Font = GameFont.Medium;
+ Widgets.Label(
+ new Rect(10f, contentY, scrollViewRect.width - 20f, 30f),
+ "AIImages.Prompt.SectionTitle".Translate()
+ );
+ contentY += 35f;
+
+ // Промпт текст
+ Text.Font = GameFont.Small;
+ string promptText = GenerateStableDiffusionPrompt();
+ float promptHeight = Text.CalcHeight(promptText, scrollViewRect.width - 30f);
+ Widgets.Label(
+ new Rect(20f, contentY, scrollViewRect.width - 30f, promptHeight),
+ promptText
+ );
+ contentY += promptHeight + 10f;
+
+ // Кнопка копирования
+ Rect copyButtonRect = new Rect(20f, contentY, 150f, 30f);
+
+ if (Widgets.ButtonText(copyButtonRect, "AIImages.Prompt.CopyButton".Translate()))
+ {
+ GUIUtility.systemCopyBuffer = promptText;
+ copiedMessageTime = 2f; // Показываем сообщение на 2 секунды
+ }
+
+ // Сообщение о копировании
+ if (copiedMessageTime > 0f)
+ {
+ Rect copiedRect = new Rect(copyButtonRect.xMax + 10f, contentY, 100f, 30f);
+ GUI.color = new Color(0f, 1f, 0f, copiedMessageTime / 2f); // Затухающий зеленый
+ Widgets.Label(copiedRect, "AIImages.Prompt.Copied".Translate());
+ GUI.color = Color.white;
+ }
Widgets.EndScrollView();
}
@@ -310,6 +494,19 @@ namespace AIImages
string apparelText = GetApparelDescription();
height += Text.CalcHeight(apparelText, 640f) + 20f;
+ // Разделитель
+ height += 15f;
+
+ // Заголовок "Промпт"
+ height += 35f;
+
+ // Текст промпта
+ string promptText = GenerateStableDiffusionPrompt();
+ height += Text.CalcHeight(promptText, 640f) + 10f;
+
+ // Кнопка и отступ
+ height += 30f + 20f;
+
return height;
}
}