Files
EmailBill/Service/IconSearch/SearchKeywordGeneratorService.cs
SunCheng 9921cd5fdf chore: migrate remaining ECharts components to Chart.js
- Migrated 4 components from ECharts to Chart.js:
  * MonthlyExpenseCard.vue (折线图)
  * DailyTrendChart.vue (双系列折线图)
  * ExpenseCategoryCard.vue (环形图)
  * BudgetChartAnalysis.vue (仪表盘 + 多种图表)

- Removed all ECharts imports and environment variable switches
- Unified all charts to use BaseChart.vue component
- Build verified: pnpm build success ✓
- No echarts imports remaining ✓

Refs: openspec/changes/migrate-remaining-echarts-to-chartjs
2026-02-16 21:55:38 +08:00

95 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<SearchKeywordSettings> settings,
ILogger<SearchKeywordGeneratorService> logger
) : ISearchKeywordGeneratorService
{
private readonly SearchKeywordSettings _settings = settings.Value;
public async Task<List<string>> 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<string> ParseKeywordsFromResponse(string response)
{
try
{
var jsonNode = JsonNode.Parse(response);
if (jsonNode is JsonArray arrayNode)
{
var keywords = new List<string>();
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<string>();
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 [];
}
}
}