import os import gradio as gr # 모듈 코드들을 환경변수에서 가져와서 동적으로 실행 def load_hidden_modules(): """환경변수에서 모듈 코드들을 가져와서 실행 (의존성 순서 고려)""" # 1단계: youtube_transcript_module 코드 먼저 로드 (다른 모듈들이 의존함) youtube_transcript_code = os.environ.get("YOUTUBE_TRANSCRIPT_MODULE_CODE", "") if youtube_transcript_code: # import 문 제거하고 실행 cleaned_code = youtube_transcript_code.replace("from youtube_transcript_module import", "# from youtube_transcript_module import") exec(cleaned_code, globals()) # 2단계: analyze_module 코드 로드 (함수명 충돌 방지) analyze_module_code = os.environ.get("ANALYZE_MODULE_CODE", "") if analyze_module_code: # import 문 수정 및 함수명 변경 cleaned_code = analyze_module_code.replace("from youtube_transcript_module import YouTubeTranscriptClient", "# from youtube_transcript_module import YouTubeTranscriptClient") cleaned_code = cleaned_code.replace("def get_youtube_script(", "def get_youtube_script_analyze(") cleaned_code = cleaned_code.replace("get_youtube_script(url)", "get_youtube_script_analyze(url)") exec(cleaned_code, globals()) # 3단계: 나머지 blog 모듈들 로드 (각각 고유한 함수명 사용) module_configs = [ ("GENERAL_BLOG_MODULE_CODE", "general", "general_process_youtube_url"), ("HEALTH_BLOG_MODULE_CODE", "health", "health_process_youtube_url"), ("TRAVEL_BLOG_MODULE_CODE", "travel", "travel_process_youtube_url"), ("PRODUCT_REVIEW_MODULE_CODE", "product", "product_process_youtube_url") ] for env_key, prefix, func_name in module_configs: module_code = os.environ.get(env_key, "") if module_code: # import 문 정리 및 함수명 변경으로 충돌 방지 cleaned_code = module_code.replace("from youtube_transcript_module import YouTubeTranscriptClient", "# from youtube_transcript_module import YouTubeTranscriptClient") cleaned_code = cleaned_code.replace("def get_youtube_script(", f"def get_youtube_script_{prefix}(") cleaned_code = cleaned_code.replace("get_youtube_script(url)", f"get_youtube_script_{prefix}(url)") cleaned_code = cleaned_code.replace("def process_youtube_url(", f"def {func_name}(") exec(cleaned_code, globals()) # 숨겨진 모듈들 로드 load_hidden_modules() # 기존 첫 번째 API에서 요구하는 형식으로 함수 래핑 def analyze_video(url): """분석 API 엔드포인트 - 기존 형식 유지""" results = analyze(url) # 제너레이터에서 마지막 결과 가져오기 last_result = None for result in results: last_result = result # 기존 반환 형식: [script_output, summary_output, thumbnail_output] return [last_result[0], last_result[1], last_result[2]] def process_youtube_url(url, style): """일반 블로그 API 엔드포인트 - 기존 형식 유지""" # general_blog_module에서 process_youtube_url 함수 호출 process_func = globals().get('general_process_youtube_url') if not process_func: return ["", "일반 블로그 모듈을 찾을 수 없습니다."] results = process_func(url, style) # 제너레이터에서 마지막 결과 가져하기 last_result = None for result in results: last_result = result # 기존 반환 형식: [script_output, blog_output] return [last_result[0], last_result[1]] def process_youtube_url_v1_2(url, style): """생활건강 블로그 API 엔드포인트 - 기존 형식 유지""" # health_blog_module에서 process_youtube_url 함수 호출 process_func = globals().get('health_process_youtube_url') if not process_func: return ["", "생활건강 블로그 모듈을 찾을 수 없습니다."] results = process_func(url, style) # 제너레이터에서 마지막 결과 가져오기 last_result = None for result in results: last_result = result # 기존 반환 형식: [script_output, blog_output] return [last_result[0], last_result[1]] def process_youtube_url_v2(url, style): """여행 블로그 API 엔드포인트 - 기존 형식 유지""" # travel_blog_module에서 process_youtube_url 함수 호출 process_func = globals().get('travel_process_youtube_url') if not process_func: return ["", "여행 블로그 모듈을 찾을 수 없습니다."] results = process_func(url, style) # 제너레이터에서 마지막 결과 가져오기 last_result = None for result in results: last_result = result # 기존 반환 형식: [script_output, blog_output] return [last_result[0], last_result[1]] def process_youtube_url_v3(url, style): """상품후기 블로그 API 엔드포인트 - 기존 형식 유지""" # product_review_module에서 process_youtube_url 함수 호출 process_func = globals().get('product_process_youtube_url') if not process_func: return ["", "상품후기 블로그 모듈을 찾을 수 없습니다."] results = process_func(url, style) # 제너레이터에서 마지막 결과 가져오기 last_result = None for result in results: last_result = result # 기존 반환 형식: [script_output, blog_output] return [last_result[0], last_result[1]] # Gradio UI 구성 (Gradio 5.0 이상의 버전에서 작동) with gr.Blocks(css=""" .thumbnail-container { display: flex; justify-content: center; margin-bottom: 15px; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .thumbnail-container img { max-width: 100%; height: auto; object-fit: cover; } .script-box { border: 1px solid #e0e0e0; padding: 15px; border-radius: 8px; background-color: #f9f9f9; margin-bottom: 15px; } .output-title { font-size: 18px; font-weight: bold; margin-bottom: 10px; color: #333; } details summary { cursor: pointer; font-weight: bold; padding: 8px 0; color: #2196F3; } li { margin-bottom: 5px; } .error-box { border: 1px solid #ff4444; padding: 15px; border-radius: 8px; background-color: #ffeeee; margin-bottom: 15px; color: #cc0000; } """) as demo: with gr.Tabs(): # 첫 번째 탭: /analyze API with gr.TabItem("유튜브 요약"): gr.Markdown("### YouTube URL 입력") with gr.Row(): url_input = gr.Textbox(label="YouTube URL 입력", placeholder="https://www.youtube.com/watch?v=example") # 출력 영역 설정 script_output = gr.HTML(label="원문 스크립트") summary_output = gr.HTML(label="요약") thumbnail_output = gr.Image(label="썸네일", show_label=True) # 버튼 클릭 시 분석 함수 호출 analyze_button = gr.Button("분석 실행") analyze_button.click(analyze_video, inputs=[url_input], outputs=[script_output, summary_output, thumbnail_output]) # 두 번째 탭: 일반 블로그 with gr.TabItem("일반 블로그"): gr.Markdown("### YouTube URL과 포스팅 스타일 입력") with gr.Row(): youtube_url_input = gr.Textbox(label="YouTube URL 입력", placeholder="https://www.youtube.com/watch?v=example") style_input = gr.Radio(["친근한", "일반적인", "전문적인"], label="포스팅 스타일", value="친근한") # 출력 영역 설정 - 원문 스크립트 및 생성된 블로그 글 script_output = gr.HTML(label="원문 스크립트") blog_output = gr.HTML(label="생성된 블로그 글") # 버튼 클릭 시 /process_youtube_url 호출 generate_blog_button = gr.Button("블로그 글 생성") generate_blog_button.click(process_youtube_url, inputs=[youtube_url_input, style_input], outputs=[script_output, blog_output]) # 세 번째 탭: 생활건강 블로그 with gr.TabItem("생활건강 블로그"): gr.Markdown("### YouTube URL과 포스팅 스타일 입력") with gr.Row(): youtube_url_input_v1_2 = gr.Textbox(label="YouTube URL 입력", placeholder="https://www.youtube.com/watch?v=example") style_input_v1_2 = gr.Radio(["친근한", "일반적인", "전문적인"], label="포스팅 스타일", value="친근한") # 출력 영역 설정 - 원문 스크립트 및 생성된 블로그 글 script_output_v1_2 = gr.HTML(label="원문 스크립트") blog_output_v1_2 = gr.HTML(label="생성된 블로그 글") # 버튼 클릭 시 /process_youtube_url 호출 generate_blog_button_v1_2 = gr.Button("블로그 글 생성") generate_blog_button_v1_2.click(process_youtube_url_v1_2, inputs=[youtube_url_input_v1_2, style_input_v1_2], outputs=[script_output_v1_2, blog_output_v1_2]) # 네 번째 탭: 여행 블로그 with gr.TabItem("여행 블로그"): gr.Markdown("### YouTube URL과 포스팅 스타일 입력") with gr.Row(): youtube_url_input_v2 = gr.Textbox(label="YouTube URL 입력", placeholder="https://www.youtube.com/watch?v=example") style_input_v2 = gr.Radio(["친근한", "일반적인", "전문적인"], label="포스팅 스타일", value="친근한") # 출력 영역 설정 - 원문 스크립트 및 생성된 블로그 글 script_output_v2 = gr.HTML(label="원문 스크립트") blog_output_v2 = gr.HTML(label="생성된 블로그 글") # 버튼 클릭 시 /process_youtube_url 호출 generate_blog_button_v2 = gr.Button("블로그 글 생성") generate_blog_button_v2.click(process_youtube_url_v2, inputs=[youtube_url_input_v2, style_input_v2], outputs=[script_output_v2, blog_output_v2]) # 다섯 번째 탭: 상품후기 블로그 with gr.TabItem("상품후기 블로그"): gr.Markdown("### YouTube URL과 포스팅 스타일 입력") with gr.Row(): youtube_url_input_v3 = gr.Textbox(label="YouTube URL 입력", placeholder="https://www.youtube.com/watch?v=example") style_input_v3 = gr.Radio(["친근한", "일반적인", "전문적인"], label="포스팅 스타일", value="친근한") # 출력 영역 설정 - 원문 스크립트 및 생성된 블로그 글 script_output_v3 = gr.HTML(label="원문 스크립트") blog_output_v3 = gr.HTML(label="생성된 블로그 글") # 버튼 클릭 시 /process_youtube_url 호출 generate_blog_button_v3 = gr.Button("블로그 글 생성") generate_blog_button_v3.click(process_youtube_url_v3, inputs=[youtube_url_input_v3, style_input_v3], outputs=[script_output_v3, blog_output_v3]) # UI 실행 if __name__ == "__main__": demo.launch()