### Generate AI Sentences for Vocabulary using OpenAI API (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Generates AI-powered example sentences for vocabulary words using OpenAI-compatible API endpoints. It supports custom prompts, vocabulary levels, and learning goals, returning a list of [sentence, translation] pairs. Requires an API client and configuration manager. ```python from api_client import generate_ai_sentence from config_manager import get_config # Generate sentences for a keyword config = get_config() keyword = "suggest" # Returns list of [sentence, translation] pairs sentence_pairs = generate_ai_sentence(config, keyword) # Example output: # [ # ["The research findings suggest a correlation between sleep quality and performance.", # "研究结果表明睡眠质量与认知表现之间存在相关性。"], # ["Children instinctively grasp simple concepts faster than abstract theories.", # "孩子们本能地掌握简单概念比抽象理论要快。"], # ... # ] # Custom prompt usage custom_prompt = """Generate 5 sentences with '{world}' for {language} learners. Vocabulary level: {vocab_level} Output JSON format: {{"sentences": [[sentence1, translation1], ...]}} """ sentence_pairs = generate_ai_sentence(config, keyword, prompt=custom_prompt) # Handle errors gracefully if sentence_pairs: for sentence, translation in sentence_pairs: print(f"Sentence: {sentence}") print(f"Translation: {translation}") else: print("Failed to generate sentences") ``` -------------------------------- ### Manage Addon Configuration UI with Python Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt This Python code snippet shows how to manage the configuration UI for an Anki addon using ui_manager. It includes registering a menu item to open the configuration dialog and displaying the dialog itself. The dialog features multiple tabs for API settings, learning preferences, prompt editing, and includes functionalities like API connection testing and deck validation. ```python from ui_manager import show_config_dialog, register_menu_item # Register menu item (call once on addon initialization) register_menu_item() # Adds "AI例句配置..." to Anki's Tools menu # Show configuration dialog (automatically called by menu item) show_config_dialog() # Opens dialog with two tabs: # 1. "基本设置" - API config, learning preferences, deck selection # 2. "提示词编辑器" - Custom prompt templates with test functionality # Dialog features: # - API connection testing with real-time feedback # - Model list fetching from API provider # - Deck name validation with dropdown selection # - Preset vocabulary levels, learning goals, difficulties # - Custom prompt creation, editing, deletion # - Live prompt testing with keyword input # - Cache management (clear all caches button) # All changes saved to Anki's addon config on "Save" button click ``` -------------------------------- ### Configuration Management (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Handles loading and saving of plugin configuration. It automatically merges default values with user settings, preserving presets. Configuration is stored within Anki's addon configuration system. ```python from config_manager import get_config, save_config # Load current configuration (merges defaults + user settings) config = get_config() # Returns dict with keys: # - api_url, api_key, model_name # - deck_name, save_deck # - vocab_level, learning_goal, difficulty_level # - sentence_length_desc, learning_language # - prompt_name, custom_prompts # - preset_* (always from defaults, never saved) # Access configuration values api_url = config.get("api_url") deck_name = config.get("deck_name") vocab_level = config.get("vocab_level", "大学英语四级 CET-4 (4000词)") # Modify and save configuration config["api_url"] = "https://api.deepseek.com/v1/chat/completions" config["api_key"] = "your-new-api-key" config["model_name"] = "deepseek-v3-250324" config["deck_name"] = "English::Vocabulary[1]" # [1] = field index config["vocab_level"] = "CEFR B2 (中级,约5000词)" save_config(config) # Automatically filters out preset_* keys before saving # User configuration stored in Anki's addon config system ``` -------------------------------- ### Generate and Style Card Templates with Python Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt This Python code demonstrates generating styled HTML for flashcard front and back sides using the card_template_manager. It handles sentence highlighting, translation placeholders, font styling, dark mode support, and original content display. It also includes a utility to process highlight tags and update card templates. ```python from card_template_manager import ( get_processed_front_html, get_processed_back_html, process_highlight, update_card_templates ) # Generate front side HTML (question) sentence = "The research suggests a correlation." front_html = get_processed_front_html(sentence) # Returns styled HTML with: # - Sentence with tags converted to highlight spans # - Placeholder lines for translation # - Font styling based on config # - Dark mode CSS support # Generate back side HTML (answer) translation = "研究表明了一种相关性。" original_html = "
suggest: v. to put forward for consideration
" back_html = get_processed_back_html(sentence, translation, original_html) # Returns styled HTML with: # - Full sentence and translation (with highlights) # - Original card content in separate section # - Responsive styling for different screen sizes # Process highlight tags text = "The important word here." highlighted = process_highlight(text) # Returns: 'The important word here.' # Update all card templates after font config change success = update_card_templates() # Updates "ContextFlow例句翻译" note type templates # Returns: True if successful, False if note type not found ``` -------------------------------- ### Discover Available Models from API Provider (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Retrieves a list of available models from an API provider for dynamic model selection in a configuration UI. It requires the API URL and API key, returning a list of model names or an empty list if the request fails. ```python from api_client import fetch_available_models api_url = "https://ark.cn-beijing.volces.com/api/v3/chat/completions" api_key = "your-api-key" models = fetch_available_models(api_url, api_key) # Returns: ["deepseek-v3-250324", "doubao-seed-1-6-flash", "qwen3-max", ...] if models: print(f"Found {len(models)} available models:") for model in models: print(f" - {model}") else: print("No models found or API request failed") ``` -------------------------------- ### Test API Connectivity and Credentials (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Tests API connectivity and validates credentials before configuration, supporting both thinking-enabled and standard completion modes. It checks for successful connection and returns either an error message or the content of a successful response. ```python from api_client import test_api_sync api_url = "https://api.deepseek.com/v1/chat/completions" api_key = "your-api-key-here" model_name = "deepseek-v3-250324" # Test API connection with timeout response_content, error_message = test_api_sync( api_url=api_url, api_key=api_key, model_name=model_name, timeout_seconds=30 ) if error_message: print(f"API Test Failed: {error_message}") # Example errors: # "API错误 401: Invalid API key" # "请求在 30 秒后超时。" else: print(f"API Test Succeeded: {response_content}") # Expected output: "Hello" (model repeats the test word) ``` -------------------------------- ### Background Task Queue Management (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Manages a priority-based background sentence generation queue using a thread pool. Supports both single-threaded and multi-threaded modes, and allows for reorganizing task priorities based on keywords or repopulating the cache. ```python from main_logic import reorganize_task_queue, get_upcoming_cards from anki.cards import Card # Reorganize queue with new priority keyword current_keyword = "dangerous" reorganize_task_queue(current_keyword, is_repopulate=False) # Adds keyword with priority 0 (highest) if not in cache # Updates existing task priorities in queue # Repopulate cache when exhausted (lowest priority) reorganize_task_queue(current_keyword, is_repopulate=True) # Adds with priority 999 (lowest) for background refill # Get upcoming cards for preloading card = Card(mw.col) # Current card deck_name = "English::Vocabulary" upcoming_keywords = get_upcoming_cards(card, deck_name) # Returns: ["adventure", "dangerous", "cereal", ...] # Fetches 100 cards for single-threaded, 10 for multi-threaded # Filters out keywords already in cache # Reorganize queue for batch preloading reorganize_task_queue(upcoming_keywords) # Sets priorities: position 1 = priority 1, position 2 = priority 2, etc. ``` -------------------------------- ### JavaScript Data Filtering and Chart Initialization for Study Time Analysis Source: https://github.com/yfftyhwsdj/contextflow/blob/main/templates/stats.html This JavaScript code defines functions to filter study data based on a specified time range (e.g., month, year) and initialize Chart.js instances. It handles data slicing, finding the first non-zero data points, and setting up various chart types (bar and line) with common options for responsiveness and scales. It also includes error handling for Chart.js loading. ```javascript let cardsChart, timeChart, avgTimeChart, totalCardsChart, totalTimeChart; let allDates = {dates}; let allCardsData = {cards_data}; let allTimeData = {time_data}; let allAvgTimeData = {avg_time_data}; let allTotalCardsData = {total_cards_data}; let allTotalTimeData = {total_time_data}; function filterDataByRange(range) { let days = 7; if (range === 'month') days = 30; if (range === 'year') days = Math.min(365, allDates.length); if (range === '5year') days = Math.min(1825, allDates.length); days = Math.min(days, allDates.length); let startIndex = Math.max(0, allDates.length - days); let filteredDates = allDates.slice(startIndex); let filteredCards = allCardsData.slice(startIndex); let filteredTime = allTimeData.slice(startIndex); let filteredAvgTime = allAvgTimeData.slice(startIndex); let filteredTotalCards = allTotalCardsData.slice(startIndex); let filteredTotalTime = allTotalTimeData.slice(startIndex); let firstNonZeroIndex = 0; for (let i = 0; i < filteredCards.length; i++) { if (filteredCards[i] > 0 || filteredTime[i] > 0) { firstNonZeroIndex = i; break; } if (i === filteredCards.length - 1) { firstNonZeroIndex = i; } } return { dates: filteredDates.slice(firstNonZeroIndex), cards: filteredCards.slice(firstNonZeroIndex), time: filteredTime.slice(firstNonZeroIndex), avgTime: filteredAvgTime.slice(firstNonZeroIndex), totalCards: filteredTotalCards.slice(firstNonZeroIndex), totalTime: filteredTotalTime.slice(firstNonZeroIndex) }; } function updateCharts(range) { const filtered = filterDataByRange(range); const charts = [ { chart: cardsChart, data: filtered.cards }, { chart: timeChart, data: filtered.time }, { chart: avgTimeChart, data: filtered.avgTime }, { chart: totalCardsChart, data: filtered.totalCards }, { chart: totalTimeChart, data: filtered.totalTime } ]; charts.forEach(item => { if (item.chart) { item.chart.data.labels = filtered.dates; item.chart.data.datasets[0].data = item.data; item.chart.update(); } }); } function initCharts() { const maxRetries = 10; let retryCount = 0; const loadingElements = document.querySelectorAll('.loading'); const canvasElements = document.querySelectorAll('canvas'); function tryInit() { if (typeof Chart === 'undefined') { if (retryCount < maxRetries) { retryCount++; setTimeout(tryInit, 100); return; } loadingElements.forEach(el => { el.textContent = '图表库加载失败,请检查网络连接。'; el.style.color = 'red'; }); return; } loadingElements.forEach(el => el.style.display = 'none'); canvasElements.forEach(cv => cv.style.display = 'block'); const defaultRange = document.querySelector('input[name="timeRange"]:checked').value; const initialFilteredData = filterDataByRange(defaultRange); const commonLineOptions = { responsive: true, maintainAspectRatio: false, tension: 0.2, plugins: { legend: { display: false }, title: { display: false }, tooltip: { position: 'nearest', intersect: false, yAlign: 'top', xAlign: 'center' } }, scales: { x: { grid: { display: false } }, y: { beginAtZero: true, grid: { color: '#e9ecef' } } } }; const commonBarOptions = { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, title: { display: false } }, scales: { x: { grid: { display: false } }, y: { beginAtZero: true, grid: { color: '#e9ecef' } } } }; // --- 修改点 1: 每日学习卡片数改为柱状图 --- cardsChart = new Chart(document.getElementById('cardsChart'), { type: 'bar', // 修改 type 为 'bar' data: { labels: initialFilteredData.dates, datasets: [{ data: initialFilteredData.cards, backgroundColor: 'rgba(75, 192, 192, 0.7)', // 应用柱状图颜色 borderColor: 'rgb(75, 192, 192)', borderWidth: 1, borderRadius: 4, }] }, options: { ...commonBarOptions } // 应用柱状图通用配置 }); timeChart = new Chart(document.getElementById('timeChart'), { type: 'bar', data: { labels: initialFilteredData.dates, datasets: [{ data: initialFilteredData.time, backgroundColor: 'rgba(54, 162, 235, 0.7)', borderColor: 'rgb(54, 162, 235)', borderWidth: 1, borderRadius: 4, }] }, options: { ...commonBarOptions } }); // --- 修改点 2: 卡片平均学习时间改为无填充折线图 --- avgTimeChart = new Chart(document.getElementById('avgTimeChart'), { type: 'line', data: { labels: initialFilteredData.dates, datasets: [{ data: initialFilteredData.avgTime, borderColor: 'rgb(255, 99, 132)', fill: false, // 修改 fill 为 false borderWidth: 2 }] }, options: { ...commonLineOptions } }); totalCardsChart = new Chart(document.getElementById('totalCardsChart'), { type: 'line', data: { labels: initialFilteredData.dates, datasets: [{ data: initialFilteredData.totalCards, borderColor: 'rgb(153, 102, 255)', backgroundColor: 'rgba(153, 102, 255, 0.1)', fill: true, borderWidth: 2 }] }, options: { ...commonLineOptions } }); totalTimeChart = new Chart(document.getElementById('totalTimeChart'), { type: 'line', data: { labels: initialFilteredData.dates, datasets: [{ data: initialFilteredData.totalTime, borderColor: 'rgb(255, 159, 64)', backgroundColor: 'rgba(255, 159, 64, ``` -------------------------------- ### Anki Card Creation for Saved Sentences (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Facilitates the creation of new Anki cards for favorite sentences. It includes functions to validate sentence and translation data, check for the existence of a target deck (creating it if necessary), and then create the card with custom note types and styling. ```python from anki_card_creator import ( create_sentence_card, check_deck_exists, get_available_decks, validate_card_data ) # Validate sentence data before creation sentence = "The research suggests a new approach." translation = "研究表明了一种新方法。" is_valid, message = validate_card_data(sentence, translation) if not is_valid: print(f"Validation failed: {message}") # Possible errors: "例句不能为空", "翻译不能为空" # Check if target deck exists deck_name = "Saved Sentences" if not check_deck_exists(deck_name): print(f"Deck '{deck_name}' does not exist, will be created") # Create sentence card success = create_sentence_card( sentence=sentence, translation=translation, deck_name=deck_name ) if success: print("Card created successfully") # Card will have: # - Field 1: The research suggests a new approach. # - Field 2: 研究表明了一种新方法。 # - Field 3: ContextFlow自动生成 - 2025-11-03 15:30 else: print("Failed to create card") # Get all available decks for UI selection decks = get_available_decks() # Returns: ["Default", "English::Vocabulary", "Saved Sentences", ...] ``` -------------------------------- ### Anki Card Rendering Hook (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Main hook to intercept Anki card rendering. It displays AI-generated sentences on the question side and translations on the answer side. Extracts keywords from card fields, utilizes caching, and preloads sentences for upcoming cards. ```python from main_logic import on_card_render, register_hooks from anki.cards import Card # Register all hooks (call once on addon initialization) register_hooks() # This registers: # - card_will_show hook for card rendering # - profile_will_close hook for cleanup # - stats_dialog_will_show hook for statistics # - context menu for right-click word lookup # Card rendering is automatic, but internally works like this: card = Card(mw.col) # Current review card context = "question" # or "answer" # On question side: # 1. Extracts keyword from card's first field # 2. Attempts to load cached sentence # 3. If cache miss, queues generation task and shows "例句生成中..." # 4. Displays generated sentence when ready # 5. Preloads sentences for upcoming 10 cards # On answer side: # Displays: AI sentence + translation + original card content ``` -------------------------------- ### Manage Sentence Cache with SQLite and In-Memory Layer (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Manages a sentence cache using an SQLite database and an in-memory caching layer for optimal performance. Supports loading, saving, atomic popping of sentences, and clearing the entire cache. Operations return success or failure indicators. ```python from cache_manager import load_cache, save_cache, pop_cache, clear_cache keyword = "adventure" # Load cached sentences for a keyword sentence_pairs = load_cache(keyword) # Returns: [[sentence1, translation1], [sentence2, translation2], ...] # Returns: [] if no cache exists # Save new sentences (merges with existing cache) new_sentences = [ ["This is an exciting adventure.", "这是一次激动人心的冒险。"], ["The adventure begins tomorrow.", "冒险明天开始。"] ] save_cache(keyword, new_sentences) # Returns: True on success, False on failure # Atomically pop first sentence from cache (for card display) sentence_pair = pop_cache(keyword) # Returns: ["This is an exciting adventure.", "这是一次激动人心的冒险。",] # Returns: None if cache is empty # Automatically removes keyword from cache when last sentence is used # Clear all caches (database and memory) success = clear_cache() # Returns: True on success, displays confirmation dialog ``` -------------------------------- ### Difficulty-Based Keyword Selection (Python) Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt Retrieves a list of the top 100 most difficult keywords, as determined by the FSRS algorithm. This is intended for use in prompt engineering, such as inserting a second keyword for more complex sentence generation. ```python from api_client import get_top_difficulty_keywords # Get most difficult keywords (FSRS difficulty >= 0.6) difficult_keywords = get_top_difficulty_keywords() # Returns: ["phenomenon", "correlation", "inevitable", ...] # Sorted by FSRS difficulty (highest first) ``` -------------------------------- ### Process Difficult Keywords with Python Source: https://context7.com/yfftyhwsdj/contextflow/llms.txt This Python code snippet processes a list of difficult keywords. It prints the count of found keywords and lists the top 10. If no difficult keywords are found (less than 100), it prints a corresponding message. This logic is used internally by the generate_ai_sentence() function. ```python if difficult_keywords: print(f"Found {len(difficult_keywords)} difficult keywords") print(f"Top 10: {difficult_keywords[:10]}") else: print("No difficult keywords found (< 100 difficult cards)") ``` -------------------------------- ### Initialize and Update Charts with Time Range Selection (JavaScript) Source: https://github.com/yfftyhwsdj/contextflow/blob/main/templates/stats.html Initializes charts with default settings and updates them based on user-selected time ranges. Handles the display of loading indicators and chart canvases. It listens for changes in radio button selections for time range. ```javascript canvasElements.forEach(cv => cv.style.display = 'none'); loadingElements.forEach(el => el.style.display = 'flex'); tryInit(); document.querySelectorAll('input[name="timeRange"]').forEach(radio => { radio.addEventListener('change', function() { loadingElements.forEach(el => el.style.display = 'flex'); canvasElements.forEach(cv => cv.style.display = 'none'); setTimeout(() => { updateCharts(this.value); loadingElements.forEach(el => el.style.display = 'none'); canvasElements.forEach(cv => cv.style.display = 'block'); }, 10); }); }); document.addEventListener('DOMContentLoaded', initCharts); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.