Files
ai-images/Source/AIImages/Services/AdvancedPromptGenerator.cs

354 lines
13 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Text;
using AIImages.Models;
using RimWorld;
using Verse;
namespace AIImages.Services
{
/// <summary>
/// Продвинутый генератор промптов для Stable Diffusion
/// </summary>
public class AdvancedPromptGenerator : IPromptGeneratorService
{
private static readonly Dictionary<string, string> TraitToMood = new Dictionary<
string,
string
>
{
{ "Kind", "warm smile, gentle expression, friendly eyes" },
{ "Bloodlust", "intense gaze, fierce expression, aggressive posture" },
{ "Psychopath", "cold eyes, emotionless face, calculating expression" },
{ "Pessimist", "sad eyes, worried expression, downcast gaze" },
{ "Optimist", "bright smile, hopeful expression, cheerful demeanor" },
{ "Nervous", "anxious expression, tense posture, worried eyes" },
{ "Careful", "focused expression, attentive gaze, composed posture" },
{ "Brave", "confident expression, determined gaze, strong posture" },
{ "Wimp", "fearful eyes, nervous expression, timid posture" },
{ "Greedy", "cunning expression, calculating eyes, sly smile" },
{ "Jealous", "envious gaze, bitter expression, tense face" },
{ "Ascetic", "serene expression, calm demeanor, peaceful eyes" },
{ "Beautiful", "stunning features, attractive appearance, graceful" },
{ "Ugly", "rough features, weathered appearance" },
{ "Pretty", "attractive features, pleasant appearance, charming" },
};
private static readonly Dictionary<ArtStyle, string> ArtStylePrompts = new Dictionary<
ArtStyle,
string
>
{
{ ArtStyle.Realistic, "photorealistic, hyperrealistic, realistic photo, photography" },
{ ArtStyle.SemiRealistic, "semi-realistic, detailed illustration, realistic art" },
{ ArtStyle.Anime, "anime style, manga style, anime character" },
{
ArtStyle.ConceptArt,
"concept art, digital art, artstation, professional concept design"
},
{ ArtStyle.DigitalPainting, "digital painting, painterly, brush strokes, artistic" },
{ ArtStyle.OilPainting, "oil painting, traditional painting, canvas, fine art" },
{ ArtStyle.Sketch, "pencil sketch, hand drawn, sketch art, line art" },
{ ArtStyle.CellShaded, "cell shaded, flat colors, toon shading, stylized" },
};
private static readonly Dictionary<ShotType, string> ShotTypePrompts = new Dictionary<
ShotType,
string
>
{
{ ShotType.Portrait, "portrait, head and shoulders" },
{ ShotType.HalfBody, "half body shot, waist up" },
{ ShotType.FullBody, "full body, full length" },
{ ShotType.CloseUp, "close up, face focus, detailed face" },
{ ShotType.ThreeQuarter, "three-quarter view, 3/4 view" },
};
public string GeneratePositivePrompt(
PawnAppearanceData appearanceData,
StableDiffusionSettings settings
)
{
if (appearanceData == null)
return "portrait of a person";
StringBuilder prompt = new StringBuilder();
// 1. Художественный стиль
if (ArtStylePrompts.TryGetValue(settings.ArtStyle, out string stylePrompt))
{
prompt.Append(stylePrompt);
prompt.Append(", ");
}
// 2. Тип кадра
if (ShotTypePrompts.TryGetValue(settings.ShotType, out string shotPrompt))
{
prompt.Append(shotPrompt);
prompt.Append(" of ");
}
// 3. Базовое описание (возраст и пол)
prompt.Append(GetAgeAndGenderDescription(appearanceData));
prompt.Append(", ");
// 4. Тип тела
string bodyType = GetBodyTypeDescription(appearanceData.BodyType);
if (!string.IsNullOrEmpty(bodyType))
{
prompt.Append(bodyType);
prompt.Append(", ");
}
// 5. Цвет кожи
string skinTone = ColorDescriptionService.GetSkinToneDescription(
appearanceData.SkinColor
);
prompt.Append(skinTone);
prompt.Append(", ");
// 6. Волосы
string hairDescription = GetHairDescription(appearanceData);
if (!string.IsNullOrEmpty(hairDescription))
{
prompt.Append(hairDescription);
prompt.Append(", ");
}
// 7. Настроение и выражение на основе черт характера
string moodDescription = GetMoodFromTraits(appearanceData.Traits);
if (!string.IsNullOrEmpty(moodDescription))
{
prompt.Append(moodDescription);
prompt.Append(", ");
}
// 8. Одежда
string apparelDescription = GetApparelDescription(appearanceData.Apparel);
if (!string.IsNullOrEmpty(apparelDescription))
{
prompt.Append(apparelDescription);
prompt.Append(", ");
}
// 9. Базовый пользовательский промпт (если указан)
if (!string.IsNullOrEmpty(settings.PositivePrompt))
{
prompt.Append(settings.PositivePrompt);
prompt.Append(", ");
}
// 10. Качественные теги
prompt.Append(GetQualityTags(settings.ArtStyle));
return prompt.ToString().Trim().TrimEnd(',');
}
public string GenerateNegativePrompt(StableDiffusionSettings settings)
{
StringBuilder negativePrompt = new StringBuilder();
// Базовые негативные промпты
negativePrompt.Append(
"ugly, deformed, low quality, blurry, bad anatomy, worst quality, "
);
negativePrompt.Append(
"mutated, disfigured, bad proportions, extra limbs, missing limbs, "
);
// Специфичные для стиля негативы
if (
settings.ArtStyle == ArtStyle.Realistic
|| settings.ArtStyle == ArtStyle.SemiRealistic
)
{
negativePrompt.Append("cartoon, anime, painting, drawing, illustration, ");
}
else if (settings.ArtStyle == ArtStyle.Anime)
{
negativePrompt.Append("realistic, photo, photography, 3d, ");
}
// Пользовательский негативный промпт
if (!string.IsNullOrEmpty(settings.NegativePrompt))
{
negativePrompt.Append(settings.NegativePrompt);
}
return negativePrompt.ToString().Trim().TrimEnd(',');
}
public string GetFullPromptDescription(
PawnAppearanceData appearanceData,
StableDiffusionSettings settings
)
{
StringBuilder description = new StringBuilder();
description.AppendLine("=== Positive Prompt ===");
description.AppendLine(GeneratePositivePrompt(appearanceData, settings));
description.AppendLine();
description.AppendLine("=== Negative Prompt ===");
description.AppendLine(GenerateNegativePrompt(settings));
description.AppendLine();
description.AppendLine("=== Technical Parameters ===");
description.AppendLine($"Steps: {settings.Steps}");
description.AppendLine($"CFG Scale: {settings.CfgScale}");
description.AppendLine($"Size: {settings.Width}x{settings.Height}");
description.AppendLine($"Sampler: {settings.Sampler}");
description.AppendLine(
$"Seed: {(settings.Seed == -1 ? "Random" : settings.Seed.ToString())}"
);
return description.ToString();
}
private string GetAgeAndGenderDescription(PawnAppearanceData data)
{
string ageGroup = data.Age switch
{
< 18 => "young",
< 25 => "young adult",
< 35 => "adult",
< 50 => "middle-aged",
< 65 => "mature",
_ => "elderly",
};
string genderLabel = data.Gender switch
{
Gender.Male => "man",
Gender.Female => "woman",
_ => "person",
};
return $"{ageGroup} {genderLabel}";
}
private string GetBodyTypeDescription(string bodyType)
{
if (string.IsNullOrEmpty(bodyType))
return "";
return bodyType.ToLower() switch
{
"thin" => "slender build, lean physique",
"hulk" => "muscular build, strong physique, athletic body",
"fat" => "heavyset build, stocky physique",
"female" => "feminine build",
"male" => "masculine build",
_ => "average build",
};
}
private string GetHairDescription(PawnAppearanceData data)
{
if (string.IsNullOrEmpty(data.HairStyle))
return "";
StringBuilder hair = new StringBuilder();
// Цвет волос
string hairColor = ColorDescriptionService.GetHairColorDescription(data.HairColor);
hair.Append(hairColor);
hair.Append(" ");
// Стиль прически (упрощаем сложные названия)
string style = data
.HairStyle.ToLower()
.Replace("_", " ")
.Replace("shaved", "very short")
.Replace("mohawk", "mohawk hairstyle");
hair.Append(style);
hair.Append(" hair");
return hair.ToString();
}
private string GetMoodFromTraits(List<Trait> traits)
{
if (traits == null || !traits.Any())
return "neutral expression";
// Ищем черты, которые влияют на внешний вид
foreach (var trait in traits)
{
string traitDefName = trait.def.defName;
if (TraitToMood.TryGetValue(traitDefName, out string mood))
{
return mood;
}
}
return "calm expression";
}
private string GetApparelDescription(List<ApparelData> apparel)
{
if (apparel == null || !apparel.Any())
return "simple clothes";
StringBuilder apparelDesc = new StringBuilder("wearing ");
// Берем топ 5 наиболее заметных предметов одежды
var visibleApparel = apparel.Take(5).ToList();
List<string> items = new List<string>();
foreach (var item in visibleApparel)
{
StringBuilder itemDesc = new StringBuilder();
// Цвет (если не белый)
if (item.Color != UnityEngine.Color.white)
{
string colorDesc = ColorDescriptionService.GetApparelColorDescription(
item.Color
);
itemDesc.Append(colorDesc);
itemDesc.Append(" ");
}
// Материал
if (!string.IsNullOrEmpty(item.Material))
{
itemDesc.Append(item.Material.ToLower());
itemDesc.Append(" ");
}
// Название предмета
itemDesc.Append(item.Label.ToLower());
items.Add(itemDesc.ToString());
}
apparelDesc.Append(string.Join(", ", items));
return apparelDesc.ToString();
}
private string GetQualityTags(ArtStyle style)
{
var baseTags = "highly detailed, professional, masterpiece, best quality";
if (style == ArtStyle.Realistic || style == ArtStyle.SemiRealistic)
{
return $"{baseTags}, professional photography, 8k uhd, dslr, high quality, sharp focus";
}
else if (style == ArtStyle.Anime)
{
return $"{baseTags}, anime masterpiece, high resolution, vibrant colors";
}
else if (style == ArtStyle.ConceptArt)
{
return $"{baseTags}, trending on artstation, professional digital art";
}
else
{
return baseTags;
}
}
}
}