feat: 完整修復 AI 同義詞功能並優化架構
同義詞功能修復: - 添加 Synonyms 屬性到 Flashcard 實體並執行 migration - 創建 Services/AI/Utils/SynonymsParser.cs 專門處理 AI 同義詞解析 - 修復 ReviewService 使用真實同義詞資料而非硬編碼空陣列 - 更新前後端 CreateFlashcardRequest DTO 支援同義詞傳輸 - 修復前端 generate page 包含 AI 生成的同義詞資料 - 前端 flashcards.ts 添加 synonyms 欄位支援 UI 優化: - 重新設計手機版分頁導航,圓形大按鈕解決觸控問題 - 修復手機版詞卡管理佈局,解決擠壓和字體過小問題 - 統一全站詞性顯示為標準簡寫格式 - 修復詞卡詳細頁面日期顯示問題 - 導航列優化:個人檔案移至右上角用戶區域 架構改進: - AI 邏輯集中在 Services/AI 模組 - Review 服務專注複習功能 - 前後端責任分離:後端解析,前端顯示 現在 AI 生成的同義詞完整保存並在各界面正確顯示。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
a5b2cc746c
commit
ad63b8fed8
|
|
@ -0,0 +1,36 @@
|
|||
using System.Text.Json;
|
||||
|
||||
namespace DramaLing.Api.Services.AI.Utils;
|
||||
|
||||
/// <summary>
|
||||
/// AI 生成同義詞的解析工具類
|
||||
/// </summary>
|
||||
public static class SynonymsParser
|
||||
{
|
||||
/// <summary>
|
||||
/// 解析 AI 生成的同義詞 JSON 字串為字串陣列
|
||||
/// </summary>
|
||||
/// <param name="synonymsJson">JSON 格式的同義詞字串,如 ["word1", "word2"]</param>
|
||||
/// <returns>解析後的同義詞陣列</returns>
|
||||
public static string[] ParseSynonymsJson(string? synonymsJson)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(synonymsJson))
|
||||
return Array.Empty<string>();
|
||||
|
||||
try
|
||||
{
|
||||
var synonyms = JsonSerializer.Deserialize<string[]>(synonymsJson);
|
||||
return synonyms ?? Array.Empty<string>();
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
// JSON 解析失敗,返回空陣列
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 其他異常,返回空陣列
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ using DramaLing.Api.Controllers;
|
|||
using DramaLing.Api.Utils;
|
||||
using DramaLing.Api.Services;
|
||||
using DramaLing.Api.Data;
|
||||
using DramaLing.Api.Services.AI.Utils;
|
||||
|
||||
namespace DramaLing.Api.Services.Review;
|
||||
|
||||
|
|
@ -62,8 +63,8 @@ public class ReviewService : IReviewService
|
|||
hasExampleImage = false,
|
||||
primaryImageUrl = (string?)null,
|
||||
|
||||
// 同義詞(暫時空陣列,未來可擴展)
|
||||
synonyms = new string[] { },
|
||||
// 同義詞(從資料庫讀取,使用 AI 工具類解析)
|
||||
synonyms = SynonymsParser.ParseSynonymsJson(item.Flashcard.Synonyms),
|
||||
|
||||
// 測驗選項 (AI 生成的混淆選項)
|
||||
quizOptions = generatedQuizOptions,
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export function Navigation({ showExitLearning = false, onExitLearning }: Navigat
|
|||
<div className="w-8 h-8 bg-primary rounded-full flex items-center justify-center text-white font-semibold">
|
||||
{user?.username?.[0]?.toUpperCase() || 'U'}
|
||||
</div>
|
||||
<span className="text-sm font-medium">👤 個人檔案</span>
|
||||
<span className="text-sm font-medium">{user?.username}</span>
|
||||
</Link>
|
||||
<button
|
||||
onClick={() => {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ const generateQuizItemsFromFlashcards = (flashcards: Flashcard[]): QuizItem[] =>
|
|||
wrongCount: 0,
|
||||
isCompleted: false,
|
||||
originalOrder: order / 2, // 原始詞卡的順序
|
||||
synonyms: [], // 確保為空數組而非 undefined
|
||||
synonyms: (card as any).synonyms || [], // 後端已解析,直接使用
|
||||
difficultyLevelNumeric: card.masteryLevel || 1 // 使用 masteryLevel 或預設值 1
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ export interface Flashcard {
|
|||
hasExampleImage: boolean;
|
||||
primaryImageUrl?: string;
|
||||
|
||||
// 同義詞欄位 (AI 生成)
|
||||
synonyms?: string[];
|
||||
|
||||
// 測驗選項 (後端提供的混淆選項)
|
||||
quizOptions?: string[];
|
||||
}
|
||||
|
|
@ -263,6 +266,8 @@ class FlashcardsService {
|
|||
exampleImages: card.exampleImages || [],
|
||||
hasExampleImage: card.hasExampleImage || false,
|
||||
primaryImageUrl: card.primaryImageUrl,
|
||||
// 同義詞欄位 (新增)
|
||||
synonyms: card.synonyms || [],
|
||||
// 測驗選項(新增:來自後端的 AI 生成混淆選項)
|
||||
quizOptions: card.quizOptions || []
|
||||
}));
|
||||
|
|
|
|||
Loading…
Reference in New Issue