В этом гайде я покажу, как интегрировать возможности YandexGPT (в частности, генерацию текста и картинок) в ваш ASP.NET Core проект.
Получение доступа к YandexGPT API
Перейдите в Консоль управления Яндекс Облака
Создайте или выберите каталог
Перейдите в раздел Сервисные аккаунты
Создайте новый сервисный аккаунт
Назначьте ему роль ai.languageModels.user для генерации текста и ai.imageGeneration.user для генерации Изображений
Создайте API ключ для этого аккаунта
Сохраните полученный ключ
Создание и написание проекта
Создаем консольное приложение .NET Core(я писал его на .NET 10)
добавим в проект класс который будет отвечать за генерацию текста MyGPTClient:
internal class MyGPTClient { private readonly string _apiKey; private readonly HttpClient _client; private readonly string _textModelUri; private readonly string _imageModelUri; public MyGPTClient(string apiKey, string textModelUri, string imageModelUri = null) { _apiKey = apiKey; _client = new HttpClient(); _client.DefaultRequestHeaders.Add("Authorization", $"Api-Key {apiKey}"); _textModelUri = textModelUri; _imageModelUri = imageModelUri; }
Метод GenerateArticleAsync генерация статьи:
public async Task<string> GenerateArticleAsync(string title) { var request = new { modelUri = _textModelUri, completionOptions = new { stream = false, temperature = 0.6, maxTokens = 2000 }, messages = new[] { new { role = "system", text = "Ты — умный ассистент, который пишет SEO-оптимизированные статьи в формате Markdown." }, new { role = "user", text = $"Напиши развернутую статью на тему: {title}." } } }; var jsonRequest = JsonConvert.SerializeObject(request); var response = await _client.PostAsync("https://llm.api.cloud.yandex.net/foundationModels/v1/completionAsync", new StringContent(jsonRequest, System.Text.Encoding.UTF8, "application/json")); response.EnsureSuccessStatusCode(); var responseBody = await response.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject<dynamic>(responseBody); if (result == null || result.id == null) { throw new Exception("Не удалось получить идентификатор задачи"); } string taskId = result.id; var taskResult = await WaitForTaskCompletionAsync(taskId); if (taskResult != null && taskResult.alternatives != null && taskResult.alternatives.Count > 0) { return taskResult.alternatives[0].message.text; } else { throw new Exception("Не удалось получить ответ от API"); } }
код основан на Документация AI Studio
По умолчанию модель возвращает ответ, отформатированный с помощью разметки Markdown.
в role = "system" задаем роль для ИИ
в role = "user" задаём тему статьи
Я столкнулся с проблемой когда проект не усп��вает получить данные с API поэтому написал вспомогательный метод WaitForTaskCompletionAsync для ожидания завершения задачи его я также использую при генерации изображения
private async Task<dynamic> WaitForTaskCompletionAsync(string taskId) { while (true) { var response = await _client.GetAsync($"https://llm.api.cloud.yandex.net/operations/{taskId}"); response.EnsureSuccessStatusCode(); var responseBody = await response.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject<dynamic>(responseBody); if (result == null) { throw new Exception("Не удалось получить статус задачи"); } if (result.done == true) { return result.response; } await Task.Delay(1000); } }
по умолчанию текст статьи содержит в себе лишние символы типа "****", "////" и другие, убираем все лишнее:
public static string ConvertToHtml(string input) { string result = TextEdit(input); // Заменяем переносы строк на <br> string html = result.Replace("\n", "<br>"); // Заменяем **текст** на <strong>текст</strong> html = System.Text.RegularExpressions.Regex.Replace( html, @"\*\*(.*?)\*\*", "<strong>$1</strong>" ); // Заменяем *текст* на <em>текст</em> (курсив) html = System.Text.RegularExpressions.Regex.Replace( html, @"\*(.*?)\*", "<em>$1</em>" ); return html; } private static string TextEdit(string input) { var lines = input.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None) .SkipWhile(line => string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("#")) .Select(line => { var trimmed = line.TrimStart(); return trimmed.StartsWith("#") ? $"<strong>{trimmed.TrimStart('#').TrimStart()}</strong>" : line; }); return string.Join(Environment.NewLine, lines); }
таким образом мы получили чистый текст без лишних символов и без темы статьи она нам тут не нужна так как мы знали её заранее передавая тему статьи в метод GenerateArticleAsync.
Далее нам нужно сгенерировать изображение создаём метод GenerateImageAsync:
public async Task<string> GenerateImageAsync(string prompt) { if (string.IsNullOrEmpty(_imageModelUri)) throw new InvalidOperationException("URI модели изображения не настроен"); var request = new { modelUri = _imageModelUri, generationOptions = new { seed = new Random().Next(1, 10000), aspectRatio = new { widthRatio = "2", heightRatio = "1" } }, messages = new[] { new { weight = "1", text = prompt } } }; var response = await _client.PostAsync( "https://llm.api.cloud.yandex.net/foundationModels/v1/imageGenerationAsync", new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json") ); response.EnsureSuccessStatusCode(); var responseBody = await response.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject<dynamic>(responseBody); if (result?.id == null) throw new Exception("Не удалось получить идентификатор задачи"); var taskResult = await WaitForTaskCompletionAsync(result.id.ToString()); if (taskResult?.image == null) throw new Exception("Нет данных изображения в ответе"); var fileName = $"{Guid.NewGuid()}.jpg"; var directoryPath = Path.Combine(Directory.GetCurrentDirectory(), "Resources", "ArticleImg"); var fullPath = Path.Combine(directoryPath, fileName); Directory.CreateDirectory(directoryPath); try { var base64String = taskResult.image.ToString(); if (base64String.StartsWith("data:image/jpeg;base64,")) { base64String = base64String.Substring("data:image/jpeg;base64,".Length); } if (!IsValidBase64String(base64String)) throw new Exception("Некорректные данные base64"); var imageBytes = Convert.FromBase64String(base64String); await File.WriteAllBytesAsync(fullPath, imageBytes); } catch (FormatException ex) { throw new Exception($"Ошибка при декодировании base64: {ex.Message}"); } catch (Exception ex) { throw new Exception($"Ошибка при обработке изображения: {ex.Message}"); } return fileName; }
в данном методе я задаю имя изображения гуидом и сохраняю в папку Resources/ArticleImg
Вспомогательный метод для проверки base64
private bool IsValidBase64String(string base64String) { try { Convert.FromBase64String(base64String); return true; } catch (FormatException) { return false; } catch (ArgumentNullException) { return false; } }
если вам нужно генерировать темы для статей то вот мой вариант как это делаю я:
public static async Task<(string result, string articleType)> CreateRandomArticleTopic() { string[] articleTypes = { "Технологии и IT", "Наука", "Экономика", "Гейминг", "Обучение", "Новости" }; var apiKey = _apiKey; var modelUri = _textModelUri; var client = new MyGPTClient(apiKey, modelUri); Random rnd = new Random(); string randomArticleType = articleTypes[rnd.Next(0, articleTypes.Length)]; try { return await client.GenerateArticleTopicAsync(randomArticleType); } catch (HttpRequestException ex) { throw new Exception($"Ошибка при обращении к API: {ex.Message}"); } catch (Exception ex) { throw new Exception($"Произошла ошибка: {ex.Message}"); } }
Ну вот и всё осталось это вызвать в вашем Program.cs
var apiKey = "{{API ключ}}"; var textModelUri = "gpt://{{тут id каталога}}/yandexgpt"; var imageModelUri = "art://{{тут id каталога}}/yandex-art/latest"; // Если есть доступ var gptClient = new MyGPTClient(apiKey, textModelUri, imageModelUri); //генерируем 5 тем для статей var articles = new (string title, string articleType)[5]; for (int i = 0; i < 5; i++) { var (title, articleType) = await rrrrGPTClient.CreateRandomArticleTopic(); articles[i] = (title, articleType); } for (int i = 0; i < 5; i++) { //генерация статьи var articleContent = await gptClient.GenerateArticleAsync(articles[i].title); //генерация изображения var imageUrl = await gptClient.GenerateImageAsync(articles[i].title); }
Спасибо за внимание!
