using Service.AI; namespace Service.IconSearch; public record SearchKeywordSettings { public string KeywordPromptTemplate { get; init; } = "为以下中文分类名称生成3-5个相关的英文搜索关键字,用于搜索图标:{categoryName}。" + "输出格式为JSON数组,例如:[\"food\", \"restaurant\", \"dining\"]。"; } public class SearchKeywordGeneratorService( IOpenAiService openAiService, IOptions settings, ILogger logger ) : ISearchKeywordGeneratorService { private readonly SearchKeywordSettings _settings = settings.Value; public async Task> GenerateKeywordsAsync(string categoryName) { if (string.IsNullOrWhiteSpace(categoryName)) { logger.LogWarning("分类名称为空,无法生成搜索关键字"); return []; } try { var prompt = _settings.KeywordPromptTemplate.Replace("{categoryName}", categoryName); var response = await openAiService.ChatAsync(prompt, timeoutSeconds: 15); if (string.IsNullOrEmpty(response)) { logger.LogWarning("AI未返回搜索关键字,分类:{CategoryName}", categoryName); return []; } var keywords = ParseKeywordsFromResponse(response); logger.LogInformation("为分类 {CategoryName} 生成了 {Count} 个搜索关键字:{Keywords}", categoryName, keywords.Count, string.Join(", ", keywords)); return keywords; } catch (Exception ex) { logger.LogError(ex, "生成搜索关键字失败,分类:{CategoryName}", categoryName); return []; } } private List ParseKeywordsFromResponse(string response) { try { var jsonNode = JsonNode.Parse(response); if (jsonNode is JsonArray arrayNode) { var keywords = new List(); foreach (var item in arrayNode) { if (item is JsonValue value && value.TryGetValue(out string keyword)) { keywords.Add(keyword); } } return keywords; } else if (jsonNode is JsonObject jsonObject) { if (jsonObject.TryGetPropertyValue("keywords", out var keywordsNode) && keywordsNode is JsonArray arrayNode2) { var keywords = new List(); foreach (var item in arrayNode2) { if (item is JsonValue value && value.TryGetValue(out string keyword)) { keywords.Add(keyword); } } return keywords; } } logger.LogWarning("无法解析AI响应为关键字数组:{Response}", response); return []; } catch (Exception ex) { logger.LogError(ex, "解析AI响应失败:{Response}", response); return []; } } }