1using System; 2using System.Collections.Generic; 3using System.Runtime.Serialization; 4 5namespace WindowCapture.Models 6{ 7 [DataContract] 8 public class GeminiSettings 9 { 10 [DataMember] 11 public string Model { get; set; } 12 13 [DataMember] 14 public int ThinkingBudget { get; set; } 15 16 [DataMember] 17 public string MediaResolution { get; set; } 18 19 [DataMember] 20 public string SystemInstruction { get; set; } 21 22 [DataMember] 23 public Dictionary<string, ModelStatus> ModelStatuses { get; set; } 24 25 [DataMember] 26 public List<string> ApiKeys { get; set; } 27 28 [DataMember] 29 public int CurrentApiKeyIndex { get; set; } 30 31 [DataMember] 32 public string LastWorkingModel { get; set; } 33 34 public GeminiSettings() 35 { 36 Model = "gemini-3.5-flash"; // newest GA flash (May 2026); recommended for multimodal/image description 37 ThinkingBudget = 0; 38 MediaResolution = "MEDIA_RESOLUTION_LOW"; 39 SystemInstruction = "Ты описываешь изображения на русском языке в формальном стиле, а также даёшь им названия.\n\n" + 40 "Пример описания:\nДалее необходимо открыть и запустить ПО, что показано на рисунке %PICNUM% и т.д.\n\n" + 41 "Пример названия рисунков: Окно вкладки 1\n\n" + 42 "Описание рисунка должно начинаться на %CAPTION% и заканчиваться на %CAPTION%.\n\n" + 43 "Название рисунка должно начинаться на %PICNAME% и заканчиваться на %PICNAME%\n\n" + 44 "Вместо номера рисунка используй %PICNUM% (он будет заменён на реальный номер).\n\n" + 45 "Объём описания примерно 30 слов."; 46 ModelStatuses = new Dictionary<string, ModelStatus>(); 47 ApiKeys = new List<string>(); 48 CurrentApiKeyIndex = 0; 49 LastWorkingModel = null; 50 } 51 52 /// <summary> 53 /// Get current API key (from list or legacy single key) 54 /// </summary> 55 public string GetCurrentApiKey(string legacyKey) 56 { 57 if (ApiKeys == null || ApiKeys.Count == 0) 58 { 59 // Migrate legacy key to list 60 if (!string.IsNullOrEmpty(legacyKey)) 61 { 62 ApiKeys = new List<string> { legacyKey }; 63 CurrentApiKeyIndex = 0; 64 return legacyKey; 65 } 66 return null; 67 } 68 69 if (CurrentApiKeyIndex >= 0 && CurrentApiKeyIndex < ApiKeys.Count) 70 return ApiKeys[CurrentApiKeyIndex]; 71 72 return ApiKeys.Count > 0 ? ApiKeys[0] : null; 73 } 74 75 /// <summary> 76 /// Switch to next API key 77 /// Returns true if switched, false if no more keys 78 /// </summary> 79 public bool SwitchToNextApiKey() 80 { 81 if (ApiKeys == null || ApiKeys.Count <= 1) 82 return false; 83 84 CurrentApiKeyIndex = (CurrentApiKeyIndex + 1) % ApiKeys.Count; 85 return true; 86 } 87 88 /// <summary> 89 /// Reset to first API key 90 /// </summary> 91 public void ResetApiKeyIndex() 92 { 93 CurrentApiKeyIndex = 0; 94 } 95 96 /// <summary> 97 /// Add API key to list 98 /// </summary> 99 public bool AddApiKey(string key) 100 { 101 if (string.IsNullOrWhiteSpace(key)) 102 return false; 103 104 if (ApiKeys == null) 105 ApiKeys = new List<string>(); 106 107 if (!ApiKeys.Contains(key)) 108 { 109 ApiKeys.Add(key); 110 return true; 111 } 112 return false; 113 } 114 115 /// <summary> 116 /// Get status for a model (default: Unknown/Green) 117 /// </summary> 118 public ModelStatusType GetModelStatus(string model) 119 { 120 if (ModelStatuses == null) 121 ModelStatuses = new Dictionary<string, ModelStatus>(); 122 123 if (ModelStatuses.ContainsKey(model)) 124 return ModelStatuses[model].Status; 125 126 return ModelStatusType.Unknown; 127 } 128 129 /// <summary> 130 /// Set status for a model 131 /// </summary> 132 public void SetModelStatus(string model, ModelStatusType status, string errorMessage = null) 133 { 134 if (ModelStatuses == null) 135 ModelStatuses = new Dictionary<string, ModelStatus>(); 136 137 ModelStatuses[model] = new ModelStatus 138 { 139 Status = status, 140 LastError = errorMessage, 141 LastUpdated = DateTime.Now 142 }; 143 } 144 145 /// <summary> 146 /// Reset all model statuses 147 /// </summary> 148 public void ResetModelStatuses() 149 { 150 if (ModelStatuses != null) 151 ModelStatuses.Clear(); 152 } 153 154 /// <summary> 155 /// Check if model is usable (not red/broken) 156 /// </summary> 157 public bool IsModelUsable(string model) 158 { 159 var status = GetModelStatus(model); 160 return status != ModelStatusType.Broken; 161 } 162 } 163 164 /// <summary> 165 /// Model status types 166 /// </summary> 167 [DataContract] 168 public enum ModelStatusType 169 { 170 [EnumMember] 171 Unknown = 0, // Not tested yet (treat as green) 172 [EnumMember] 173 Working = 1, // Green - works fine 174 [EnumMember] 175 RateLimited = 2, // Yellow - 429 error, temporary 176 [EnumMember] 177 Broken = 3 // Red - other errors, don't use 178 } 179 180 /// <summary> 181 /// Stores status info for a model 182 /// </summary> 183 [DataContract] 184 public class ModelStatus 185 { 186 [DataMember] 187 public ModelStatusType Status { get; set; } 188 189 [DataMember] 190 public string LastError { get; set; } 191 192 [DataMember] 193 public DateTime LastUpdated { get; set; } 194 195 public ModelStatus() 196 { 197 Status = ModelStatusType.Unknown; 198 LastError = null; 199 LastUpdated = DateTime.Now; 200 } 201 } 202}