""" 词典子图节点 - 完善版(使用API客户端) Dictionary Subgraph Nodes - Complete (with API Client) """ from typing import Dict, Any, List from datetime import datetime import random from .state import ( DictionaryState, DictionaryAction, WordEntry, ExtractedTerm ) from .api_client import dictionary_api # ========== 模拟生词本存储(后续可替换为数据库) ========== WORD_BOOK_DB: Dict[str, List[Dict]] = {} # user_id -> [word_entries] def parse_intent(state: DictionaryState) -> DictionaryState: """ 解析用户意图节点 确定用户想做什么操作 """ state.current_phase = "intent_parsing" query_lower = state.user_query.lower() # 简单的关键词匹配 if any(keyword in query_lower for keyword in ["翻译", "translate", "英语", "英文"]): state.action = DictionaryAction.TRANSLATE state.action_params = {"text": state.user_query} # 同时设置source_text text = state.user_query for keyword in ["翻译", "translate", "英语", "英文"]: text = text.replace(keyword, "") state.source_text = text.strip() elif any(keyword in query_lower for keyword in ["查询", "query", "单词", "word"]): state.action = DictionaryAction.QUERY state.action_params = {"word": state.user_query} elif any(keyword in query_lower for keyword in ["每日", "daily", "一词"]): state.action = DictionaryAction.DAILY_WORD elif any(keyword in query_lower for keyword in ["提取", "extract", "术语", "term"]): state.action = DictionaryAction.EXTRACT state.action_params = {"text": state.user_query} elif any(keyword in query_lower for keyword in ["生词本", "wordbook", "我的单词"]): state.action = DictionaryAction.WORD_BOOK_LOOKUP elif any(keyword in query_lower for keyword in ["添加到生词本", "添加单词", "add to wordbook"]): state.action = DictionaryAction.WORD_BOOK_ADD state.action_params = {"word": state.user_query} else: # 默认翻译 state.action = DictionaryAction.TRANSLATE state.source_text = state.user_query return state def query_word(state: DictionaryState) -> DictionaryState: """ 查询单词节点 """ state.current_phase = "querying_word" word = state.action_params.get("word", state.user_query) word = word.replace("查询", "").replace("单词", "").strip() # 使用API客户端查询单词 data = dictionary_api.query_word_mock(word) state.word_entry = WordEntry( word=word, phonetic=data.get("phonetic", ""), part_of_speech=data.get("part_of_speech", "n."), definitions=data.get("definitions", []), examples=data.get("examples", []), ) state.success = True return state def translate_text(state: DictionaryState) -> DictionaryState: """ 翻译文本节点 """ state.current_phase = "translating" text = state.source_text or state.action_params.get("text", state.user_query) # 使用API客户端翻译 data = dictionary_api.translate_mock(text, state.source_language, state.target_language) state.translated_text = data.get("translated_text", f"【翻译结果】{text}") state.translation_confidence = data.get("confidence", 0.95) state.success = True return state def extract_terms(state: DictionaryState) -> DictionaryState: """ 提取专业术语节点 """ state.current_phase = "extracting_terms" text = state.source_text or state.action_params.get("text", state.user_query) # 使用API客户端提取术语 terms_data = dictionary_api.extract_terms_mock(text) for term_data in terms_data: state.extracted_terms.append(ExtractedTerm( term=term_data.get("term", ""), type=term_data.get("type", ""), definition=term_data.get("definition", ""), confidence=term_data.get("confidence", 0.0) )) state.success = True return state def get_daily_word(state: DictionaryState) -> DictionaryState: """ 获取每日一词节点 """ state.current_phase = "getting_daily_word" # 每日一词候选 words = ["serendipity", "ephemeral", "ubiquitous", "eloquent", "resilient"] # 基于日期选择固定词,这样同一天的每日一词是固定的 day_of_year = datetime.now().timetuple().tm_yday chosen_idx = day_of_year % len(words) chosen_word = words[chosen_idx] # 使用API客户端查询单词详情 data = dictionary_api.query_word_mock(chosen_word) state.daily_word = WordEntry( word=chosen_word, phonetic=data.get("phonetic", ""), part_of_speech=data.get("part_of_speech", "adj."), definitions=data.get("definitions", []), examples=data.get("examples", []), ) state.success = True return state def lookup_word_book(state: DictionaryState) -> DictionaryState: """ 查询生词本节点 """ state.current_phase = "looking_up_wordbook" user_id = state.user_id or "default_user" word_book = WORD_BOOK_DB.get(user_id, []) # 构建WordEntry列表 if word_book: for entry in word_book: state.extracted_terms.append(ExtractedTerm( term=entry.get("word", ""), type="生词本单词", definition=entry.get("definitions", [""])[0] if entry.get("definitions") else "", confidence=1.0 )) state.success = True return state def add_to_word_book(state: DictionaryState) -> DictionaryState: """ 添加到生词本节点 """ state.current_phase = "adding_to_wordbook" user_id = state.user_id or "default_user" word = state.action_params.get("word", state.user_query) word = word.replace("添加到生词本", "").replace("添加单词", "").strip() # 查询单词信息 query_state = DictionaryState(user_query=word, action=DictionaryAction.QUERY) query_state = query_word(query_state) if query_state.word_entry: we = query_state.word_entry # 添加到模拟数据库 if user_id not in WORD_BOOK_DB: WORD_BOOK_DB[user_id] = [] # 检查是否已存在 exists = any(entry.get("word") == we.word for entry in WORD_BOOK_DB[user_id]) if not exists: entry_dict = { "word": we.word, "phonetic": we.phonetic, "part_of_speech": we.part_of_speech, "definitions": we.definitions, "examples": we.examples, "added_at": datetime.now().isoformat(), "review_count": 0, "next_review_at": None } WORD_BOOK_DB[user_id].append(entry_dict) state.final_result = f"✅ 已将 '{we.word}' 添加到生词本!" else: state.final_result = f"ℹ️ '{we.word}' 已在生词本中!" state.success = True return state def format_result(state: DictionaryState) -> DictionaryState: """ 格式化结果节点 - 精美输出 """ state.current_phase = "formatting" if state.action == DictionaryAction.QUERY and state.word_entry: we = state.word_entry result = [] result.append("═══════════════════════════════════════════") result.append("📚 单词查询结果") result.append("═══════════════════════════════════════════") result.append(f"") result.append(f" {we.word}") if we.phonetic: result.append(f" {we.phonetic}") result.append(f" 【{we.part_of_speech}】") result.append(f"") result.append("📖 释义:") for i, definition in enumerate(we.definitions, 1): result.append(f" {i}. {definition}") if we.examples: result.append("") result.append("💡 例句:") for example in we.examples: result.append(f" \"{example}\"") if we.synonyms: result.append("") result.append("🔗 同义词:") result.append(f" {', '.join(we.synonyms)}") if we.antonyms: result.append("") result.append("🔗 反义词:") result.append(f" {', '.join(we.antonyms)}") result.append("") result.append("═══════════════════════════════════════════") result.append("💡 提示:回复 '添加到生词本 + 单词' 可收藏") state.final_result = "\n".join(result) elif state.action == DictionaryAction.TRANSLATE: result = [] result.append("═══════════════════════════════════════════") result.append("🔄 翻译结果") result.append("═══════════════════════════════════════════") result.append(f"") result.append(f" 原文:{state.source_text}") result.append(f" 译文:{state.translated_text}") result.append(f"") result.append(f" 🎯 置信度:{state.translation_confidence:.0%}") result.append("") result.append("═══════════════════════════════════════════") state.final_result = "\n".join(result) elif state.action == DictionaryAction.DAILY_WORD and state.daily_word: dw = state.daily_word result = [] result.append("═══════════════════════════════════════════") result.append("🌟 每日一词") result.append("═══════════════════════════════════════════") result.append(f"") result.append(f" {dw.word}") if dw.phonetic: result.append(f" {dw.phonetic}") result.append(f" 【{dw.part_of_speech}】") result.append(f"") if dw.definitions: result.append("📖 释义:") for i, definition in enumerate(dw.definitions, 1): result.append(f" {i}. {definition}") if dw.examples: result.append("") result.append("💡 例句:") for example in dw.examples: result.append(f" \"{example}\"") result.append("") result.append("═══════════════════════════════════════════") result.append("💡 学习提示:尝试用这个词造一个句子") result.append("💡 收藏提示:回复 '添加到生词本' 可收藏") state.final_result = "\n".join(result) elif state.action == DictionaryAction.EXTRACT and state.extracted_terms: result = [] result.append("═══════════════════════════════════════════") result.append("📋 提取的术语") result.append("═══════════════════════════════════════════") result.append("") for i, term in enumerate(state.extracted_terms, 1): result.append(f" {i}. {term.term} 【{term.type}】") result.append(f" {term.definition}") result.append(f" 🎯 置信度:{term.confidence:.0%}") result.append("") result.append("═══════════════════════════════════════════") state.final_result = "\n".join(result) elif state.action == DictionaryAction.WORD_BOOK_LOOKUP: user_id = state.user_id or "default_user" word_book = WORD_BOOK_DB.get(user_id, []) result = [] result.append("═══════════════════════════════════════════") result.append("📚 我的生词本") result.append("═══════════════════════════════════════════") result.append(f"") if word_book: result.append(f" 共 {len(word_book)} 个单词") result.append("") for i, entry in enumerate(word_book, 1): word = entry.get("word", "") added_at = entry.get("added_at", "") added_date = datetime.fromisoformat(added_at).strftime("%Y-%m-%d") if added_at else "" result.append(f" {i}. {word} (添加于:{added_date})") else: result.append(" 生词本为空") result.append(" 💡 提示:查询单词后可添加到生词本") result.append("") result.append("═══════════════════════════════════════════") state.final_result = "\n".join(result) elif state.action == DictionaryAction.WORD_BOOK_ADD: if state.final_result: result = state.final_result else: result = "添加完成" state.final_result = result else: if not state.final_result: state.final_result = "词典操作完成" state.current_phase = "done" return state def should_continue(state: DictionaryState) -> str: """ 条件路由:决定下一步该做什么 """ if state.error_message: return "format_result" # 根据action路由 if state.action == DictionaryAction.NONE: return "parse_intent" elif state.action == DictionaryAction.QUERY: return "query_word" elif state.action == DictionaryAction.TRANSLATE: return "translate_text" elif state.action == DictionaryAction.EXTRACT: return "extract_terms" elif state.action == DictionaryAction.DAILY_WORD: return "get_daily_word" elif state.action == DictionaryAction.WORD_BOOK_LOOKUP: return "lookup_word_book" elif state.action == DictionaryAction.WORD_BOOK_ADD: return "add_to_word_book" else: return "format_result"