Joon’s API Special Lecture[2024.06.16. 14:00-18:00]

영상 요약

주제: 맥북에서 로컬로 LLM 실행하기
목표: 챗GPT와 같은 LLM을 개인 컴퓨터에서 실행하여 사용하는 방법을 소개함
환경: 2022년형 맥북 에어 15 (M2, 램 24GB) - 윈도우, 리눅스에서도 가능함
필요한 프로그램:
1.
Docker (도커): 애플리케이션을 컨테이너로 패키징, 배포, 실행할 수 있게 해주는 오픈소스 플랫폼
2.
Ollama (올라마): LLM을 실행할 수 있게 도와줌. 엄청 간단함.
3.
Open WebUI (오픈웹유아이): 올라마 등의 LLM의 챗GPT-Like 인터페이스 제공
설치 및 실행 과정:
1.
Docker 설치:
Docker Desktop을 다운로드 받음
애플, 윈도우, 리눅스 전부 지원함
다운로드 받고 실행하여 설치함
Docker를 실행해 봄
설치 성공 시 특정 화면이 나옴
2.
Ollama 설치:
Ollama를 다운로드 받음 (다운로드 버튼 클릭)
자신의 컴퓨터에 맞는 버전을 선택하여 다운로드 받음
압축을 풀고 "응용 프로그램" 폴더에 실행파일을 넣어 줌
Ollama를 실행해 봄
올라마에 오신 것을 환영! 당신의 LLM을 올리고 실행 가능함!
터미널에서 사용가능한 커맨드라인을 설치함
관리자 권한이 필요, 비밀번호 입력하고 확인
터미널에 직접 입력하면 라마3 사용가능!
Ollama까지만 설치해도 일반적인 사용이 가능함.
Ollama는 기본적으로 여러가지 모델을 지원함
이번 영상에서는 qwen2:1.5B를 사용해 봄
지원하는 모델의 크기를 확인할 수 있는데, 당연히 모델의 크기가 클수록 많은 잠재력을 갖지만 고성능의 컴퓨터 노력이 필요함!
펼치기 목록을 클릭해서 설치하기 원하는 모델을 클릭함
이쪽에 설치할 수 있는 코드가 있음. 버튼을 눌러 복사함
터미널을 열어 실행을 해볼까요?
여기 복사한 명령어를 붙여넣고 실행!
이 과정에서는 모델을 다운로드 받고 가상 컴퓨터 메모리에 올리는 작업을 함
시간이 꽤 걸리니 커피 한 잔 (이 과정은 최초 1회만 진행함)
실행이 완료되면 이렇게 프롬프트가 뜨는데 이 터미널에서 qwen2를 사용할 수 있음
(배속 없는 실제 속도임)
이렇게 잉여롭게 사용할 수도 있고 UI를 설치해서 더 편하게 사용할 수도 있음
CPU와 메모리 사용량 확인
3.
Open WebUI 설치:
Open WebUI를 설치해서 더 편하게 사용해 보죠
아래쪽으로 내리면 How to Install - Installation with Default Configuration
이 스크립트를 복사해서 터미널에 붙여넣고 실행
이 과정에서는 Open WebUI의 Docker 이미지를 다운로드 받고 실행함
커피 한 잔 (이 과정은 최초 1회만 진행함)
완료!
브라우저를 열고 localhost:3000 으로 이동함
로그인 시스템이 있는데 Sign up을 눌러 간단하게 계정을 만들어 봄
로그인 아이디, 이메일(아무거나 입력), 비밀번호를 입력하여 계정 생성
성공
챗GPT와 비슷한 화면이 뜨죠?
왼쪽 위에 Select a model을 눌러 아까 설치한 qwen2:1.5b를 선택
(모델 최초 실행 시에 시간이 걸릴 수 있음)
영상 편집하니 5분도 채 안걸리는군요! (실제 시간 재외)
재밌게 사용하시고 유용하셨다면 구독과 좋아요 부탁드립니다!
다음에 더 신기하고 재밌는 프로젝트로 만나뵙도록 할게요. 안녕
(테스트는 실시간으로 영상 촬영)
피보나치 수열에 관해 질문, 코드를 생성해 줌
결론: Docker, Ollama, Open WebUI를 이용하여 맥북에서 로컬로 LLM을 실행하고 사용할 수 있음. 챗GPT와 비슷한 인터페이스를 제공하는 Open WebUI를 통해 쉽고 편하게 LLM을 활용할 수 있음.
https://www.developerfastlane.com/blog/ollama-usage-guide 이것도 제가 블로그로 정리해둔 내용이 있으니 참고해보세요 ㅎ
구글 코랩에서 코드 블럭을 동시에 선택하고 싶을 때는 command(ctrl) + click
PDF는 텍스트만 인식하기 때문에, PDF 안에 이미지를 분석시키고 싶을 때는 PDF를 이미지로 변환한 후에 분석을 인공지능에게 요청해야 합니다.
만약에 업로드한 이미지를 찾지 못하는 경우에는 해당 이미지를 오른쪽 마우스 클릭하여 경로 복사를 해서 그 경로를 제공하면 이미지를 다시 잘 찾는다.
수학 공식은 mathpix.com에서 참고하면 수학 공식 OCR을 활용할 수 있음.
위의 코드를 다음 요청사항에 맞추어 수정해.
1. 영상 분석 버튼을 누르기 전에 출력 언어를 설정할 수 있도록 할 것. - 한국어 - 영어 - 중국어 - 일본어 2. 영상 분석 버튼을 눌렀을 때, "진행 중"이라고 뜨지 않고, "Loading"이라고 뜨도록 수정해줘. 3. 타이틀 아래에 조그만 글씨를 "By Park Joon" 대산 다음 내용으로 바꿔서 넣어줘. "유튜브 영상 URL을 입력하시면 무료로 분석해드립니다." 4. API Key를 사용자가 넣도록 하지 말고, 다음 API Key로 설정해서 바로 URL만 입력하면 부석할 수 있도록 수정해. API Key: AIzaSyDHuZgvaw6zEzWGSSkuq7CHSC3aE1uwdko
Plain Text
복사
1차 프롬프트
UI 추가하는 프롬프트
업로드한 코드에 다음 기능 및 UI를 추가해줘.
1. 영상 분석 방식을 선택할 수 있도록 해줘.
- 3줄 요약
- 심화 요약
- 타임스탬프 생성
3줄 요약을 선택하면, 다음 프롬프트가 입력이 되도록 해줘 :
업로드한 영상을 한국어로 3줄로 불렛포인트 형식으로 요약해줘. 어미는 ~임, ~함과 같이 간결하게 할 것. 각 문장의 앞에는 이모지를 하나 넣을 것.
심화 요약을 선택하면, 다음 프롬프트가 입력이 되도록 해줘 :
업로드한 영상을 한국어로 마크다운 형식으로 구체적으로 요약해줘. 어미는 ~임, ~함과 같이 간결하게 할 것. 각 문장의 앞에는 이모지를 하나 넣을 것.
타임스탬프 생성을 선택하면, 다음 프롬프트가 입력이 되도록 해줘 :
업로드한 영상을 다음과 같은 형식으로 타임스탬프를 생성해줘 :
``
Timestamp
*:** {subtitle}
*:** {subtitle}
*:** {subtitle}
...
``
수정된 코드(2차 프롬프트)
import streamlit as st from pytube import YouTube from moviepy.editor import * import google.generativeai as genai from datetime import datetime import time import os from PIL import Image from streamlit_player import st_player from googleapiclient.discovery import build from googleapiclient.errors import HttpError import pandas as pd import re import mock from pytube.cipher import get_throttling_function_code from pytube import YouTube st.set_page_config( page_title="나만의 YouTube 요약 서비스", page_icon="🎬", ) google_youtube_api_key = "AIzaSyAuKiyYNDPq_Q3Sf0FLw7onz6vIifsB7NQ" api_key_index = 0 def patched_throttling_plan(js: str): raw_code = get_throttling_function_code(js) transform_start = r"try{" plan_regex = re.compile(transform_start) match = plan_regex.search(raw_code) transform_plan_raw = js step_start = r"c\[(\d+)\]\(c\[(\d+)\](,c(\[(\d+)\]))?\)" step_regex = re.compile(step_start) matches = step_regex.findall(transform_plan_raw) transform_steps = [] for match in matches: if match[4] != '': transform_steps.append((match[0],match[1],match[4])) else: transform_steps.append((match[0],match[1])) return transform_steps def get_comments(youtube, video_id): comments = [] next_page_token = None while True: response = youtube.commentThreads().list( part="snippet", videoId=video_id, pageToken=next_page_token, maxResults=100, textFormat="plainText" ).execute() for item in response["items"]: comment = item["snippet"]["topLevelComment"]["snippet"] comments.append({ "authorDisplayName": comment["authorDisplayName"], "textDisplay": comment["textDisplay"], "likeCount": comment["likeCount"], "publishedAt": comment["publishedAt"] }) comment_id = item["snippet"]["topLevelComment"]["id"] reply_response = youtube.comments().list( part="snippet", parentId=comment_id, textFormat="plainText" ).execute() for reply in reply_response["items"]: reply_comment = reply["snippet"] comments.append({ "authorDisplayName": reply_comment["authorDisplayName"], "textDisplay": reply_comment["textDisplay"], "likeCount": reply_comment["likeCount"], "publishedAt": reply_comment["publishedAt"] }) next_page_token = response.get("nextPageToken") if not next_page_token: return pd.DataFrame(comments) def get_video_details(youtube, video_id): request = youtube.videos().list( part=["snippet","statistics","contentDetails"], id=video_id ) response = request.execute() for item in response["items"]: data = dict(contentDetails=item["snippet"]["description"]) if "likeCount" in item["statistics"]: data["like_count"] = item["statistics"]["likeCount"] if "commentCount" in item["statistics"]: data["comment_count"] = item["statistics"]["commentCount"] return data st.title("YouTube 영상 요약기") st.caption("유튜브 영상 URL을 입력하시면 무료로 분석해드립니다.") api_key = "AIzaSyAJnXJEkXtWUDDFJGUw8AzGMWspyOe21uk" genai.configure(api_key=api_key) generation_config = { "temperature": 0.4, "top_p": 0.95, "top_k": 0, } safety_settings = [ { "category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE" }, { "category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE" }, { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE" }, { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE" }, ] model_selection = st.sidebar.radio("**사용할 모델을 선택하세요 :**",("gemini-1.5-pro", "gemini-1.5-flash"), captions = ("가격↑/성능↑/속도↓", "가격↓/성능↓/속도↑")) if model_selection == "gemini-1.5-pro": model_name = "gemini-1.5-pro" else: model_name = "gemini-1.5-flash" url = st.text_input("YouTube 영상 URL을 입력해주세요:") youtube = build("youtube", "v3", developerKey=google_youtube_api_key) output_lang = st.selectbox("출력 언어를 선택하세요:", ("한국어", "영어", "일본어", "중국어")) if url: try: if "youtube.com/shorts/" in url: video_id = url.split("shorts/")[1] url = f"https://www.youtube.com/watch?v={video_id}" elif "youtube.com/live/" in url: video_id = url.split("live/")[1] url = f"https://www.youtube.com/watch?v={video_id}" yt = YouTube(url) video_id = yt.vid_info['videoDetails']['videoId'] st.markdown(f"## {yt.title}") st_player(url) with st.expander("영상 정보"): detail = get_video_details(youtube, video_id) st.text_area(label="**영상 설명**", value=detail['contentDetails']) st.markdown(f"- #### 조회수 : {yt.views:,} 회") hours, remainder = divmod(yt.length, 3600) minutes, seconds = divmod(remainder, 60) if hours > 0: st.markdown(f"- #### 영상 길이 : {hours}시간 {minutes}{seconds}초") else: st.markdown(f"- #### 영상 길이 : {minutes}{seconds}초") publish_date = yt.publish_date.strftime("%Y년 %m월 %d일") st.markdown(f"- #### 게시 날짜 : {publish_date}") st.markdown(f"- #### 채널명 : [{yt.author}]({yt.channel_url})") if 'like_count' in detail: st.markdown(f"- #### 좋아요 수 : {detail['like_count']} 개") else: st.markdown("- #### 좋아요 수가 제공되지 않습니다.") if 'comment_count' in detail: st.markdown(f"- #### 댓글 수 : {detail['comment_count']} 개") else: st.markdown("- #### 댓글 수 : 댓글 사용이 중지되어 가져올 수 없습니다.") if yt.length > 3599: attachment_type = st.radio("**영상 분석 방식을 선택하세요 :**", ("음성만",), index=0) st.warning("1시간 이상의 영상은 현재 음성 분석만 가능합니다.") else: attachment_type = st.radio("**첨부 파일 형식을 선택하세요 :**", ("영상 + 음성", "영상만", "영성만"), index=0) analysis_type = st.radio("**영상 분석 방식을 선택하세요 :**", ("3줄 요약", "심화 요약", "타임스탬프 생성"), index=0) analyze_video = st.button("영상 분석") if analyze_video: output_lang_dict = {"한국어": "한국어로", "영어": "영어로", "일본어": "일본어로", "중국어": "중국어로"} with st.spinner("Loading..."): with mock.patch('pytube.cipher.get_throttling_plan', patched_throttling_plan): videos = yt.streams.filter(adaptive=True, file_extension='mp4', res="360p") if len(videos) == 0: videos = yt.streams.filter(adaptive=True, file_extension='mp4') video = videos[0] else: video = videos[0] video.download(filename='video.mp4') audios = yt.streams.filter(only_audio=True, abr="128kbps", file_extension='mp4') if len(audios) == 0: audios = yt.streams.filter(only_audio=True, file_extension='mp4') audio = audios[0] else: audio = audios[0] audio.download(filename='audio.mp4') audio_clip = AudioFileClip("audio.mp4") audio_clip.write_audiofile("audio.m4a", codec='aac') video_file = genai.upload_file(path="video.mp4") audio_file = genai.upload_file(path="audio.m4a") while video_file.state.name == "PROCESSING" or audio_file.state.name == "PROCESSING": time.sleep(5) video_file = genai.get_file(video_file.name) audio_file = genai.get_file(audio_file.name) if video_file.state.name == "FAILED" or audio_file.state.name == "FAILED": raise ValueError("파일 처리 실패") with st.spinner("영상 분석 중..."): if analysis_type == "3줄 요약": system_instruction = f""" 업로드한 영상을 한국어로 3줄로 불렛포인트 형식으로 요약해줘. 어미는 ~임, ~함과 같이 간결하게 할 것. 각 문장의 앞에는 이모지를 하나 넣을 것. """ elif analysis_type == "심화 요약": system_instruction = f""" 업로드한 영상을 한국어로 마크다운 형식으로 구체적으로 요약해줘. 어미는 ~임, ~함과 같이 간결하게 할 것. 각 문장의 앞에는 이모지를 하나 넣을 것. """ else: system_instruction = f""" 업로드한 영상을 다음과 같은 형식으로 타임스탬프를 생성해줘 : Timestamp ** : {{subtitle}} ** : {{subtitle}} ** : {{subtitle}} ... """ model = genai.GenerativeModel(model_name=model_name, generation_config=generation_config, system_instruction=system_instruction, safety_settings=safety_settings) if attachment_type == "영상 + 음성": response = model.generate_content([video_file, audio_file], request_options={"timeout": 600}) elif attachment_type == "영상만": response = model.generate_content(video_file, request_options={"timeout": 600}) else: response = model.generate_content(audio_file, request_options={"timeout": 600}) if 'result_text' not in st.session_state: st.session_state.result_text = "" result_text = st.empty() result_text.success(response.text) st.session_state.result_text = response.text with st.expander("📋 마크다운 복사"): st.code(st.session_state.result_text, language='markdown') genai.delete_file(video_file.name) genai.delete_file(audio_file.name) os.remove("video.mp4") os.remove("audio.mp4") os.remove("audio.m4a") except Exception as e: st.error(f"에러 발생: {str(e)}")
Python
복사
전문
프롬프트 :
업로드한 코드에 다음 기능 및 UI를 추가해줘.
1. 영상 분석 방식을 선택할 수 있도록 해줘.
- 3줄 요약
- 심화 요약
- 타임스탬프 생성
3줄 요약을 선택하면, 다음 프롬프트가 입력이 되도록 해줘 :
업로드한 영상을 한국어로 3줄로 불렛포인트 형식으로 요약해줘. 어미는 ~임, ~함과 같이 간결하게 할 것. 각 문장의 앞에는 이모지를 하나 넣을 것.
심화 요약을 선택하면, 다음 프롬프트가 입력이 되도록 해줘 :
업로드한 영상을 한국어로 마크다운 형식으로 구체적으로 요약해줘. 어미는 ~임, ~함과 같이 간결하게 할 것. 각 문장의 앞에는 이모지를 하나 넣을 것.
타임스탬프 생성을 선택하면, 다음 프롬프트가 입력이 되도록 해줘 :
업로드한 영상을 다음과 같은 형식으로 타임스탬프를 생성해줘 :
``
Timestamp
*:** {subtitle}
*:** {subtitle}
*:** {subtitle}
...
``
수정된 코드 :
import streamlit as st
from pytube import YouTube
from moviepy.editor import *
import google.generativeai as genai
from datetime import datetime
import time
import os
from PIL import Image
from streamlit_player import st_player
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import pandas as pd
import re
import mock
from pytube.cipher import get_throttling_function_code
from pytube import YouTube
st.set_page_config(
page_title="나만의 YouTube 요약 서비스",
page_icon="",
)
google_youtube_api_key = "AIzaSyAuKiyYNDPq_Q3Sf0FLw7onz6vIifsB7NQ"
api_key_index = 0
def patched_throttling_plan(js: str):
raw_code = get_throttling_function_code(js)
transform_start = r"try{"
plan_regex = re.compile(transform_start)
match = plan_regex.search(raw_code)
transform_plan_raw = js
step_start = r"c\[(\d+)\]\(c\[(\d+)\](,c(\[(\d+)\]))?\)"
step_regex = re.compile(step_start)
matches = step_regex.findall(transform_plan_raw)
transform_steps = []
for match in matches:
if match[4] != '':
transform_steps.append((match[0],match[1],match[4]))
else:
transform_steps.append((match[0],match[1]))
return transform_steps
def get_comments(youtube, video_id):
comments = []
next_page_token = None
while True:
response = youtube.commentThreads().list(
part="snippet",
videoId=video_id,
pageToken=next_page_token,
maxResults=100,
textFormat="plainText"
).execute()
for item in response["items"]:
comment = item["snippet"]["topLevelComment"]["snippet"]
comments.append({
"authorDisplayName": comment["authorDisplayName"],
"textDisplay": comment["textDisplay"],
"likeCount": comment["likeCount"],
"publishedAt": comment["publishedAt"]
})
comment_id = item["snippet"]["topLevelComment"]["id"]
reply_response = youtube.comments().list(
part="snippet",
parentId=comment_id,
textFormat="plainText"
).execute()
for reply in reply_response["items"]:
reply_comment = reply["snippet"]
comments.append({
"authorDisplayName": reply_comment["authorDisplayName"],
"textDisplay": reply_comment["textDisplay"],
"likeCount": reply_comment["likeCount"],
"publishedAt": reply_comment["publishedAt"]
})
next_page_token = response.get("nextPageToken")
if not next_page_token:
return pd.DataFrame(comments)
def get_video_details(youtube, video_id):
request = youtube.videos().list(
part=["snippet","statistics","contentDetails"],
id=video_id
)
response = request.execute()
for item in response["items"]:
data = dict(contentDetails=item["snippet"]["description"])
if "likeCount" in item["statistics"]:
data["like_count"] = item["statistics"]["likeCount"]
if "commentCount" in item["statistics"]:
data["comment_count"] = item["statistics"]["commentCount"]
return data
st.title("YouTube 영상 요약기")
st.caption("유튜브 영상 URL을 입력하시면 무료로 분석해드립니다.")
api_key = "AIzaSyAJnXJEkXtWUDDFJGUw8AzGMWspyOe21uk"
genai.configure(api_key=api_key)
generation_config = {
"temperature": 0.4,
"top_p": 0.95,
"top_k": 0,
}
safety_settings = [
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "BLOCK_NONE"
},
]
model_selection = st.sidebar.radio("**사용할 모델을 선택하세요 :**",("gemini-1.5-pro", "gemini-1.5-flash"), captions = ("가격↑/성능↑/속도↓", "가격↓/성능↓/속도↑"))
if model_selection == "gemini-1.5-pro":
model_name = "gemini-1.5-pro"
else:
model_name = "gemini-1.5-flash"
url = st.text_input("YouTube 영상 URL을 입력해주세요:")
youtube = build("youtube", "v3", developerKey=google_youtube_api_key)
output_lang = st.selectbox("출력 언어를 선택하세요:", ("한국어", "영어", "일본어", "중국어"))
if url:
try:
if "youtube.com/shorts/" in url:
video_id = url.split("shorts/")[1]
url = f"https://www.youtube.com/watch?v={video_id}"
elif "youtube.com/live/" in url:
video_id = url.split("live/")[1]
url = f"https://www.youtube.com/watch?v={video_id}"
yt = YouTube(url)
video_id = yt.vid_info['videoDetails']['videoId']
st.markdown(f"## {yt.title}")
st_player(url)
with st.expander("영상 정보"):
detail = get_video_details(youtube, video_id)
st.text_area(label="**영상 설명**", value=detail['contentDetails'])
st.markdown(f"- #### 조회수 : {yt.views:,} 회")
hours, remainder = divmod(yt.length, 3600)
minutes, seconds = divmod(remainder, 60)
if hours > 0:
st.markdown(f"- #### 영상 길이 : {hours}시간 {minutes}분 {seconds}초")
else:
st.markdown(f"- #### 영상 길이 : {minutes}분 {seconds}초")
publish_date = yt.publish_date.strftime("%Y년 %m월 %d일")
st.markdown(f"- #### 게시 날짜 : {publish_date}")
st.markdown(f"- #### 채널명 : [{yt.author}]({yt.channel_url})")
if 'like_count' in detail:
st.markdown(f"- #### 좋아요 수 : {detail['like_count']} 개")
else:
st.markdown("- #### 좋아요 수가 제공되지 않습니다.")
if 'comment_count' in detail:
st.markdown(f"- #### 댓글 수 : {detail['comment_count']} 개")
else:
st.markdown("- #### 댓글 수 : 댓글 사용이 중지되어 가져올 수 없습니다.")
if yt.length > 3599:
attachment_type = st.radio("**영상 분석 방식을 선택하세요 :**", ("음성만",), index=0)
st.warning("1시간 이상의 영상은 현재 음성 분석만 가능합니다.")
else:
attachment_type = st.radio("**첨부 파일 형식을 선택하세요 :**", ("영상 + 음성", "영상만", "영성만"), index=0)
analysis_type = st.radio("**영상 분석 방식을 선택하세요 :**", ("3줄 요약", "심화 요약", "타임스탬프 생성"), index=0)
analyze_video = st.button("영상 분석")
if analyze_video:
output_lang_dict = {"한국어": "한국어로", "영어": "영어로", "일본어": "일본어로", "중국어": "중국어로"}
with st.spinner("Loading..."):
with mock.patch('pytube.cipher.get_throttling_plan', patched_throttling_plan):
videos = yt.streams.filter(adaptive=True, file_extension='mp4', res="360p")
if len(videos) == 0:
videos = yt.streams.filter(adaptive=True, file_extension='mp4')
video = videos[0]
else:
video = videos[0]
video.download(filename='video.mp4')
audios = yt.streams.filter(only_audio=True, abr="128kbps", file_extension='mp4')
if len(audios) == 0:
audios = yt.streams.filter(only_audio=True, file_extension='mp4')
audio = audios[0]
else:
audio = audios[0]
audio.download(filename='audio.mp4')
audio_clip = AudioFileClip("audio.mp4")
audio_clip.write_audiofile("audio.m4a", codec='aac')
video_file = genai.upload_file(path="video.mp4")
audio_file = genai.upload_file(path="audio.m4a")
while video_file.state.name == "PROCESSING" or audio_file.state.name == "PROCESSING":
time.sleep(5)
video_file = genai.get_file(video_file.name)
audio_file = genai.get_file(audio_file.name)
if video_file.state.name == "FAILED" or audio_file.state.name == "FAILED":
raise ValueError("파일 처리 실패")
with st.spinner("영상 분석 중..."):
if analysis_type == "3줄 요약":
system_instruction = f"""
업로드한 영상을 {output_lang_dict[output_lang]} 3줄로 불렛포인트 형식으로 요약해줘. 어미는 ~임, ~함과 같이 간결하게 할 것. 각 문장의 앞에는 이모지를 하나 넣을 것.
"""
elif analysis_type == "심화 요약":
system_instruction = f"""
업로드한 영상을 {output_lang_dict[output_lang]} 마크다운 형식으로 구체적으로 요약해줘. 어미는 ~임, ~함과 같이 간결하게 할 것. 각 문장의 앞에는 이모지를 하나 넣을 것.
"""
else:
system_instruction = f"""
업로드한 영상을 다음과 같은 형식으로 타임스탬프를 생성해줘 :
Timestamp
** : {{subtitle}}
** : {{subtitle}}
** : {{subtitle}}
...
"""
model = genai.GenerativeModel(model_name=model_name,
generation_config=generation_config,
system_instruction=system_instruction,
safety_settings=safety_settings)
if attachment_type == "영상 + 음성":
response = model.generate_content([video_file, audio_file], request_options={"timeout": 600})
elif attachment_type == "영상만":
response = model.generate_content(video_file, request_options={"timeout": 600})
else:
response = model.generate_content(audio_file, request_options={"timeout": 600})
if 'result_text' not in st.session_state:
st.session_state.result_text = ""
result_text = st.empty()
result_text.success(response.text)
st.session_state.result_text = response.text
with st.expander(" 마크다운 복사"):
st.code(st.session_state.result_text, language='markdown')
genai.delete_file(video_file.name)
genai.delete_file(audio_file.name)
os.remove("video.mp4")
os.remove("audio.mp4")
os.remove("audio.m4a")
except Exception as e:
st.error(f"에러 발생: {str(e)}")

사진