В этом гайде я покажу, как интегрировать возможности 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[] { "rn", "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);
}
Спасибо за внимание!
Автор: vova8977
