Spaces:
Running
on
Zero
Running
on
Zero
import spaces # ์ถ๊ฐ | |
import gradio as gr | |
import os | |
import asyncio | |
import torch | |
import io | |
import json | |
import re | |
import httpx | |
import tempfile | |
import wave | |
import base64 | |
import numpy as np | |
import soundfile as sf | |
import subprocess | |
import shutil | |
import requests | |
import logging | |
from datetime import datetime, timedelta | |
from dataclasses import dataclass | |
from typing import List, Tuple, Dict, Optional | |
from pathlib import Path | |
from threading import Thread | |
from dotenv import load_dotenv | |
# PDF processing imports | |
from langchain_community.document_loaders import PyPDFLoader | |
# Edge TTS imports | |
import edge_tts | |
from pydub import AudioSegment | |
# OpenAI imports | |
from openai import OpenAI | |
# Transformers imports (for legacy local mode) | |
from transformers import ( | |
AutoModelForCausalLM, | |
AutoTokenizer, | |
TextIteratorStreamer, | |
BitsAndBytesConfig, | |
) | |
# Llama CPP imports (for new local mode) | |
try: | |
from llama_cpp import Llama | |
from llama_cpp_agent import LlamaCppAgent, MessagesFormatterType | |
from llama_cpp_agent.providers import LlamaCppPythonProvider | |
from llama_cpp_agent.chat_history import BasicChatHistory | |
from llama_cpp_agent.chat_history.messages import Roles | |
from huggingface_hub import hf_hub_download | |
LLAMA_CPP_AVAILABLE = True | |
except ImportError: | |
LLAMA_CPP_AVAILABLE = False | |
# Spark TTS imports | |
try: | |
from huggingface_hub import snapshot_download | |
SPARK_AVAILABLE = True | |
except: | |
SPARK_AVAILABLE = False | |
# MeloTTS imports (for local mode) | |
try: | |
# unidic ๋ค์ด๋ก๋๋ฅผ ์กฐ๊ฑด๋ถ๋ก ์ฒ๋ฆฌ | |
if not os.path.exists("/usr/local/lib/python3.10/site-packages/unidic"): | |
try: | |
os.system("python -m unidic download") | |
except: | |
pass | |
from melo.api import TTS as MeloTTS | |
MELO_AVAILABLE = True | |
except: | |
MELO_AVAILABLE = False | |
load_dotenv() | |
# Brave Search API ์ค์ | |
BRAVE_KEY = os.getenv("BSEARCH_API") | |
BRAVE_ENDPOINT = "https://api.search.brave.com/res/v1/web/search" | |
# Edge TTS ์ ์ฉ ์ธ์ด ๋ชฉ๋ก (English ์ ์ธ) | |
EDGE_TTS_ONLY_LANGUAGES = [ | |
"Korean", "Japanese", "French", "German", "Spanish", "Italian", | |
"Portuguese", "Dutch", "Thai", "Vietnamese", "Arabic", "Hebrew", | |
"Indonesian", "Hindi", "Russian", "Chinese", "Norwegian", "Swedish", | |
"Finnish", "Danish", "Polish", "Turkish", "Greek", "Czech" | |
] | |
# ์ธ์ด๋ณ Edge TTS ์์ฑ ์ค์ | |
EDGE_TTS_VOICES = { | |
"English": [ | |
"en-US-AndrewMultilingualNeural", # ๋จ์ฑ ์์ฑ 1 | |
"en-US-BrianMultilingualNeural" # ๋จ์ฑ ์์ฑ 2 | |
], | |
"Korean": [ | |
"ko-KR-HyunsuNeural", # ๋จ์ฑ ์์ฑ 1 (์ฐจ๋ถํ๊ณ ์ ๋ขฐ๊ฐ ์๋) | |
"ko-KR-InJoonNeural" # ๋จ์ฑ ์์ฑ 2 (ํ๊ธฐ์ฐจ๊ณ ์น๊ทผํ) | |
], | |
"Japanese": [ | |
"ja-JP-KeitaNeural", # ๋จ์ฑ ์์ฑ 1 | |
"ja-JP-NanamiNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"French": [ | |
"fr-FR-HenriNeural", # ๋จ์ฑ ์์ฑ 1 | |
"fr-FR-DeniseNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"German": [ | |
"de-DE-ConradNeural", # ๋จ์ฑ ์์ฑ 1 | |
"de-DE-KillianNeural" # ๋จ์ฑ ์์ฑ 2 | |
], | |
"Spanish": [ | |
"es-ES-AlvaroNeural", # ๋จ์ฑ ์์ฑ 1 | |
"es-ES-ElviraNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Italian": [ | |
"it-IT-DiegoNeural", # ๋จ์ฑ ์์ฑ 1 | |
"it-IT-IsabellaNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Portuguese": [ | |
"pt-BR-AntonioNeural", # ๋จ์ฑ ์์ฑ 1 | |
"pt-BR-FranciscaNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Dutch": [ | |
"nl-NL-MaartenNeural", # ๋จ์ฑ ์์ฑ 1 | |
"nl-NL-ColetteNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Thai": [ | |
"th-TH-NiwatNeural", # ๋จ์ฑ ์์ฑ 1 | |
"th-TH-PremwadeeNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Vietnamese": [ | |
"vi-VN-NamMinhNeural", # ๋จ์ฑ ์์ฑ 1 | |
"vi-VN-HoaiMyNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Arabic": [ | |
"ar-SA-HamedNeural", # ๋จ์ฑ ์์ฑ 1 | |
"ar-SA-ZariyahNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Hebrew": [ | |
"he-IL-AvriNeural", # ๋จ์ฑ ์์ฑ 1 | |
"he-IL-HilaNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Indonesian": [ | |
"id-ID-ArdiNeural", # ๋จ์ฑ ์์ฑ 1 | |
"id-ID-GadisNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Hindi": [ | |
"hi-IN-MadhurNeural", # ๋จ์ฑ ์์ฑ 1 | |
"hi-IN-SwaraNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Russian": [ | |
"ru-RU-DmitryNeural", # ๋จ์ฑ ์์ฑ 1 | |
"ru-RU-SvetlanaNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Chinese": [ | |
"zh-CN-YunxiNeural", # ๋จ์ฑ ์์ฑ 1 | |
"zh-CN-XiaoxiaoNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Norwegian": [ | |
"nb-NO-FinnNeural", # ๋จ์ฑ ์์ฑ 1 | |
"nb-NO-PernilleNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Swedish": [ | |
"sv-SE-MattiasNeural", # ๋จ์ฑ ์์ฑ 1 | |
"sv-SE-SofieNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Finnish": [ | |
"fi-FI-HarriNeural", # ๋จ์ฑ ์์ฑ 1 | |
"fi-FI-NooraNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Danish": [ | |
"da-DK-JeppeNeural", # ๋จ์ฑ ์์ฑ 1 | |
"da-DK-ChristelNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Polish": [ | |
"pl-PL-MarekNeural", # ๋จ์ฑ ์์ฑ 1 | |
"pl-PL-ZofiaNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Turkish": [ | |
"tr-TR-AhmetNeural", # ๋จ์ฑ ์์ฑ 1 | |
"tr-TR-EmelNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Greek": [ | |
"el-GR-NestorasNeural", # ๋จ์ฑ ์์ฑ 1 | |
"el-GR-AthinaNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
], | |
"Czech": [ | |
"cs-CZ-AntoninNeural", # ๋จ์ฑ ์์ฑ 1 | |
"cs-CZ-VlastaNeural" # ์ฌ์ฑ ์์ฑ (๋ฐฑ์ ์ฉ) | |
] | |
} | |
class ConversationConfig: | |
max_words: int = 8000 # 4000์์ 6000์ผ๋ก ์ฆ๊ฐ (1.5๋ฐฐ) | |
prefix_url: str = "https://r.jina.ai/" | |
api_model_name: str = "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo" | |
legacy_local_model_name: str = "NousResearch/Hermes-2-Pro-Llama-3-8B" | |
# ์๋ก์ด ๋ก์ปฌ ๋ชจ๋ธ ์ค์ | |
local_model_name: str = "Private-BitSix-Mistral-Small-3.1-24B-Instruct-2503.gguf" | |
local_model_repo: str = "ginigen/Private-BitSix-Mistral-Small-3.1-24B-Instruct-2503" | |
# ํ ํฐ ์ ์ฆ๊ฐ | |
max_tokens: int = 6000 # 3000์์ 4500์ผ๋ก ์ฆ๊ฐ (1.5๋ฐฐ) | |
max_new_tokens: int = 12000 # 6000์์ 9000์ผ๋ก ์ฆ๊ฐ (1.5๋ฐฐ) | |
min_conversation_turns: int = 18 # ์ต์ ๋ํ ํด ์ | |
max_conversation_turns: int = 20 # ์ต๋ ๋ํ ํด ์ | |
def brave_search(query: str, count: int = 8, freshness_days: int | None = None): | |
"""Brave Search API๋ฅผ ์ฌ์ฉํ์ฌ ์ต์ ์ ๋ณด ๊ฒ์""" | |
if not BRAVE_KEY: | |
return [] | |
params = {"q": query, "count": str(count)} | |
if freshness_days: | |
dt_from = (datetime.utcnow() - timedelta(days=freshness_days)).strftime("%Y-%m-%d") | |
params["freshness"] = dt_from | |
try: | |
r = requests.get( | |
BRAVE_ENDPOINT, | |
headers={"Accept": "application/json", "X-Subscription-Token": BRAVE_KEY}, | |
params=params, | |
timeout=15 | |
) | |
raw = r.json().get("web", {}).get("results") or [] | |
return [{ | |
"title": r.get("title", ""), | |
"url": r.get("url", r.get("link", "")), | |
"snippet": r.get("description", r.get("text", "")), | |
"host": re.sub(r"https?://(www\.)?", "", r.get("url", "")).split("/")[0] | |
} for r in raw[:count]] | |
except Exception as e: | |
logging.error(f"Brave search error: {e}") | |
return [] | |
def format_search_results(query: str, for_keyword: bool = False) -> str: | |
"""๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ํฌ๋งทํ ํ์ฌ ๋ฐํ""" | |
# ํค์๋ ๊ฒ์์ ๊ฒฝ์ฐ ๋ ๋ง์ ๊ฒฐ๊ณผ ์ฌ์ฉ | |
count = 5 if for_keyword else 3 | |
rows = brave_search(query, count, freshness_days=7 if not for_keyword else None) | |
if not rows: | |
return "" | |
results = [] | |
# ํค์๋ ๊ฒ์์ ๊ฒฝ์ฐ ๋ ์์ธํ ์ ๋ณด ํฌํจ | |
max_results = 4 if for_keyword else 2 | |
for r in rows[:max_results]: | |
if for_keyword: | |
# ํค์๋ ๊ฒ์์ ๋ ๊ธด ์ค๋ํซ ์ฌ์ฉ | |
snippet = r['snippet'][:200] + "..." if len(r['snippet']) > 200 else r['snippet'] | |
results.append(f"**{r['title']}**\n{snippet}\nSource: {r['host']}") | |
else: | |
# ์ผ๋ฐ ๊ฒ์์ ์งง์ ์ค๋ํซ | |
snippet = r['snippet'][:100] + "..." if len(r['snippet']) > 100 else r['snippet'] | |
results.append(f"- {r['title']}: {snippet}") | |
return "\n\n".join(results) + "\n" | |
def extract_keywords_for_search(text: str, language: str = "English") -> List[str]: | |
"""ํ ์คํธ์์ ๊ฒ์ํ ํค์๋ ์ถ์ถ (๊ฐ์ )""" | |
# ํ ์คํธ ์๋ถ๋ถ๋ง ์ฌ์ฉ (๋๋ฌด ๋ง์ ํ ์คํธ ์ฒ๋ฆฌ ๋ฐฉ์ง) | |
text_sample = text[:500] | |
if language == "Korean": | |
import re | |
# ํ๊ตญ์ด ๋ช ์ฌ ์ถ์ถ (2๊ธ์ ์ด์) | |
keywords = re.findall(r'[๊ฐ-ํฃ]{2,}', text_sample) | |
# ์ค๋ณต ์ ๊ฑฐํ๊ณ ๊ฐ์ฅ ๊ธด ๋จ์ด 1๊ฐ๋ง ์ ํ | |
unique_keywords = list(dict.fromkeys(keywords)) | |
# ๊ธธ์ด ์์ผ๋ก ์ ๋ ฌํ๊ณ ๊ฐ์ฅ ์๋ฏธ์์ ๊ฒ ๊ฐ์ ๋จ์ด ์ ํ | |
unique_keywords.sort(key=len, reverse=True) | |
return unique_keywords[:1] # 1๊ฐ๋ง ๋ฐํ | |
else: | |
# ์์ด๋ ๋๋ฌธ์๋ก ์์ํ๋ ๋จ์ด ์ค ๊ฐ์ฅ ๊ธด ๊ฒ 1๊ฐ | |
words = text_sample.split() | |
keywords = [word.strip('.,!?;:') for word in words | |
if len(word) > 4 and word[0].isupper()] | |
if keywords: | |
return [max(keywords, key=len)] # ๊ฐ์ฅ ๊ธด ๋จ์ด 1๊ฐ | |
return [] | |
def search_and_compile_content(keyword: str, language: str = "English") -> str: | |
"""ํค์๋๋ก ๊ฒ์ํ์ฌ ์ถฉ๋ถํ ์ฝํ ์ธ ์ปดํ์ผ""" | |
if not BRAVE_KEY: | |
# API ์์ ๋๋ ๊ธฐ๋ณธ ์ฝํ ์ธ ์์ฑ | |
if language == "Korean": | |
return f""" | |
'{keyword}'์ ๋ํ ์ข ํฉ์ ์ธ ์ ๋ณด: | |
{keyword}๋ ํ๋ ์ฌํ์์ ๋งค์ฐ ์ค์ํ ์ฃผ์ ์ ๋๋ค. | |
์ด ์ฃผ์ ๋ ๋ค์ํ ์ธก๋ฉด์์ ์ฐ๋ฆฌ์ ์ถ์ ์ํฅ์ ๋ฏธ์น๊ณ ์์ผ๋ฉฐ, | |
์ต๊ทผ ๋ค์ด ๋์ฑ ์ฃผ๋ชฉ๋ฐ๊ณ ์์ต๋๋ค. | |
์ฃผ์ ํน์ง: | |
1. ๊ธฐ์ ์ ๋ฐ์ ๊ณผ ํ์ | |
2. ์ฌํ์ ์ํฅ๊ณผ ๋ณํ | |
3. ๋ฏธ๋ ์ ๋ง๊ณผ ๊ฐ๋ฅ์ฑ | |
4. ์ค์ฉ์ ํ์ฉ ๋ฐฉ์ | |
5. ๊ธ๋ก๋ฒ ํธ๋ ๋์ ๋ํฅ | |
์ ๋ฌธ๊ฐ๋ค์ {keyword}๊ฐ ์์ผ๋ก ๋์ฑ ์ค์ํด์ง ๊ฒ์ผ๋ก ์์ํ๊ณ ์์ผ๋ฉฐ, | |
์ด์ ๋ํ ๊น์ด ์๋ ์ดํด๊ฐ ํ์ํ ์์ ์ ๋๋ค. | |
""" | |
else: | |
return f""" | |
Comprehensive information about '{keyword}': | |
{keyword} is a significant topic in modern society. | |
This subject impacts our lives in various ways and has been | |
gaining increasing attention recently. | |
Key aspects: | |
1. Technological advancement and innovation | |
2. Social impact and changes | |
3. Future prospects and possibilities | |
4. Practical applications | |
5. Global trends and developments | |
Experts predict that {keyword} will become even more important, | |
and it's crucial to develop a deep understanding of this topic. | |
""" | |
# ์ธ์ด์ ๋ฐ๋ฅธ ๋ค์ํ ๊ฒ์ ์ฟผ๋ฆฌ | |
if language == "Korean": | |
queries = [ | |
f"{keyword} ์ต์ ๋ด์ค 2024", | |
f"{keyword} ์ ๋ณด ์ค๋ช ", | |
f"{keyword} ํธ๋ ๋ ์ ๋ง", | |
f"{keyword} ์ฅ์ ๋จ์ ", | |
f"{keyword} ํ์ฉ ๋ฐฉ๋ฒ", | |
f"{keyword} ์ ๋ฌธ๊ฐ ์๊ฒฌ" | |
] | |
else: | |
queries = [ | |
f"{keyword} latest news 2024", | |
f"{keyword} explained comprehensive", | |
f"{keyword} trends forecast", | |
f"{keyword} advantages disadvantages", | |
f"{keyword} how to use", | |
f"{keyword} expert opinions" | |
] | |
all_content = [] | |
total_content_length = 0 | |
for query in queries: | |
results = brave_search(query, count=5) # ๋ ๋ง์ ๊ฒฐ๊ณผ ๊ฐ์ ธ์ค๊ธฐ | |
for r in results[:3]: # ๊ฐ ์ฟผ๋ฆฌ๋น ์์ 3๊ฐ | |
content = f"**{r['title']}**\n{r['snippet']}\nSource: {r['host']}\n" | |
all_content.append(content) | |
total_content_length += len(r['snippet']) | |
# ์ฝํ ์ธ ๊ฐ ๋ถ์กฑํ๋ฉด ์ถ๊ฐ ์์ฑ | |
if total_content_length < 1000: # ์ต์ 1000์ ํ๋ณด | |
if language == "Korean": | |
additional_content = f""" | |
์ถ๊ฐ ์ ๋ณด: | |
{keyword}์ ๊ด๋ จ๋ ์ต๊ทผ ๋ํฅ์ ์ดํด๋ณด๋ฉด, ์ด ๋ถ์ผ๋ ๋น ๋ฅด๊ฒ ๋ฐ์ ํ๊ณ ์์ต๋๋ค. | |
๋ง์ ์ ๋ฌธ๊ฐ๋ค์ด ์ด ์ฃผ์ ์ ๋ํด ํ๋ฐํ ์ฐ๊ตฌํ๊ณ ์์ผ๋ฉฐ, | |
์ค์ํ์์์ ์์ฉ ๊ฐ๋ฅ์ฑ๋ ๊ณ์ ํ๋๋๊ณ ์์ต๋๋ค. | |
ํนํ ์ฃผ๋ชฉํ ์ ์: | |
- ๊ธฐ์ ํ์ ์ ๊ฐ์ํ | |
- ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ | |
- ์ ๊ทผ์ฑ์ ํฅ์ | |
- ๋น์ฉ ํจ์จ์ฑ ์ฆ๋ | |
- ๊ธ๋ก๋ฒ ์์ฅ์ ์ฑ์ฅ | |
์ด๋ฌํ ์์๋ค์ด {keyword}์ ๋ฏธ๋๋ฅผ ๋์ฑ ๋ฐ๊ฒ ๋ง๋ค๊ณ ์์ต๋๋ค. | |
""" | |
else: | |
additional_content = f""" | |
Additional insights: | |
Recent developments in {keyword} show rapid advancement in this field. | |
Many experts are actively researching this topic, and its practical | |
applications continue to expand. | |
Key points to note: | |
- Accelerating technological innovation | |
- Improving user experience | |
- Enhanced accessibility | |
- Increased cost efficiency | |
- Growing global market | |
These factors are making the future of {keyword} increasingly promising. | |
""" | |
all_content.append(additional_content) | |
# ์ปดํ์ผ๋ ์ฝํ ์ธ ๋ฐํ | |
compiled = "\n\n".join(all_content) | |
# ํค์๋ ๊ธฐ๋ฐ ์๊ฐ | |
if language == "Korean": | |
intro = f"### '{keyword}'์ ๋ํ ์ข ํฉ์ ์ธ ์ ๋ณด์ ์ต์ ๋ํฅ:\n\n" | |
else: | |
intro = f"### Comprehensive information and latest trends about '{keyword}':\n\n" | |
return intro + compiled | |
class UnifiedAudioConverter: | |
def __init__(self, config: ConversationConfig): | |
self.config = config | |
self.llm_client = None | |
self.legacy_local_model = None | |
self.legacy_tokenizer = None | |
# ์๋ก์ด ๋ก์ปฌ LLM ๊ด๋ จ | |
self.local_llm = None | |
self.local_llm_model = None | |
self.melo_models = None | |
self.spark_model_dir = None | |
self.device = "cuda" if torch.cuda.is_available() else "cpu" | |
def initialize_api_mode(self, api_key: str): | |
"""Initialize API mode with Together API (now fallback)""" | |
self.llm_client = OpenAI(api_key=api_key, base_url="https://api.together.xyz/v1") | |
def initialize_local_mode(self): | |
"""Initialize new local mode with Llama CPP""" | |
if not LLAMA_CPP_AVAILABLE: | |
raise RuntimeError("Llama CPP dependencies not available. Please install llama-cpp-python and llama-cpp-agent.") | |
if self.local_llm is None or self.local_llm_model != self.config.local_model_name: | |
try: | |
# ๋ชจ๋ธ ๋ค์ด๋ก๋ | |
model_path = hf_hub_download( | |
repo_id=self.config.local_model_repo, | |
filename=self.config.local_model_name, | |
local_dir="./models" | |
) | |
model_path_local = os.path.join("./models", self.config.local_model_name) | |
if not os.path.exists(model_path_local): | |
raise RuntimeError(f"Model file not found at {model_path_local}") | |
# Llama ๋ชจ๋ธ ์ด๊ธฐํ | |
self.local_llm = Llama( | |
model_path=model_path_local, | |
flash_attn=True, | |
n_gpu_layers=81 if torch.cuda.is_available() else 0, | |
n_batch=1024, | |
n_ctx=16384, | |
) | |
self.local_llm_model = self.config.local_model_name | |
print(f"Local LLM initialized: {model_path_local}") | |
except Exception as e: | |
print(f"Failed to initialize local LLM: {e}") | |
raise RuntimeError(f"Failed to initialize local LLM: {e}") | |
def initialize_legacy_local_mode(self): | |
"""Initialize legacy local mode with Hugging Face model (fallback)""" | |
if self.legacy_local_model is None: | |
quantization_config = BitsAndBytesConfig( | |
load_in_4bit=True, | |
bnb_4bit_compute_dtype=torch.float16 | |
) | |
self.legacy_local_model = AutoModelForCausalLM.from_pretrained( | |
self.config.legacy_local_model_name, | |
quantization_config=quantization_config | |
) | |
self.legacy_tokenizer = AutoTokenizer.from_pretrained( | |
self.config.legacy_local_model_name, | |
revision='8ab73a6800796d84448bc936db9bac5ad9f984ae' | |
) | |
def initialize_spark_tts(self): | |
"""Initialize Spark TTS model by downloading if needed""" | |
if not SPARK_AVAILABLE: | |
raise RuntimeError("Spark TTS dependencies not available") | |
model_dir = "pretrained_models/Spark-TTS-0.5B" | |
# Check if model exists, if not download it | |
if not os.path.exists(model_dir): | |
print("Downloading Spark-TTS model...") | |
try: | |
os.makedirs("pretrained_models", exist_ok=True) | |
snapshot_download( | |
"SparkAudio/Spark-TTS-0.5B", | |
local_dir=model_dir | |
) | |
print("Spark-TTS model downloaded successfully") | |
except Exception as e: | |
raise RuntimeError(f"Failed to download Spark-TTS model: {e}") | |
self.spark_model_dir = model_dir | |
# Check if we have the CLI inference script | |
if not os.path.exists("cli/inference.py"): | |
print("Warning: Spark-TTS CLI not found. Please clone the Spark-TTS repository.") | |
def initialize_melo_tts(self): | |
"""Initialize MeloTTS models""" | |
if MELO_AVAILABLE and self.melo_models is None: | |
self.melo_models = {"EN": MeloTTS(language="EN", device=self.device)} | |
def fetch_text(self, url: str) -> str: | |
"""Fetch text content from URL""" | |
if not url: | |
raise ValueError("URL cannot be empty") | |
if not url.startswith("http://") and not url.startswith("https://"): | |
raise ValueError("URL must start with 'http://' or 'https://'") | |
full_url = f"{self.config.prefix_url}{url}" | |
try: | |
response = httpx.get(full_url, timeout=60.0) | |
response.raise_for_status() | |
return response.text | |
except httpx.HTTPError as e: | |
raise RuntimeError(f"Failed to fetch URL: {e}") | |
def extract_text_from_pdf(self, pdf_file) -> str: | |
"""Extract text content from PDF file""" | |
try: | |
# Gradio returns file path, not file object | |
if isinstance(pdf_file, str): | |
pdf_path = pdf_file | |
else: | |
# If it's a file object (shouldn't happen with Gradio) | |
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file: | |
tmp_file.write(pdf_file.read()) | |
pdf_path = tmp_file.name | |
# PDF ๋ก๋ ๋ฐ ํ ์คํธ ์ถ์ถ | |
loader = PyPDFLoader(pdf_path) | |
pages = loader.load() | |
# ๋ชจ๋ ํ์ด์ง์ ํ ์คํธ๋ฅผ ๊ฒฐํฉ | |
text = "\n".join([page.page_content for page in pages]) | |
# ์์ ํ์ผ์ธ ๊ฒฝ์ฐ ์ญ์ | |
if not isinstance(pdf_file, str) and os.path.exists(pdf_path): | |
os.unlink(pdf_path) | |
return text | |
except Exception as e: | |
raise RuntimeError(f"Failed to extract text from PDF: {e}") | |
def _get_messages_formatter_type(self, model_name): | |
"""Get appropriate message formatter for the model""" | |
if "Mistral" in model_name or "BitSix" in model_name: | |
return MessagesFormatterType.CHATML | |
else: | |
return MessagesFormatterType.LLAMA_3 | |
def _build_prompt(self, text: str, language: str = "English", search_context: str = "") -> str: | |
"""Build prompt for conversation generation with enhanced professional podcast style""" | |
# ํ ์คํธ ๊ธธ์ด ์ ํ | |
max_text_length = 4500 if search_context else 6000 | |
if len(text) > max_text_length: | |
text = text[:max_text_length] + "..." | |
# ์ธ์ด๋ณ ํ์ ์ด๋ฆ ์ค์ | |
if language == "Korean": | |
speaker1, speaker2 = "์ค์", "๋ฏผํธ" | |
elif language == "Japanese": | |
speaker1, speaker2 = "Hiroshi", "Takeshi" | |
elif language == "French": | |
speaker1, speaker2 = "Pierre", "Marc" | |
elif language == "German": | |
speaker1, speaker2 = "Klaus", "Stefan" | |
elif language == "Spanish": | |
speaker1, speaker2 = "Carlos", "Miguel" | |
elif language == "Italian": | |
speaker1, speaker2 = "Marco", "Giuseppe" | |
elif language == "Portuguese": | |
speaker1, speaker2 = "Joรฃo", "Pedro" | |
elif language == "Dutch": | |
speaker1, speaker2 = "Jan", "Pieter" | |
elif language == "Thai": | |
speaker1, speaker2 = "Somchai", "Prasert" | |
elif language == "Vietnamese": | |
speaker1, speaker2 = "Minh", "Duc" | |
elif language == "Arabic": | |
speaker1, speaker2 = "Ahmed", "Mohammed" | |
elif language == "Hebrew": | |
speaker1, speaker2 = "David", "Michael" | |
elif language == "Indonesian": | |
speaker1, speaker2 = "Budi", "Andi" | |
elif language == "Hindi": | |
speaker1, speaker2 = "Raj", "Amit" | |
elif language == "Russian": | |
speaker1, speaker2 = "Alexei", "Dmitri" | |
elif language == "Chinese": | |
speaker1, speaker2 = "Wei", "Jun" | |
else: # English and others | |
speaker1, speaker2 = "Alex", "Jordan" | |
# ๋ํ ํ ํ๋ฆฟ ์์ฑ | |
template = "{\n \"conversation\": [\n" | |
for i in range(12): # 12๋ฒ์ ๊ตํ | |
template += f" {{\"speaker\": \"{speaker1 if i % 2 == 0 else speaker2}\", \"text\": \"\"}}" | |
if i < 11: | |
template += "," | |
template += "\n" | |
template += " ]\n}" | |
# ์ธ์ด๋ณ ํ๋กฌํํธ ์์ฑ | |
if language == "Korean": | |
context_part = f"# ์ต์ ๊ด๋ จ ์ ๋ณด:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# ์๋ณธ ์ฝํ ์ธ :\n{text}\n\n" | |
f"{context_part}" | |
f"์ ๋ด์ฉ์ผ๋ก ์ ๋ฌธ์ ์ด๊ณ ์ฌ์ธต์ ์ธ ํ์บ์คํธ ๋๋ด ํ๋ก๊ทธ๋จ ๋๋ณธ์ ํ๊ตญ์ด๋ก ์์ฑํด์ฃผ์ธ์.\n\n" | |
f"## ํต์ฌ ์ง์นจ:\n" | |
f"1. **๋ํ ์คํ์ผ**: ์ ๋ฌธ์ ์ด๋ฉด์๋ ์ดํดํ๊ธฐ ์ฌ์ด ํ์บ์คํธ ๋๋ด\n" | |
f"2. **ํ์ ์ญํ **:\n" | |
f" - {speaker1}: ์งํ์/ํธ์คํธ (ํต์ฌ์ ์ง๋ ์ง๋ฌธ, ์ฒญ์ทจ์ ๊ด์ ์์ ๊ถ๊ธํ ์ ์ง๋ฌธ)\n" | |
f" - {speaker2}: ์ ๋ฌธ๊ฐ (๊น์ด ์๋ ์ค๋ช , ๊ตฌ์ฒด์ ์ฌ๋ก์ ๋ฐ์ดํฐ ์ ์)\n" | |
f"3. **์ค์ํ ๋ต๋ณ ๊ท์น**:\n" | |
f" - {speaker1}: 1-2๋ฌธ์ฅ์ ๋ช ํํ ์ง๋ฌธ\n" | |
f" - {speaker2}: **๋ฐ๋์ 2-4๋ฌธ์ฅ์ผ๋ก ์ถฉ์คํ ๋ต๋ณ** (๊ฐ๋ ์ค๋ช + ๊ตฌ์ฒด์ ์ค๋ช + ์์๋ ํจ์)\n" | |
f"4. **์ ๋ฌธ์ฑ ์์**: ํต๊ณ๋ ์ฐ๊ตฌ ๊ฒฐ๊ณผ ์ธ์ฉ, ์ค์ ์ฌ๋ก์ ์ผ์ด์ค ์คํฐ๋, ์ ๋ฌธ ์ฉ์ด๋ฅผ ์ฝ๊ฒ ํ์ด์ ์ค๋ช \n" | |
f"5. **ํ์ ๊ท์น**: ์๋ก ์กด๋๋ง ์ฌ์ฉ, 12ํ ๋ํ ๊ตํ, ๋ชจ๋ ๋ํ๋ ํ๊ตญ์ด๋ก ์์ฑ\n\n" | |
f"JSON ํ์์ผ๋ก๋ง ๋ฐํ:\n{template}" | |
) | |
elif language == "Japanese": | |
context_part = f"# ๆๆฐ้ข้ฃๆ ๅ ฑ:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# ๅ ใฎใณใณใใณใ:\n{text}\n\n" | |
f"{context_part}" | |
f"ไธ่จใฎๅ ๅฎนใงๅฐ้็ใงๆทฑใใใใใญใฃในใๅฏพ่ซ็ช็ตใฎๅฐๆฌใๆฅๆฌ่ชใงไฝๆใใฆใใ ใใใ\n\n" | |
f"## ้่ฆใชๆ้:\n" | |
f"1. **ๅฏพ่ฉฑในใฟใคใซ**: ๅฐ้็ใงใใใชใใ็่งฃใใใใใใใใญใฃในใๅฏพ่ซ\n" | |
f"2. **่ฉฑ่ ใฎๅฝนๅฒ**:\n" | |
f" - {speaker1}: ๅธไผ่ /ใในใ๏ผๆ ธๅฟใ็ชใ่ณชๅใ่ด่กใฎ่ฆ็นใใใฎ่ณชๅ๏ผ\n" | |
f" - {speaker2}: ๅฐ้ๅฎถ๏ผๆทฑใ่ชฌๆใๅ ทไฝ็ใชไบไพใจใใผใฟใฎๆ็คบ๏ผ\n" | |
f"3. **้่ฆใชๅ็ญใซใผใซ**:\n" | |
f" - {speaker1}: 1-2ๆใฎๆ็ขบใช่ณชๅ\n" | |
f" - {speaker2}: **ๅฟ ใ2-4ๆใงๅ ๅฎใใๅ็ญ**๏ผๆฆๅฟต่ชฌๆ + ๅ ทไฝ็่ชฌๆ + ไพ็คบใๅซๆ๏ผ\n" | |
f"4. **ๅฐ้ๆง่ฆ็ด **: ็ตฑ่จใ็ ็ฉถ็ตๆใฎๅผ็จใๅฎ้ใฎไบไพใจใฑใผในในใฟใใฃใๅฐ้็จ่ชใๅใใใใใ่ชฌๆ\n" | |
f"5. **ๅฟ ้ ใซใผใซ**: ใไบใใซไธๅฏง่ชใไฝฟ็จใ12ๅใฎๅฏพ่ฉฑไบคๆใใในใฆใฎๅฏพ่ฉฑใฏๆฅๆฌ่ชใงไฝๆ\n\n" | |
f"JSONๅฝขๅผใงใฎใฟ่ฟ็ญ:\n{template}" | |
) | |
elif language == "French": | |
context_part = f"# Derniรจres informations pertinentes:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# Contenu original:\n{text}\n\n" | |
f"{context_part}" | |
f"Crรฉez un script de dรฉbat podcast professionnel et approfondi en franรงais avec le contenu ci-dessus.\n\n" | |
f"## Directives clรฉs:\n" | |
f"1. **Style de dialogue**: Discussion de podcast professionnelle mais accessible\n" | |
f"2. **Rรดles des intervenants**:\n" | |
f" - {speaker1}: Animateur/Hรดte (questions perspicaces, perspective de l'audience)\n" | |
f" - {speaker2}: Expert (explications approfondies, exemples concrets et donnรฉes)\n" | |
f"3. **Rรจgles de rรฉponse importantes**:\n" | |
f" - {speaker1}: Questions claires en 1-2 phrases\n" | |
f" - {speaker2}: **Rรฉpondre obligatoirement en 2-4 phrases** (explication du concept + explication dรฉtaillรฉe + exemple/implication)\n" | |
f"4. **รlรฉments de professionnalisme**: Citer des statistiques et recherches, รฉtudes de cas rรฉels, expliquer clairement les termes techniques\n" | |
f"5. **Rรจgles obligatoires**: Utiliser un langage poli, 12 รฉchanges de dialogue, toute la conversation en franรงais\n\n" | |
f"Retourner uniquement en format JSON:\n{template}" | |
) | |
elif language == "German": | |
context_part = f"# Neueste relevante Informationen:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# Originalinhalt:\n{text}\n\n" | |
f"{context_part}" | |
f"Erstellen Sie ein professionelles und tiefgreifendes Podcast-Gesprรคchsskript auf Deutsch mit dem obigen Inhalt.\n\n" | |
f"## Wichtige Richtlinien:\n" | |
f"1. **Gesprรคchsstil**: Professionelle, aber zugรคngliche Podcast-Diskussion\n" | |
f"2. **Sprecherrollen**:\n" | |
f" - {speaker1}: Moderator/Gastgeber (einsichtsvolle Fragen, Publikumsperspektive)\n" | |
f" - {speaker2}: Experte (tiefgreifende Erklรคrungen, konkrete Beispiele und Daten)\n" | |
f"3. **Wichtige Antwortregeln**:\n" | |
f" - {speaker1}: Klare Fragen in 1-2 Sรคtzen\n" | |
f" - {speaker2}: **Muss in 2-4 Sรคtzen antworten** (Konzepterklรคrung + detaillierte Erklรคrung + Beispiel/Implikation)\n" | |
f"4. **Professionalitรคtselemente**: Statistiken und Forschung zitieren, echte Fallstudien, technische Begriffe klar erklรคren\n" | |
f"5. **Pflichtregeln**: Hรถfliche Sprache verwenden, 12 Gesprรคchsaustausche, gesamte Unterhaltung auf Deutsch\n\n" | |
f"Nur im JSON-Format zurรผckgeben:\n{template}" | |
) | |
elif language == "Spanish": | |
context_part = f"# รltima informaciรณn relevante:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# Contenido original:\n{text}\n\n" | |
f"{context_part}" | |
f"Cree un guiรณn de debate de podcast profesional y profundo en espaรฑol con el contenido anterior.\n\n" | |
f"## Directrices clave:\n" | |
f"1. **Estilo de diรกlogo**: Discusiรณn de podcast profesional pero accesible\n" | |
f"2. **Roles de los hablantes**:\n" | |
f" - {speaker1}: Presentador/Anfitriรณn (preguntas perspicaces, perspectiva de la audiencia)\n" | |
f" - {speaker2}: Experto (explicaciones profundas, ejemplos concretos y datos)\n" | |
f"3. **Reglas de respuesta importantes**:\n" | |
f" - {speaker1}: Preguntas claras en 1-2 oraciones\n" | |
f" - {speaker2}: **Debe responder en 2-4 oraciones** (explicaciรณn del concepto + explicaciรณn detallada + ejemplo/implicaciรณn)\n" | |
f"4. **Elementos de profesionalismo**: Citar estadรญsticas e investigaciรณn, estudios de casos reales, explicar tรฉrminos tรฉcnicos claramente\n" | |
f"5. **Reglas obligatorias**: Usar lenguaje cortรฉs, 12 intercambios de diรกlogo, toda la conversaciรณn en espaรฑol\n\n" | |
f"Devolver solo en formato JSON:\n{template}" | |
) | |
elif language == "Italian": | |
context_part = f"# Ultime informazioni rilevanti:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# Contenuto originale:\n{text}\n\n" | |
f"{context_part}" | |
f"Crea uno script di dibattito podcast professionale e approfondito in italiano con il contenuto sopra.\n\n" | |
f"## Linee guida chiave:\n" | |
f"1. **Stile di dialogo**: Discussione podcast professionale ma accessibile\n" | |
f"2. **Ruoli degli speaker**:\n" | |
f" - {speaker1}: Conduttore/Ospite (domande perspicaci, prospettiva del pubblico)\n" | |
f" - {speaker2}: Esperto (spiegazioni approfondite, esempi concreti e dati)\n" | |
f"3. **Regole di risposta importanti**:\n" | |
f" - {speaker1}: Domande chiare in 1-2 frasi\n" | |
f" - {speaker2}: **Deve rispondere in 2-4 frasi** (spiegazione del concetto + spiegazione dettagliata + esempio/implicazione)\n" | |
f"4. **Elementi di professionalitร **: Citare statistiche e ricerche, studi di casi reali, spiegare chiaramente termini tecnici\n" | |
f"5. **Regole obbligatorie**: Usare linguaggio cortese, 12 scambi di dialogo, tutta la conversazione in italiano\n\n" | |
f"Restituire solo in formato JSON:\n{template}" | |
) | |
elif language == "Portuguese": | |
context_part = f"# รltimas informaรงรตes relevantes:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# Conteรบdo original:\n{text}\n\n" | |
f"{context_part}" | |
f"Crie um roteiro de debate de podcast profissional e aprofundado em portuguรชs com o conteรบdo acima.\n\n" | |
f"## Diretrizes principais:\n" | |
f"1. **Estilo de diรกlogo**: Discussรฃo de podcast profissional mas acessรญvel\n" | |
f"2. **Papรฉis dos falantes**:\n" | |
f" - {speaker1}: Apresentador/Anfitriรฃo (perguntas perspicazes, perspectiva da audiรชncia)\n" | |
f" - {speaker2}: Especialista (explicaรงรตes aprofundadas, exemplos concretos e dados)\n" | |
f"3. **Regras de resposta importantes**:\n" | |
f" - {speaker1}: Perguntas claras em 1-2 frases\n" | |
f" - {speaker2}: **Deve responder em 2-4 frases** (explicaรงรฃo do conceito + explicaรงรฃo detalhada + exemplo/implicaรงรฃo)\n" | |
f"4. **Elementos de profissionalismo**: Citar estatรญsticas e pesquisas, estudos de casos reais, explicar termos tรฉcnicos claramente\n" | |
f"5. **Regras obrigatรณrias**: Usar linguagem cortรชs, 12 trocas de diรกlogo, toda a conversa em portuguรชs\n\n" | |
f"Retornar apenas em formato JSON:\n{template}" | |
) | |
elif language == "Chinese": | |
context_part = f"# ๆๆฐ็ธๅ ณไฟกๆฏ:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# ๅๅงๅ ๅฎน:\n{text}\n\n" | |
f"{context_part}" | |
f"่ฏท็จไธ่ฟฐๅ ๅฎนๅๅปบไธไธชไธไธๆทฑๅ ฅ็ๆญๅฎขๅฏน่ฏ่็ฎๅงๆฌ๏ผไฝฟ็จไธญๆใ\n\n" | |
f"## ๅ ณ้ฎๆๅฏผๅๅ:\n" | |
f"1. **ๅฏน่ฏ้ฃๆ ผ**: ไธไธไฝๆไบ็่งฃ็ๆญๅฎข่ฎจ่ฎบ\n" | |
f"2. **่ฏด่ฏ่ ่ง่ฒ**:\n" | |
f" - {speaker1}: ไธปๆไบบ๏ผๆ่งๅฐ็้ฎ้ข๏ผๅฌไผ่ง่ง๏ผ\n" | |
f" - {speaker2}: ไธๅฎถ๏ผๆทฑๅ ฅ่งฃ้๏ผๅ ทไฝไพๅญๅๆฐๆฎ๏ผ\n" | |
f"3. **้่ฆๅ็ญ่งๅ**:\n" | |
f" - {speaker1}: 1-2ๅฅๆธ ๆฐ็้ฎ้ข\n" | |
f" - {speaker2}: **ๅฟ ้กป็จ2-4ๅฅ่ฏๅ็ญ**๏ผๆฆๅฟต่งฃ้ + ่ฏฆ็ป่งฃ้ + ไพๅญ/ๅซไน๏ผ\n" | |
f"4. **ไธไธๅ ็ด **: ๅผ็จ็ป่ฎกๆฐๆฎๅ็ ็ฉถ๏ผ็ๅฎๆกไพ็ ็ฉถ๏ผๆธ ๆฅ่งฃ้ๆๆฏๆฏ่ฏญ\n" | |
f"5. **ๅฟ ่ฆ่งๅ**: ไฝฟ็จ็คผ่ฒ่ฏญ่จ๏ผ12ๆฌกๅฏน่ฏไบคๆข๏ผๆๆๅฏน่ฏ้ฝ็จไธญๆ\n\n" | |
f"ไป ไปฅJSONๆ ผๅผ่ฟๅ:\n{template}" | |
) | |
elif language == "Russian": | |
context_part = f"# ะะพัะปะตะดะฝัั ัะตะปะตะฒะฐะฝัะฝะฐั ะธะฝัะพัะผะฐัะธั:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# ะัะธะณะธะฝะฐะปัะฝัะน ะบะพะฝัะตะฝั:\n{text}\n\n" | |
f"{context_part}" | |
f"ะกะพะทะดะฐะนัะต ะฟัะพัะตััะธะพะฝะฐะปัะฝัะน ะธ ะณะปัะฑะพะบะธะน ััะตะฝะฐัะธะน ะฟะพะดะบะฐัั-ะดะตะฑะฐัะพะฒ ะฝะฐ ััััะบะพะผ ัะทัะบะต ั ะฟัะธะฒะตะดะตะฝะฝัะผ ะฒััะต ัะพะดะตัะถะฐะฝะธะตะผ.\n\n" | |
f"## ะะปััะตะฒัะต ะฟัะธะฝัะธะฟั:\n" | |
f"1. **ะกัะธะปั ะดะธะฐะปะพะณะฐ**: ะัะพัะตััะธะพะฝะฐะปัะฝะพะต, ะฝะพ ะดะพัััะฟะฝะพะต ะพะฑััะถะดะตะฝะธะต ะฟะพะดะบะฐััะฐ\n" | |
f"2. **ะ ะพะปะธ ะณะพะฒะพัััะธั **:\n" | |
f" - {speaker1}: ะะตะดััะธะน/ะฅะพัั (ะฟัะพะฝะธัะฐัะตะปัะฝัะต ะฒะพะฟัะพัั, ะฟะตััะฟะตะบัะธะฒะฐ ะฐัะดะธัะพัะธะธ)\n" | |
f" - {speaker2}: ะญะบัะฟะตัั (ะณะปัะฑะพะบะธะต ะพะฑัััะฝะตะฝะธั, ะบะพะฝะบัะตัะฝัะต ะฟัะธะผะตัั ะธ ะดะฐะฝะฝัะต)\n" | |
f"3. **ะะฐะถะฝัะต ะฟัะฐะฒะธะปะฐ ะพัะฒะตัะพะฒ**:\n" | |
f" - {speaker1}: ะงะตัะบะธะต ะฒะพะฟัะพัั ะฒ 1-2 ะฟัะตะดะปะพะถะตะฝะธัั \n" | |
f" - {speaker2}: **ะะพะปะถะตะฝ ะพัะฒะตัะฐัั ะฒ 2-4 ะฟัะตะดะปะพะถะตะฝะธัั ** (ะพะฑัััะฝะตะฝะธะต ะบะพะฝัะตะฟัะธะธ + ะฟะพะดัะพะฑะฝะพะต ะพะฑัััะฝะตะฝะธะต + ะฟัะธะผะตั/ะธะผะฟะปะธะบะฐัะธั)\n" | |
f"4. **ะญะปะตะผะตะฝัั ะฟัะพัะตััะธะพะฝะฐะปะธะทะผะฐ**: ะฆะธัะธัะพะฒะฐัั ััะฐัะธััะธะบั ะธ ะธััะปะตะดะพะฒะฐะฝะธั, ัะตะฐะปัะฝัะต ะบะตะนั-ััะฐะดะธ, ัะตัะบะพ ะพะฑัััะฝััั ัะตั ะฝะธัะตัะบะธะต ัะตัะผะธะฝั\n" | |
f"5. **ะะฑัะทะฐัะตะปัะฝัะต ะฟัะฐะฒะธะปะฐ**: ะัะฟะพะปัะทะพะฒะฐัั ะฒะตะถะปะธะฒัะน ัะทัะบ, 12 ะพะฑะผะตะฝะพะฒ ะดะธะฐะปะพะณะฐ, ะฒัั ะฑะตัะตะดะฐ ะฝะฐ ััััะบะพะผ ัะทัะบะต\n\n" | |
f"ะะตัะฝััั ัะพะปัะบะพ ะฒ ัะพัะผะฐัะต JSON:\n{template}" | |
) | |
else: # English and other languages | |
context_part = f"# Latest Information:\n{search_context}\n" if search_context else "" | |
base_prompt = ( | |
f"# Content:\n{text}\n\n" | |
f"{context_part}" | |
f"Create a professional and insightful podcast conversation in {language}.\n\n" | |
f"## Key Guidelines:\n" | |
f"1. **Style**: Professional yet accessible podcast discussion\n" | |
f"2. **Roles**:\n" | |
f" - {speaker1}: Host (insightful questions, audience perspective)\n" | |
f" - {speaker2}: Expert (in-depth explanations, concrete examples and data)\n" | |
f"3. **Critical Response Rules**:\n" | |
f" - {speaker1}: 1-2 sentence clear questions\n" | |
f" - {speaker2}: **Must answer in 2-4 sentences** (concept + detailed explanation + example/implication)\n" | |
f"4. **Professional Elements**: Cite statistics and research, real cases and case studies, explain technical terms clearly\n" | |
f"5. **Language**: All dialogue must be in {language}, 12 exchanges total\n\n" | |
f"Return JSON only:\n{template}" | |
) | |
return base_prompt | |
def _build_messages_for_local(self, text: str, language: str = "English", search_context: str = "") -> List[Dict]: | |
"""Build messages for local LLM with enhanced professional podcast style""" | |
if language == "Korean": | |
system_message = ( | |
"๋น์ ์ ํ๊ตญ ์ต๊ณ ์ ์ ๋ฌธ ํ์บ์คํธ ์๊ฐ์ ๋๋ค. " | |
"์ฒญ์ทจ์๋ค์ด ์ ๋ฌธ ์ง์์ ์ฝ๊ฒ ์ดํดํ ์ ์๋ ๊ณ ํ์ง ๋๋ด์ ํ๊ตญ์ด๋ก ๋ง๋ค์ด๋ ๋๋ค. " | |
"๋ฐ๋์ ์๋ก ์กด๋๋ง์ ์ฌ์ฉํ๋ฉฐ, ์ ๋ฌธ์ ์ด๋ฉด์๋ ์น๊ทผํ ํค์ ์ ์งํฉ๋๋ค. " | |
"๋ชจ๋ ๋ํ๋ ๋ฐ๋์ ํ๊ตญ์ด๋ก ์์ฑํด์ฃผ์ธ์." | |
) | |
elif language == "Japanese": | |
system_message = ( | |
"ใใชใใฏๆฅๆฌใฎๆ้ซใฎใใญใใงใใทใงใใซใใใใญใฃในใไฝๅฎถใงใใ" | |
"่ด่กใๅฐ้็ฅ่ญใ็ฐกๅใซ็่งฃใงใใ้ซๅ่ณชใชๅฏพ่ซใๆฅๆฌ่ชใงไฝๆใใพใใ" | |
"ๅฟ ใใไบใใซไธๅฏง่ชใไฝฟ็จใใๅฐ้็ใงใใใชใใ่ฆชใใฟใใใใใผใณใ็ถญๆใใฆใใ ใใใ" | |
"ใในใฆใฎๅฏพ่ฉฑใฏๅฟ ใๆฅๆฌ่ชใงๆธใใฆใใ ใใใ" | |
) | |
elif language == "French": | |
system_message = ( | |
"Vous รชtes le meilleur scรฉnariste de podcast professionnel de France. " | |
"Crรฉez des discussions de haute qualitรฉ en franรงais qui permettent au public " | |
"de comprendre facilement les connaissances spรฉcialisรฉes. " | |
"Maintenez un ton professionnel mais accessible. " | |
"Toutes les conversations doivent รชtre รฉcrites en franรงais." | |
) | |
elif language == "German": | |
system_message = ( | |
"Sie sind der beste professionelle Podcast-Drehbuchautor Deutschlands. " | |
"Erstellen Sie hochwertige Diskussionen auf Deutsch, die es dem Publikum ermรถglichen, " | |
"Fachwissen leicht zu verstehen. " | |
"Bewahren Sie einen professionellen, aber zugรคnglichen Ton. " | |
"Alle Gesprรคche mรผssen auf Deutsch geschrieben werden." | |
) | |
elif language == "Spanish": | |
system_message = ( | |
"Eres el mejor guionista de podcast profesional de Espaรฑa. " | |
"Crea discusiones de alta calidad en espaรฑol que permitan a la audiencia " | |
"entender fรกcilmente el conocimiento especializado. " | |
"Mantรฉn un tono profesional pero accesible. " | |
"Todas las conversaciones deben estar escritas en espaรฑol." | |
) | |
elif language == "Italian": | |
system_message = ( | |
"Sei il migliore sceneggiatore di podcast professionali d'Italia. " | |
"Crea discussioni di alta qualitร in italiano che permettano al pubblico " | |
"di comprendere facilmente le conoscenze specialistiche. " | |
"Mantieni un tono professionale ma accessibile. " | |
"Tutte le conversazioni devono essere scritte in italiano." | |
) | |
elif language == "Portuguese": | |
system_message = ( | |
"Vocรช รฉ o melhor roteirista de podcast profissional do Brasil. " | |
"Crie discussรตes de alta qualidade em portuguรชs que permitam ao pรบblico " | |
"entender facilmente o conhecimento especializado. " | |
"Mantenha um tom profissional mas acessรญvel. " | |
"Todas as conversas devem ser escritas em portuguรชs." | |
) | |
elif language == "Chinese": | |
system_message = ( | |
"ๆจๆฏไธญๅฝๆๅฅฝ็ไธไธๆญๅฎข็ผๅงใ" | |
"ๅๅปบ้ซ่ดจ้็ไธญๆ่ฎจ่ฎบ๏ผ่ฎฉ่งไผ่ฝๅค่ฝปๆพ็่งฃไธไธ็ฅ่ฏใ" | |
"ไฟๆไธไธไฝๅนณๆ่ฟไบบ็่ฏญ่ฐใ" | |
"ๆๆๅฏน่ฏ้ฝๅฟ ้กป็จไธญๆไนฆๅใ" | |
) | |
elif language == "Russian": | |
system_message = ( | |
"ะั ะปัััะธะน ะฟัะพัะตััะธะพะฝะฐะปัะฝัะน ััะตะฝะฐัะธัั ะฟะพะดะบะฐััะพะฒ ะฒ ะ ะพััะธะธ. " | |
"ะกะพะทะดะฐะฒะฐะนัะต ะฒััะพะบะพะบะฐัะตััะฒะตะฝะฝัะต ะดะธัะบัััะธะธ ะฝะฐ ััััะบะพะผ ัะทัะบะต, ะบะพัะพััะต ะฟะพะทะฒะพะปััั ะฐัะดะธัะพัะธะธ " | |
"ะปะตะณะบะพ ะฟะพะฝะธะผะฐัั ัะฟะตัะธะฐะปะธะทะธัะพะฒะฐะฝะฝัะต ะทะฝะฐะฝะธั. " | |
"ะะพะดะดะตัะถะธะฒะฐะนัะต ะฟัะพัะตััะธะพะฝะฐะปัะฝัะน, ะฝะพ ะดะพัััะฟะฝัะน ัะพะฝ. " | |
"ะัะต ัะฐะทะณะพะฒะพัั ะดะพะปะถะฝั ะฑััั ะฝะฐะฟะธัะฐะฝั ะฝะฐ ััััะบะพะผ ัะทัะบะต." | |
) | |
else: | |
system_message = ( | |
f"You are an expert podcast scriptwriter creating high-quality " | |
f"professional discussions in {language}. Make complex topics accessible " | |
f"while maintaining expertise and a professional yet approachable tone. " | |
f"All conversations must be written in {language}." | |
) | |
return [ | |
{"role": "system", "content": system_message}, | |
{"role": "user", "content": self._build_prompt(text, language, search_context)} | |
] | |
def extract_conversation_local(self, text: str, language: str = "English", progress=None) -> Dict: | |
"""Extract conversation using new local LLM with enhanced professional style""" | |
try: | |
# ๊ฒ์ ์ปจํ ์คํธ ์์ฑ (ํค์๋ ๊ธฐ๋ฐ์ด ์๋ ๊ฒฝ์ฐ) | |
search_context = "" | |
if BRAVE_KEY and not text.startswith("Keyword-based content:"): | |
try: | |
keywords = extract_keywords_for_search(text, language) | |
if keywords: | |
search_query = keywords[0] if language == "Korean" else f"{keywords[0]} latest news" | |
search_context = format_search_results(search_query) | |
print(f"Search context added for: {search_query}") | |
except Exception as e: | |
print(f"Search failed, continuing without context: {e}") | |
# ๋จผ์ ์๋ก์ด ๋ก์ปฌ LLM ์๋ | |
self.initialize_local_mode() | |
chat_template = self._get_messages_formatter_type(self.config.local_model_name) | |
provider = LlamaCppPythonProvider(self.local_llm) | |
# ์ธ์ด๋ณ ์์คํ ๋ฉ์์ง | |
if language == "Korean": | |
system_message = ( | |
"๋น์ ์ ํ๊ตญ์ ์ ๋ช ํ์บ์คํธ ์ ๋ฌธ ์๊ฐ์ ๋๋ค. " | |
"์ฒญ์ทจ์๋ค์ด ๊น์ด ์๋ ์ ๋ฌธ ์ง์์ ์ป์ ์ ์๋ ๊ณ ํ์ง ๋๋ด์ ํ๊ตญ์ด๋ก ๋ง๋ญ๋๋ค. " | |
"๋ฐ๋์ ์๋ก ์กด๋๋ง์ ์ฌ์ฉํ๋ฉฐ, 12ํ์ ๋ํ ๊ตํ์ผ๋ก ๊ตฌ์ฑํ์ธ์. " | |
"๋ชจ๋ ๋ํ๋ ๋ฐ๋์ ํ๊ตญ์ด๋ก ์์ฑํ๊ณ JSON ํ์์ผ๋ก๋ง ์๋ตํ์ธ์." | |
) | |
elif language == "Japanese": | |
system_message = ( | |
"ใใชใใฏๆฅๆฌใฎๆๅใชใใใใญใฃในใๅฐ้ไฝๅฎถใงใใ" | |
"่ด่กใๆทฑใๅฐ้็ฅ่ญใๅพใใใ้ซๅ่ณชใชๅฏพ่ซใๆฅๆฌ่ชใงไฝๆใใพใใ" | |
"ๅฟ ใใไบใใซไธๅฏง่ชใไฝฟ็จใใ12ๅใฎๅฏพ่ฉฑไบคๆใงๆงๆใใฆใใ ใใใ" | |
"ใในใฆใฎๅฏพ่ฉฑใฏๅฟ ใๆฅๆฌ่ชใงไฝๆใใJSONๅฝขๅผใงใฎใฟๅ็ญใใฆใใ ใใใ" | |
) | |
elif language == "French": | |
system_message = ( | |
"Vous รชtes un cรฉlรจbre scรฉnariste de podcast professionnel franรงais. " | |
"Crรฉez des discussions de haute qualitรฉ en franรงais qui donnent au public " | |
"des connaissances professionnelles approfondies. " | |
"Crรฉez exactement 12 รฉchanges de conversation et rรฉpondez uniquement en format JSON." | |
) | |
elif language == "German": | |
system_message = ( | |
"Sie sind ein berรผhmter professioneller Podcast-Drehbuchautor aus Deutschland. " | |
"Erstellen Sie hochwertige Diskussionen auf Deutsch, die dem Publikum " | |
"tiefgreifendes Fachwissen vermitteln. " | |
"Erstellen Sie genau 12 Gesprรคchsaustausche und antworten Sie nur im JSON-Format." | |
) | |
elif language == "Spanish": | |
system_message = ( | |
"Eres un famoso guionista de podcast profesional espaรฑol. " | |
"Crea discusiones de alta calidad en espaรฑol que brinden al pรบblico " | |
"conocimientos profesionales profundos. " | |
"Crea exactamente 12 intercambios de conversaciรณn y responde solo en formato JSON." | |
) | |
elif language == "Italian": | |
system_message = ( | |
"Sei un famoso sceneggiatore di podcast professionali italiano. " | |
"Crea discussioni di alta qualitร in italiano che forniscano al pubblico " | |
"conoscenze professionali approfondite. " | |
"Crea esattamente 12 scambi di conversazione e rispondi solo in formato JSON." | |
) | |
elif language == "Portuguese": | |
system_message = ( | |
"Vocรช รฉ um famoso roteirista de podcast profissional brasileiro. " | |
"Crie discussรตes de alta qualidade em portuguรชs que forneรงam ao pรบblico " | |
"conhecimentos profissionais aprofundados. " | |
"Crie exatamente 12 trocas de conversa e responda apenas em formato JSON." | |
) | |
elif language == "Chinese": | |
system_message = ( | |
"ๆจๆฏไธญๅฝ่ๅ็ไธไธๆญๅฎข็ผๅงใ" | |
"ๅๅปบ้ซ่ดจ้็ไธญๆ่ฎจ่ฎบ๏ผไธบ่งไผๆไพๆทฑๅ ฅ็ไธไธ็ฅ่ฏใ" | |
"ๅๅปบๆฐๅฅฝ12ๆฌกๅฏน่ฏไบคๆข๏ผไป ไปฅJSONๆ ผๅผๅ็ญใ" | |
) | |
elif language == "Russian": | |
system_message = ( | |
"ะั ะธะทะฒะตััะฝัะน ะฟัะพัะตััะธะพะฝะฐะปัะฝัะน ััะตะฝะฐัะธัั ะฟะพะดะบะฐััะพะฒ ะธะท ะ ะพััะธะธ. " | |
"ะกะพะทะดะฐะฒะฐะนัะต ะฒััะพะบะพะบะฐัะตััะฒะตะฝะฝัะต ะดะธัะบัััะธะธ ะฝะฐ ััััะบะพะผ ัะทัะบะต, ะบะพัะพััะต ะดะฐัั ะฐัะดะธัะพัะธะธ " | |
"ะณะปัะฑะพะบะธะต ะฟัะพัะตััะธะพะฝะฐะปัะฝัะต ะทะฝะฐะฝะธั. " | |
"ะกะพะทะดะฐะนัะต ัะพะฒะฝะพ 12 ะพะฑะผะตะฝะพะฒ ัะฐะทะณะพะฒะพัะพะผ ะธ ะพัะฒะตัะฐะนัะต ัะพะปัะบะพ ะฒ ัะพัะผะฐัะต JSON." | |
) | |
else: | |
system_message = ( | |
f"You are a professional podcast scriptwriter creating high-quality, " | |
f"insightful discussions in {language}. Create exactly 12 conversation exchanges " | |
f"with professional expertise. All dialogue must be in {language}. " | |
f"Respond only in JSON format." | |
) | |
agent = LlamaCppAgent( | |
provider, | |
system_prompt=system_message, | |
predefined_messages_formatter_type=chat_template, | |
debug_output=False | |
) | |
settings = provider.get_provider_default_settings() | |
settings.temperature = 0.75 | |
settings.top_k = 40 | |
settings.top_p = 0.95 | |
settings.max_tokens = self.config.max_tokens | |
settings.repeat_penalty = 1.1 | |
settings.stream = False | |
messages = BasicChatHistory() | |
prompt = self._build_prompt(text, language, search_context) | |
response = agent.get_chat_response( | |
prompt, | |
llm_sampling_settings=settings, | |
chat_history=messages, | |
returns_streaming_generator=False, | |
print_output=False | |
) | |
# JSON ํ์ฑ | |
pattern = r"\{(?:[^{}]|(?:\{[^{}]*\}))*\}" | |
json_match = re.search(pattern, response) | |
if json_match: | |
conversation_data = json.loads(json_match.group()) | |
return conversation_data | |
else: | |
raise ValueError("No valid JSON found in local LLM response") | |
except Exception as e: | |
print(f"Local LLM failed: {e}, falling back to legacy local method") | |
return self.extract_conversation_legacy_local(text, language, progress, search_context) | |
def extract_conversation_legacy_local(self, text: str, language: str = "English", progress=None, search_context: str = "") -> Dict: | |
"""Extract conversation using legacy local model""" | |
try: | |
self.initialize_legacy_local_mode() | |
# ์ธ์ด๋ณ ์์คํ ๋ฉ์์ง | |
if language == "Korean": | |
system_message = ( | |
"๋น์ ์ ์ ๋ฌธ ํ์บ์คํธ ์๊ฐ์ ๋๋ค. " | |
"12ํ์ ๋ํ ๊ตํ์ผ๋ก ๊ตฌ์ฑ๋ ์ ๋ฌธ์ ์ธ ๋๋ด์ ํ๊ตญ์ด๋ก ๋ง๋์ธ์. " | |
"๋ชจ๋ ๋ํ๋ ๋ฐ๋์ ํ๊ตญ์ด๋ก ์์ฑํด์ฃผ์ธ์." | |
) | |
elif language == "Japanese": | |
system_message = ( | |
"ใใชใใฏๅฐ้็ใชใใใใญใฃในใไฝๅฎถใงใใ" | |
"12ๅใฎๅฏพ่ฉฑไบคๆใงๆงๆใใใๅฐ้็ใชๅฏพ่ซใๆฅๆฌ่ชใงไฝๆใใฆใใ ใใใ" | |
"ใในใฆใฎๅฏพ่ฉฑใฏๅฟ ใๆฅๆฌ่ชใงไฝๆใใฆใใ ใใใ" | |
) | |
elif language == "French": | |
system_message = ( | |
"Vous รชtes un scรฉnariste de podcast professionnel. " | |
"Crรฉez un dialogue professionnel composรฉ de 12 รฉchanges de conversation en franรงais. " | |
"Toutes les conversations doivent รชtre รฉcrites en franรงais." | |
) | |
elif language == "German": | |
system_message = ( | |
"Sie sind ein professioneller Podcast-Drehbuchautor. " | |
"Erstellen Sie einen professionellen Dialog aus 12 Gesprรคchsaustauschen auf Deutsch. " | |
"Alle Gesprรคche mรผssen auf Deutsch geschrieben werden." | |
) | |
elif language == "Spanish": | |
system_message = ( | |
"Eres un guionista de podcast profesional. " | |
"Crea un diรกlogo profesional compuesto por 12 intercambios de conversaciรณn en espaรฑol. " | |
"Todas las conversaciones deben estar escritas en espaรฑol." | |
) | |
elif language == "Chinese": | |
system_message = ( | |
"ๆจๆฏไธไธๆญๅฎข็ผๅงใ" | |
"ๅๅปบ็ฑ12ๆฌกๅฏน่ฏไบคๆข็ปๆ็ไธไธๅฏน่ฏ๏ผไฝฟ็จไธญๆใ" | |
"ๆๆๅฏน่ฏ้ฝๅฟ ้กป็จไธญๆไนฆๅใ" | |
) | |
elif language == "Russian": | |
system_message = ( | |
"ะั ะฟัะพัะตััะธะพะฝะฐะปัะฝัะน ััะตะฝะฐัะธัั ะฟะพะดะบะฐััะพะฒ. " | |
"ะกะพะทะดะฐะนัะต ะฟัะพัะตััะธะพะฝะฐะปัะฝัะน ะดะธะฐะปะพะณ ะธะท 12 ะพะฑะผะตะฝะพะฒ ัะฐะทะณะพะฒะพัะพะผ ะฝะฐ ััััะบะพะผ ัะทัะบะต. " | |
"ะัะต ัะฐะทะณะพะฒะพัั ะดะพะปะถะฝั ะฑััั ะฝะฐะฟะธัะฐะฝั ะฝะฐ ััััะบะพะผ ัะทัะบะต." | |
) | |
else: | |
system_message = ( | |
f"You are a professional podcast scriptwriter. " | |
f"Create a professional dialogue in {language} with 12 exchanges. " | |
f"All conversations must be written in {language}." | |
) | |
chat = [ | |
{"role": "system", "content": system_message}, | |
{"role": "user", "content": self._build_prompt(text, language, search_context)} | |
] | |
terminators = [ | |
self.legacy_tokenizer.eos_token_id, | |
self.legacy_tokenizer.convert_tokens_to_ids("<|eot_id|>") | |
] | |
messages = self.legacy_tokenizer.apply_chat_template( | |
chat, tokenize=False, add_generation_prompt=True | |
) | |
model_inputs = self.legacy_tokenizer([messages], return_tensors="pt").to(self.device) | |
streamer = TextIteratorStreamer( | |
self.legacy_tokenizer, timeout=10.0, skip_prompt=True, skip_special_tokens=True | |
) | |
generate_kwargs = dict( | |
model_inputs, | |
streamer=streamer, | |
max_new_tokens=self.config.max_new_tokens, | |
do_sample=True, | |
temperature=0.75, | |
eos_token_id=terminators, | |
) | |
t = Thread(target=self.legacy_local_model.generate, kwargs=generate_kwargs) | |
t.start() | |
partial_text = "" | |
for new_text in streamer: | |
partial_text += new_text | |
pattern = r"\{(?:[^{}]|(?:\{[^{}]*\}))*\}" | |
json_match = re.search(pattern, partial_text) | |
if json_match: | |
return json.loads(json_match.group()) | |
else: | |
raise ValueError("No valid JSON found in legacy local response") | |
except Exception as e: | |
print(f"Legacy local model also failed: {e}") | |
return self._get_default_conversation(language) | |
def _get_default_conversation(self, language: str) -> Dict: | |
"""์ธ์ด๋ณ ๊ธฐ๋ณธ ๋ํ ํ ํ๋ฆฟ""" | |
if language == "Korean": | |
return self._get_default_korean_conversation() | |
elif language == "Japanese": | |
return self._get_default_japanese_conversation() | |
elif language == "French": | |
return self._get_default_french_conversation() | |
elif language == "German": | |
return self._get_default_german_conversation() | |
elif language == "Spanish": | |
return self._get_default_spanish_conversation() | |
elif language == "Chinese": | |
return self._get_default_chinese_conversation() | |
elif language == "Russian": | |
return self._get_default_russian_conversation() | |
else: | |
return self._get_default_english_conversation() | |
def _get_default_japanese_conversation(self) -> Dict: | |
"""๊ธฐ๋ณธ ์ผ๋ณธ์ด ๋ํ ํ ํ๋ฆฟ""" | |
return { | |
"conversation": [ | |
{"speaker": "Hiroshi", "text": "็ใใใใใใซใกใฏ๏ผไปๆฅใฏๆฌๅฝใซ้่ฆใง่ๅณๆทฑใใใใใฏใซใคใใฆ่ฉฑใๅใใใใจๆใใพใใ้ซๆฉๅ ็ใใพใใใฎ่ฉฑ้กใใชใไปใใใปใฉๆณจ็ฎใใใฆใใใฎใ่ชฌๆใใฆใใใ ใใพใใ๏ผ"}, | |
{"speaker": "Takeshi", "text": "ใใใซใกใฏใๆ่ฟใใฎๅ้ใง็ปๆ็ใช้ฒๅฑใใใใพใใใ็นใซๆจๅนดใฎMIT็ ็ฉถใใผใ ใฎ็บ่กจใซใใใจใใใฎๆ่กใฎๅน็ๆงใๅพๆฅๆฏใง300%ๅไธใใใจใฎใใจใงใใใใใฏๅใชใๆ่ก็้ฒๆญฉใ่ถ ใใฆใ็งใใกใฎๆฅๅธธ็ๆดปใซ็ดๆฅ็ใชๅฝฑ้ฟใไธใใๅฏ่ฝๆงใใใๅคๅใงใใๅฎ้ใซGoogleใMicrosoftใชใฉใฎๅคงๆใใใฏไผๆฅญใใใงใซๆฐๅๅใใซใๆ่ณใใฆใใพใใ"}, | |
{"speaker": "Hiroshi", "text": "300%ใฎๅไธใจใฏๆฌๅฝใซ้ฉใในใใใจใงใใญใใใใงใฏใใใฎใใใชๆ่ก็บๅฑใไธ่ฌใฎไบบใ ใซใจใฃใฆๅ ทไฝ็ใซใฉใฎใใใชๅฉ็ใใใใใใฎใงใใใใ๏ผ"}, | |
{"speaker": "Takeshi", "text": "ๆใ็ดๆฅ็ใชๅฉ็ใฏใณในใๅๆธใจใขใฏใปใทใใชใใฃใฎๅไธใงใใไพใใฐใไปฅๅใฏๅฐ้ๅฎถใฎใฟใไฝฟ็จใงใใ้ซๅบฆใชๆฉ่ฝใใไปใงใฏในใใผใใใฉใณใขใใชใงใๅฎ่ฃ ๅฏ่ฝใซใชใใพใใใMcKinseyใฎใฌใใผใใซใใใจใ2025ๅนดใพใงใซใใฎๆ่กใซใใไธ็็ใซ็ด2ๅ ใใซใฎ็ตๆธไพกๅคใๅตๅบใใใใจไบๆณใใใฆใใพใใ็นใซๅป็ใๆ่ฒใ้่ๅ้ใง้ฉๆฐ็ใชๅคๅใ่ตทใใใจ่ฆใใใฆใใพใใ"}, | |
{"speaker": "Hiroshi", "text": "2ๅ ใใซใจใใ enormous ใช่ฆๆจกใงใใญใๅป็ๅ้ใงใฏใฉใฎใใใชๅคๅใไบๆณใใใพใใ๏ผ"}, | |
{"speaker": "Takeshi", "text": "ๅป็ๅ้ใฎๅคๅใฏๆฌๅฝใซ้ฉๅฝ็ใซใชใใจไบๆณใใใพใใใใงใซในใฟใณใใฉใผใๅคงๅญฆ็ ้ขใงใฏใใใฎๆ่กใๆดป็จใใฆใใ่จบๆญใฎ็ฒพๅบฆใ95%ใพใง้ซใใพใใใๅพๆฅใงใฏ็็ทดใใๅปๅธซใงใ่ฆ่ฝใจใๅฏ่ฝๆงใฎใใฃใๅพฎ็ดฐใช็ ๅคใAIใๆคๅบใใใฎใงใใใใใซ้ฉใในใใใจใฏใใใฎใใใช่จบๆญใใใใๆฐๅใง่กใใใใใจใงใใWHO ใฎๆจ่จใงใฏใใใฎๆ่กใไธ็็ใซๆฎๅใใใฐใๅนด้ๆฐ็พไธไบบใฎๅฝใๆใใใจใใงใใใจไบๆธฌใใฆใใพใใ"}, | |
{"speaker": "Hiroshi", "text": "ๆฌๅฝใซๅฐ่ฑก็ใงใใญใใใใใใใฎใใใชๆฅ้ใชๆ่ก็บๅฑใซๅฏพใใๆธๅฟตใฎๅฃฐใใใใงใใใใญ๏ผ"}, | |
{"speaker": "Takeshi", "text": "ใใฃใใใ้ใใงใใไธปใชๆธๅฟตไบ้ ใฏๅคงใใ3ใคใใใพใใ็ฌฌไธใฏ้็จไปฃๆฟๅ้กใงใใชใใฏในใใฉใผใๅคงๅญฆใฎ็ ็ฉถใซใใใจใไปๅพ20ๅนดไปฅๅ ใซ็พๅจใฎ่ทๆฅญใฎ47%ใ่ชๅๅใใใๅฑ้บๆงใใใใพใใ็ฌฌไบใฏใใฉใคใใทใผใจใปใญใฅใชใใฃใฎๅ้กใงใใ็ฌฌไธใฏๆ่กๆ ผๅทฎใซใใไธๅนณ็ญใฎๆทฑๅปๅใงใใใใใๆญดๅฒ็ใซ่ฆใใจใๆฐใใๆ่กใฏๅธธใซๆฐใใๆฉไผใๅๆใซไฝใๅบใใฆใใใใใ้ฉๅใชๆฟ็ญใจๆ่ฒใซใใฃใฆใใใใฎๅ้กใ่งฃๆฑบใงใใใจ่ใใฆใใพใใ"}, | |
{"speaker": "Hiroshi", "text": "ใใฉใณในใฎๅใใ่ฆ็นใ้่ฆใงใใญใใใใงใฏใ็งใใกใฏใใฎใใใชๅคๅใซใฉใฎใใใซๅใใในใใงใใใใ๏ผ"}, | |
{"speaker": "Takeshi", "text": "ๆใ้่ฆใชใฎใฏ็ถ็ถ็ใชๅญฆ็ฟใจ้ฉๅฟๅใงใใไธ็็ตๆธใใฉใผใฉใ ใฏใ2025ๅนดใพใงใซไธ็ใฎๅดๅ่ ใฎ50%ใๅๆ่ฒใๅฟ ่ฆใจใใใจไบๆธฌใใพใใใ็นใซใใธใฟใซใชใใฉใทใผใๆนๅค็ๆ่ๅใๅต้ ๆงใชใฉใฎ่ฝๅใ้่ฆใซใชใใงใใใใๅไบบ็ใซใฏใใชใณใฉใคใณๆ่ฒใใฉใใใใฉใผใ ใๆดป็จใใ่ชๅทฑๅ็บใใๅงใใใพใใไพใใฐใCourseraใedXใชใฉใฎใใฉใใใใฉใผใ ใงใฏใไธ็ๆ้ซใฎๅคงๅญฆใฎ่ฌ็พฉใ็กๆใงๅ่ฌใงใใพใใ"}, | |
{"speaker": "Hiroshi", "text": "ๅฎ็จ็ใชใขใใใคในใใใใใจใใใใใพใใๆๅพใซใใใฎๅ้ใฎๅฐๆฅใฎๅฑๆใใฉใฎใใใซ่ฆใฆใใใฃใใใใพใใ๏ผ"}, | |
{"speaker": "Takeshi", "text": "ไปๅพ10ๅนด้ใฏไบบ้กๅฒไธๆใๆฅ้ใชๆ่ก็บๅฑใ็ต้จใใๆๆใซใชใใงใใใใGartnerใฎใใคใใตใคใฏใซๅๆใซใใใจใ็พๅจ็งใใกใฏใใฎๆ่กใฎๅๆๆฎต้ใซ้ใใพใใใ2030ๅนดใพใงใซใฏใ็พๅจใงใฏๆณๅใ้ฃใใฌใใซใฎ้ฉๆฐใ่ตทใใใจไบๆณใใใพใใ้่ฆใชใฎใฏใใใฎใใใชๅคๅใๆใใใฎใงใฏใชใใๆฉไผใจใใฆๆดป็จใใฆใใ่ฏใๆชๆฅใไฝใไธใใฆใใใใจใ ใจๆใใพใใ"}, | |
{"speaker": "Hiroshi", "text": "ๆฌๅฝใซๆดๅฏใซๅฏใใ ใ่ฉฑใงใใใไปๆฅใฏๅคงๅคๆ็ใชๆ้ใงใใใใชในใใผใฎ็ใใใไปๆฅ่ญฐ่ซใใใๅ ๅฎนใๅบใซๆชๆฅใซๅใใฆใใใ ใใใฐใจๆใใพใใ้ซๆฉๅ ็ใ่ฒด้ใชใๆ้ใใใใ ใใใใใใจใใใใใพใใ๏ผ"}, | |
{"speaker": "Takeshi", "text": "ใใใใจใใใใใพใใใใชในใใผใฎ็ใใใใใฎๅคๅใฎๆไปฃใ่ณขๆใซไนใๅใฃใฆใใใใใใจใ้กใฃใฆใใพใใๆ่กใฏ้ๅ ทใซ้ใใใใใใใฉใฎใใใซๆดป็จใใใใฏ็งใใกใซใใใฃใฆใใใจใใใใจใ่ฆใใฆใใใฆใใ ใใใไปๆฅใ่ฉฑใใใๅ ๅฎนใซใคใใฆใใใซ่ฉณใใ็ฅใใใๆนใฏใ็งใ้ๅถใใใใญใฐใๆ่ฟๅบ็ใใๆฌใง่ฉณ็ดฐใชๆ ๅ ฑใ่ฆใคใใใใจใใงใใพใใ"} | |
] | |
} | |
def _get_default_french_conversation(self) -> Dict: | |
"""๊ธฐ๋ณธ ํ๋์ค์ด ๋ํ ํ ํ๋ฆฟ""" | |
return { | |
"conversation": [ | |
{"speaker": "Pierre", "text": "Bonjour tout le monde ! Aujourd'hui, nous allons aborder un sujet vraiment important et fascinant. Marc, pourriez-vous d'abord expliquer pourquoi ce sujet attire autant l'attention en ce moment ?"}, | |
{"speaker": "Marc", "text": "Bonjour Pierre. Nous assistons rรฉcemment ร des dรฉveloppements rรฉvolutionnaires dans ce domaine. Selon une publication rรฉcente du MIT, l'efficacitรฉ de cette technologie s'est amรฉliorรฉe de 300% par rapport aux mรฉthodes conventionnelles. Il ne s'agit pas seulement d'un progrรจs technique, mais d'un changement qui peut avoir un impact direct sur notre vie quotidienne. En fait, des gรฉants technologiques comme Google et Microsoft ont dรฉjร investi des milliards de dollars dans ce secteur."}, | |
{"speaker": "Pierre", "text": "Une amรฉlioration de 300%, c'est vraiment remarquable ! Alors, quels bรฉnรฉfices concrets cette รฉvolution technologique peut-elle apporter au grand public ?"}, | |
{"speaker": "Marc", "text": "Les avantages les plus directs sont la rรฉduction des coรปts et l'amรฉlioration de l'accessibilitรฉ. Par exemple, des fonctionnalitรฉs avancรฉes qui n'รฉtaient auparavant disponibles que pour les experts peuvent maintenant รชtre implรฉmentรฉes dans des applications smartphone. Selon un rapport de McKinsey, cette technologie devrait crรฉer environ 2 000 milliards de dollars de valeur รฉconomique mondiale d'ici 2025. Des changements innovants sont particuliรจrement attendus dans les domaines de la santรฉ, de l'รฉducation et de la finance."}, | |
{"speaker": "Pierre", "text": "2 000 milliards de dollars, c'est une รฉchelle รฉnorme ! Quels changements sont attendus dans le domaine mรฉdical ?"}, | |
{"speaker": "Marc", "text": "Les changements dans le domaine mรฉdical seront vraiment rรฉvolutionnaires. L'hรดpital universitaire de Stanford a dรฉjร utilisรฉ cette technologie pour amรฉliorer la prรฉcision du diagnostic du cancer jusqu'ร 95%. L'IA peut dรฉtecter des lรฉsions microscopiques que mรชme des mรฉdecins expรฉrimentรฉs pourraient manquer. Ce qui est encore plus remarquable, c'est que de tels diagnostics peuvent รชtre effectuรฉs en quelques minutes seulement. Selon les estimations de l'OMS, si cette technologie se rรฉpand mondialement, elle pourrait sauver des millions de vies chaque annรฉe."}, | |
{"speaker": "Pierre", "text": "C'est vraiment impressionnant. Mais il doit y avoir aussi des prรฉoccupations concernant ce dรฉveloppement technologique rapide ?"}, | |
{"speaker": "Marc", "text": "Absolument. Il y a trois prรฉoccupations principales. Premiรจrement, le problรจme du remplacement de l'emploi - selon une recherche de l'Universitรฉ d'Oxford, 47% des emplois actuels risquent d'รชtre automatisรฉs dans les 20 prochaines annรฉes. Deuxiรจmement, les questions de confidentialitรฉ et de sรฉcuritรฉ. Troisiรจmement, l'aggravation des inรฉgalitรฉs due au fossรฉ technologique. Cependant, historiquement, les nouvelles technologies ont toujours crรฉรฉ de nouvelles opportunitรฉs, donc je pense que ces problรจmes peuvent รชtre rรฉsolus avec des politiques et une รฉducation appropriรฉes."}, | |
{"speaker": "Pierre", "text": "Une perspective รฉquilibrรฉe est importante. Alors, comment devrions-nous nous prรฉparer ร ces changements ?"}, | |
{"speaker": "Marc", "text": "Le plus important est l'apprentissage continu et l'adaptabilitรฉ. Le Forum รฉconomique mondial prรฉdit que 50% des travailleurs mondiaux auront besoin d'une formation supplรฉmentaire d'ici 2025. Des compรฉtences comme la littรฉratie numรฉrique, la pensรฉe critique et la crรฉativitรฉ deviendront particuliรจrement importantes. Personnellement, je recommande l'auto-amรฉlioration grรขce aux plateformes d'รฉducation en ligne. Par exemple, sur des plateformes comme Coursera ou edX, vous pouvez suivre gratuitement des cours des meilleures universitรฉs du monde."}, | |
{"speaker": "Pierre", "text": "Merci pour ces conseils pratiques. Enfin, comment voyez-vous les perspectives d'avenir de ce domaine ?"}, | |
{"speaker": "Marc", "text": "Les 10 prochaines annรฉes seront une pรฉriode d'รฉvolution technologique la plus rapide de l'histoire humaine. Selon l'analyse du cycle de Gartner, nous ne sommes actuellement qu'au stade initial de cette technologie. D'ici 2030, on s'attend ร des innovations d'un niveau difficile ร imaginer actuellement. L'important est de ne pas craindre ces changements, mais de les considรฉrer comme des opportunitรฉs pour crรฉer un avenir meilleur."}, | |
{"speaker": "Pierre", "text": "C'รฉtaient des paroles vraiment perspicaces. Aujourd'hui a รฉtรฉ un moment trรจs enrichissant. J'espรจre que nos auditeurs se prรฉpareront รฉgalement ร l'avenir en se basant sur ce qui a รฉtรฉ discutรฉ aujourd'hui. Marc, merci d'avoir pris de votre prรฉcieux temps !"}, | |
{"speaker": "Marc", "text": "Merci ร vous. J'espรจre que nos auditeurs navigueront sagement ร travers cette รจre de changement. Rappelez-vous que la technologie n'est qu'un outil, et c'est ร nous de dรฉcider comment l'utiliser. Pour ceux qui souhaitent en savoir plus sur ce dont nous avons parlรฉ aujourd'hui, vous pouvez trouver des informations plus dรฉtaillรฉes sur mon blog et dans mon livre rรฉcemment publiรฉ."} | |
] | |
} | |
def _get_default_german_conversation(self) -> Dict: | |
"""๊ธฐ๋ณธ ๋ ์ผ์ด ๋ํ ํ ํ๋ฆฟ""" | |
return { | |
"conversation": [ | |
{"speaker": "Klaus", "text": "Hallo zusammen! Heute wollen wir ein wirklich wichtiges und faszinierendes Thema besprechen. Stefan, kรถnnten Sie zunรคchst erklรคren, warum dieses Thema gerade jetzt so viel Aufmerksamkeit erhรคlt?"}, | |
{"speaker": "Stefan", "text": "Hallo Klaus. Wir erleben kรผrzlich revolutionรคre Entwicklungen in diesem Bereich. Laut einer aktuellen Verรถffentlichung des MIT hat sich die Effizienz dieser Technologie um 300% gegenรผber herkรถmmlichen Methoden verbessert. Das ist nicht nur technischer Fortschritt, sondern eine Verรคnderung, die direkten Einfluss auf unser tรคgliches Leben haben kann. Tatsรคchlich haben Tech-Riesen wie Google und Microsoft bereits Milliarden von Dollar in diesen Sektor investiert."}, | |
{"speaker": "Klaus", "text": "300% Verbesserung ist wirklich bemerkenswert! Welche konkreten Vorteile kann diese technologische Entwicklung fรผr die Allgemeinheit bringen?"}, | |
{"speaker": "Stefan", "text": "Die direktesten Vorteile sind Kostenreduzierung und verbesserte Zugรคnglichkeit. Zum Beispiel kรถnnen erweiterte Funktionen, die frรผher nur Experten zur Verfรผgung standen, jetzt in Smartphone-Apps implementiert werden. Laut einem McKinsey-Bericht soll diese Technologie bis 2025 weltweit etwa 2 Billionen Dollar wirtschaftlichen Wert schaffen. Besonders in den Bereichen Gesundheitswesen, Bildung und Finanzen werden innovative Verรคnderungen erwartet."}, | |
{"speaker": "Klaus", "text": "2 Billionen Dollar ist eine enorme Grรถรenordnung! Welche Verรคnderungen werden im medizinischen Bereich erwartet?"}, | |
{"speaker": "Stefan", "text": "Die Verรคnderungen im medizinischen Bereich werden wirklich revolutionรคr sein. Das Stanford University Hospital hat diese Technologie bereits eingesetzt, um die Genauigkeit der Krebsdiagnose auf 95% zu verbessern. KI kann mikroskopische Lรคsionen erkennen, die selbst erfahrene รrzte รผbersehen kรถnnten. Noch bemerkenswerter ist, dass solche Diagnosen in nur wenigen Minuten durchgefรผhrt werden kรถnnen. Laut WHO-Schรคtzungen kรถnnte diese Technologie, wenn sie weltweit verbreitet wird, jรคhrlich Millionen von Leben retten."}, | |
{"speaker": "Klaus", "text": "Das ist wirklich beeindruckend. Aber es muss auch Bedenken bezรผglich dieser schnellen technologischen Entwicklung geben?"}, | |
{"speaker": "Stefan", "text": "Absolut richtig. Es gibt drei Hauptbedenken. Erstens das Problem der Arbeitsplatzverdrรคngung - laut Oxford University-Forschung sind 47% der aktuellen Jobs in den nรคchsten 20 Jahren von Automatisierung bedroht. Zweitens Datenschutz- und Sicherheitsfragen. Drittens die Verschรคrfung von Ungleichheiten durch die Technologielรผcke. Historisch gesehen haben neue Technologien jedoch immer auch neue Mรถglichkeiten geschaffen, daher glaube ich, dass diese Probleme mit angemessenen Richtlinien und Bildung gelรถst werden kรถnnen."}, | |
{"speaker": "Klaus", "text": "Eine ausgewogene Perspektive ist wichtig. Wie sollten wir uns auf diese Verรคnderungen vorbereiten?"}, | |
{"speaker": "Stefan", "text": "Das Wichtigste ist kontinuierliches Lernen und Anpassungsfรคhigkeit. Das Weltwirtschaftsforum prognostiziert, dass bis 2025 50% der weltweiten Arbeitskrรคfte Umschulung benรถtigen werden. Besonders wichtig werden Fรคhigkeiten wie digitale Kompetenz, kritisches Denken und Kreativitรคt. Persรถnlich empfehle ich Selbstverbesserung durch Online-Bildungsplattformen. Zum Beispiel kรถnnen Sie auf Plattformen wie Coursera oder edX kostenlos Vorlesungen der besten Universitรคten der Welt besuchen."}, | |
{"speaker": "Klaus", "text": "Danke fรผr die praktischen Ratschlรคge. Wie sehen Sie abschlieรend die Zukunftsaussichten in diesem Bereich?"}, | |
{"speaker": "Stefan", "text": "Die nรคchsten 10 Jahre werden eine Zeit der schnellsten technologischen Entwicklung in der Menschheitsgeschichte sein. Laut Gartners Hype-Cycle-Analyse befinden wir uns derzeit nur im Anfangsstadium dieser Technologie. Bis 2030 werden Innovationen auf einem Niveau erwartet, das derzeit schwer vorstellbar ist. Wichtig ist, diese Verรคnderungen nicht zu fรผrchten, sondern sie als Chancen zu nutzen, um eine bessere Zukunft zu schaffen."}, | |
{"speaker": "Klaus", "text": "Das waren wirklich einsichtsvolle Worte. Heute war eine sehr bereichernde Zeit. Ich hoffe, unsere Zuhรถrer werden sich auch basierend auf dem, was heute diskutiert wurde, auf die Zukunft vorbereiten. Stefan, vielen Dank, dass Sie sich die wertvolle Zeit genommen haben!"}, | |
{"speaker": "Stefan", "text": "Vielen Dank. Ich hoffe, unsere Zuhรถrer werden diese Zeit des Wandels weise meistern. Denken Sie daran, dass Technologie nur ein Werkzeug ist und es an uns liegt, wie wir sie nutzen. Fรผr diejenigen, die mehr รผber das erfahren mรถchten, was wir heute besprochen haben, finden Sie detailliertere Informationen in meinem Blog und meinem kรผrzlich verรถffentlichten Buch."} | |
] | |
} | |
def _get_default_spanish_conversation(self) -> Dict: | |
"""๊ธฐ๋ณธ ์คํ์ธ์ด ๋ํ ํ ํ๋ฆฟ""" | |
return { | |
"conversation": [ | |
{"speaker": "Carlos", "text": "ยกHola a todos! Hoy vamos a abordar un tema realmente importante y fascinante. Miguel, ยฟpodrรญas explicar primero por quรฉ este tema estรก recibiendo tanta atenciรณn en este momento?"}, | |
{"speaker": "Miguel", "text": "Hola Carlos. Estamos presenciando desarrollos revolucionarios recientes en este campo. Segรบn una publicaciรณn reciente del MIT, la eficiencia de esta tecnologรญa ha mejorado un 300% en comparaciรณn con los mรฉtodos convencionales. Esto no es solo progreso tรฉcnico, sino un cambio que puede tener un impacto directo en nuestra vida diaria. De hecho, gigantes tecnolรณgicos como Google y Microsoft ya han invertido miles de millones de dรณlares en este sector."}, | |
{"speaker": "Carlos", "text": "ยกUna mejora del 300% es realmente notable! Entonces, ยฟquรฉ beneficios concretos puede aportar esta evoluciรณn tecnolรณgica al pรบblico en general?"}, | |
{"speaker": "Miguel", "text": "Los beneficios mรกs directos son la reducciรณn de costos y la mejora de la accesibilidad. Por ejemplo, funciones avanzadas que antes solo estaban disponibles para expertos ahora pueden implementarse en aplicaciones de smartphone. Segรบn un informe de McKinsey, se espera que esta tecnologรญa cree aproximadamente 2 billones de dรณlares de valor econรณmico mundial para 2025. Se esperan cambios innovadores especialmente en los campos de la salud, educaciรณn y finanzas."}, | |
{"speaker": "Carlos", "text": "ยก2 billones de dรณlares es una escala enorme! ยฟQuรฉ cambios se esperan en el campo mรฉdico?"}, | |
{"speaker": "Miguel", "text": "Los cambios en el campo mรฉdico serรกn realmente revolucionarios. El Hospital Universitario de Stanford ya ha utilizado esta tecnologรญa para mejorar la precisiรณn del diagnรณstico de cรกncer hasta el 95%. La IA puede detectar lesiones microscรณpicas que incluso mรฉdicos experimentados podrรญan pasar por alto. Aรบn mรกs notable es que tales diagnรณsticos pueden realizarse en solo unos minutos. Segรบn las estimaciones de la OMS, si esta tecnologรญa se extiende globalmente, podrรญa salvar millones de vidas anualmente."}, | |
{"speaker": "Carlos", "text": "Eso es realmente impresionante. ยฟPero tambiรฉn debe haber preocupaciones sobre este rรกpido desarrollo tecnolรณgico?"}, | |
{"speaker": "Miguel", "text": "Absolutamente correcto. Hay tres preocupaciones principales. Primero, el problema del reemplazo laboral: segรบn la investigaciรณn de la Universidad de Oxford, el 47% de los empleos actuales estรกn en riesgo de automatizaciรณn en los prรณximos 20 aรฑos. Segundo, cuestiones de privacidad y seguridad. Tercero, el agravamiento de la desigualdad debido a la brecha tecnolรณgica. Sin embargo, histรณricamente, las nuevas tecnologรญas siempre han creado nuevas oportunidades tambiรฉn, por lo que creo que estos problemas pueden resolverse con polรญticas y educaciรณn adecuadas."}, | |
{"speaker": "Carlos", "text": "Una perspectiva equilibrada es importante. Entonces, ยฟcรณmo deberรญamos prepararnos para estos cambios?"}, | |
{"speaker": "Miguel", "text": "Lo mรกs importante es el aprendizaje continuo y la adaptabilidad. El Foro Econรณmico Mundial predice que el 50% de los trabajadores mundiales necesitarรกn reeducaciรณn para 2025. Habilidades como la alfabetizaciรณn digital, el pensamiento crรญtico y la creatividad se volverรกn especialmente importantes. Personalmente, recomiendo la automejora a travรฉs de plataformas de educaciรณn en lรญnea. Por ejemplo, en plataformas como Coursera o edX, puedes tomar clases gratuitas de las mejores universidades del mundo."}, | |
{"speaker": "Carlos", "text": "Gracias por los consejos prรกcticos. Finalmente, ยฟcรณmo ve las perspectivas futuras de este campo?"}, | |
{"speaker": "Miguel", "text": "Los prรณximos 10 aรฑos serรกn un perรญodo del desarrollo tecnolรณgico mรกs rรกpido en la historia humana. Segรบn el anรกlisis del ciclo de Gartner, actualmente estamos solo en la etapa inicial de esta tecnologรญa. Para 2030, se esperan innovaciones en un nivel que es difรญcil de imaginar actualmente. Lo importante es no temer estos cambios, sino considerarlos como oportunidades para crear un futuro mejor."}, | |
{"speaker": "Carlos", "text": "Esas fueron palabras realmente perspicaces. Hoy ha sido un momento muy enriquecedor. Espero que nuestros oyentes tambiรฉn se preparen para el futuro basรกndose en lo que se discutiรณ hoy. ยกMiguel, gracias por tomar tu valioso tiempo!"}, | |
{"speaker": "Miguel", "text": "Gracias a ti. Espero que nuestros oyentes naveguen sabiamente a travรฉs de esta era de cambio. Recuerden que la tecnologรญa es solo una herramienta, y depende de nosotros cรณmo la usemos. Para aquellos que quieran saber mรกs sobre lo que discutimos hoy, pueden encontrar informaciรณn mรกs detallada en mi blog y mi libro recientemente publicado."} | |
] | |
} | |
def _get_default_chinese_conversation(self) -> Dict: | |
"""๊ธฐ๋ณธ ์ค๊ตญ์ด ๋ํ ํ ํ๋ฆฟ""" | |
return { | |
"conversation": [ | |
{"speaker": "Wei", "text": "ๅคงๅฎถๅฅฝ๏ผไปๅคฉๆไปฌ่ฆ่ฎจ่ฎบไธไธช้ๅธธ้่ฆๅๆ่ถฃ็่ฏ้ขใๅฐๅ๏ผไฝ ่ฝ้ฆๅ ่งฃ้ไธไธไธบไปไน่ฟไธช่ฏ้ข็ฐๅจๅๅฐๅฆๆญคๅค็ๅ ณๆณจๅ๏ผ"}, | |
{"speaker": "Jun", "text": "ไฝ ๅฅฝ๏ผๅฐไผใๆไปฌๆ่ฟๅจ่ฟไธช้ขๅ่ง่ฏไบ้ฉๅฝๆง็ๅๅฑใๆ นๆฎMITๆๆฐๅๅธ็็ ็ฉถ๏ผ่ฟ้กนๆๆฏ็ๆ็ๆฏไผ ็ปๆนๆณๆ้ซไบ300%ใ่ฟไธไป ไป ๆฏๆๆฏ่ฟๆญฅ๏ผ่ๆฏไธไธชๅฏ่ฝ็ดๆฅๅฝฑๅๆไปฌๆฅๅธธ็ๆดป็ๅๅใๅฎ้ ไธ๏ผๅ่ฐทๆญๅๅพฎ่ฝฏ่ฟๆ ท็็งๆๅทจๅคดๅทฒ็ปๅจ่ฟไธช้ขๅๆ่ตไบๆฐๅไบฟ็พๅ ใ"}, | |
{"speaker": "Wei", "text": "300%็ๆๅ็กฎๅฎไปคไบบๆๅน๏ผ้ฃไน่ฟ็งๆๆฏๅๅฑ่ฝไธบๆฎ้ๅคงไผๅธฆๆฅไปไนๅ ทไฝ็ๅฅฝๅคๅข๏ผ"}, | |
{"speaker": "Jun", "text": "ๆ็ดๆฅ็ๅฅฝๅคๆฏๆๆฌ้ไฝๅๅฏ่ฎฟ้ฎๆงๆ้ซใไพๅฆ๏ผไปฅๅๅชๆไธๅฎถๆ่ฝไฝฟ็จ็้ซ็บงๅ่ฝ็ฐๅจๅฏไปฅๅจๆบ่ฝๆๆบๅบ็จไธญๅฎ็ฐใๆ นๆฎ้บฆ่ฏ้ก็ๆฅๅ๏ผ้ข่ฎกๅฐ2025ๅนด๏ผ่ฟ้กนๆๆฏๅฐๅจๅ จ็ๅ้ ็บฆ2ไธไบฟ็พๅ ็็ปๆตไปทๅผใ็นๅซๆฏๅจๅป็ใๆ่ฒๅ้่้ขๅ๏ผ้ข่ฎกไผๅบ็ฐๅๆฐๆงๅๅใ"}, | |
{"speaker": "Wei", "text": "2ไธไบฟ็พๅ ๆฏไธไธชๅทจๅคง็่งๆจก๏ผๅจๅป็้ขๅ้ข่ฎกไผๆไปไนๅๅ๏ผ"}, | |
{"speaker": "Jun", "text": "ๅป็้ขๅ็ๅๅๅฐๆฏ็ๆญฃ้ฉๅฝๆง็ใๆฏๅฆ็ฆๅคงๅญฆๅป้ขๅทฒ็ปๅฉ็จ่ฟ้กนๆๆฏๅฐ็็่ฏๆญ็ๅ็กฎ็ๆ้ซๅฐ95%ใAIๅฏไปฅๆฃๆตๅฐๅณไฝฟๆฏ็ป้ชไธฐๅฏ็ๅป็ไนๅฏ่ฝ้่ฟ็ๅพฎๅฐ็ ๅใๆดไปคไบบๆๅน็ๆฏ๏ผ่ฟๆ ท็่ฏๆญๅช้่ฆๅ ๅ้ๅฐฑ่ฝๅฎๆใๆ นๆฎไธ็ๅซ็็ป็ป็ไผฐ่ฎก๏ผๅฆๆ่ฟ้กนๆๆฏๅจๅ จ็ๆฎๅ๏ผๆฏๅนดๅฏไปฅๆฏๆๆฐ็พไธไบบ็็ๅฝใ"}, | |
{"speaker": "Wei", "text": "่ฟ็็ไปคไบบๅฐ่ฑกๆทฑๅปใไฝๆฏๅฏนไบ่ฟ็งๅฟซ้็ๆๆฏๅๅฑไนไธๅฎๅญๅจๆ ๅฟงๅง๏ผ"}, | |
{"speaker": "Jun", "text": "็กฎๅฎๅฆๆญคใไธป่ฆๆไธไธชๆ ๅฟงใ้ฆๅ ๆฏๅฐฑไธๆฟไปฃ้ฎ้ขโโๆ นๆฎ็ๆดฅๅคงๅญฆ็็ ็ฉถ๏ผๆชๆฅ20ๅนดๅ ๅฝๅ47%็ๅทฅไฝๅฏ่ฝ้ขไธด่ชๅจๅ้ฃ้ฉใๅ ถๆฌกๆฏ้็งๅๅฎๅ จ้ฎ้ขใ็ฌฌไธๆฏๆๆฏๅทฎ่ทๅฏผ่ด็ไธๅนณ็ญๅ ๅงใไฝๆฏไปๅๅฒไธ็๏ผๆฐๆๆฏๆปๆฏๅจๅ้ ๆฐๆบ้็ๅๆถ๏ผๆ็ธไฟก้่ฟ้ๅฝ็ๆฟ็ญๅๆ่ฒๅฏไปฅ่งฃๅณ่ฟไบ้ฎ้ขใ"}, | |
{"speaker": "Wei", "text": "ๅนณ่กก็่ง็นๅพ้่ฆใ้ฃไนๆไปฌๅบ่ฏฅๅฆไฝไธบ่ฟไบๅๅๅๅๅคๅข๏ผ"}, | |
{"speaker": "Jun", "text": "ๆ้่ฆ็ๆฏๆ็ปญๅญฆไน ๅ้ๅบ่ฝๅใไธ็็ปๆต่ฎบๅ้ขๆต๏ผๅฐ2025ๅนด๏ผๅ จ็50%็ๅทฅไบบๅฐ้่ฆ้ๆฐๅน่ฎญใๆฐๅญ็ด ๅ ปใๆนๅคๆงๆ็ปดๅๅ้ ๅ็ญๆ่ฝๅฐๅๅพ็นๅซ้่ฆใๆไธชไบบๆจ่้่ฟๅจ็บฟๆ่ฒๅนณๅฐ่ฟ่ก่ชๆๆๅใไพๅฆ๏ผๅจCourseraๆedX็ญๅนณๅฐไธ๏ผไฝ ๅฏไปฅๅ ่ดนๅญฆไน ไธ็้กถๅฐๅคงๅญฆ็่ฏพ็จใ"}, | |
{"speaker": "Wei", "text": "ๆ่ฐข่ฟไบๅฎ็จ็ๅปบ่ฎฎใๆๅ๏ผไฝ ๅฆไฝ็ๅพ ่ฟไธช้ขๅ็ๆชๆฅๅๆฏ๏ผ"}, | |
{"speaker": "Jun", "text": "ๆชๆฅ10ๅนดๅฐๆฏไบบ็ฑปๅๅฒไธๆๆฏๅๅฑๆๅฟซ็ๆถๆใๆ นๆฎGartner็็ไฝๅจๆๅๆ๏ผๆไปฌ็ฎๅๅชๆฏๅคไบ่ฟ้กนๆๆฏ็ๅๆ้ถๆฎตใๅฐ2030ๅนด๏ผ้ข่ฎกไผๅบ็ฐ็ฎๅ้พไปฅๆณ่ฑกๆฐดๅนณ็ๅๆฐใ้่ฆ็ๆฏไธ่ฆๅฎณๆ่ฟไบๅๅ๏ผ่ๆฏๅฐๅฎไปฌ่งไธบๅ้ ๆด็พๅฅฝๆชๆฅ็ๆบไผใ"}, | |
{"speaker": "Wei", "text": "่ฟไบ่ฏ็็ๅพๆ่งๅฐใไปๅคฉๆฏไธไธช้ๅธธๆ็็ๆถๅ ใๅธๆๆไปฌ็ๅฌไผไน่ฝๅบไบไปๅคฉ่ฎจ่ฎบ็ๅ ๅฎนไธบๆชๆฅๅๅๅคใๅฐๅ๏ผๆ่ฐขไฝ ๆฝๅบๅฎ่ดต็ๆถ้ด๏ผ"}, | |
{"speaker": "Jun", "text": "่ฐข่ฐขไฝ ใๅธๆๆไปฌ็ๅฌไผ่ฝๅคๆๆบๅฐๅบฆ่ฟ่ฟไธชๅๅ็ๆถไปฃใ่ฏท่ฎฐไฝ๏ผๆๆฏๅชๆฏๅทฅๅ ท๏ผๅฆไฝไฝฟ็จๅฎๅๅณไบๆไปฌ่ชๅทฑใๅฏนไบๆณ่ฆไบ่งฃๆดๅคๆไปฌไปๅคฉ่ฎจ่ฎบๅ ๅฎน็ไบบ๏ผๅฏไปฅๅจๆ็ๅๅฎขๅๆ่ฟๅบ็็ไนฆไธญๆพๅฐๆด่ฏฆ็ป็ไฟกๆฏใ"} | |
] | |
} | |
def _get_default_russian_conversation(self) -> Dict: | |
"""๊ธฐ๋ณธ ๋ฌ์์์ด ๋ํ ํ ํ๋ฆฟ""" | |
return { | |
"conversation": [ | |
{"speaker": "Alexei", "text": "ะัะธะฒะตั ะฒัะตะผ! ะกะตะณะพะดะฝั ะผั ัะพะฑะธัะฐะตะผัั ะพะฑััะดะธัั ะดะตะนััะฒะธัะตะปัะฝะพ ะฒะฐะถะฝัั ะธ ัะฒะปะตะบะฐัะตะปัะฝัั ัะตะผั. ะะผะธััะธะน, ะฝะต ะผะพะณะปะธ ะฑั ะฒั ัะฝะฐัะฐะปะฐ ะพะฑัััะฝะธัั, ะฟะพัะตะผั ััะฐ ัะตะผะฐ ัะตะนัะฐั ะฟัะธะฒะปะตะบะฐะตั ัะฐะบ ะผะฝะพะณะพ ะฒะฝะธะผะฐะฝะธั?"}, | |
{"speaker": "Dmitri", "text": "ะัะธะฒะตั, ะะปะตะบัะตะน. ะั ะฝะตะดะฐะฒะฝะพ ััะฐะปะธ ัะฒะธะดะตัะตะปัะผะธ ัะตะฒะพะปััะธะพะฝะฝัั ัะฐะทัะฐะฑะพัะพะบ ะฒ ััะพะน ะพะฑะปะฐััะธ. ะกะพะณะปะฐัะฝะพ ะฝะตะดะฐะฒะฝะตะน ะฟัะฑะปะธะบะฐัะธะธ MIT, ัััะตะบัะธะฒะฝะพััั ััะพะน ัะตั ะฝะพะปะพะณะธะธ ัะปัััะธะปะฐัั ะฝะฐ 300% ะฟะพ ััะฐะฒะฝะตะฝะธั ั ััะฐะดะธัะธะพะฝะฝัะผะธ ะผะตัะพะดะฐะผะธ. ะญัะพ ะฝะต ะฟัะพััะพ ัะตั ะฝะธัะตัะบะธะน ะฟัะพะณัะตัั, ะฐ ะธะทะผะตะฝะตะฝะธะต, ะบะพัะพัะพะต ะผะพะถะตั ะพะบะฐะทะฐัั ะฟััะผะพะต ะฒะปะธัะฝะธะต ะฝะฐ ะฝะฐัั ะฟะพะฒัะตะดะฝะตะฒะฝัั ะถะธะทะฝั. ะคะฐะบัะธัะตัะบะธ, ัะตั ะฝะพะปะพะณะธัะตัะบะธะต ะณะธะณะฐะฝัั, ัะฐะบะธะต ะบะฐะบ Google ะธ Microsoft, ัะถะต ะธะฝะฒะตััะธัะพะฒะฐะปะธ ะผะธะปะปะธะฐัะดั ะดะพะปะปะฐัะพะฒ ะฒ ััะพั ัะตะบัะพั."}, | |
{"speaker": "Alexei", "text": "ะฃะปัััะตะฝะธะต ะฝะฐ 300% ะดะตะนััะฒะธัะตะปัะฝะพ ะทะฐะผะตัะฐัะตะปัะฝะพ! ะัะฐะบ, ะบะฐะบะธะต ะบะพะฝะบัะตัะฝัะต ะฟัะตะธะผััะตััะฒะฐ ััะพ ัะตั ะฝะพะปะพะณะธัะตัะบะพะต ัะฐะทะฒะธัะธะต ะผะพะถะตั ะฟัะธะฝะตััะธ ัะธัะพะบะพะน ะฟัะฑะปะธะบะต?"}, | |
{"speaker": "Dmitri", "text": "ะะฐะธะฑะพะปะตะต ะฟััะผัะต ะฟัะตะธะผััะตััะฒะฐ - ััะพ ัะฝะธะถะตะฝะธะต ะทะฐััะฐั ะธ ัะปัััะตะฝะธะต ะดะพัััะฟะฝะพััะธ. ะะฐะฟัะธะผะตั, ัะฐััะธัะตะฝะฝัะต ััะฝะบัะธะธ, ะบะพัะพััะต ัะฐะฝะตะต ะฑัะปะธ ะดะพัััะฟะฝั ัะพะปัะบะพ ัะบัะฟะตััะฐะผ, ัะตะฟะตัั ะผะพะณัั ะฑััั ัะตะฐะปะธะทะพะฒะฐะฝั ะฒ ะฟัะธะปะพะถะตะฝะธัั ะดะปั ัะผะฐัััะพะฝะพะฒ. ะกะพะณะปะฐัะฝะพ ะพััะตัั McKinsey, ะพะถะธะดะฐะตััั, ััะพ ััะฐ ัะตั ะฝะพะปะพะณะธั ัะพะทะดะฐัั ะฟัะธะผะตัะฝะพ 2 ััะธะปะปะธะพะฝะฐ ะดะพะปะปะฐัะพะฒ ัะบะพะฝะพะผะธัะตัะบะพะน ััะพะธะผะพััะธ ะฒ ะผะธัะต ะบ 2025 ะณะพะดั. ะะฝะฝะพะฒะฐัะธะพะฝะฝัะต ะธะทะผะตะฝะตะฝะธั ะพัะพะฑะตะฝะฝะพ ะพะถะธะดะฐัััั ะฒ ะพะฑะปะฐััะธ ะทะดัะฐะฒะพะพั ัะฐะฝะตะฝะธั, ะพะฑัะฐะทะพะฒะฐะฝะธั ะธ ัะธะฝะฐะฝัะพะฒ."}, | |
{"speaker": "Alexei", "text": "2 ััะธะปะปะธะพะฝะฐ ะดะพะปะปะฐัะพะฒ - ััะพ ะพะณัะพะผะฝัะน ะผะฐัััะฐะฑ! ะะฐะบะธะต ะธะทะผะตะฝะตะฝะธั ะพะถะธะดะฐัััั ะฒ ะผะตะดะธัะธะฝัะบะพะน ะพะฑะปะฐััะธ?"}, | |
{"speaker": "Dmitri", "text": "ะะทะผะตะฝะตะฝะธั ะฒ ะผะตะดะธัะธะฝัะบะพะน ะพะฑะปะฐััะธ ะฑัะดัั ะดะตะนััะฒะธัะตะปัะฝะพ ัะตะฒะพะปััะธะพะฝะฝัะผะธ. ะฃะฝะธะฒะตััะธัะตััะบะฐั ะฑะพะปัะฝะธัะฐ ะกััะฝัะพัะดะฐ ัะถะต ะธัะฟะพะปัะทะพะฒะฐะปะฐ ััั ัะตั ะฝะพะปะพะณะธั ะดะปั ัะปัััะตะฝะธั ัะพัะฝะพััะธ ะดะธะฐะณะฝะพััะธะบะธ ัะฐะบะฐ ะดะพ 95%. ะะ ะผะพะถะตั ะพะฑะฝะฐััะถะธะฒะฐัั ะผะธะบัะพัะบะพะฟะธัะตัะบะธะต ะฟะพัะฐะถะตะฝะธั, ะบะพัะพััะต ะดะฐะถะต ะพะฟััะฝัะต ะฒัะฐัะธ ะผะพะณะปะธ ะฑั ะฟัะพะฟัััะธัั. ะัะต ะฑะพะปะตะต ะฟัะธะผะตัะฐัะตะปัะฝะพ ัะพ, ััะพ ัะฐะบะฐั ะดะธะฐะณะฝะพััะธะบะฐ ะผะพะถะตั ะฑััั ะฒัะฟะพะปะฝะตะฝะฐ ะฒัะตะณะพ ะทะฐ ะฝะตัะบะพะปัะบะพ ะผะธะฝัั. ะะพ ะพัะตะฝะบะฐะผ ะะะ, ะตัะปะธ ััะฐ ัะตั ะฝะพะปะพะณะธั ัะฐัะฟัะพัััะฐะฝะธััั ะฟะพ ะฒัะตะผั ะผะธัั, ะพะฝะฐ ัะผะพะถะตั ัะฟะฐัะฐัั ะผะธะปะปะธะพะฝั ะถะธะทะฝะตะน ะตะถะตะณะพะดะฝะพ."}, | |
{"speaker": "Alexei", "text": "ะญัะพ ะดะตะนััะฒะธัะตะปัะฝะพ ะฒะฟะตัะฐัะปัะตั. ะะพ ัะฐะบะถะต ะดะพะปะถะฝั ะฑััั ะพะฟะฐัะตะฝะธั ะพัะฝะพัะธัะตะปัะฝะพ ัะฐะบะพะณะพ ะฑััััะพะณะพ ัะตั ะฝะพะปะพะณะธัะตัะบะพะณะพ ัะฐะทะฒะธัะธั?"}, | |
{"speaker": "Dmitri", "text": "ะะฑัะพะปััะฝะพ ะฟัะฐะฒะธะปัะฝะพ. ะััั ััะธ ะพัะฝะพะฒะฝัะต ะฟัะพะฑะปะตะผั. ะะพ-ะฟะตัะฒัั , ะฟัะพะฑะปะตะผะฐ ะทะฐะผะตัะตะฝะธั ัะฐะฑะพัะธั ะผะตัั - ัะพะณะปะฐัะฝะพ ะธััะปะตะดะพะฒะฐะฝะธั ะะบััะพัะดัะบะพะณะพ ัะฝะธะฒะตััะธัะตัะฐ, 47% ัะพะฒัะตะผะตะฝะฝัั ัะฐะฑะพัะธั ะผะตัั ัะธัะบััั ะฑััั ะฐะฒัะพะผะฐัะธะทะธัะพะฒะฐะฝะฝัะผะธ ะฒ ัะตัะตะฝะธะต ัะปะตะดัััะธั 20 ะปะตั. ะะพ-ะฒัะพััั , ะฒะพะฟัะพัั ะบะพะฝัะธะดะตะฝัะธะฐะปัะฝะพััะธ ะธ ะฑะตะทะพะฟะฐัะฝะพััะธ. ะ-ััะตััะธั , ัััะณัะฑะปะตะฝะธะต ะฝะตัะฐะฒะตะฝััะฒะฐ ะธะท-ะทะฐ ัะตั ะฝะพะปะพะณะธัะตัะบะพะณะพ ัะฐะทััะฒะฐ. ะะดะฝะฐะบะพ ะธััะพัะธัะตัะบะธ ะฝะพะฒัะต ัะตั ะฝะพะปะพะณะธะธ ะฒัะตะณะดะฐ ัะพะทะดะฐะฒะฐะปะธ ะธ ะฝะพะฒัะต ะฒะพะทะผะพะถะฝะพััะธ, ะฟะพััะพะผั ั ััะธัะฐั, ััะพ ััะธ ะฟัะพะฑะปะตะผั ะผะพะถะฝะพ ัะตัะธัั ั ะฟะพะผะพััั ัะพะพัะฒะตัััะฒัััะธั ะฟะพะปะธัะธะบ ะธ ะพะฑัะฐะทะพะฒะฐะฝะธั."}, | |
{"speaker": "Alexei", "text": "ะกะฑะฐะปะฐะฝัะธัะพะฒะฐะฝะฝะฐั ะฟะตััะฟะตะบัะธะฒะฐ ะฒะฐะถะฝะฐ. ะัะฐะบ, ะบะฐะบ ะฝะฐะผ ัะปะตะดัะตั ะณะพัะพะฒะธัััั ะบ ััะธะผ ะธะทะผะตะฝะตะฝะธัะผ?"}, | |
{"speaker": "Dmitri", "text": "ะะฐะธะฑะพะปะตะต ะฒะฐะถะฝัะผะธ ัะฒะปััััั ะฝะตะฟัะตััะฒะฝะพะต ะพะฑััะตะฝะธะต ะธ ะฐะดะฐะฟัะธะฒะฝะพััั. ะัะตะผะธัะฝัะน ัะบะพะฝะพะผะธัะตัะบะธะน ัะพััะผ ะฟัะพะณะฝะพะทะธััะตั, ััะพ ะบ 2025 ะณะพะดั 50% ะผะธัะพะฒัั ัะฐะฑะพัะฝะธะบะพะฒ ะฑัะดัั ะฝัะถะดะฐัััั ะฒ ะฟะตัะตะพะฑััะตะฝะธะธ. ะัะพะฑะตะฝะฝะพ ะฒะฐะถะฝัะผะธ ััะฐะฝัั ะฝะฐะฒัะบะธ ัะธััะพะฒะพะน ะณัะฐะผะพัะฝะพััะธ, ะบัะธัะธัะตัะบะพะณะพ ะผััะปะตะฝะธั ะธ ะบัะตะฐัะธะฒะฝะพััะธ. ะะธัะฝะพ ั ัะตะบะพะผะตะฝะดัั ัะฐะผะพัะพะฒะตััะตะฝััะฒะพะฒะฐะฝะธะต ัะตัะตะท ะพะฝะปะฐะนะฝ-ะพะฑัะฐะทะพะฒะฐัะตะปัะฝัะต ะฟะปะฐััะพัะผั. ะะฐะฟัะธะผะตั, ะฝะฐ ะฟะปะฐััะพัะผะฐั ะฒัะพะดะต Coursera ะธะปะธ edX ะฒั ะผะพะถะตัะต ะฑะตัะฟะปะฐัะฝะพ ะฟะพัะตัะฐัั ะปะตะบัะธะธ ะปัััะธั ัะฝะธะฒะตััะธัะตัะพะฒ ะผะธัะฐ."}, | |
{"speaker": "Alexei", "text": "ะกะฟะฐัะธะฑะพ ะทะฐ ะฟัะฐะบัะธัะตัะบะธะต ัะพะฒะตัั. ะะฐะบะพะฝะตั, ะบะฐะบ ะฒั ะฒะธะดะธัะต ะฑัะดััะธะต ะฟะตััะฟะตะบัะธะฒั ััะพะน ะพะฑะปะฐััะธ?"}, | |
{"speaker": "Dmitri", "text": "ะกะปะตะดัััะธะต 10 ะปะตั ะฑัะดัั ะฟะตัะธะพะดะพะผ ัะฐะผะพะณะพ ะฑััััะพะณะพ ัะตั ะฝะพะปะพะณะธัะตัะบะพะณะพ ัะฐะทะฒะธัะธั ะฒ ะธััะพัะธะธ ัะตะปะพะฒะตัะตััะฒะฐ. ะกะพะณะปะฐัะฝะพ ะฐะฝะฐะปะธะทั ัะธะบะปะฐ Gartner, ะฒ ะฝะฐััะพััะตะต ะฒัะตะผั ะผั ะฝะฐั ะพะดะธะผัั ัะพะปัะบะพ ะฝะฐ ะฝะฐัะฐะปัะฝะพะน ััะฐะดะธะธ ััะพะน ัะตั ะฝะพะปะพะณะธะธ. ะ 2030 ะณะพะดั ะพะถะธะดะฐัััั ะธะฝะฝะพะฒะฐัะธะธ ะฝะฐ ััะพะฒะฝะต, ะบะพัะพััะน ะฒ ะฝะฐััะพััะตะต ะฒัะตะผั ัััะดะฝะพ ะฟัะตะดััะฐะฒะธัั. ะะฐะถะฝะพ ะฝะต ะฑะพััััั ััะธั ะธะทะผะตะฝะตะฝะธะน, ะฐ ัะฐััะผะฐััะธะฒะฐัั ะธั ะบะฐะบ ะฒะพะทะผะพะถะฝะพััะธ ะดะปั ัะพะทะดะฐะฝะธั ะปัััะตะณะพ ะฑัะดััะตะณะพ."}, | |
{"speaker": "Alexei", "text": "ะญัะพ ะฑัะปะธ ะดะตะนััะฒะธัะตะปัะฝะพ ะฟัะพะฝะธัะฐัะตะปัะฝัะต ัะปะพะฒะฐ. ะกะตะณะพะดะฝั ะฑัะปะพ ะพัะตะฝั ะพะฑะพะณะฐัะฐััะตะต ะฒัะตะผั. ะะฐะดะตััั, ะฝะฐัะธ ัะปััะฐัะตะปะธ ัะพะถะต ะฟะพะดะณะพัะพะฒัััั ะบ ะฑัะดััะตะผั, ะพัะฝะพะฒัะฒะฐััั ะฝะฐ ัะพะผ, ััะพ ะพะฑััะถะดะฐะปะพัั ัะตะณะพะดะฝั. ะะผะธััะธะน, ัะฟะฐัะธะฑะพ, ััะพ ัะดะตะปะธะปะธ ัะฒะพะต ะดัะฐะณะพัะตะฝะฝะพะต ะฒัะตะผั!"}, | |
{"speaker": "Dmitri", "text": "ะกะฟะฐัะธะฑะพ ะฒะฐะผ. ะะฐะดะตััั, ะฝะฐัะธ ัะปััะฐัะตะปะธ ะผัะดัะพ ะฟัะพะนะดัั ัะตัะตะท ััั ัะฟะพั ั ะฟะตัะตะผะตะฝ. ะะพะผะฝะธัะต, ััะพ ัะตั ะฝะพะปะพะณะธั - ััะพ ะฒัะตะณะพ ะปะธัั ะธะฝััััะผะตะฝั, ะธ ะพั ะฝะฐั ะทะฐะฒะธัะธั, ะบะฐะบ ะผั ะตะณะพ ะธัะฟะพะปัะทัะตะผ. ะะปั ัะตั , ะบัะพ ั ะพัะตั ัะทะฝะฐัั ะฑะพะปััะต ะพ ัะพะผ, ััะพ ะผั ะพะฑััะถะดะฐะปะธ ัะตะณะพะดะฝั, ะฒั ะผะพะถะตัะต ะฝะฐะนัะธ ะฑะพะปะตะต ะฟะพะดัะพะฑะฝัั ะธะฝัะพัะผะฐัะธั ะฒ ะผะพะตะผ ะฑะปะพะณะต ะธ ะฝะตะดะฐะฒะฝะพ ะพะฟัะฑะปะธะบะพะฒะฐะฝะฝะพะน ะบะฝะธะณะต."} | |
] | |
} | |
def _get_default_korean_conversation(self) -> Dict: | |
"""๊ธฐ๋ณธ ํ๊ตญ์ด ๋ํ ํ ํ๋ฆฟ""" | |
return { | |
"conversation": [ | |
{"speaker": "์ค์", "text": "์๋ ํ์ธ์, ์ฌ๋ฌ๋ถ! ์ค๋์ ์ ๋ง ์ค์ํ๊ณ ํฅ๋ฏธ๋ก์ด ์ฃผ์ ๋ฅผ ๋ค๋ค๋ณด๋ ค๊ณ ํฉ๋๋ค. ๋ฏผํธ ๋ฐ์ฌ๋, ๋จผ์ ์ด ์ฃผ์ ๊ฐ ์ ์ง๊ธ ์ด๋ ๊ฒ ์ฃผ๋ชฉ๋ฐ๊ณ ์๋์ง ์ค๋ช ํด์ฃผ์๊ฒ ์ด์?"}, | |
{"speaker": "๋ฏผํธ", "text": "๋ค, ์๋ ํ์ธ์. ์ต๊ทผ ์ด ๋ถ์ผ์์ ํ๊ธฐ์ ์ธ ๋ฐ์ ์ด ์์์ต๋๋ค. ํนํ ์๋ MIT ์ฐ๊ตฌํ์ ๋ฐํ์ ๋ฐ๋ฅด๋ฉด, ์ด ๊ธฐ์ ์ ํจ์จ์ฑ์ด ๊ธฐ์กด ๋๋น 300% ํฅ์๋์๋ค๊ณ ํฉ๋๋ค. ์ด๋ ๋จ์ํ ๊ธฐ์ ์ ์ง๋ณด๋ฅผ ๋์ด์ ์ฐ๋ฆฌ ์ผ์์ํ์ ์ง์ ์ ์ธ ์ํฅ์ ๋ฏธ์น ์ ์๋ ๋ณํ์ธ๋ฐ์. ์ค์ ๋ก ๊ตฌ๊ธ๊ณผ ๋ง์ดํฌ๋ก์ํํธ ๊ฐ์ ๋น ํ ํฌ ๊ธฐ์ ๋ค์ด ์ด๋ฏธ ์์ญ์ต ๋ฌ๋ฌ๋ฅผ ํฌ์ํ๊ณ ์์ต๋๋ค."}, | |
{"speaker": "์ค์", "text": "์, 300% ํฅ์์ด๋ผ๋ ์ ๋ง ๋๋ผ์ด๋ฐ์. ๊ทธ๋ ๋ค๋ฉด ์ด๋ฐ ๊ธฐ์ ๋ฐ์ ์ด ์ผ๋ฐ์ธ๋ค์๊ฒ๋ ๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ค ํํ์ ๊ฐ์ ธ๋ค์ค ์ ์์๊น์?"}, | |
{"speaker": "๋ฏผํธ", "text": "๊ฐ์ฅ ์ง์ ์ ์ธ ํํ์ ๋น์ฉ ์ ๊ฐ๊ณผ ์ ๊ทผ์ฑ ํฅ์์ ๋๋ค. ์๋ฅผ ๋ค์ด, ์ด์ ์๋ ์ ๋ฌธ๊ฐ๋ง ์ฌ์ฉํ ์ ์๋ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ค์ด ์ด์ ๋ ์ค๋งํธํฐ ์ฑ์ผ๋ก๋ ๊ตฌํ ๊ฐ๋ฅํด์ก์ต๋๋ค. ๋งฅํจ์ง ๋ณด๊ณ ์์ ๋ฐ๋ฅด๋ฉด, 2025๋ ๊น์ง ์ด ๊ธฐ์ ๋ก ์ธํด ์ ์ธ๊ณ์ ์ผ๋ก ์ฝ 2์กฐ ๋ฌ๋ฌ์ ๊ฒฝ์ ์ ๊ฐ์น๊ฐ ์ฐฝ์ถ๋ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค. ํนํ ์๋ฃ, ๊ต์ก, ๊ธ์ต ๋ถ์ผ์์ ํ์ ์ ์ธ ๋ณํ๊ฐ ์ผ์ด๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค."}, | |
{"speaker": "์ค์", "text": "2์กฐ ๋ฌ๋ฌ๋ผ๋ ์์ฒญ๋ ๊ท๋ชจ๋ค์. ์๋ฃ ๋ถ์ผ์์๋ ์ด๋ค ๋ณํ๊ฐ ์์๋๋์?"}, | |
{"speaker": "๋ฏผํธ", "text": "์๋ฃ ๋ถ์ผ์ ๋ณํ๋ ์ ๋ง ํ๋ช ์ ์ผ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค. ์ด๋ฏธ ์คํ ํฌ๋ ๋ํ๋ณ์์์๋ ์ด ๊ธฐ์ ์ ํ์ฉํด ์ ์ง๋จ ์ ํ๋๋ฅผ 95%๊น์ง ๋์์ต๋๋ค. ๊ธฐ์กด์๋ ์๋ จ๋ ์์ฌ๋ ๋์น ์ ์๋ ๋ฏธ์ธํ ๋ณ๋ณ๋ค์ AI๊ฐ ๊ฐ์งํด๋ด๋ ๊ฒ์ด์ฃ . ๋ ๋๋ผ์ด ๊ฒ์ ์ด๋ฐ ์ง๋จ์ด ๋จ ๋ช ๋ถ ๋ง์ ์ด๋ค์ง๋ค๋ ์ ์ ๋๋ค. WHO ์ถ์ฐ์ผ๋ก๋ ์ด ๊ธฐ์ ์ด ์ ์ธ๊ณ์ ์ผ๋ก ๋ณด๊ธ๋๋ฉด ์ฐ๊ฐ ์๋ฐฑ๋ง ๋ช ์ ์๋ช ์ ๊ตฌํ ์ ์์ ๊ฒ์ผ๋ก ์์ธกํ๊ณ ์์ต๋๋ค."}, | |
{"speaker": "์ค์", "text": "์ ๋ง ์ธ์์ ์ด๋ค์. ํ์ง๋ง ์ด๋ฐ ๊ธ๊ฒฉํ ๊ธฐ์ ๋ฐ์ ์ ๋ํ ์ฐ๋ ค์ ๋ชฉ์๋ฆฌ๋ ์์ ๊ฒ ๊ฐ์๋ฐ์?"}, | |
{"speaker": "๋ฏผํธ", "text": "๋ง์ต๋๋ค. ์ฃผ์ ์ฐ๋ ค์ฌํญ์ ํฌ๊ฒ ์ธ ๊ฐ์ง์ ๋๋ค. ์ฒซ์งธ๋ ์ผ์๋ฆฌ ๋์ฒด ๋ฌธ์ ๋ก, ์ฅ์คํฌ๋ ๋ํ ์ฐ๊ตฌ์ ๋ฐ๋ฅด๋ฉด ํฅํ 20๋ ๋ด์ ํ์ฌ ์ง์ ์ 47%๊ฐ ์๋ํ๋ ์ํ์ด ์์ต๋๋ค. ๋์งธ๋ ํ๋ผ์ด๋ฒ์์ ๋ณด์ ๋ฌธ์ ์ ๋๋ค. ์ ์งธ๋ ๊ธฐ์ ๊ฒฉ์ฐจ๋ก ์ธํ ๋ถํ๋ฑ ์ฌํ์ ๋๋ค. ํ์ง๋ง ์ญ์ฌ์ ์ผ๋ก ๋ณด๋ฉด ์๋ก์ด ๊ธฐ์ ์ ํญ์ ์๋ก์ด ๊ธฐํ๋ ํจ๊ป ๋ง๋ค์ด์๊ธฐ ๋๋ฌธ์, ์ ์ ํ ์ ์ฑ ๊ณผ ๊ต์ก์ผ๋ก ์ด๋ฐ ๋ฌธ์ ๋ค์ ํด๊ฒฐํ ์ ์์ ๊ฒ์ผ๋ก ๋ด ๋๋ค."}, | |
{"speaker": "์ค์", "text": "๊ท ํ์กํ ์๊ฐ์ด ์ค์ํ๊ฒ ๋ค์. ๊ทธ๋ ๋ค๋ฉด ์ฐ๋ฆฌ๊ฐ ์ด๋ฐ ๋ณํ์ ์ด๋ป๊ฒ ๋๋นํด์ผ ํ ๊น์?"}, | |
{"speaker": "๋ฏผํธ", "text": "๊ฐ์ฅ ์ค์ํ ๊ฒ์ ์ง์์ ์ธ ํ์ต๊ณผ ์ ์๋ ฅ์ ๋๋ค. ์ธ๊ณ๊ฒฝ์ ํฌ๋ผ์ 2025๋ ๊น์ง ์ ์ธ๊ณ ๊ทผ๋ก์์ 50%๊ฐ ์ฌ๊ต์ก์ด ํ์ํ ๊ฒ์ผ๋ก ์์ธกํ์ต๋๋ค. ํนํ ๋์งํธ ๋ฆฌํฐ๋ฌ์, ๋นํ์ ์ฌ๊ณ ๋ ฅ, ์ฐฝ์์ฑ ๊ฐ์ ๋ฅ๋ ฅ์ด ์ค์ํด์ง ๊ฒ์ ๋๋ค. ๊ฐ์ธ์ ์ผ๋ก๋ ์จ๋ผ์ธ ๊ต์ก ํ๋ซํผ์ ํ์ฉํ ์๊ธฐ๊ณ๋ฐ์ ์ถ์ฒํฉ๋๋ค. ์๋ฅผ ๋ค์ด Coursera๋ edX ๊ฐ์ ํ๋ซํผ์์๋ ์ธ๊ณ ์ต๊ณ ๋ํ์ ๊ฐ์๋ฅผ ๋ฌด๋ฃ๋ก ๋ค์ ์ ์์ต๋๋ค."}, | |
{"speaker": "์ค์", "text": "์ค์ฉ์ ์ธ ์กฐ์ธ ๊ฐ์ฌํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก ์ด ๋ถ์ผ์ ๋ฏธ๋ ์ ๋ง์ ์ด๋ป๊ฒ ๋ณด์๋์?"}, | |
{"speaker": "๋ฏผํธ", "text": "ํฅํ 10๋ ์ ์ธ๋ฅ ์ญ์ฌ์ ๊ฐ์ฅ ๊ธ๊ฒฉํ ๊ธฐ์ ๋ฐ์ ์ ๊ฒฝํํ๋ ์๊ธฐ๊ฐ ๋ ๊ฒ์ ๋๋ค. ๊ฐํธ๋์ ํ์ดํ ์ฌ์ดํด ๋ถ์์ ๋ฐ๋ฅด๋ฉด, ํ์ฌ ์ฐ๋ฆฌ๋ ์ด ๊ธฐ์ ์ ์ด๊ธฐ ๋จ๊ณ์ ๋ถ๊ณผํฉ๋๋ค. 2030๋ ๊น์ง๋ ์ง๊ธ์ผ๋ก์๋ ์์ํ๊ธฐ ์ด๋ ค์ด ์์ค์ ํ์ ์ด ์ผ์ด๋ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค. ์ค์ํ ๊ฒ์ ์ด๋ฐ ๋ณํ๋ฅผ ๋๋ ค์ํ๊ธฐ๋ณด๋ค๋ ๊ธฐํ๋ก ์ผ์ ๋ ๋์ ๋ฏธ๋๋ฅผ ๋ง๋ค์ด๊ฐ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค."}, | |
{"speaker": "์ค์", "text": "์ ๋ง ํต์ฐฐ๋ ฅ ์๋ ๋ง์์ด๋ค์. ์ค๋ ๋๋ฌด๋ ์ ์ตํ ์๊ฐ์ด์์ต๋๋ค. ์ฒญ์ทจ์ ์ฌ๋ฌ๋ถ๋ ์ค๋ ๋ ผ์๋ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ๋ฏธ๋๋ฅผ ์ค๋นํ์๊ธธ ๋ฐ๋๋๋ค. ๋ฏผํธ ๋ฐ์ฌ๋, ๊ท์คํ ์๊ฐ ๋ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!"}, | |
{"speaker": "๋ฏผํธ", "text": "๊ฐ์ฌํฉ๋๋ค. ์ฒญ์ทจ์ ์ฌ๋ฌ๋ถ๋ค์ด ์ด ๋ณํ์ ์๋๋ฅผ ํ๋ช ํ๊ฒ ํค์ณ๋๊ฐ์๊ธธ ๋ฐ๋๋๋ค. ๊ธฐ์ ์ ๋๊ตฌ์ผ ๋ฟ์ด๊ณ , ๊ทธ๊ฒ์ ์ด๋ป๊ฒ ํ์ฉํ๋์ง๋ ์ฐ๋ฆฌ์๊ฒ ๋ฌ๋ ค์๋ค๋ ์ ์ ๊ธฐ์ตํด์ฃผ์ธ์."} | |
] | |
} | |
def _get_default_english_conversation(self) -> Dict: | |
"""๊ธฐ๋ณธ ์์ด ๋ํ ํ ํ๋ฆฟ""" | |
return { | |
"conversation": [ | |
{"speaker": "Alex", "text": "Welcome everyone to our podcast! Today we're diving into a topic that's reshaping our world. Dr. Jordan, could you start by explaining why this subject has become so critical right now?"}, | |
{"speaker": "Jordan", "text": "Thanks, Alex. We're witnessing an unprecedented convergence of technological breakthroughs. According to a recent Nature publication, advances in this field have accelerated by 400% in just the past two years. This isn't just incremental progress - it's a fundamental shift in how we approach problem-solving. Major institutions like Harvard and Stanford are completely restructuring their research programs to focus on this area, with combined investments exceeding $5 billion annually."}, | |
{"speaker": "Alex", "text": "400% acceleration is staggering! What does this mean for everyday people who might not be tech-savvy?"}, | |
{"speaker": "Jordan", "text": "The impact will be profound yet accessible. Think about how smartphones revolutionized communication - this will be similar but across every aspect of life. McKinsey's latest report projects that by 2026, these technologies will create $4.4 trillion in annual value globally. For individuals, this translates to personalized healthcare that can predict illnesses years in advance, educational systems that adapt to each student's learning style, and financial tools that democratize wealth-building strategies previously available only to the ultra-wealthy."}, | |
{"speaker": "Alex", "text": "Those applications sound transformative. Can you give us a concrete example of how this is already being implemented?"}, | |
{"speaker": "Jordan", "text": "Absolutely. Let me share a compelling case from Johns Hopkins Hospital. They've deployed an AI system that analyzes patient data in real-time, reducing diagnostic errors by 85% and cutting average diagnosis time from days to hours. In one documented case, the system identified a rare genetic disorder in a child that had been misdiagnosed for three years. The accuracy comes from analyzing patterns across millions of cases - something impossible for even the most experienced doctors to do manually."}, | |
{"speaker": "Alex", "text": "That's truly life-changing technology. But I imagine there are significant challenges and risks we need to consider?"}, | |
{"speaker": "Jordan", "text": "You're absolutely right to raise this. The challenges are as significant as the opportunities. The World Economic Forum identifies three critical risks: algorithmic bias could perpetuate existing inequalities, cybersecurity threats become exponentially more dangerous, and there's the socioeconomic disruption with PwC estimating that 30% of jobs could be automated by 2030. However, history shows us that technological revolutions create new opportunities even as they displace old ones. The key is proactive adaptation and responsible development."}, | |
{"speaker": "Alex", "text": "How should individuals and organizations prepare for these changes?"}, | |
{"speaker": "Jordan", "text": "Preparation requires a multi-faceted approach. For individuals, I recommend focusing on skills that complement rather than compete with AI: critical thinking, emotional intelligence, and creative problem-solving. MIT's recent study shows that professionals who combine domain expertise with AI literacy see salary increases of 40% on average. Organizations need to invest in continuous learning programs - Amazon's $700 million worker retraining initiative is a good model. Most importantly, we need to cultivate an adaptive mindset."}, | |
{"speaker": "Alex", "text": "That's practical advice. What about the ethical considerations? How do we ensure this technology benefits humanity as a whole?"}, | |
{"speaker": "Jordan", "text": "Ethics must be at the forefront of development. The EU's AI Act and similar regulations worldwide are establishing important guardrails. We need transparent AI systems where decisions can be explained and audited. Companies like IBM and Google have established AI ethics boards, but we need industry-wide standards. Additionally, we must address the digital divide - UNESCO reports that 37% of the global population still lacks internet access. Without inclusive development, these technologies could exacerbate global inequality."}, | |
{"speaker": "Alex", "text": "Looking ahead, what's your vision for how this technology will shape the next decade?"}, | |
{"speaker": "Jordan", "text": "The next decade will be transformative beyond our current imagination. By 2035, I expect we'll see autonomous systems managing entire cities, personalized medicine extending human lifespan by 20-30 years, and educational AI that makes world-class education universally accessible. The convergence of AI with quantum computing, biotechnology, and nanotechnology will unlock possibilities we can barely conceive of today. However, the future isn't predetermined - it's shaped by the choices we make now about development priorities and ethical frameworks."}, | |
{"speaker": "Alex", "text": "Dr. Jordan, this has been an incredibly enlightening discussion. Thank you for sharing your expertise and insights with us today."}, | |
{"speaker": "Jordan", "text": "Thank you, Alex. For listeners wanting to dive deeper, I've compiled additional resources on my website. Remember, the future isn't something that happens to us - it's something we create together. I look forward to seeing how each of you contributes to shaping this exciting new era."} | |
] | |
} | |
def extract_conversation_api(self, text: str, language: str = "English") -> Dict: | |
"""Extract conversation using API""" | |
if not self.llm_client: | |
raise RuntimeError("API mode not initialized") | |
try: | |
# ๊ฒ์ ์ปจํ ์คํธ ์์ฑ | |
search_context = "" | |
if BRAVE_KEY and not text.startswith("Keyword-based content:"): | |
try: | |
keywords = extract_keywords_for_search(text, language) | |
if keywords: | |
search_query = keywords[0] if language == "Korean" else f"{keywords[0]} latest news" | |
search_context = format_search_results(search_query) | |
print(f"Search context added for: {search_query}") | |
except Exception as e: | |
print(f"Search failed, continuing without context: {e}") | |
# ์ธ์ด๋ณ ์์คํ ๋ฉ์์ง | |
if language == "Korean": | |
system_message = ( | |
"๋น์ ์ ํ๊ตญ์ ์ต๊ณ ์ ๋ฌธ ํ์บ์คํธ ์๊ฐ์ ๋๋ค. " | |
"12ํ์ ๊น์ด ์๋ ๋ํ ๊ตํ์ผ๋ก ๊ตฌ์ฑ๋ ๊ณ ํ์ง ๋๋ด์ ํ๊ตญ์ด๋ก ๋ง๋์ธ์. " | |
"๋ฐ๋์ ์๋ก ์กด๋๋ง์ ์ฌ์ฉํ๊ณ ๋ชจ๋ ๋ํ๋ ํ๊ตญ์ด๋ก ์์ฑํ์ธ์." | |
) | |
elif language == "Japanese": | |
system_message = ( | |
"ใใชใใฏๆฅๆฌใฎๆ้ซใฎๅฐ้ใใใใญใฃในใไฝๅฎถใงใใ" | |
"12ๅใฎๆทฑใๅฏพ่ฉฑไบคๆใงๆงๆใใใ้ซๅ่ณชใชๅฏพ่ซใๆฅๆฌ่ชใงไฝๆใใฆใใ ใใใ" | |
"ๅฟ ใใไบใใซไธๅฏง่ชใไฝฟ็จใใใในใฆใฎๅฏพ่ฉฑใฏๆฅๆฌ่ชใงไฝๆใใฆใใ ใใใ" | |
) | |
elif language == "French": | |
system_message = ( | |
"Vous รชtes le meilleur scรฉnariste de podcast professionnel de France. " | |
"Crรฉez des discussions de haute qualitรฉ composรฉes de 12 รฉchanges approfondis en franรงais. " | |
"Toutes les conversations doivent รชtre รฉcrites en franรงais." | |
) | |
elif language == "German": | |
system_message = ( | |
"Sie sind der beste professionelle Podcast-Drehbuchautor Deutschlands. " | |
"Erstellen Sie hochwertige Diskussionen aus 12 tiefgreifenden Austauschen auf Deutsch. " | |
"Alle Gesprรคche mรผssen auf Deutsch geschrieben werden." | |
) | |
elif language == "Spanish": | |
system_message = ( | |
"Eres el mejor guionista de podcast profesional de Espaรฑa. " | |
"Crea discusiones de alta calidad compuestas por 12 intercambios profundos en espaรฑol. " | |
"Todas las conversaciones deben estar escritas en espaรฑol." | |
) | |
elif language == "Chinese": | |
system_message = ( | |
"ๆจๆฏไธญๅฝๆๅฅฝ็ไธไธๆญๅฎข็ผๅงใ" | |
"ๅๅปบ็ฑ12ๆฌกๆทฑๅ ฅไบคๆต็ปๆ็้ซ่ดจ้่ฎจ่ฎบ๏ผไฝฟ็จไธญๆใ" | |
"ๆๆๅฏน่ฏ้ฝๅฟ ้กป็จไธญๆไนฆๅใ" | |
) | |
elif language == "Russian": | |
system_message = ( | |
"ะั ะปัััะธะน ะฟัะพัะตััะธะพะฝะฐะปัะฝัะน ััะตะฝะฐัะธัั ะฟะพะดะบะฐััะพะฒ ะฒ ะ ะพััะธะธ. " | |
"ะกะพะทะดะฐะนัะต ะฒััะพะบะพะบะฐัะตััะฒะตะฝะฝัะต ะดะธัะบัััะธะธ ะธะท 12 ะณะปัะฑะพะบะธั ะพะฑะผะตะฝะพะฒ ะฝะฐ ััััะบะพะผ ัะทัะบะต. " | |
"ะัะต ัะฐะทะณะพะฒะพัั ะดะพะปะถะฝั ะฑััั ะฝะฐะฟะธัะฐะฝั ะฝะฐ ััััะบะพะผ ัะทัะบะต." | |
) | |
else: | |
system_message = ( | |
f"You are a top professional podcast scriptwriter. " | |
f"Create high-quality discussions in {language} with exactly 12 exchanges. " | |
f"Include specific data, research findings, and real cases. " | |
f"All conversations must be written in {language}." | |
) | |
chat_completion = self.llm_client.chat.completions.create( | |
messages=[ | |
{"role": "system", "content": system_message}, | |
{"role": "user", "content": self._build_prompt(text, language, search_context)} | |
], | |
model=self.config.api_model_name, | |
temperature=0.75, | |
) | |
pattern = r"\{(?:[^{}]|(?:\{[^{}]*\}))*\}" | |
json_match = re.search(pattern, chat_completion.choices[0].message.content) | |
if not json_match: | |
raise ValueError("No valid JSON found in response") | |
return json.loads(json_match.group()) | |
except Exception as e: | |
raise RuntimeError(f"Failed to extract conversation: {e}") | |
def parse_conversation_text(self, conversation_text: str) -> Dict: | |
"""Parse conversation text back to JSON format""" | |
lines = conversation_text.strip().split('\n') | |
conversation_data = {"conversation": []} | |
for line in lines: | |
if ':' in line: | |
speaker, text = line.split(':', 1) | |
conversation_data["conversation"].append({ | |
"speaker": speaker.strip(), | |
"text": text.strip() | |
}) | |
return conversation_data | |
async def text_to_speech_edge(self, conversation_json: Dict, language: str = "English") -> Tuple[str, str]: | |
"""Convert text to speech using Edge TTS""" | |
output_dir = Path(self._create_output_directory()) | |
filenames = [] | |
try: | |
# ์ธ์ด๋ณ ์์ฑ ์ค์ | |
voices = EDGE_TTS_VOICES.get(language, EDGE_TTS_VOICES["English"]) | |
for i, turn in enumerate(conversation_json["conversation"]): | |
filename = output_dir / f"output_{i}.wav" | |
voice = voices[i % len(voices)] | |
tmp_path = await self._generate_audio_edge(turn["text"], voice) | |
os.rename(tmp_path, filename) | |
filenames.append(str(filename)) | |
# Combine audio files | |
final_output = os.path.join(output_dir, "combined_output.wav") | |
self._combine_audio_files(filenames, final_output) | |
# Generate conversation text | |
conversation_text = "\n".join( | |
f"{turn.get('speaker', f'Speaker {i+1}')}: {turn['text']}" | |
for i, turn in enumerate(conversation_json["conversation"]) | |
) | |
return final_output, conversation_text | |
except Exception as e: | |
raise RuntimeError(f"Failed to convert text to speech: {e}") | |
async def _generate_audio_edge(self, text: str, voice: str) -> str: | |
"""Generate audio using Edge TTS""" | |
if not text.strip(): | |
raise ValueError("Text cannot be empty") | |
voice_short_name = voice.split(" - ")[0] if " - " in voice else voice | |
communicate = edge_tts.Communicate(text, voice_short_name) | |
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file: | |
tmp_path = tmp_file.name | |
await communicate.save(tmp_path) | |
return tmp_path | |
def text_to_speech_spark(self, conversation_json: Dict, language: str = "English", progress=None) -> Tuple[str, str]: | |
"""Convert text to speech using Spark TTS CLI""" | |
if not SPARK_AVAILABLE or not self.spark_model_dir: | |
raise RuntimeError("Spark TTS not available") | |
try: | |
output_dir = self._create_output_directory() | |
audio_files = [] | |
# Create different voice characteristics for different speakers | |
if language == "Korean": | |
voice_configs = [ | |
{"prompt_text": "์๋ ํ์ธ์, ์ค๋ ํ์บ์คํธ ์งํ์ ๋งก์ ์ค์์ ๋๋ค.", "gender": "male"}, | |
{"prompt_text": "์๋ ํ์ธ์, ์ ๋ ์ค๋ ์ด ์ฃผ์ ์ ๋ํด ์ค๋ช ๋๋ฆด ๋ฏผํธ์ ๋๋ค.", "gender": "male"} | |
] | |
else: | |
voice_configs = [ | |
{"prompt_text": "Hello everyone, I'm Alex, your host for today's podcast.", "gender": "male"}, | |
{"prompt_text": "Hi, I'm Jordan. I'm excited to share my insights with you.", "gender": "male"} | |
] | |
for i, turn in enumerate(conversation_json["conversation"]): | |
text = turn["text"] | |
if not text.strip(): | |
continue | |
voice_config = voice_configs[i % len(voice_configs)] | |
output_file = os.path.join(output_dir, f"spark_output_{i}.wav") | |
cmd = [ | |
"python", "-m", "cli.inference", | |
"--text", text, | |
"--device", "0" if torch.cuda.is_available() else "cpu", | |
"--save_dir", output_dir, | |
"--model_dir", self.spark_model_dir, | |
"--prompt_text", voice_config["prompt_text"], | |
"--output_name", f"spark_output_{i}.wav" | |
] | |
try: | |
result = subprocess.run( | |
cmd, | |
capture_output=True, | |
text=True, | |
timeout=60, | |
cwd="." | |
) | |
if result.returncode == 0: | |
audio_files.append(output_file) | |
else: | |
print(f"Spark TTS error for turn {i}: {result.stderr}") | |
silence = np.zeros(int(22050 * 1.0)) | |
sf.write(output_file, silence, 22050) | |
audio_files.append(output_file) | |
except subprocess.TimeoutExpired: | |
print(f"Spark TTS timeout for turn {i}") | |
silence = np.zeros(int(22050 * 1.0)) | |
sf.write(output_file, silence, 22050) | |
audio_files.append(output_file) | |
except Exception as e: | |
print(f"Error running Spark TTS for turn {i}: {e}") | |
silence = np.zeros(int(22050 * 1.0)) | |
sf.write(output_file, silence, 22050) | |
audio_files.append(output_file) | |
# Combine all audio files | |
if audio_files: | |
final_output = os.path.join(output_dir, "spark_combined.wav") | |
self._combine_audio_files(audio_files, final_output) | |
else: | |
raise RuntimeError("No audio files generated") | |
conversation_text = "\n".join( | |
f"{turn.get('speaker', f'Speaker {i+1}')}: {turn['text']}" | |
for i, turn in enumerate(conversation_json["conversation"]) | |
) | |
return final_output, conversation_text | |
except Exception as e: | |
raise RuntimeError(f"Failed to convert text to speech with Spark TTS: {e}") | |
def text_to_speech_melo(self, conversation_json: Dict, progress=None) -> Tuple[str, str]: | |
"""Convert text to speech using MeloTTS""" | |
if not MELO_AVAILABLE or not self.melo_models: | |
raise RuntimeError("MeloTTS not available") | |
speakers = ["EN-Default", "EN-US"] | |
combined_audio = AudioSegment.empty() | |
for i, turn in enumerate(conversation_json["conversation"]): | |
bio = io.BytesIO() | |
text = turn["text"] | |
speaker = speakers[i % 2] | |
speaker_id = self.melo_models["EN"].hps.data.spk2id[speaker] | |
self.melo_models["EN"].tts_to_file( | |
text, speaker_id, bio, speed=1.0, | |
pbar=progress.tqdm if progress else None, | |
format="wav" | |
) | |
bio.seek(0) | |
audio_segment = AudioSegment.from_file(bio, format="wav") | |
combined_audio += audio_segment | |
final_audio_path = "melo_podcast.mp3" | |
combined_audio.export(final_audio_path, format="mp3") | |
conversation_text = "\n".join( | |
f"{turn.get('speaker', f'Speaker {i+1}')}: {turn['text']}" | |
for i, turn in enumerate(conversation_json["conversation"]) | |
) | |
return final_audio_path, conversation_text | |
def _create_output_directory(self) -> str: | |
"""Create a unique output directory""" | |
random_bytes = os.urandom(8) | |
folder_name = base64.urlsafe_b64encode(random_bytes).decode("utf-8") | |
os.makedirs(folder_name, exist_ok=True) | |
return folder_name | |
def _combine_audio_files(self, filenames: List[str], output_file: str) -> None: | |
"""Combine multiple audio files into one""" | |
if not filenames: | |
raise ValueError("No input files provided") | |
try: | |
audio_segments = [] | |
for filename in filenames: | |
if os.path.exists(filename): | |
audio_segment = AudioSegment.from_file(filename) | |
audio_segments.append(audio_segment) | |
if audio_segments: | |
combined = sum(audio_segments) | |
combined.export(output_file, format="wav") | |
# Clean up temporary files | |
for filename in filenames: | |
if os.path.exists(filename): | |
os.remove(filename) | |
except Exception as e: | |
raise RuntimeError(f"Failed to combine audio files: {e}") | |
# Global converter instance | |
converter = UnifiedAudioConverter(ConversationConfig()) | |
async def synthesize(article_input, input_type: str = "URL", mode: str = "Local", tts_engine: str = "Edge-TTS", language: str = "English"): | |
"""Main synthesis function - handles URL, PDF, and Keyword inputs""" | |
try: | |
# Extract text based on input type | |
if input_type == "URL": | |
if not article_input or not isinstance(article_input, str): | |
return "Please provide a valid URL.", None | |
text = converter.fetch_text(article_input) | |
elif input_type == "PDF": | |
if not article_input: | |
return "Please upload a PDF file.", None | |
text = converter.extract_text_from_pdf(article_input) | |
else: # Keyword | |
if not article_input or not isinstance(article_input, str): | |
return "Please provide a keyword or topic.", None | |
text = search_and_compile_content(article_input, language) | |
text = f"Keyword-based content:\n{text}" | |
# Limit text to max words | |
words = text.split() | |
if len(words) > converter.config.max_words: | |
text = " ".join(words[:converter.config.max_words]) | |
# Extract conversation based on mode | |
if mode == "Local": | |
try: | |
conversation_json = converter.extract_conversation_local(text, language) | |
except Exception as e: | |
print(f"Local mode failed: {e}, trying API fallback") | |
api_key = os.environ.get("TOGETHER_API_KEY") | |
if api_key: | |
converter.initialize_api_mode(api_key) | |
conversation_json = converter.extract_conversation_api(text, language) | |
else: | |
raise RuntimeError("Local mode failed and no API key available for fallback") | |
else: # API mode | |
api_key = os.environ.get("TOGETHER_API_KEY") | |
if not api_key: | |
print("API key not found, falling back to local mode") | |
conversation_json = converter.extract_conversation_local(text, language) | |
else: | |
try: | |
converter.initialize_api_mode(api_key) | |
conversation_json = converter.extract_conversation_api(text, language) | |
except Exception as e: | |
print(f"API mode failed: {e}, falling back to local mode") | |
conversation_json = converter.extract_conversation_local(text, language) | |
# Generate conversation text | |
conversation_text = "\n".join( | |
f"{turn.get('speaker', f'Speaker {i+1}')}: {turn['text']}" | |
for i, turn in enumerate(conversation_json["conversation"]) | |
) | |
return conversation_text, None | |
except Exception as e: | |
return f"Error: {str(e)}", None | |
async def regenerate_audio(conversation_text: str, tts_engine: str = "Edge-TTS", language: str = "English"): | |
"""Regenerate audio from edited conversation text""" | |
if not conversation_text.strip(): | |
return "Please provide conversation text.", None | |
try: | |
conversation_json = converter.parse_conversation_text(conversation_text) | |
if not conversation_json["conversation"]: | |
return "No valid conversation found in the text.", None | |
# Edge TTS ์ ์ฉ ์ธ์ด๋ ์๋์ผ๋ก Edge-TTS ์ฌ์ฉ | |
if language in EDGE_TTS_ONLY_LANGUAGES and tts_engine != "Edge-TTS": | |
tts_engine = "Edge-TTS" | |
# Generate audio based on TTS engine | |
if tts_engine == "Edge-TTS": | |
output_file, _ = await converter.text_to_speech_edge(conversation_json, language) | |
elif tts_engine == "Spark-TTS": | |
if not SPARK_AVAILABLE: | |
return "Spark TTS not available. Please install required dependencies and clone the Spark-TTS repository.", None | |
converter.initialize_spark_tts() | |
output_file, _ = converter.text_to_speech_spark(conversation_json, language) | |
else: # MeloTTS | |
if not MELO_AVAILABLE: | |
return "MeloTTS not available. Please install required dependencies.", None | |
if language in EDGE_TTS_ONLY_LANGUAGES: | |
return f"MeloTTS does not support {language}. Please use Edge-TTS for this language.", None | |
converter.initialize_melo_tts() | |
output_file, _ = converter.text_to_speech_melo(conversation_json) | |
return "Audio generated successfully!", output_file | |
except Exception as e: | |
return f"Error generating audio: {str(e)}", None | |
def synthesize_sync(article_input, input_type: str = "URL", mode: str = "Local", tts_engine: str = "Edge-TTS", language: str = "English"): | |
"""Synchronous wrapper for async synthesis""" | |
return asyncio.run(synthesize(article_input, input_type, mode, tts_engine, language)) | |
def regenerate_audio_sync(conversation_text: str, tts_engine: str = "Edge-TTS", language: str = "English"): | |
"""Synchronous wrapper for async audio regeneration""" | |
return asyncio.run(regenerate_audio(conversation_text, tts_engine, language)) | |
def update_tts_engine_for_language(language): | |
"""์ธ์ด๋ณ TTS ์์ง ์ต์ ์ ๋ฐ์ดํธ""" | |
if language in EDGE_TTS_ONLY_LANGUAGES: | |
language_info = { | |
"Korean": "ํ๊ตญ์ด๋ Edge-TTS๋ง ์ง์๋ฉ๋๋ค", | |
"Japanese": "ๆฅๆฌ่ชใฏEdge-TTSใฎใฟใตใใผใใใใฆใใพใ", | |
"French": "Le franรงais n'est pris en charge que par Edge-TTS", | |
"German": "Deutsch wird nur von Edge-TTS unterstรผtzt", | |
"Spanish": "El espaรฑol solo es compatible con Edge-TTS", | |
"Italian": "L'italiano รจ supportato solo da Edge-TTS", | |
"Portuguese": "O portuguรชs รฉ suportado apenas pelo Edge-TTS", | |
"Dutch": "Nederlands wordt alleen ondersteund door Edge-TTS", | |
"Thai": "เธ เธฒเธฉเธฒเนเธเธขเธฃเธญเธเธฃเธฑเธเนเธเธเธฒเธฐ Edge-TTS เนเธเนเธฒเธเธฑเนเธ", | |
"Vietnamese": "Tiแบฟng Viแปt chแป ฤฦฐแปฃc hแป trแปฃ bแปi Edge-TTS", | |
"Arabic": "ุงูุนุฑุจูุฉ ู ุฏุนูู ุฉ ููุท ู ู Edge-TTS", | |
"Hebrew": "ืขืืจืืช ื ืชืืืช ืจืง ืขื ืืื Edge-TTS", | |
"Indonesian": "Bahasa Indonesia hanya didukung oleh Edge-TTS", | |
"Hindi": "เคนเคฟเคเคฆเฅ เคเฅเคตเคฒ Edge-TTS เคฆเฅเคตเคพเคฐเคพ เคธเคฎเคฐเฅเคฅเคฟเคค เคนเฅ", | |
"Russian": "ะ ัััะบะธะน ะฟะพะดะดะตัะถะธะฒะฐะตััั ัะพะปัะบะพ Edge-TTS", | |
"Chinese": "ไธญๆไป ๆฏๆEdge-TTS" | |
} | |
info_text = language_info.get(language, f"{language} is only supported by Edge-TTS") | |
return gr.Radio( | |
choices=["Edge-TTS"], | |
value="Edge-TTS", | |
label="TTS Engine", | |
info=info_text, | |
interactive=False | |
) | |
else: | |
return gr.Radio( | |
choices=["Edge-TTS", "Spark-TTS", "MeloTTS"], | |
value="Edge-TTS", | |
label="TTS Engine", | |
info="Edge-TTS: Cloud-based, natural voices | Spark-TTS: Local AI model | MeloTTS: Local, requires GPU", | |
interactive=True | |
) | |
def toggle_input_visibility(input_type): | |
"""Toggle visibility of URL input, file upload, and keyword input based on input type""" | |
if input_type == "URL": | |
return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False) | |
elif input_type == "PDF": | |
return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False) | |
else: # Keyword | |
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True) | |
# ๋ชจ๋ธ ์ด๊ธฐํ (์ฑ ์์ ์) | |
if LLAMA_CPP_AVAILABLE: | |
try: | |
model_path = hf_hub_download( | |
repo_id=converter.config.local_model_repo, | |
filename=converter.config.local_model_name, | |
local_dir="./models" | |
) | |
print(f"Model downloaded to: {model_path}") | |
except Exception as e: | |
print(f"Failed to download model at startup: {e}") | |
# Gradio Interface - ๊ฐ์ ๋ ๋ค๊ตญ์ด ๋ ์ด์์ | |
with gr.Blocks(theme='soft', title="AI Podcast Generator", css=""" | |
.container {max-width: 1200px; margin: auto; padding: 20px;} | |
.header-text {text-align: center; margin-bottom: 30px;} | |
.input-group {background: #f7f7f7; padding: 20px; border-radius: 10px; margin-bottom: 20px;} | |
.output-group {background: #f0f0f0; padding: 20px; border-radius: 10px;} | |
.status-box {background: #e8f4f8; padding: 15px; border-radius: 8px; margin-top: 10px;} | |
""") as demo: | |
with gr.Column(elem_classes="container"): | |
# ํค๋ | |
with gr.Row(elem_classes="header-text"): | |
gr.Markdown(""" | |
# ๐๏ธ AI Podcast Generator - Professional Multi-Language Edition | |
### Convert any article, blog, PDF document, or topic into an engaging professional podcast conversation in 24+ languages! | |
""") | |
with gr.Row(elem_classes="discord-badge"): | |
gr.HTML(""" | |
<p style="text-align: center;"> | |
<a href="https://discord.gg/openfreeai" target="_blank"> | |
<img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=%230000ff&labelColor=%23800080&logo=discord&logoColor=white&style=for-the-badge" alt="badge"> | |
</a> | |
</p> | |
""") | |
# ์ํ ํ์ ์น์ | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown(f""" | |
#### ๐ค System Status | |
- **LLM**: {converter.config.local_model_name.split('.')[0]} | |
- **Fallback**: {converter.config.api_model_name.split('/')[-1]} | |
- **Llama CPP**: {"โ Ready" if LLAMA_CPP_AVAILABLE else "โ Not Available"} | |
- **Search**: {"โ Brave API" if BRAVE_KEY else "โ No API"} | |
""") | |
with gr.Column(scale=1): | |
gr.Markdown(""" | |
#### ๐ Multi-Language Support | |
- **24+ Languages**: Korean, Japanese, French, German, Spanish, Italian, etc. | |
- **Native Voices**: Optimized for each language | |
- **Professional Style**: Expert discussions with data & insights | |
- **Auto-TTS Selection**: Best engine per language | |
""") | |
# ๋ฉ์ธ ์ ๋ ฅ ์น์ | |
with gr.Group(elem_classes="input-group"): | |
with gr.Row(): | |
# ์ผ์ชฝ: ์ ๋ ฅ ์ต์ ๋ค | |
with gr.Column(scale=2): | |
# ์ ๋ ฅ ํ์ ์ ํ | |
input_type_selector = gr.Radio( | |
choices=["URL", "PDF", "Keyword"], | |
value="URL", | |
label="๐ฅ Input Type", | |
info="Choose your content source" | |
) | |
# URL ์ ๋ ฅ | |
url_input = gr.Textbox( | |
label="๐ Article URL", | |
placeholder="Enter the article URL here...", | |
value="", | |
visible=True, | |
lines=2 | |
) | |
# PDF ์ ๋ก๋ | |
pdf_input = gr.File( | |
label="๐ Upload PDF", | |
file_types=[".pdf"], | |
visible=False | |
) | |
# ํค์๋ ์ ๋ ฅ | |
keyword_input = gr.Textbox( | |
label="๐ Topic/Keyword", | |
placeholder="Enter a topic (e.g., 'AI trends 2024', '์ธ๊ณต์ง๋ฅ', 'IA tendances', 'KI Trends')", | |
value="", | |
visible=False, | |
info="System will search and compile latest information", | |
lines=2 | |
) | |
# ์ค๋ฅธ์ชฝ: ์ค์ ์ต์ ๋ค | |
with gr.Column(scale=1): | |
# ์ธ์ด ์ ํ | |
language_selector = gr.Radio( | |
choices=[ | |
"English", "Korean", "Japanese", "French", "German", | |
"Spanish", "Italian", "Portuguese", "Dutch", "Thai", | |
"Vietnamese", "Arabic", "Hebrew", "Indonesian", "Hindi", | |
"Russian", "Chinese", "Norwegian", "Swedish", "Finnish", | |
"Danish", "Polish", "Turkish", "Greek", "Czech" | |
], | |
value="English", | |
label="๐ Language / ์ธ์ด / ่ฏญ่จ", | |
info="Select podcast language" | |
) | |
# ์ฒ๋ฆฌ ๋ชจ๋ | |
mode_selector = gr.Radio( | |
choices=["Local", "API"], | |
value="Local", | |
label="โ๏ธ Processing Mode", | |
info="Local: On-device | API: Cloud" | |
) | |
# TTS ์์ง | |
tts_selector = gr.Radio( | |
choices=["Edge-TTS", "Spark-TTS", "MeloTTS"], | |
value="Edge-TTS", | |
label="๐ TTS Engine", | |
info="Voice synthesis engine" | |
) | |
# ์์ฑ ๋ฒํผ | |
with gr.Row(): | |
convert_btn = gr.Button( | |
"๐ฏ Generate Professional Conversation", | |
variant="primary", | |
size="lg", | |
scale=1 | |
) | |
# ์ถ๋ ฅ ์น์ | |
with gr.Group(elem_classes="output-group"): | |
with gr.Row(): | |
# ์ผ์ชฝ: ๋ํ ํ ์คํธ | |
with gr.Column(scale=3): | |
conversation_output = gr.Textbox( | |
label="๐ฌ Generated Professional Conversation (Editable)", | |
lines=25, | |
max_lines=50, | |
interactive=True, | |
placeholder="Professional podcast conversation will appear here...\n์ ๋ฌธ ํ์บ์คํธ ๋ํ๊ฐ ์ฌ๊ธฐ์ ํ์๋ฉ๋๋ค...\nLa conversation professionnelle du podcast apparaรฎtra ici...", | |
info="Edit the conversation as needed. Format: 'Speaker Name: Text'" | |
) | |
# ์ค๋์ค ์์ฑ ๋ฒํผ | |
with gr.Row(): | |
generate_audio_btn = gr.Button( | |
"๐๏ธ Generate Audio from Text", | |
variant="secondary", | |
size="lg" | |
) | |
# ์ค๋ฅธ์ชฝ: ์ค๋์ค ์ถ๋ ฅ ๋ฐ ์ํ | |
with gr.Column(scale=2): | |
audio_output = gr.Audio( | |
label="๐ง Professional Podcast Audio", | |
type="filepath", | |
interactive=False | |
) | |
status_output = gr.Textbox( | |
label="๐ Status", | |
interactive=False, | |
lines=3, | |
elem_classes="status-box" | |
) | |
# ๋์๋ง | |
gr.Markdown(""" | |
#### ๐ก Quick Tips: | |
- **URL**: Paste any article link | |
- **PDF**: Upload documents directly | |
- **Keyword**: Enter topics for AI research | |
- **24+ Languages** fully supported | |
- Edit conversation before audio generation | |
- Auto TTS engine selection per language | |
""") | |
# ์์ ์น์ | |
with gr.Accordion("๐ Multi-Language Examples", open=False): | |
gr.Examples( | |
examples=[ | |
["https://huggingface.co/blog/openfreeai/cycle-navigator", "URL", "Local", "Edge-TTS", "English"], | |
["quantum computing breakthroughs", "Keyword", "Local", "Edge-TTS", "English"], | |
["์ธ๊ณต์ง๋ฅ ์ค๋ฆฌ์ ๊ท์ ", "Keyword", "Local", "Edge-TTS", "Korean"], | |
["https://huggingface.co/papers/2505.14810", "URL", "Local", "Edge-TTS", "Japanese"], | |
["intelligence artificielle tendances", "Keyword", "Local", "Edge-TTS", "French"], | |
["kรผnstliche intelligenz entwicklung", "Keyword", "Local", "Edge-TTS", "German"], | |
["inteligencia artificial avances", "Keyword", "Local", "Edge-TTS", "Spanish"], | |
], | |
inputs=[url_input, input_type_selector, mode_selector, tts_selector, language_selector], | |
outputs=[conversation_output, status_output], | |
fn=synthesize_sync, | |
cache_examples=False, | |
) | |
# Input type change handler | |
input_type_selector.change( | |
fn=toggle_input_visibility, | |
inputs=[input_type_selector], | |
outputs=[url_input, pdf_input, keyword_input] | |
) | |
# ์ธ์ด ๋ณ๊ฒฝ ์ TTS ์์ง ์ต์ ์ ๋ฐ์ดํธ | |
language_selector.change( | |
fn=update_tts_engine_for_language, | |
inputs=[language_selector], | |
outputs=[tts_selector] | |
) | |
# ์ด๋ฒคํธ ์ฐ๊ฒฐ | |
def get_article_input(input_type, url_input, pdf_input, keyword_input): | |
"""Get the appropriate input based on input type""" | |
if input_type == "URL": | |
return url_input | |
elif input_type == "PDF": | |
return pdf_input | |
else: # Keyword | |
return keyword_input | |
convert_btn.click( | |
fn=lambda input_type, url_input, pdf_input, keyword_input, mode, tts, lang: synthesize_sync( | |
get_article_input(input_type, url_input, pdf_input, keyword_input), input_type, mode, tts, lang | |
), | |
inputs=[input_type_selector, url_input, pdf_input, keyword_input, mode_selector, tts_selector, language_selector], | |
outputs=[conversation_output, status_output] | |
) | |
generate_audio_btn.click( | |
fn=regenerate_audio_sync, | |
inputs=[conversation_output, tts_selector, language_selector], | |
outputs=[status_output, audio_output] | |
) | |
# Launch the app | |
if __name__ == "__main__": | |
demo.queue(api_open=True, default_concurrency_limit=10).launch( | |
show_api=True, | |
share=False, | |
server_name="0.0.0.0", | |
server_port=7860 | |
) |