๐ ๐ ืคืชืืืช ืฉืืืืืช ืืจืืืืช ืขื ืงืืฆื ืฉืืข / ืืงืกื
-
ืืฆืืจืช ืฉืืืืืช ืืจืืืืช
ืฉืืื ืืืืื!
ื"ื ืืฆื ืื ืืขืฉืืช ืกืงืจืืคื ืคืฉืื, ืฉืขืืืจ ืืืฆืืจ ืืืืขืืืช ืฉืืืืืช ืืืขืจืืช ืืืืช ืืืฉืื ืืงืืืช, ืืืื ืืฆืืจืช ืงืืฆื ืฉืืข (TTS) ืืงืืืฆื ืืืืจืืช (ext.ini) ืืืืืืืืช.ืฉืื ืืื:
ืื ืืกืงืจืืคื ืขืืฉื?
ืืกืงืจืืคื ืงืืจื ืงืืืฅ ืืงืกื ืคืฉืื, ืืขื ืคืื:- ืืืฆืจ ืฉืืืืืช ืืชืชื ืฉืืืืืช ืืืขืจืืช ืืืืช ืืืฉืื.
- ืืขืื ืงืืฆื ืืืืจื (ext.ini) ืืืืืืืืช.
- ืืืืจ ืืงืกื ืืงืืฆื ืฉืืข (TTS) ืืขืืจืืช ืืืขืื ืืืชื ืืฉืืืื ืืคื ืื ืชืื
- ืืขืื ืงืืืฆื ืืงืกื/TTS ืจืืืืื.
- ืืื ืืืื ืืืชืงื ื ืืืืืืืืช ืฉื ืชืืื ืช FFmpeg.
ืฉืื ืฉืชืืื:
ืืืื ืื ืืช ืืงืืฆืื...
ืงืืืฅ ืืกืงืจืืคื: ืฉืืจื ืืช ืงืื ืืคืืืชืื ืฉืคื (ืืกืคืืืืจ) ืืงืืืฅ ืืฉื make_audio.py (ืื ืื ืฉื ืืืจ ืขื ืกืืืืช .py).import pandas as pd import requests from requests_toolbelt.multipart.encoder import MultipartEncoder import os import asyncio import edge_tts import subprocess import json import urllib.request import zipfile import shutil import warnings warnings.filterwarnings("ignore") DEFAULT_TTS_VOICE = "he-IL-AvriNeural" # ื ืืืืจ ืืช FFMPEG_EXECUTABLE ื-None ืืืชืืื, ืืจืง ื ืืชืื ืืืชื ืืฉื ืฆืืจื FFMPEG_EXECUTABLE = None def read_excel_data(excel_file_path): print(f"๐ ืงืืจื ืงืืืฅ ืืงืกื: {excel_file_path}") try: df = pd.read_excel(excel_file_path, header=None) username = str(df.iloc[0, 1]).strip() password = str(df.iloc[1, 1]).strip() if not username: print("โ ืฉืืืื: ืื ื ืืื ืก ืืกืคืจ ืืขืจืืช (ืชื B1 ืืืงืกื).") return None, None, None if not password: print("โ ืฉืืืื: ืื ื ืืื ืก ืกืืกืื (ืชื B2 ืืืงืกื).") return None, None, None extensions = df.iloc[5:, [0, 1, 2, 3, 4]].dropna(how='all') extensions.columns = ['ื ืชืื', 'ืืืืจื', 'ืฉื ืืฉืืืื', 'ืงืืืฅ ืฉืืข ืืืขืืื', 'ืงืืืฅ ืืงืกื ืืืขืืื'] extensions = extensions.apply(lambda x: x.astype(str).str.strip().replace('nan', '') if x.dtype == 'object' else x) print(f"โ๏ธ ื ืงืจืื ืืืฆืืื: ืืฉืชืืฉ={username}, ืกืืกืื={'*' * len(password)}") print(f"๐ ื ืชืื ื ืืฉืืืืืช ืฉื ืงืจืื:\n{extensions.to_string()}") return username, password, extensions.to_dict('records') except FileNotFoundError: print(f"โ ืฉืืืื: ืงืืืฅ ืืืงืกื '{excel_file_path}' ืื ื ืืฆื. ืืื ืฉืืื ืืืืชื ืชืืงืืื ืืื ืืกืงืจืืคื.") return None, None, None except Exception as e: print(f"โ ืฉืืืื ืืงืจืืืช ืงืืืฅ ืืืงืกื: {e}") return None, None, None def create_ext_ini_file(extension_type, extension_name, output_file_name, is_subpath=False, direct_ini_content=None): content = "" if direct_ini_content: content = direct_ini_content.strip() if not content.endswith('\n'): content += '\n' print(f"โ๏ธ ืืืฆืจ ืงืืืฅ ext.ini ืืชืืื INI ืืฉืืจ.") elif is_subpath: content = "type=menu\n" else: normalized_extension_type = str(extension_type).strip().lower() if extension_type else "" if pd.isna(extension_type): normalized_extension_type = "" if normalized_extension_type == 'ืืฉืืขืช ืงืืฆืื': content = "type=playfile\n" elif normalized_extension_type == 'ืชืคืจืื': content = "type=menu\n" elif normalized_extension_type in ['ืืงืืื', 'ืืงืืืืช']: content = "type=record\n" else: print(f"โ ๏ธ ืกืื ืฉืืืื ืื ืืืืจ '{extension_type}'. ืืืืืจ ื-'ืชืคืจืื' ืืืจืืจืช ืืืื.") content = "type=menu\n" if extension_name and extension_name.strip(): content += f"title={extension_name.strip()}\n" try: with open(output_file_name, 'w', encoding='utf-8') as f: f.write(content) print(f"โ ื ืืฆืจ ืงืืืฅ {output_file_name} ืขื ืชืืื: {content.strip() or '[ืจืืง]'}") return True except Exception as e: print(f"โ ืฉืืืื ืืืฆืืจืช ืงืืืฅ {output_file_name}: {e}") return False async def create_and_convert_audio_file(text, output_wav_name): output_mp3_temp = f"temp_{os.path.splitext(output_wav_name)[0]}.mp3" print(f"๐ ืืืฆืจ ืงืืืฅ ืฉืืข {output_wav_name} ืืืงืกื: '{text}'") # ืืืืืงื ืืืืืชืืื ืฉื FFMPEG_EXECUTABLE ืืชืจืืฉืื ืืื ืืืื global FFMPEG_EXECUTABLE if not FFMPEG_EXECUTABLE or not os.path.exists(FFMPEG_EXECUTABLE): print(f"โณ ืื ืกื ืืืืจืื ืื ืืืชืจ ืืช FFmpeg ืืืืื ืฉื ืืจืฉ ืืืืคืื ืืงืืฆื ืฉืืข...") ensure_ffmpeg() # ืงืืจืืื ื-ensure_ffmpeg ืจืง ืืื if not FFMPEG_EXECUTABLE or not os.path.exists(FFMPEG_EXECUTABLE): print(f"โ ืื ื ืืชื ืืืฆืืจ ืงืืืฅ ืฉืืข {output_wav_name} ืื FFmpeg ืื ืืืื.") return False try: comm = edge_tts.Communicate(text, voice=DEFAULT_TTS_VOICE) await comm.save(output_mp3_temp) print(f"โ ืงืืืฅ ืืืืื ืืื ื ื ืืฆืจ ืืืฆืืื: {output_mp3_temp}") result = subprocess.run( [FFMPEG_EXECUTABLE, "-loglevel", "error", "-y", "-i", output_mp3_temp, "-ar", "8000", "-ac", "1", "-acodec", "pcm_s16le", output_wav_name], check=True ) print(f"โ ืงืืืฅ WAV ืกืืคื ื ืืฆืจ ืืืฆืืื: {output_wav_name}") return True except edge_tts.exceptions.NoAudioReceived as e: print(f"โ ืฉืืืื ืืืฆืืจืช ืงืืืฅ ืฉืืข {output_wav_name}: {e}") print("โ ืืื/ื ืืืืืจ ืืื ืืจื ื ืชืงืื, ืืื ืืกืืืืช ืืืืช ืืฉ/ืื ืื-ืืืจืืก, ืื ื ืกื/ื ืงืื ืืืจ.") except subprocess.CalledProcessError as e: print(f"โ ืฉืืืื ืืืืจืช ืืืืื (FFmpeg) ืขืืืจ {output_wav_name}: {e}. ืืื/ื ืฉ-FFmpeg ืืืชืงื ืื ืืืฉ.") except FileNotFoundError: print(f"โ ืฉืืืื: FFmpeg ืื ื ืืฆื ืื ืชืื ืืืืืืจ. ืืื/ื ืฉืืืจื ืืืืืืจ ืืจืืื.") except Exception as e: print(f"โ ืฉืืืื ืืืืืช ืืืฆืืจืช/ืืืจืช ืืืืื ืขืืืจ {output_wav_name}: {e}") finally: if os.path.exists(output_mp3_temp): os.remove(output_mp3_temp) return False def create_text_file(text, output_file_name): print(f"๐ ืืืฆืจ ืงืืืฅ ืืงืกื {output_file_name} ืขื ืชืืื: {text}") try: with open(output_file_name, 'w', encoding='utf-8') as f: f.write(text) print(f"โ ืงืืืฅ ืืงืกื {output_file_name} ื ืืฆืจ ืืืฆืืื") return True except Exception as e: print(f"โ ืฉืืืื ืืืฆืืจืช ืงืืืฅ ืืงืกื {output_file_name}: {e}") return False def upload_file_to_yemot(file_path, yemot_full_path, username, password): token = f"{username}:{password}" file_ext = file_path.lower() if file_ext.endswith('.wav'): content_type = 'audio/wav' elif file_ext.endswith('.txt') or file_ext.endswith('.tts'): content_type = 'text/plain' elif file_ext.endswith('.ini'): content_type = 'text/plain' else: content_type = 'application/octet-stream' try: with open(file_path, 'rb') as f_read: m = MultipartEncoder(fields={ "token": token, "path": yemot_full_path, "upload": (os.path.basename(file_path), f_read, content_type) }) print(f"โฌ๏ธ ืืขืื ืงืืืฅ {os.path.basename(file_path)} ืื ืชืื: {yemot_full_path}") r = requests.post("https://www.call2all.co.il/ym/api/UploadFile", data=m, headers={'Content-Type': m.content_type}) r.raise_for_status() print(f"โ๏ธ ืืงืืืฅ '{os.path.basename(file_path)}' ืืืขืื ืืืฆืืื") return True except FileNotFoundError: print(f"โ ืฉืืืื: ืงืืืฅ ืืงืืจ ืืืขืืื ืื ื ืืฆื: {file_path}") return False except requests.exceptions.RequestException as e: print(f"โ ืฉืืืื ืืืขืืืช ืงืืืฅ {os.path.basename(file_path)}: {e}") print(f"๐ค ืชืืืืช ืฉืจืช: {r.text if 'r' in locals() else 'ืืื ืชืืืื ืืืฉืจืช'}") return False except Exception as e: print(f"โ ืฉืืืื ืืืชื ืฆืคืืื ืืืขืืืช ืงืืืฅ {os.path.basename(file_path)}: {e}") return False def generate_subpaths(full_path): parts = [p for p in full_path.split('/') if p] subpaths = [] current_path_parts = [] for part in parts[:-1]: current_path_parts.append(part) subpaths.append('/'.join(current_path_parts)) return subpaths def test_yemot_credentials(username, password): token = f"{username}:{password}" dummy_file_name = "temp_cred_test.txt" dummy_file_path_local = os.path.join(os.getcwd(), dummy_file_name) yemot_target_path = "ivr2:/temp_credential_test_folder/test_file.txt" try: with open(dummy_file_path_local, "w") as f: f.write("test_content") print("โณ ืืืืง ืฉื ืืฉืชืืฉ ืืกืืกืื ืืื ืืขืจืืช ืืืืช ืืืฉืื...") with open(dummy_file_path_local, 'rb') as f_read_dummy: m = MultipartEncoder(fields={ "token": token, "path": yemot_target_path, "upload": (dummy_file_name, f_read_dummy, 'text/plain') }) r = requests.post("https://www.call2all.co.il/ym/api/UploadFile", data=m, headers={'Content-Type': m.content_type}) response_text = r.text.strip() response_text_upper = response_text.upper() if r.status_code == 401 or r.status_code == 403: print("โ ืฉื ืืฉืชืืฉ ื/ืื ืกืืกืื ืื ืชืงืื. ืฉืืืืช ืืืืืช (Unauthorized/Forbidden).") return False try: response_json = json.loads(response_text) if response_json.get("responseStatus") == "OK" and response_json.get("success") == True: print("โ ืฉื ืืฉืชืืฉ ืืกืืกืื ืชืงืื ืื.") return True elif "TOKEN INVALID" in response_text_upper or \ "ืืืกืคืจ ืืื ื ืืืจืฉื" in response_text_upper or \ "THE NUMBER IS NOT VALID" in response_text_upper or \ "ืืกืคืจ ืืืขืจืืช ืืื ื ืชืงืื" in response_text_upper: print("โ ืฉื ืืฉืชืืฉ ื/ืื ืกืืกืื ืื ืชืงืื.") return False else: print(f"โ ืฉื ืืฉืชืืฉ ื/ืื ืกืืกืื ืื ืชืงืื. ืชืืืืช ืฉืจืช ืื ืฆืคืืื: {response_text}") return False except json.JSONDecodeError: if "ERROR:" in response_text_upper: if "TOKEN INVALID" in response_text_upper or \ "ืืืกืคืจ ืืื ื ืืืจืฉื" in response_text_upper or \ "THE NUMBER IS NOT VALID" in response_text_upper or \ "ืืกืคืจ ืืืขืจืืช ืืื ื ืชืงืื" in response_text_upper: print("โ ืฉื ืืฉืชืืฉ ื/ืื ืกืืกืื ืื ืชืงืื.") return False else: print(f"โ ืฉื ืืฉืชืืฉ ื/ืื ืกืืกืื ืื ืชืงืื. ืฉืืืืช ืฉืจืช ืื ืกืคืฆืืคืืช: {response_text}") return False else: print(f"โ ืฉื ืืฉืชืืฉ ื/ืื ืกืืกืื ืื ืชืงืื. ืชืืืืช ืฉืจืช ืืคืืจืื ืื ืฆืคืื: {response_text}") return False except requests.exceptions.RequestException as e: print(f"โ ืฉืืืืช ืืืืืจ ืื ืชืงืฉืืจืช ืืขืช ืืืืงืช ืืชืืืจืืช: {e}") print("โ ืืื/ื ืืืืืจ ืืื ืืจื ื ืชืงืื.") return False except Exception as e: print(f"โ ืฉืืืื ืืืชื ืฆืคืืื ืืขืช ืืืืงืช ืืชืืืจืืช: {e}") return False finally: if os.path.exists(dummy_file_path_local): try: os.remove(dummy_file_path_local) except OSError as e: print(f"โ ๏ธ ืืืืจื: ืื ื ืืชื ืืืืืง ืืช ืงืืืฅ ืืืื '{dummy_file_path_local}': {e}") def ensure_ffmpeg(): global FFMPEG_EXECUTABLE local_ffmpeg_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin", "ffmpeg.exe") if os.path.exists(local_ffmpeg_path): print("โฉ ffmpeg ืืืจ ืงืืื ืื ืชืื ืืืงืืื.") FFMPEG_EXECUTABLE = local_ffmpeg_path return print("โฌ๏ธ ืืืจืื ืืืืืืจ ffmpeg...") os.makedirs(os.path.dirname(local_ffmpeg_path), exist_ok=True) url = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip" archive_path = os.path.join(os.path.dirname(local_ffmpeg_path), "ffmpeg.zip") try: print(f"๐ฅ ืืืจืื ืงืืืฅ FFmpeg ื: {url}") urllib.request.urlretrieve(url, archive_path) print(f"๐ฆ ืืืืฅ ืืช ืงืืืฅ FFmpeg ื: {archive_path}") with zipfile.ZipFile(archive_path, 'r') as zip_ref: found_ffmpeg_in_zip = False for member in zip_ref.namelist(): if member.endswith('ffmpeg.exe'): source = zip_ref.open(member) target = open(local_ffmpeg_path, "wb") with source, target: shutil.copyfileobj(source, target) print(f"โ FFmpeg ืืืื ืืืฆืืื ื: {local_ffmpeg_path}") FFMPEG_EXECUTABLE = local_ffmpeg_path found_ffmpeg_in_zip = True break if not found_ffmpeg_in_zip: print("โ ืฉืืืื: ืื ื ืืฆื ffmpeg.exe ืืชืื ืงืืืฅ ื-ZIP ืฉืืืจื.") FFMPEG_EXECUTABLE = None return except Exception as e: print(f"โ ืฉืืืื ืืืืจืื ืื ืืืืืืฅ ืฉื FFmpeg: {e}") print("โ ืืื/ื ืืืืืจ ืืื ืืจื ื ืชืงืื ืื ืกื/ื ืฉืื.") FFMPEG_EXECUTABLE = None finally: if os.path.exists(archive_path): try: os.remove(archive_path) except OSError as e: print(f"โ ๏ธ ืืืืจื: ืื ื ืืชื ืืืืืง ืืช ืงืืืฅ ื-ZIP ืืืื ื '{archive_path}': {e}") if not os.path.exists(local_ffmpeg_path): print("โ FFmpeg ืื ืืืชืงื ืืืืืืืืช. ืื ื ืืืจื/ื ืืืชืงื/ื ืืืชื ืืื ืืช.") print("ื ืืชื ืืืืจืื ืืืื: https://www.gyan.dev/ffmpeg/builds/ (ืืืจ/ื ืืช ืืจืกืช Essentials ืื Full ืขืืืจ Windows).") FFMPEG_EXECUTABLE = None async def main(): print("๐ ืืชืืื ืชืืืื ืืฆืืจืช ืืืขืืืช ืฉืืืืืช...") # ensure_ffmpeg() ืืืกืจ ืืืื - ืืืคืขื ืจืง ืืืืืช ืืฆืืจื # if not FFMPEG_EXECUTABLE or not os.path.exists(FFMPEG_EXECUTABLE): # print("โ ๏ธ ืืชืืืื ื ืขืฆืจ ืขืงื ืืืกืจ ื-FFmpeg. ืื ื ืืชืงื/ื ืืืชื ืืื ืืช ืืื ืืืืฉืื.") # return script_dir = os.path.dirname(os.path.abspath(__file__)) excel_file = os.path.join(script_dir, "ืืฉื ื.xlsx") print(f"๐ ืชืืงืืืช ืืกืงืจืืคื: {script_dir}") print(f"๐ ืืืคืฉ ืงืืืฅ ืืงืกื: {excel_file}") if not os.path.exists(excel_file): print(f"โ ืงืืืฅ ืืืงืกื '{excel_file}' ืื ื ืืฆื ืืชืืงืืืช ืืกืงืจืืคื!") print(f"๐ ืงืืฆืื ืืชืืงืืื: {os.listdir(script_dir)}") return username, password, extensions_data = read_excel_data(excel_file) if not username or not password or not extensions_data: print("โ ๏ธ ืืชืืืื ื ืขืฆืจ ืขืงื ืืืกืจ ืื ืชืื ื ืืชืืืจืืช ืื ื ืชืื ื ืฉืืืืืช.") return if not test_yemot_credentials(username, password): print("โ ๏ธ ืืชืืืื ื ืขืฆืจ ืขืงื ืคืจืื ืืชืืืจืืช ืื ืชืงืื ืื.") return processed_subfolders = set() for ext in extensions_data: path = ext.get('ื ืชืื') extension_type = ext.get('ืืืืจื') extension_name = ext.get('ืฉื ืืฉืืืื') audio_content = ext.get('ืงืืืฅ ืฉืืข ืืืขืืื', '') text_content = ext.get('ืงืืืฅ ืืงืกื ืืืขืืื', '') if isinstance(path, str): path = path.strip() if isinstance(extension_type, str): extension_type = extension_type.strip() if isinstance(extension_name, str): extension_name = extension_name.strip() if isinstance(audio_content, str): audio_content = audio_content.strip().replace('...', '') if isinstance(text_content, str): text_content = text_content.strip().replace('...', '') if not path: print(f"โ ๏ธ ืืืืื ืขื ืฉืืืื: ื ืชืื ืื ืชืงืื ืื ืืกืจ '{path}'") continue clean_path = path print(f"\n๐ ืืขืื ืฉืืืื: {extension_name} ({path})") subpaths_to_create = generate_subpaths(clean_path) for subpath_item in subpaths_to_create: full_sub_yemot_ini_path = f"ivr2:/{subpath_item}/ext.ini" if full_sub_yemot_ini_path not in processed_subfolders: print(f"โ๏ธ ืืขืื ืชืช-ืฉืืืื (ืืจืืจืช ืืืื menu): {full_sub_yemot_ini_path}") ini_file_name = "ext.ini" if create_ext_ini_file(None, None, ini_file_name, is_subpath=True): if not upload_file_to_yemot(ini_file_name, full_sub_yemot_ini_path, username, password): print(f"โ ืฉืืืื ืืืขืืืช INI ืืชืช-ืฉืืืื {full_sub_yemot_ini_path}. ืืืฉื ืขืืืื...") else: print(f"โ ืฉืืืื ืืืฆืืจืช INI ืืชืช-ืฉืืืื {full_sub_yemot_ini_path}. ืืืื.") if os.path.exists(ini_file_name): os.remove(ini_file_name) processed_subfolders.add(full_sub_yemot_ini_path) main_ini_file = "ext.ini" target_yemot_ini_path = f"ivr2:/{clean_path}/ext.ini" should_create_main_ext_ini = True is_direct_ini_input = False ini_content_for_direct_upload = "" if isinstance(extension_type, str) and extension_type.strip(): if ("type=" in extension_type.strip().lower() and "=" in extension_type.strip()) or "\n" in extension_type.strip(): is_direct_ini_input = True ini_content_for_direct_upload = extension_type.strip() if is_direct_ini_input: if not create_ext_ini_file(None, None, main_ini_file, direct_ini_content=ini_content_for_direct_upload): print(f"โ ืฉืืืื ืืืฆืืจืช INI ืจืืฉื ืืชืืื ืืฉืืจ ืขืืืจ {extension_name}. ืืืื ืขื ืฉืืืื ืื.") continue else: normalized_ext_type_for_check = str(extension_type).strip().lower() if extension_type else "" if pd.isna(extension_type): normalized_ext_type_for_check = "" if normalized_ext_type_for_check == 'ืชืืงืืื' or not normalized_ext_type_for_check: print(f"๐๏ธ ืฉืืืื ืืกืื '{normalized_ext_type_for_check or 'ืจืืง'}'. ืื ื ืืฆืจ ืงืืืฅ ext.ini ืจืืฉื.") should_create_main_ext_ini = False else: if not create_ext_ini_file(extension_type, extension_name, main_ini_file): print(f"โ ืฉืืืื ืืืฆืืจืช INI ืจืืฉื ืขืืืจ {extension_name}. ืืืื ืขื ืฉืืืื ืื.") continue if should_create_main_ext_ini: if not upload_file_to_yemot(main_ini_file, target_yemot_ini_path, username, password): print(f"โ ืฉืืืื ืืืขืืืช INI ืจืืฉื ืขืืืจ {extension_name}. ืืืฉื ืขืืืื...") if os.path.exists(main_ini_file): os.remove(main_ini_file) continue if os.path.exists(main_ini_file): os.remove(main_ini_file) # ืืฉืื ืื ืืขืืงืจื: ืืืืงืช audio_content ืืคื ื ื ืืกืืื ืืฆืืจืช ืงืืืฅ ืฉืืข if audio_content and audio_content.strip(): audio_texts = [t.strip() for t in audio_content.split(' + ') if t.strip()] for i, text_to_tts in enumerate(audio_texts): audio_wav_final = f"{str(i).zfill(3)}.wav" # ืงืจืืื ื-create_and_convert_audio_file ืชืืคื ืืืืชืืื FFmpeg ืื ื ืืจืฉ if await create_and_convert_audio_file(text_to_tts, audio_wav_final): audio_yemot_path = f"ivr2:/{clean_path}/{audio_wav_final}" upload_file_to_yemot(audio_wav_final, audio_yemot_path, username, password) else: print(f"โ ๏ธ ืืืืื ืขื ืืขืืืช ืงืืืฅ ืฉืืข {audio_wav_final} ืขืงื ืฉืืืื ืืืฆืืจื/ืืืจื.") if os.path.exists(audio_wav_final): os.remove(audio_wav_final) # ืงืืฆื ืืงืกื ืืื ื ืืืจืฉืื ืืช FFmpeg, ืื ืื ืืืฉืืืื ืืคืขืื ืืจืืื if text_content and text_content.strip() and (extension_type and pd.notna(extension_type)): text_files_list = [t.strip() for t in text_content.split(' + ') if t.strip()] for i, item_text_content in enumerate(text_files_list): if os.path.exists(item_text_content): file_name_to_upload = os.path.basename(item_text_content) print(f"๐ ืืขืื ืงืืืฅ ืืงืกื ืงืืื: {file_name_to_upload}") text_yemot_path = f"ivr2:/{clean_path}/{file_name_to_upload}" upload_file_to_yemot(item_text_content, text_yemot_path, username, password) else: text_file_name_final = f"{str(i).zfill(3)}.tts" if create_text_file(item_text_content, text_file_name_final): text_yemot_path = f"ivr2:/{clean_path}/{text_file_name_final}" upload_file_to_yemot(text_file_name_final, text_yemot_path, username, password) else: print(f"โ ๏ธ ืืืืื ืขื ืืขืืืช ืงืืืฅ ืืงืกื {text_file_name_final} ืขืงื ืฉืืืื ืืืฆืืจื.") if os.path.exists(text_file_name_final): os.remove(text_file_name_final) print("\nโ ืกืืื ืขืืืื ืื ืืฉืืืืืช ืืืฆืืื!") if __name__ == "__main__": asyncio.run(main())ืงืืืฅ ืืืงืกื: ื ืืชื ืืืืจืื ืืคื ืืฉื ื.xlsx
ืืฉืื ืืืื: ืฉืืืจื ืขื ืืื ื ืืืงืกื ืืื ืืืืืื ืืืงืืจืืช ืฉืงืืืืชื.
ืืฉืื ืืืื ืฉืฉืชื ืืงืืฆืื (ืืงืื ืืืจืฆื ืืืงืืืฅ ืืงืกื) ืืืื ืืืืชื ืชืืงืืื ืขื ืืืืฉื!!ืฉืื ืฉืืืฉ:
ืคืฉืื ืชืืืื ืืช ืืงืืืฅ ืืงืกื ืืคื ืืฉืืืืืช ืฉืชืจืฆื ืืืืฆืจ ืืืืืื:
ืืื ืืืืื ืื ืืืข ืืืืืื ืืฉืืืช:
-
ืืฉืืืช ืฉืื ืืืื ืื - ืืืขืื ืืฉื ืืฉืชืืฉ ืืืกืืกืื, ืืืฅ ืืื ืืื ืืืื ืืืืฉืืจ ืจืืง - ืื "ืืืืจืืช ืฉืืืื" ื ืฉืืจ ืจืืง - ืื ืืืืฆืจ ืชืืงืืื ืืืื ืืื ืฉืื ืืืืจืืช.
-
ืืฉืืืืืื ืืืืจืืช ืฉืืืื ืืขืืงืจืื ืฆืจืื ืืืื ืืก ืืฉืื ืืช ืืืืืจืืช ืฉื ืืฉืืืื ืืื ืื ืื ืฉืืืื - ืื ืชืคืจืื ืื ืืฉืืขืช ืงืืฆืื ืื ืืงืืื - ืืคืฉืจ ืืืื ืืก ืืช ืืืืืื "ืืงืืื" ืื "ืืฉืืขืช ืงืืฆืื" ืื "ืชืคืจืื" ืืื ืืืฆืจ ืืื ืืช ืืืืจืืช ืืฉืืืื.
-
ืื ืจืืฆืื ืืืฉื ืืขืฉืืช ืืื ืชืืงืืืช / ืฉืืืืืช - ืื ืฆืจืื ืืืืืืช ืืื ืฉืืืช ืืคืฉืจ ืคืฉืื ืืขืฉืืช ืฉืชื ืฉืืืช ืืืฉื:
1/1/1
1/1/2
ืืื ืืืจืืจ ืืืคื ืืื. -
ืืืืื ืืืืืืจืื ื"ื ืชืื" ืืืฉื ืฉืืืื 1/1/1 ืืืืืืจืื ื"ืืืืจืืช ืืฉืืืื" ืฉืืืื ืืฉืืขืช ืงืืฆืื ืื ืื ืืืืจื ืืืจืช - ื ืืฆืจ ืฉืืืื ืืชืื ืฉืืืื ืืชืื ืฉืืืื - ืืืืืื ืฉืจืง ืืฉืืืื ืืืืจืื ื ืืืืืจื - ืืจืืจืช ืืืื ืฉืืฉืืืืืช ืืืืืจืืช ื"ืชืคืจืื".
-
ื"ืืขืืืช ืงืืืฅ ืฉืืข / ืืงืกื - ืืจืืจืช ืืืื ื ืืฆืจ ืงืืืฅ ืืฉื 000 ืืคืฉืจ ืืืืฆืจ ืืื ืงืืฆืื ืืื ืฉืืืื ืขื ืืื ืืคืจืื ืฉื + ืืืืืื "ืฉืืื ืืืจืืืื ืืืืื ืืงื ืืืืืข + ืืชืื ืื ื ืืกืคืื ืืงืฉ ืืืืืืช"
ืื ื ืืฆืจืื ืฉืชื ืงืืฆืื 000, 001.
ืฉืื ืืจืืข:
ืฉืืื ืื ืืคื ื ืฉืืจืืฆืื ืืช ืืงืื ืฆืจืื ืืืืื ืฉืคืืืชืื ืืืชืงื ืขื ืืืืฉื
ืืคืฉืจ ืืืชืงืื ืขื ืืคืงืืื ืืื ืืฉืืจืช ืืคืงืืืwinget install Python.Python.3.12 --source wingetืืืืจ ืืื ืชืจืืฆื ืืช ืืคืงืืื ืืื
pip install pandas requests requests-toolbelt edge-ttsืืื ืืืจืืจ ืืช ืืงืืืฅ ืคืืืชืื ืืชืื ืืฉืืจืช ืคืงืืื (ืื ืืืขืชืืง ืืช ืื ืชืื ืฉืื) ืืืืืื - ืื ืืจ!
ืืฉืืืืฉ ืืืืจืืืช ืืืฉืชืืฉ ืืืื!
ืื ืืืฉืื ืืกืชืื ืขื ืืืจืฆื ืฉื ืืงืื ืืฉืื ืืขืืืจ
ืืฉืื ืืฉืืืข ืฉืื ืขืืจ ืืืืฉืื... ืืืคืืื ืืืืฉืื ืืื... ืืืื ื! -
ืืืืืจ ืขื-ืืื ืช ืชืคืืจืช ืืขืงืื
-
ืืืืืจ ืขื-ืืื Y y6714453
-
@y6714453
ืชืืื ืจืื
ื ืขืืจืชื ืืื ืืื ืืฆืืื
ืืฆืืื ืฉืืื ืื 2 ืชืงืืืช ืืกืืืจืชื ืืช ืื (ืืขืืจืชื ืฉื ื'ืืื ื)- ืืฉืจืช ืื ืืฆืืื ืืืืจืื ืืช ืืชืืื ื ืฉืืืืจื ืืงืกื ืืฉืืข ืืื ืืฆืจ ืืขืื (ืื ื ืื ืืคืจื ืืืื ืื ืงืฉืืจ) ืืืคืืชืจืื ืืื ืืืืจืื ืืืชื ืืืืืืืืช
- ืื ืชืืืืจืื ืื ืฉืืืืช ืื ืืื ืชืช ืฉืืืื ืืฉืื ืืืืืจ ืืช ืชืช ืืฉืืืื ืืื ืืืจืก ืืช ืฉืืืืช ืืื ืืืืคื ืืืชื ืืชืคืจืื
ืืืฅ ืืื ืฉืืจืืชื ืืช ืืกืงืจืืคื ืฉืืขืื ืงืืฆื ืกืืื ื ืืืื ืื ืืื ืืงืืข ืื ืืืื ืืฉื ืฉืืื ืืืขืจืืช
ืืฆืจืฃimport pandas as pd import requests from requests_toolbelt.multipart.encoder import MultipartEncoder import os import asyncio import edge_tts import subprocess import json import urllib.request import zipfile import shutil import warnings warnings.filterwarnings("ignore") DEFAULT_TTS_VOICE = "he-IL-AvriNeural" FFMPEG_EXECUTABLE = None def read_excel_data(excel_file_path): print(f"๐ ืงืืจื ืงืืืฅ ืืงืกื: {excel_file_path}") try: df = pd.read_excel(excel_file_path, header=None) username = str(df.iloc[0, 1]).strip() password = str(df.iloc[1, 1]).strip() if not username: print("โ ืฉืืืื: ืื ื ืืื ืก ืืกืคืจ ืืขืจืืช (ืชื B1 ืืืงืกื).") return None, None, None if not password: print("โ ืฉืืืื: ืื ื ืืื ืก ืกืืกืื (ืชื B2 ืืืงืกื).") return None, None, None extensions = df.iloc[5:, [0, 1, 2, 3, 4]].dropna(how='all') extensions.columns = ['ื ืชืื', 'ืืืืจื', 'ืฉื ืืฉืืืื', 'ืงืืืฅ ืฉืืข ืืืขืืื', 'ืงืืืฅ ืืงืกื ืืืขืืื'] extensions = extensions.apply(lambda x: x.astype(str).str.strip().replace('nan', '') if x.dtype == 'object' else x) print(f"โ๏ธ ื ืงืจืื ืืืฆืืื: ืืฉืชืืฉ={username}, ืกืืกืื={'*' * len(password)}") return username, password, extensions.to_dict('records') except FileNotFoundError: print(f"โ ืฉืืืื: ืงืืืฅ ืืืงืกื '{excel_file_path}' ืื ื ืืฆื. ืืื ืฉืืื ืืืืชื ืชืืงืืื ืืื ืืกืงืจืืคื.") return None, None, None except Exception as e: print(f"โ ืฉืืืื ืืงืจืืืช ืงืืืฅ ืืืงืกื: {e}") return None, None, None def create_ext_ini_file(extension_type, extension_name, output_file_name, is_subpath=False, direct_ini_content=None): # ืคืื ืงืฆืื ืื ื ืฉืืจืช ืืื ืฉืื ืื content = "" if direct_ini_content: content = direct_ini_content.strip() + '\n' elif is_subpath: content = "type=menu\n" # ... (ืฉืืจ ืืงืื ืฉื ืืคืื ืงืฆืื ืืื) try: with open(output_file_name, 'w', encoding='utf-8') as f: f.write(content) return True except Exception: return False async def create_and_convert_audio_file(text, output_wav_name): # ืคืื ืงืฆืื ืื ื ืฉืืจืช ืืื ืฉืื ืื output_mp3_temp = f"temp_{os.path.splitext(output_wav_name)[0]}.mp3" print(f"๐ ืืืฆืจ ืงืืืฅ ืฉืืข {output_wav_name} ืืืงืกื: '{text}'") global FFMPEG_EXECUTABLE if not FFMPEG_EXECUTABLE or not os.path.exists(FFMPEG_EXECUTABLE): ensure_ffmpeg() if not FFMPEG_EXECUTABLE or not os.path.exists(FFMPEG_EXECUTABLE): return False # ... (ืฉืืจ ืืงืื ืฉื ืืคืื ืงืฆืื ืืื) try: comm = edge_tts.Communicate(text, voice=DEFAULT_TTS_VOICE) await comm.save(output_mp3_temp) subprocess.run( [FFMPEG_EXECUTABLE, "-loglevel", "error", "-y", "-i", output_mp3_temp, "-ar", "8000", "-ac", "1", "-acodec", "pcm_s16le", output_wav_name], check=True ) return True except Exception: return False finally: if os.path.exists(output_mp3_temp): os.remove(output_mp3_temp) def upload_file_to_yemot(file_path, yemot_full_path, username, password): # ืคืื ืงืฆืื ืื ื ืฉืืจืช ืืื ืฉืื ืื token = f"{username}:{password}" content_type = 'application/octet-stream' if file_path.lower().endswith('.wav'): content_type = 'audio/wav' if file_path.lower().endswith('.ini'): content_type = 'text/plain' try: with open(file_path, 'rb') as f_read: m = MultipartEncoder(fields={ "token": token, "path": yemot_full_path, "upload": (os.path.basename(yemot_full_path), f_read, content_type) # ืฉืื ืื ืงืื ืืฉื ืืงืืืฅ ืืฉืจืช }) print(f"โฌ๏ธ ืืขืื ืงืืืฅ '{os.path.basename(file_path)}' ืื ืชืื: '{yemot_full_path}'") r = requests.post("https://www.call2all.co.il/ym/api/UploadFile", data=m, headers={'Content-Type': m.content_type}) r.raise_for_status() print(f"โ๏ธ ืืงืืืฅ ืืืขืื ืืืฆืืื") return True except Exception as e: print(f"โ ืฉืืืื ืืืขืืืช ืงืืืฅ {os.path.basename(file_path)}: {e}") return False def generate_subpaths(full_path): # ืคืื ืงืฆืื ืื ื ืฉืืจืช ืืื ืฉืื ืื parts = [p for p in full_path.split('/') if p] subpaths = [] current_path_parts = [] for part in parts[:-1]: current_path_parts.append(part) subpaths.append('/'.join(current_path_parts)) return subpaths def ensure_ffmpeg(): # ืคืื ืงืฆืื ืื ื ืฉืืจืช ืืื ืฉืื ืื global FFMPEG_EXECUTABLE local_ffmpeg_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin", "ffmpeg.exe") if os.path.exists(local_ffmpeg_path): FFMPEG_EXECUTABLE = local_ffmpeg_path return print("โ FFmpeg ืื ื ืืฆื ืืชืืงืืืช 'bin'. ืืฆืืจืช ืฉืืข ืืืงืกื ืื ืชืชืืคืฉืจ.") FFMPEG_EXECUTABLE = None async def main(): print("๐ ืืชืืื ืชืืืื ืืฆืืจืช ืืืขืืืช ืฉืืืืืช...") script_dir = os.path.dirname(os.path.abspath(__file__)) excel_file = os.path.join(script_dir, "ืืฉื ื.xlsx") if not os.path.exists(excel_file): print(f"โ ืงืืืฅ ืืืงืกื '{excel_file}' ืื ื ืืฆื!") return username, password, extensions_data = read_excel_data(excel_file) if not username or not password or not extensions_data: return all_defined_paths = {ext.get('ื ืชืื', '').strip() for ext in extensions_data if ext.get('ื ืชืื')} for ext in extensions_data: path = ext.get('ื ืชืื', '').strip() extension_type = ext.get('ืืืืจื', '').strip() audio_content = ext.get('ืงืืืฅ ืฉืืข ืืืขืืื', '').strip() if not path: continue print(f"\n๐ ืืขืื ืฉืืืื: {ext.get('ืฉื ืืฉืืืื', 'ืืื ืฉื')} ({path})") # ืืืืืงืช ืืฆืืจืช ืชืืงืืืช ืืื ืืื ื-ext.ini ื ืฉืืจืช ืืื... # ... if extension_type: main_ini_file = "ext_temp_main.ini" if create_ext_ini_file(None, None, main_ini_file, direct_ini_content=extension_type): upload_file_to_yemot(main_ini_file, f"ivr2:/{path}/ext.ini", username, password) os.remove(main_ini_file) # --- โญ ืืชืืงืื ืืืจืืื ื ืืฆื ืืื โญ --- if audio_content: source_filename = audio_content dest_filename = "" # ืืืืงื ืื ืืฉ ืืืืจืช ืฉื ืืืชืื if '>' in audio_content: parts = audio_content.split('>', 1) source_filename = parts[0].strip() dest_filename = parts[1].strip() local_audio_path = os.path.join(script_dir, source_filename) # ืขืืืคืืช 1: ืืืืงืช ืงืืืฅ ืืงืืื if os.path.exists(local_audio_path): # ืื ืื ืืืืืจ ืฉื ืืขื, ืืฉืชืืฉ ืืฉื ืืืงืืจื if not dest_filename: dest_filename = os.path.basename(local_audio_path) audio_yemot_path = f"ivr2:/{path}/{dest_filename}" upload_file_to_yemot(local_audio_path, audio_yemot_path, username, password) # ืขืืืคืืช 2: ืืฆืืจืช ืฉืืข ืืืงืกื else: print(f"๐ ืื ื ืืฆื ืงืืืฅ ืืงืืื '{source_filename}'. ืื ืกื ืืืฆืืจ ืฉืืข ืืืืงืกื...") # ืื ืื ืืืืืจ ืฉื ืืขื, ืืฉืชืืฉ ืืฉื ืืจืืจืช ืืืื if not dest_filename: dest_filename = "000.wav" temp_tts_wav_file = "temp_tts_generated.wav" if await create_and_convert_audio_file(source_filename, temp_tts_wav_file): audio_yemot_path = f"ivr2:/{path}/{dest_filename}" upload_file_to_yemot(temp_tts_wav_file, audio_yemot_path, username, password) if os.path.exists(temp_tts_wav_file): os.remove(temp_tts_wav_file) else: print(f"โ ๏ธ ืืืืื ืขื ืืขืืืช ืงืืืฅ ืฉืืข ืขืงื ืฉืืืื ืืืฆืืจื.") # --- โญ ืกืืฃ ืืชืืงืื โญ --- print("\nโ ืกืืื ืขืืืื ืื ืืฉืืืืืช ืืืฆืืื!") if __name__ == "__main__": asyncio.run(main()) -
@NA73438
ืฉืื ืืฉืืืข ืฉืื ืขืืจ...
ืงืืืืชื ืืช ืืืขืจืืช- ืื ื ืืืืืง ืืื ืืืืช ืื ืื ืืืจืื
- ืืืืช ืฆืจืื ืืฉื ืืช ืืช ืื ืชืืื.
ืืื ืื ืืชื ืจืืฆื ืืขืฉืืช ืืงืกื ืฉืืืคืืข ืืื ืงืื ืืชื ืฆืจืื ืืืืจืื ืฉืืจื ืืคื ื ืืืืจื - (ืื ื ืจืืื ืฉืืืืง ืืฆืืืช ืืืืืง ืื...)
-
ืคืืกื ืื ื ืืืง! -
@y6714453
ืชืืื ืืขืืืจ ืื ืืืจืืฅ ืืช ืืงืื? -
@ืA ืขืืฉืื ืชืฆืืจื ืืื ืืขืฉืืช ืืช ืื ืืืืืืช ืืืืฉ
-
@ืขืืื
ืืืืื ื?
ืืืคื ืื ื ืืืื ืืขืืื?
ืืื ืคื ืฉืืืื. -
@ืA https://f2.freeivr.co.il/topic/18488/ืืืืื-ืืืืืืช-ืื-ืฉืืื-ืืขืชืื/347
ืืจืืข ืฉืืชื ื ืืืฉ ืAPI ืชืฆืืจื ืืขืืืจ ืืืืืช ืื ืฉืืื (ืื ืืืคืขื ืืฆืื ืืืขืจืืช)
-
@ืขืืื
ืืื ืชื.
ืื ื ืจืง ืฉืืื ืืืงืจื ืื ื ืืืคื ืื ื ืืขืืื ืืช ืืืืงื? -
@ืA ืืืงื ืื ืืืขืื, ืฆืจืื ืืช ืืืืื ืฉื ืlogin
-
@ืขืืื
ืืืงื.
ืชืืื. -
-
@y6714453
ืชืืื ืจืื.