Created
October 29, 2025 08:34
-
-
Save Ziaeemehr/517a6804584b3f07fdd0b6ada5ea0ad5 to your computer and use it in GitHub Desktop.
anki_add_tts_both_side
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import base64 | |
| import os | |
| import re | |
| import time | |
| from gtts import gTTS | |
| import requests | |
| from tqdm import tqdm | |
| # ----------------------------- | |
| DECK_NAME = "Mobile_A1" # change it accordingly | |
| FRONT_FIELD = "Front" # فیلدی که متن فرانسوی جلوی کارت در آن است | |
| BACK_FIELD = "Back" # فیلدی که پشت کارت است (ممکن است شامل فارسی هم باشد) | |
| FIELD_NAME = "Front" # فیلدی که صدا به آن افزوده میشود (در اینجا همان Front) | |
| LANG = "fr" | |
| TTS_SLOW = False | |
| SLEEP_TIME = 0.5 | |
| CACHE_DIR = "tts_cache" | |
| # ----------------------------- | |
| os.makedirs(CACHE_DIR, exist_ok=True) | |
| def invoke(action, **params): | |
| r = requests.post("http://localhost:8765", json={ | |
| "action": action, | |
| "version": 6, | |
| "params": params | |
| }).json() | |
| if r.get("error"): | |
| raise Exception(r["error"]) | |
| return r["result"] | |
| def strip_html(text): | |
| return re.sub(r"<.*?>", "", text).strip() | |
| def extract_french_text(text): | |
| """برمیگرداند فقط جملهها و کلمات فرانسوی از متن (حذف فارسی و انگلیسی)""" | |
| text = strip_html(text) | |
| # فقط حروف و علائم فرانسوی را نگه میدارد | |
| french_only = re.findall(r"[A-Za-zÀ-ÖØ-öø-ÿœŒçÇ'\- ]+", text) | |
| return " ".join(french_only).strip() | |
| # 1️⃣ یافتن کارتها | |
| cards = invoke("findCards", query=f'deck:"{DECK_NAME}"') | |
| print(f"✅ {len(cards)} کارت در دک '{DECK_NAME}' یافت شد.\n") | |
| # 2️⃣ استخراج note ID ها از کارتها | |
| notes = invoke("cardsToNotes", cards=cards) | |
| notes_info = invoke("notesInfo", notes=notes) | |
| for note in tqdm(notes_info, desc="🔊 در حال تولید تلفظها"): | |
| note_id = note["noteId"] | |
| fields = note["fields"] | |
| # ========== FRONT ========== | |
| front_text = fields.get(FRONT_FIELD, {}).get("value", "") | |
| if front_text.strip() and "[sound:" not in fields.get(FRONT_FIELD, {}).get("value", ""): | |
| clean_text = strip_html(front_text) | |
| if clean_text: | |
| filename = f"{clean_text}.mp3".replace(" ", "_").replace("/", "_") | |
| audio_path = os.path.join(CACHE_DIR, filename) | |
| if not os.path.exists(audio_path): | |
| try: | |
| tts = gTTS(clean_text, lang=LANG, slow=TTS_SLOW) | |
| tts.save(audio_path) | |
| time.sleep(SLEEP_TIME) | |
| except Exception as e: | |
| print(f"\n⚠️ خطا در ساخت صدا برای '{clean_text}': {e}") | |
| continue | |
| with open(audio_path, "rb") as f: | |
| audio_b64 = base64.b64encode(f.read()).decode() | |
| invoke("storeMediaFile", filename=filename, data=audio_b64) | |
| sound_tag = f"[sound:{filename}]" | |
| new_value = fields[FRONT_FIELD]["value"] + "<br>" + sound_tag | |
| invoke("updateNoteFields", note={"id": note_id, "fields": {FRONT_FIELD: new_value}}) | |
| # ========== BACK ========== | |
| back_text = fields.get(BACK_FIELD, {}).get("value", "") | |
| if back_text.strip() and "[sound:" not in back_text: | |
| french_part = extract_french_text(back_text) | |
| if not french_part: | |
| continue | |
| filename_back = f"{french_part}_back.mp3".replace(" ", "_").replace("/", "_") | |
| audio_path_back = os.path.join(CACHE_DIR, filename_back) | |
| if not os.path.exists(audio_path_back): | |
| try: | |
| tts = gTTS(french_part, lang=LANG, slow=TTS_SLOW) | |
| tts.save(audio_path_back) | |
| time.sleep(SLEEP_TIME) | |
| except Exception as e: | |
| print(f"\n⚠️ خطا در ساخت صدا برای پشت کارت '{french_part}': {e}") | |
| continue | |
| with open(audio_path_back, "rb") as f: | |
| audio_b64_back = base64.b64encode(f.read()).decode() | |
| invoke("storeMediaFile", filename=filename_back, data=audio_b64_back) | |
| sound_tag_back = f"[sound:{filename_back}]" | |
| new_value_back = back_text + "<br>" + sound_tag_back | |
| invoke("updateNoteFields", note={"id": note_id, "fields": {BACK_FIELD: new_value_back}}) | |
| print("\n✅ تمام تلفظها (Front + Back فرانسوی) اضافه شدند (با پشتیبانی Cache).") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment