import gradio as gr
from gradio_client import Client
import json
import logging
import ast
import openai
import os
import random
import re
logging.basicConfig(filename='youtube_script_extractor.log', level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s')
openai.api_key = os.getenv("OPENAI_API_KEY")
def parse_api_response(response):
try:
if isinstance(response, str):
response = json.loads(response)
if isinstance(response, list) and len(response) > 0:
response = response[0]
if not isinstance(response, dict):
raise ValueError(f"예상치 못한 응답 형식입니다. 받은 데이터 타입: {type(response)}")
return response
except Exception as e:
raise ValueError(f"API 응답 파싱 실패: {str(e)}")
def split_sentences(text):
sentences = re.split(r"(니다|에요|구나|해요|군요|겠어요|시오|해라|예요|아요|데요|대요|세요|어요|게요|구요|고요|나요|하죠)(?![\w])", text)
combined_sentences = []
current_sentence = ""
for i in range(0, len(sentences), 2):
if i + 1 < len(sentences):
sentence = sentences[i] + sentences[i + 1]
else:
sentence = sentences[i]
if len(current_sentence) + len(sentence) > 100:
combined_sentences.append(current_sentence.strip())
current_sentence = sentence.strip()
else:
current_sentence += sentence
if sentence.endswith(('.', '?', '!')):
combined_sentences.append(current_sentence.strip())
current_sentence = ""
if current_sentence:
combined_sentences.append(current_sentence.strip())
return combined_sentences
def get_youtube_script(url):
logging.info(f"스크립트 추출 시작: URL = {url}")
client = Client("whispersound/YT_Ts_R")
try:
logging.debug("API 호출 시작")
result = client.predict(youtube_url=url, api_name="/predict")
logging.debug("API 호출 완료")
parsed_result = parse_api_response(result)
if 'data' not in parsed_result or not parsed_result['data']:
raise ValueError("API 응답에 유효한 데이터가 없습니다.")
title = parsed_result["data"][0].get("title", "제목 없음")
transcription_text = parsed_result["data"][0].get("transcriptionAsText", "")
sections = parsed_result["data"][0].get("sections", [])
if not transcription_text:
raise ValueError("추출된 스크립트가 없습니다.")
logging.info("스크립트 추출 완료")
return title, transcription_text, sections
except Exception as e:
error_msg = f"스크립트 추출 중 오류 발생: {str(e)}"
logging.exception(error_msg)
raise
def call_api(prompt, max_tokens, temperature, top_p):
try:
response = openai.ChatCompletion.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
max_tokens=max_tokens,
temperature=temperature,
top_p=top_p
)
return response['choices'][0]['message']['content']
except Exception as e:
logging.exception("LLM API 호출 중 오류 발생")
raise
def summarize_section(section_text):
prompt = f"""
다음 유튜브 대본 섹션의 핵심 내용을 간결하게 요약하세요:
1. 한글로 작성하세요.
2. 주요 논점과 중요한 세부사항을 포함하세요.
3. 요약은 2-3문장으로 제한하세요.
섹션 내용:
{section_text}
"""
return call_api(prompt, max_tokens=150, temperature=0.3, top_p=0.9)
def format_time(seconds):
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
def generate_timeline_summary(sections):
combined_sections = "\n\n".join([f"{format_time(section['start_time'])}: {section['text']}" for section in sections])
prompt = f"""
다음은 유튜브 영상의 타임라인과 각 섹션의 내용입니다. 이를 바탕으로 타임라인 요약을 생성해주세요:
1. 각 섹션의 시작 시간을 유지하면서 핵심 내용을 간결하게 요약하세요.
2. 요약은 한글로 작성하세요.
3. 각 섹션의 요약은 1-2문장으로 제한하세요.
4. 전체 맥락을 고려하여 요약하되, 각 섹션의 고유한 내용을 놓치지 마세요.
5. 출력 형식은 다음과 같이 유지하세요:
[시작 시간] 섹션 요약
섹션 내용:
{combined_sections}
"""
response = call_api(prompt, max_tokens=1000, temperature=0.3, top_p=0.9)
# 응답을 줄 단위로 분리하고 각 줄을 HTML 형식으로 변환
timeline_html = "
".join(response.split('\n'))
return f"""