├── .env_sample
├── .gitignore
├── 01-ChatCompletion.ipynb
├── 02-ImageGeneration.ipynb
├── 03-TTS-and-STT.ipynb
├── 04-Creating-Transcripts.ipynb
├── 05-Assistant-API.ipynb
├── README.md
├── audio_utils.py
├── data
├── edited_image.jpg
├── generated_image1.jpg
├── generated_image2.jpg
├── generated_image_porche.png
├── porche_911.jpg
├── sample-mask.png
├── sample.png
├── 오디오샘플_01.wav
├── 채용면접_샘플_01.wav
└── 채용면접_샘플_02.wav
├── images
├── NotRealCorp_chart.png
├── assistant-code-interpreter.png
├── assistant-create.png
├── assistant-file-id.png
├── assistant-file-upload.png
├── assistant-function1.png
├── assistant-function2.png
├── assistant-lists.png
├── assistant-math-tutor.png
├── assistant-retrieval.png
├── assistants_overview_assistants_dashboard.png
├── assistants_overview_assistants_playground.png
├── assistants_overview_diagram.png
├── assistants_overview_enable_code_interpreter.png
├── assistants_overview_enable_function.png
├── assistants_overview_enable_retrieval.png
├── assistants_overview_new_assistant.png
├── chain_of_thought_fig1.png
├── chain_of_thought_fig11.png
├── chain_of_thought_fig3.png
├── chain_of_thought_fig5.png
├── dalle_image.png
├── data_vis_slide.png
├── faithful-reasoning_fig1.png
├── faithful-reasoning_fig2.png
├── faithful-reasoning_fig3.png
├── faithful-reasoning_fig4.png
├── faithful-reasoning_fig5.png
├── faithful-reasoning_fig7.png
├── faithful-reasoning_tab2.png
├── faithful-reasoning_tab5.png
├── least-to-most_fig1.png
├── least-to-most_tab11.png
├── least-to-most_tab4.png
├── least-to-most_tab9.png
├── llamaindex_rag_overview.png
├── lm_cascades_fig1.png
├── lm_cascades_fig3.png
├── lm_cascades_fig4.png
├── lm_cascades_fig5.png
├── lm_cascades_fig6.png
├── maieutic_fig2.png
├── maieutic_fig6.png
├── maieutic_tab1.png
├── openai-cookbook-white.png
├── openai-cookbook.png
├── search_rerank_answer.png
├── selection-inference_fig1.png
├── selection-inference_fig4.png
├── self-consistency_fig1.png
├── self-consistency_fig3.png
├── star_fig1.png
├── star_tab1.png
├── structures.png
├── title_slide.png
├── verifiers_fig3.png
├── verifiers_fig5.png
├── zero-shot_reasoners_fig1.png
├── zero-shot_reasoners_fig2.png
├── zero-shot_reasoners_tab1.png
└── zero-shot_reasoners_tab5.png
├── requirements_mac.txt
└── requirements_windows.txt
/.env_sample:
--------------------------------------------------------------------------------
1 | OPENAI_API_KEY=sk-5K9kI4dia...
2 | HUGGINGFACEHUB_API_TOKEN=hf_oEHVwJ...
3 | LANGCHAIN_TRACING_V2=true
4 | LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
5 | LANGCHAIN_API_KEY=ls__0ca6d2a2108...
6 | LANGCHAIN_PROJECT=LANGCHAIN_PROJECT
7 | TAVILY_API_KEY=tvly-mGxBGvzzJiubH...
8 | GOOGLE_API_KEY=AIzaSyCSttRIEqEf1_X...
9 | PINECONE_API_KEY=549b555d-c388-4d...
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/jupyternotebooks,python
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=jupyternotebooks,python
3 |
4 | ### JupyterNotebooks ###
5 | # gitignore template for Jupyter Notebooks
6 | # website: http://jupyter.org/
7 |
8 | *.env
9 | *.DS_Store
10 | *.pdf
11 |
12 | .ipynb_checkpoints
13 | */.ipynb_checkpoints/*
14 |
15 | # IPython
16 | profile_default/
17 | ipython_config.py
18 |
19 | # Remove previous ipynb_checkpoints
20 | # git rm -r .ipynb_checkpoints/
21 |
22 | ### Python ###
23 | # Byte-compiled / optimized / DLL files
24 | __pycache__/
25 | *.py[cod]
26 | *$py.class
27 |
28 | # C extensions
29 | *.so
30 |
31 | # Distribution / packaging
32 | .Python
33 | build/
34 | develop-eggs/
35 | dist/
36 | downloads/
37 | eggs/
38 | .eggs/
39 | lib/
40 | lib64/
41 | parts/
42 | sdist/
43 | var/
44 | wheels/
45 | share/python-wheels/
46 | *.egg-info/
47 | .installed.cfg
48 | *.egg
49 | MANIFEST
50 |
51 | # PyInstaller
52 | # Usually these files are written by a python script from a template
53 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
54 | *.manifest
55 | *.spec
56 |
57 | # Installer logs
58 | pip-log.txt
59 | pip-delete-this-directory.txt
60 |
61 | # Unit test / coverage reports
62 | htmlcov/
63 | .tox/
64 | .nox/
65 | .coverage
66 | .coverage.*
67 | .cache
68 | nosetests.xml
69 | coverage.xml
70 | *.cover
71 | *.py,cover
72 | .hypothesis/
73 | .pytest_cache/
74 | cover/
75 |
76 | # Translations
77 | *.mo
78 | *.pot
79 |
80 | # Django stuff:
81 | *.log
82 | local_settings.py
83 | db.sqlite3
84 | db.sqlite3-journal
85 |
86 | # Flask stuff:
87 | instance/
88 | .webassets-cache
89 |
90 | # Scrapy stuff:
91 | .scrapy
92 |
93 | # Sphinx documentation
94 | docs/_build/
95 |
96 | # PyBuilder
97 | .pybuilder/
98 | target/
99 |
100 | # Jupyter Notebook
101 |
102 | # IPython
103 |
104 | # pyenv
105 | # For a library or package, you might want to ignore these files since the code is
106 | # intended to run in multiple environments; otherwise, check them in:
107 | # .python-version
108 |
109 | # pipenv
110 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
111 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
112 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
113 | # install all needed dependencies.
114 | #Pipfile.lock
115 |
116 | # poetry
117 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
118 | # This is especially recommended for binary packages to ensure reproducibility, and is more
119 | # commonly ignored for libraries.
120 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
121 | #poetry.lock
122 |
123 | # pdm
124 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
125 | #pdm.lock
126 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
127 | # in version control.
128 | # https://pdm.fming.dev/#use-with-ide
129 | .pdm.toml
130 |
131 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
132 | __pypackages__/
133 |
134 | # Celery stuff
135 | celerybeat-schedule
136 | celerybeat.pid
137 |
138 | # SageMath parsed files
139 | *.sage.py
140 |
141 | # Environments
142 | .env
143 | .venv
144 | env/
145 | venv/
146 | ENV/
147 | env.bak/
148 | venv.bak/
149 |
150 | # Spyder project settings
151 | .spyderproject
152 | .spyproject
153 |
154 | # Rope project settings
155 | .ropeproject
156 |
157 | # mkdocs documentation
158 | /site
159 |
160 | # mypy
161 | .mypy_cache/
162 | .dmypy.json
163 | dmypy.json
164 |
165 | # Pyre type checker
166 | .pyre/
167 |
168 | # pytype static type analyzer
169 | .pytype/
170 |
171 | # Cython debug symbols
172 | cython_debug/
173 |
174 | # PyCharm
175 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
176 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
177 | # and can be added to the global gitignore or merged into this file. For a more nuclear
178 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
179 | #.idea/
180 |
181 | ### Python Patch ###
182 | # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
183 | poetry.toml
184 |
185 | # ruff
186 | .ruff_cache/
187 |
188 | # LSP config files
189 | pyrightconfig.json
190 |
191 | # End of https://www.toptal.com/developers/gitignore/api/jupyternotebooks,python
--------------------------------------------------------------------------------
/01-ChatCompletion.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## 환경설정\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": null,
13 | "metadata": {},
14 | "outputs": [],
15 | "source": [
16 | "# 토큰 정보로드를 위한 라이브러리\n",
17 | "# 설치: pip install python-dotenv\n",
18 | "from dotenv import load_dotenv\n",
19 | "\n",
20 | "# 토큰 정보로드\n",
21 | "load_dotenv()"
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | "## Client 생성\n",
29 | "\n",
30 | "- `client` 는 OpenAI 모듈로 생성된 인스턴스 입니다.\n",
31 | "\n",
32 | "[주의] 아래의 코드에서 오류가 난다면 API 키의 오류일 가능성이 높습니다.\n"
33 | ]
34 | },
35 | {
36 | "cell_type": "code",
37 | "execution_count": null,
38 | "metadata": {},
39 | "outputs": [],
40 | "source": [
41 | "!pip install -U openai"
42 | ]
43 | },
44 | {
45 | "cell_type": "code",
46 | "execution_count": null,
47 | "metadata": {},
48 | "outputs": [],
49 | "source": [
50 | "import openai\n",
51 | "\n",
52 | "openai.__version__"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": null,
58 | "metadata": {},
59 | "outputs": [],
60 | "source": [
61 | "from openai import OpenAI\n",
62 | "\n",
63 | "client = OpenAI()\n",
64 | "client"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {},
70 | "source": [
71 | "## ChatCompletions\n",
72 | "\n",
73 | "- API Reference: https://platform.openai.com/docs/api-reference/chat\n",
74 | "\n",
75 | "**주요 파라미터**\n",
76 | "\n",
77 | "- `messages`: 지금까지의 대화를 구성하는 메시지 목록입니다.\n",
78 | "- `frequency_penalty`: -2.0에서 2.0 사이의 숫자. 양수 값은 지금까지 텍스트에 나타난 기존 빈도에 따라 새로운 토큰에 불이익을 주어 모델이 같은 줄을 그대로 반복할 가능성을 낮춥니다.\n",
79 | "- `max_tokens`: 생성할 수 있는 최대 토큰 수입니다. 입력 토큰과 생성된 토큰의 총 길이는 모델의 컨텍스트 길이에 의해 제한됩니다.\n",
80 | "- `n`: 각 입력 메시지에 대해 생성할 선택지(choices) 수입니다. [주의] 모든 선택 항목에서 생성된 토큰 수에 따라 요금이 부과된다는 점에 유의하세요. 비용을 최소화하려면 n을 1로 유지하세요.\n",
81 | "- `presence_penalty`: -2.0에서 2.0 사이의 숫자. 값이 양수이면 지금까지 텍스트에 등장한 토큰에 따라 새로운 토큰에 불이익을 주므로 모델이 새로운 주제에 대해 이야기할 가능성이 높아집니다.\n",
82 | "- `response_format`: 모델이 출력해야 하는 형식을 지정하는 객체입니다. `gpt-4-turbo-preview` 및 `gpt-3.5-turbo` 과 호환됩니다. `{ \"type\": \"json_object\" }` 로 설정하면 JSON 모드가 활성화되어 모델이 생성하는 메시지가 유효한 JSON임을 보장합니다.\n",
83 | "- `seed`: 이 기능을 지정하면 시스템이 결정론적으로 샘플링하여 동일한 시드와 매개변수를 사용한 반복 요청이 동일한 결과를 반환하도록 최선을 다할 것입니다. 결정론은 보장되지 않으며, `system_fingerprint` 응답 매개변수를 참조하여 백엔드의 변경 사항을 모니터링해야 합니다.\n",
84 | "- `temperature`: 0에서 2 사이에서 사용할 샘플링 온도입니다. 0.8과 같이 값이 높으면 출력이 더 무작위적이고, 0.2와 같이 값이 낮으면 더 집중적이고 결정론적인 출력이 됩니다. 일반적으로 이 값이나 `top_p` 중 하나만 변경하는 것이 좋지만 둘 다 변경하지는 않는 것이 좋습니다.\n",
85 | "- `top_p`: `temperature` 를 이용한 샘플링의 대안으로, 핵 샘플링이라고 하며, 모델이 `top_p` 확률을 가진 토큰의 결과를 고려하는 방식입니다. 따라서 0.1은 상위 10% 확률을 구성하는 토큰만 고려한다는 의미입니다. 일반적으로 이 값이나 `temperature` 중 하나를 변경하는 것이 좋지만 둘 다 변경하는 것은 권장하지 않습니다.\n"
86 | ]
87 | },
88 | {
89 | "cell_type": "code",
90 | "execution_count": null,
91 | "metadata": {},
92 | "outputs": [],
93 | "source": [
94 | "completion = client.chat.completions.create(\n",
95 | " model=\"gpt-3.5-turbo\",\n",
96 | " messages=[\n",
97 | " {\n",
98 | " \"role\": \"system\",\n",
99 | " \"content\": \"당신은 파이썬 프로그래머입니다.\",\n",
100 | " },\n",
101 | " {\n",
102 | " \"role\": \"user\",\n",
103 | " \"content\": \"피보나치 수열을 생성하는 파이썬 프로그램을 작성해주세요.\",\n",
104 | " },\n",
105 | " ],\n",
106 | ")"
107 | ]
108 | },
109 | {
110 | "cell_type": "code",
111 | "execution_count": null,
112 | "metadata": {},
113 | "outputs": [],
114 | "source": [
115 | "print(completion.choices[0].message.content)"
116 | ]
117 | },
118 | {
119 | "cell_type": "markdown",
120 | "metadata": {},
121 | "source": [
122 | "## 스트리밍(Streaming)\n",
123 | "\n",
124 | "스트리밍은 실시간으로 데이터를 전송하고 수신하는 프로세스입니다. 이 기능을 사용하면, 대화형 모델이 토큰 단위로 응답을 생성하고, 사용자는 모델이 응답을 생성하는 과정을 실시간으로 볼 수 있습니다. 이는 특히 긴 답변을 생성하는 경우 유용하며, 사용자에게 대화가 더 자연스럽고 동적으로 느껴지게 만듭니다.\n",
125 | "\n",
126 | "Jupyter Notebook에서 스트리밍 형식으로 실시간 답변을 출력하는 것은 다음과 같은 방법으로 수행할 수 있습니다.\n",
127 | "\n",
128 | "이때, create() 함수내에 stream=True 옵션을 지정하면 됩니다.\n",
129 | "\n",
130 | "또한, 토큰 단위로 실시간 출력을 위해서는 `completion` 을 순회하면서, `choices.delta.content` 를 출력해야 합니다.\n"
131 | ]
132 | },
133 | {
134 | "cell_type": "code",
135 | "execution_count": null,
136 | "metadata": {},
137 | "outputs": [],
138 | "source": [
139 | "from openai import OpenAI\n",
140 | "\n",
141 | "client = OpenAI()\n",
142 | "\n",
143 | "completion = client.chat.completions.create(\n",
144 | " model=\"gpt-4-turbo-preview\",\n",
145 | " messages=[\n",
146 | " {\n",
147 | " \"role\": \"system\",\n",
148 | " \"content\": \"당신은 파이썬 프로그래머입니다.\",\n",
149 | " },\n",
150 | " {\n",
151 | " \"role\": \"user\",\n",
152 | " \"content\": \"피보나치 수열을 생성하는 파이썬 프로그램을 작성해주세요.\",\n",
153 | " },\n",
154 | " ],\n",
155 | " stream=True, # 스트림 모드 활성화\n",
156 | ")\n",
157 | "\n",
158 | "final_answer = []\n",
159 | "\n",
160 | "# 스트림 모드에서는 completion.choices 를 반복문으로 순회\n",
161 | "for chunk in completion:\n",
162 | " # chunk 를 저장\n",
163 | " chunk_content = chunk.choices[0].delta.content\n",
164 | " # chunk 가 문자열이면 final_answer 에 추가\n",
165 | " if isinstance(chunk_content, str):\n",
166 | " final_answer.append(chunk_content)\n",
167 | " # 토큰 단위로 실시간 답변 출력\n",
168 | " print(chunk_content, end=\"\")"
169 | ]
170 | },
171 | {
172 | "cell_type": "code",
173 | "execution_count": null,
174 | "metadata": {},
175 | "outputs": [],
176 | "source": [
177 | "# 전체 답변인 final_answer 를 문자열로 변환하여 출력\n",
178 | "final_answer = \"\".join(final_answer)\n",
179 | "print(final_answer)"
180 | ]
181 | },
182 | {
183 | "cell_type": "markdown",
184 | "metadata": {},
185 | "source": [
186 | "## 연쇄적인 대화\n"
187 | ]
188 | },
189 | {
190 | "cell_type": "markdown",
191 | "metadata": {},
192 | "source": [
193 | "`client.chat.completions.create()` 함수는 자체적으로 대화를 저장하는 기능이 없습니다.\n",
194 | "\n",
195 | "따라서, 이전 문맥(context)을 기억하면서 대화를 이어나가기 위해서는(일반적인 ChatBot을 생각하시면 됩니다) 다음과 같이 `messages` 옵션에 메시지를 추가해야 합니다.\n",
196 | "\n",
197 | "messages는 대화의 각 부분을 구성하는 데 사용되며, 각 메시지는 \"role\"과 \"content\"라는 두 가지 주요 요소를 포함하는 딕셔너리 형태로 되어 있습니다. 이 구조를 사용하면 복잡한 대화 흐름을 더 명확하게 관리하고 조작할 수 있습니다.\n",
198 | "\n",
199 | "각 \"role\"의 의미는 다음과 같습니다:\n",
200 | "\n",
201 | "- \"system\": 시스템 전역 설정에 대한 지시문을 포함합니다. 예를 들어, 모델에 특정한 페르소나(persona)를 부여하거나, 대화의 맥락을 설정하는 데 사용됩니다.\n",
202 | "- \"user\": 사용자의 입력을 나타냅니다. 이는 대화에서 사용자가 질문하거나 요청한 내용을 담고 있습니다.\n",
203 | "- \"assistant\": AI 모델(예: ChatGPT)의 응답을 나타냅니다. 이는 모델이 생성한 답변이나 정보를 포함합니다.\n"
204 | ]
205 | },
206 | {
207 | "cell_type": "code",
208 | "execution_count": null,
209 | "metadata": {},
210 | "outputs": [],
211 | "source": [
212 | "completion = client.chat.completions.create(\n",
213 | " model=\"gpt-3.5-turbo\",\n",
214 | " messages=[\n",
215 | " {\n",
216 | " \"role\": \"system\",\n",
217 | " \"content\": \"You are a helpful assistant. You must answer in Korean.\",\n",
218 | " },\n",
219 | " {\n",
220 | " \"role\": \"user\",\n",
221 | " \"content\": \"대한민국의 수도는 어디인가요?\",\n",
222 | " },\n",
223 | " ],\n",
224 | ")\n",
225 | "\n",
226 | "print(completion.choices[0].message.content)"
227 | ]
228 | },
229 | {
230 | "cell_type": "code",
231 | "execution_count": null,
232 | "metadata": {},
233 | "outputs": [],
234 | "source": [
235 | "def ask(question):\n",
236 | " completion = client.chat.completions.create(\n",
237 | " model=\"gpt-3.5-turbo\",\n",
238 | " messages=[\n",
239 | " {\n",
240 | " \"role\": \"system\",\n",
241 | " \"content\": \"You are a helpful assistant. You must answer in Korean.\",\n",
242 | " },\n",
243 | " {\n",
244 | " \"role\": \"user\",\n",
245 | " \"content\": question, # 사용자의 질문을 입력\n",
246 | " },\n",
247 | " ],\n",
248 | " )\n",
249 | " # 답변을 반환\n",
250 | " return completion.choices[0].message.content"
251 | ]
252 | },
253 | {
254 | "cell_type": "code",
255 | "execution_count": null,
256 | "metadata": {},
257 | "outputs": [],
258 | "source": [
259 | "# 첫 번째 질문\n",
260 | "ask(\"대한민국의 수도는 어디인가요?\")"
261 | ]
262 | },
263 | {
264 | "cell_type": "code",
265 | "execution_count": null,
266 | "metadata": {},
267 | "outputs": [],
268 | "source": [
269 | "# 두 번째 질문\n",
270 | "ask(\"영어로 답변해 주세요\")"
271 | ]
272 | },
273 | {
274 | "cell_type": "markdown",
275 | "metadata": {},
276 | "source": [
277 | "위의 답변에서 보듯이, GPT가 **다음 질문에 대한 답변을 잘못했습니다.** 이는 이전 대화내용에 대한 **저장을 하지 않았기 때문** 입니다.\n",
278 | "\n",
279 | "이를 해결하기 위해, 대화의 연속성을 유지하는 로직을 추가해야 합니다. 대화의 각 부분(사용자의 질문과 AI의 응답)을 messages 리스트에 순차적으로 추가함으로써, 챗봇은 이전의 대화 내용을 참조하여 적절한 답변을 생성할 수 있습니다.\n"
280 | ]
281 | },
282 | {
283 | "cell_type": "code",
284 | "execution_count": null,
285 | "metadata": {},
286 | "outputs": [],
287 | "source": [
288 | "completion = client.chat.completions.create(\n",
289 | " model=\"gpt-3.5-turbo\",\n",
290 | " messages=[\n",
291 | " {\n",
292 | " \"role\": \"system\",\n",
293 | " \"content\": \"You are a helpful assistant. You must answer in Korean.\",\n",
294 | " },\n",
295 | " {\n",
296 | " \"role\": \"user\",\n",
297 | " \"content\": \"대한민국의 수도는 어디인가요?\", # 첫 번째 질문\n",
298 | " },\n",
299 | " {\n",
300 | " \"role\": \"assistant\",\n",
301 | " \"content\": \"대한민국의 수도는 서울입니다.\", # 첫 번째 답변\n",
302 | " },\n",
303 | " {\n",
304 | " \"role\": \"user\",\n",
305 | " \"content\": \"이전의 답변을 영어로 번역해 주세요.\", # 두 번째 질문\n",
306 | " },\n",
307 | " ],\n",
308 | ")\n",
309 | "\n",
310 | "# 두 번째 답변을 출력\n",
311 | "print(completion.choices[0].message.content)"
312 | ]
313 | },
314 | {
315 | "cell_type": "markdown",
316 | "metadata": {},
317 | "source": [
318 | "좀 더 깔끔하게 함수화하여 구현해 보겠습니다.\n"
319 | ]
320 | },
321 | {
322 | "cell_type": "code",
323 | "execution_count": null,
324 | "metadata": {},
325 | "outputs": [],
326 | "source": [
327 | "def ask(question, message_history=[], model=\"gpt-3.5-turbo\"):\n",
328 | " if len(message_history) == 0:\n",
329 | " # 최초 질문\n",
330 | " message_history.append(\n",
331 | " {\n",
332 | " \"role\": \"system\",\n",
333 | " \"content\": \"You are a helpful assistant. You must answer in Korean.\",\n",
334 | " }\n",
335 | " )\n",
336 | "\n",
337 | " # 사용자 질문 추가\n",
338 | " message_history.append(\n",
339 | " {\n",
340 | " \"role\": \"user\",\n",
341 | " \"content\": question,\n",
342 | " },\n",
343 | " )\n",
344 | "\n",
345 | " # GPT에 질문을 전달하여 답변을 생성\n",
346 | " completion = client.chat.completions.create(\n",
347 | " model=model,\n",
348 | " messages=message_history,\n",
349 | " )\n",
350 | "\n",
351 | " # 사용자 질문에 대한 답변을 추가\n",
352 | " message_history.append(\n",
353 | " {\"role\": \"assistant\", \"content\": completion.choices[0].message.content}\n",
354 | " )\n",
355 | "\n",
356 | " return message_history"
357 | ]
358 | },
359 | {
360 | "cell_type": "code",
361 | "execution_count": null,
362 | "metadata": {},
363 | "outputs": [],
364 | "source": [
365 | "# 최초 질문\n",
366 | "message_history = ask(\"양자역학에 대해서 쉽게 설명해 주세요\", message_history=[])\n",
367 | "# 최초 답변\n",
368 | "print(message_history[-1])"
369 | ]
370 | },
371 | {
372 | "cell_type": "code",
373 | "execution_count": null,
374 | "metadata": {},
375 | "outputs": [],
376 | "source": [
377 | "message_history"
378 | ]
379 | },
380 | {
381 | "cell_type": "code",
382 | "execution_count": null,
383 | "metadata": {},
384 | "outputs": [],
385 | "source": [
386 | "# 두 번째 질문\n",
387 | "message_history = ask(\n",
388 | " \"이전의 내용을 영어로 답변해 주세요\", message_history=message_history\n",
389 | ")\n",
390 | "# 두 번째 답변\n",
391 | "print(message_history[-1])"
392 | ]
393 | },
394 | {
395 | "cell_type": "code",
396 | "execution_count": null,
397 | "metadata": {},
398 | "outputs": [],
399 | "source": [
400 | "message_history"
401 | ]
402 | },
403 | {
404 | "cell_type": "markdown",
405 | "metadata": {},
406 | "source": [
407 | "이번에는 이전 대화내용을 `message_history` 에 저장하여 전달하였습니다. 이전 대화내용을 저장하면서 `message_history` 를 통해 대화를 이어나갈 수 있습니다.\n"
408 | ]
409 | },
410 | {
411 | "cell_type": "markdown",
412 | "metadata": {},
413 | "source": [
414 | "## json_object 답변형식\n",
415 | "\n",
416 | "이번에는 GPT 의 출력 형식을 지정하는 방법을 살펴보겠습니다. 다음의 예시는 프롬프트를 활용하여 답변을 JSON 형식으로 받는 예제 입니다.\n"
417 | ]
418 | },
419 | {
420 | "cell_type": "code",
421 | "execution_count": null,
422 | "metadata": {},
423 | "outputs": [],
424 | "source": [
425 | "completion = client.chat.completions.create(\n",
426 | " model=\"gpt-3.5-turbo-1106\",\n",
427 | " messages=[\n",
428 | " {\n",
429 | " \"role\": \"system\",\n",
430 | " # 답변 형식을 JSON 으로 받기 위해 프롬프트에 JSON 형식을 지정\n",
431 | " \"content\": \"You are a helpful assistant designed to output JSON. You must answer in Korean.\",\n",
432 | " },\n",
433 | " {\n",
434 | " \"role\": \"user\",\n",
435 | " \"content\": \"대한민국의 수도는 어디인가요?\",\n",
436 | " },\n",
437 | " ],\n",
438 | " response_format={\"type\": \"json_object\"}, # 답변 형식을 JSON 으로 지정\n",
439 | ")\n",
440 | "\n",
441 | "print(completion.choices[0].message.content)"
442 | ]
443 | },
444 | {
445 | "cell_type": "code",
446 | "execution_count": null,
447 | "metadata": {},
448 | "outputs": [],
449 | "source": [
450 | "response = client.chat.completions.create(\n",
451 | " model=\"gpt-3.5-turbo-1106\",\n",
452 | " response_format={\"type\": \"json_object\"},\n",
453 | " messages=[\n",
454 | " {\n",
455 | " \"role\": \"system\",\n",
456 | " \"content\": \"You are a helpful assistant designed to output JSON.\",\n",
457 | " },\n",
458 | " {\n",
459 | " \"role\": \"user\",\n",
460 | " \"content\": \"통계를 주제로 4지선다형 객관식 문제를 만들어주세요.\",\n",
461 | " },\n",
462 | " ],\n",
463 | " temperature=0.5,\n",
464 | " max_tokens=300,\n",
465 | ")\n",
466 | "print(response.choices[0].message.content)"
467 | ]
468 | },
469 | {
470 | "cell_type": "markdown",
471 | "metadata": {},
472 | "source": [
473 | "`response_format={\"type\": \"json_object\"}` 으로 출력시 json 형태로 출력되는 것을 확인할 수 있습니다.\n",
474 | "\n",
475 | "`json` 형식으로 출력 값을 받으면 데이터베이스에 저장하거나 파일형태로 저장하는데 용이합니다.\n"
476 | ]
477 | },
478 | {
479 | "cell_type": "code",
480 | "execution_count": null,
481 | "metadata": {},
482 | "outputs": [],
483 | "source": [
484 | "response = client.chat.completions.create(\n",
485 | " model=\"gpt-3.5-turbo-1106\",\n",
486 | " response_format={\"type\": \"json_object\"},\n",
487 | " messages=[\n",
488 | " {\n",
489 | " \"role\": \"system\",\n",
490 | " \"content\": \"You are a helpful assistant designed to output JSON.\",\n",
491 | " },\n",
492 | " {\n",
493 | " \"role\": \"user\",\n",
494 | " \"content\": \"통계를 주제로 4지선다형 객관식 문제를 만들어주세요. 정답은 index 번호로 알려주세요. \"\n",
495 | " \"난이도는 [상, 중, 하] 중 하나로 표기해 주세요.\",\n",
496 | " },\n",
497 | " ],\n",
498 | " temperature=0.5,\n",
499 | " max_tokens=300,\n",
500 | " n=5,\n",
501 | ")"
502 | ]
503 | },
504 | {
505 | "cell_type": "markdown",
506 | "metadata": {},
507 | "source": [
508 | "5개의 결과 값을 출력합니다.\n"
509 | ]
510 | },
511 | {
512 | "cell_type": "code",
513 | "execution_count": null,
514 | "metadata": {},
515 | "outputs": [],
516 | "source": [
517 | "for res in response.choices:\n",
518 | " print(res.message.content)"
519 | ]
520 | },
521 | {
522 | "cell_type": "markdown",
523 | "metadata": {},
524 | "source": [
525 | "아래의 코드는 json 라이브러리를 사용하여 JSON 형식의 답변을 파이썬 객체로 변환하는 코드입니다.\n"
526 | ]
527 | },
528 | {
529 | "cell_type": "code",
530 | "execution_count": null,
531 | "metadata": {},
532 | "outputs": [],
533 | "source": [
534 | "import json\n",
535 | "\n",
536 | "# JSON 형식의 답변을 파이썬 객체로 변환\n",
537 | "json_obj = json.loads(res.message.content)\n",
538 | "json_obj"
539 | ]
540 | },
541 | {
542 | "cell_type": "code",
543 | "execution_count": null,
544 | "metadata": {},
545 | "outputs": [],
546 | "source": [
547 | "# type 함수로 json_obj 의 타입을 확인: dict 타입\n",
548 | "type(json_obj)"
549 | ]
550 | },
551 | {
552 | "cell_type": "code",
553 | "execution_count": null,
554 | "metadata": {},
555 | "outputs": [],
556 | "source": [
557 | "# 모든 json 형식의 답변을 파이썬 객체로 변환\n",
558 | "json_result = [json.loads(res.message.content) for res in response.choices]\n",
559 | "json_result"
560 | ]
561 | },
562 | {
563 | "cell_type": "markdown",
564 | "metadata": {},
565 | "source": [
566 | "아래는 Pandas 라이브러리를 사용하여 Python dictionary를 데이터프레임으로 변환하는 코드입니다.\n"
567 | ]
568 | },
569 | {
570 | "cell_type": "code",
571 | "execution_count": null,
572 | "metadata": {},
573 | "outputs": [],
574 | "source": [
575 | "import pandas as pd\n",
576 | "\n",
577 | "# 데이터프레임으로 변환\n",
578 | "df = pd.DataFrame(json_result)\n",
579 | "df.head()"
580 | ]
581 | },
582 | {
583 | "cell_type": "code",
584 | "execution_count": null,
585 | "metadata": {},
586 | "outputs": [],
587 | "source": [
588 | "# 데이터프레임을 csv 파일로 저장\n",
589 | "df.to_csv(\"stats_quiz.csv\", index=False)"
590 | ]
591 | },
592 | {
593 | "cell_type": "code",
594 | "execution_count": null,
595 | "metadata": {},
596 | "outputs": [],
597 | "source": [
598 | "# 데이터프레임을 엑셀 파일로 저장\n",
599 | "df.to_excel(\"stats_quiz.xlsx\", index=False)"
600 | ]
601 | },
602 | {
603 | "cell_type": "code",
604 | "execution_count": null,
605 | "metadata": {},
606 | "outputs": [],
607 | "source": []
608 | }
609 | ],
610 | "metadata": {
611 | "kernelspec": {
612 | "display_name": "base",
613 | "language": "python",
614 | "name": "python3"
615 | },
616 | "language_info": {
617 | "codemirror_mode": {
618 | "name": "ipython",
619 | "version": 3
620 | },
621 | "file_extension": ".py",
622 | "mimetype": "text/x-python",
623 | "name": "python",
624 | "nbconvert_exporter": "python",
625 | "pygments_lexer": "ipython3",
626 | "version": "3.10.13"
627 | }
628 | },
629 | "nbformat": 4,
630 | "nbformat_minor": 2
631 | }
632 |
--------------------------------------------------------------------------------
/02-ImageGeneration.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "# 토큰 정보로드를 위한 라이브러리\n",
10 | "# 설치: pip install python-dotenv\n",
11 | "from dotenv import load_dotenv\n",
12 | "\n",
13 | "# 토큰 정보로드\n",
14 | "load_dotenv()"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "## 🌱 DALL-E\n",
22 | "\n",
23 | "- 웹사이트: [DALL-E](https://labs.openai.com/)\n",
24 | "- 웹사이트에서 이미지를 업로드 하거나, 이미지를 생성하는 기능 구현이 잘 되어 있습니다.\n",
25 | "- in-painting, out-painting 도구도 함께 제공합니다.\n"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {},
31 | "source": [
32 | "## Client 생성\n",
33 | "\n",
34 | "- `client` 는 OpenAI 모듈로 생성된 인스턴스 입니다.\n",
35 | "\n",
36 | "[주의] 아래의 코드에서 오류가 난다면 API 키의 오류일 가능성이 높습니다.\n"
37 | ]
38 | },
39 | {
40 | "cell_type": "markdown",
41 | "metadata": {},
42 | "source": [
43 | "설치된 openai 버전 확인\n"
44 | ]
45 | },
46 | {
47 | "cell_type": "code",
48 | "execution_count": null,
49 | "metadata": {},
50 | "outputs": [],
51 | "source": [
52 | "import openai\n",
53 | "\n",
54 | "print(f\"설치된 버전: {openai.__version__}\")"
55 | ]
56 | },
57 | {
58 | "cell_type": "code",
59 | "execution_count": null,
60 | "metadata": {},
61 | "outputs": [],
62 | "source": [
63 | "from openai import OpenAI\n",
64 | "\n",
65 | "client = OpenAI()"
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "metadata": {},
71 | "source": [
72 | "## ① 이미지 생성\n",
73 | "\n",
74 | "- Reference: https://platform.openai.com/docs/guides/images/introduction?context=node\n",
75 | "- `model`\n",
76 | " - 생성: 사용 가능한 모델은 `dall-e-3` 및 `dall-e-2`\n",
77 | " - 편집(edit): `dall-e-2`\n",
78 | " - 기준 이미지에 대한 다양화(variation): `dall-e-2`\n",
79 | "\n",
80 | "**이미지 크기**\n",
81 | "\n",
82 | "- `dall-e-2`\n",
83 | " - `256x256`, `512x512`, `1024x1024`\n",
84 | "- `dall-e-3`\n",
85 | " - `1024x1024`, `1792x1024`, `1024x1792`\n",
86 | "\n",
87 | "기본적으로 이미지는 표준 화질로 생성되지만, DALL-E 3을 사용할 때는 화질을 설정할 수 있습니다. \"HD\"로 설정하면 디테일이 향상됩니다. 정사각형의 표준 화질 이미지가 가장 빠르게 생성됩니다.\n",
88 | "\n",
89 | "**사진요청 개수**\n",
90 | "\n",
91 | "DALL-E 3을 사용하면 **한 번에 1개의 이미지를 요청** 할 수 있고(병렬 요청을 통해 더 많은 이미지를 요청할 수 있음), DALL-E 2를 사용하면 n 매개변수와 함께 **한 번에 최대 10개의 이미지를 요청** 할 수 있습니다.\n"
92 | ]
93 | },
94 | {
95 | "cell_type": "markdown",
96 | "metadata": {},
97 | "source": [
98 | "- 참고: https://dallery.gallery/the-dalle-2-prompt-book/\n"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "execution_count": null,
104 | "metadata": {},
105 | "outputs": [],
106 | "source": [
107 | "# DALL-E 3 모델을 사용하여 이미지를 생성합니다.\n",
108 | "response = client.images.generate(\n",
109 | " model=\"dall-e-3\",\n",
110 | " prompt=\"A detailed neoclassicism painting depicting the frustration of being put on hold during a phone call(iphone)\",\n",
111 | " size=\"1024x1024\",\n",
112 | " quality=\"standard\",\n",
113 | " n=1,\n",
114 | ")\n",
115 | "\n",
116 | "# 생성된 이미지의 URL을 저장합니다.\n",
117 | "image_url = response.data[0].url"
118 | ]
119 | },
120 | {
121 | "cell_type": "markdown",
122 | "metadata": {},
123 | "source": [
124 | "다운로드 받을 수 있는 이미지의 URL을 출력합니다.\n"
125 | ]
126 | },
127 | {
128 | "cell_type": "code",
129 | "execution_count": null,
130 | "metadata": {},
131 | "outputs": [],
132 | "source": [
133 | "# 생성된 이미지의 URL을 출력합니다.\n",
134 | "print(image_url)"
135 | ]
136 | },
137 | {
138 | "cell_type": "markdown",
139 | "metadata": {},
140 | "source": [
141 | "생성된 결과 (예시)\n",
142 | "\n",
143 | "\n",
158 | "\n",
159 | "
\n",
160 | "
\n",
161 | "

\n",
162 | "
\n",
163 | "
\n",
164 | "

\n",
165 | "
\n",
166 | "
\n"
167 | ]
168 | },
169 | {
170 | "cell_type": "markdown",
171 | "metadata": {},
172 | "source": [
173 | "Jupyter Notebook 에서 출력하기 위하여 Image 를 사용합니다.\n"
174 | ]
175 | },
176 | {
177 | "cell_type": "code",
178 | "execution_count": null,
179 | "metadata": {},
180 | "outputs": [],
181 | "source": [
182 | "from IPython.display import Image\n",
183 | "\n",
184 | "# 생성된 이미지를 출력합니다.\n",
185 | "Image(url=image_url, width=500)"
186 | ]
187 | },
188 | {
189 | "cell_type": "markdown",
190 | "metadata": {},
191 | "source": [
192 | "`urllib` 라이브러리를 사용하여 이미지를 다운로드합니다.\n"
193 | ]
194 | },
195 | {
196 | "cell_type": "code",
197 | "execution_count": null,
198 | "metadata": {},
199 | "outputs": [],
200 | "source": [
201 | "import urllib\n",
202 | "\n",
203 | "# 생성된 이미지를 URL로부터 다운로드하여 저장합니다.\n",
204 | "urllib.request.urlretrieve(image_url, \"generated_image.jpg\")"
205 | ]
206 | },
207 | {
208 | "cell_type": "markdown",
209 | "metadata": {},
210 | "source": [
211 | "### ✔️ DALLE-3 프롬프트 예시\n",
212 | "\n",
213 | "- 1️⃣ 예시 프롬프트:\n",
214 | " - `a closeup of a female face with headphones in retro colors, synthwave style, 2d digital vector art`\n",
215 | "- 2️⃣ 예시 프롬프트:\n",
216 | "\n",
217 | " - `A detailed neoclassicism painting depicting the frustration of being put on hold during a phone call(iphone)`\n",
218 | "\n",
219 | "- 더 많은 예시는 다음의 링크를 참고해 보세요:\n",
220 | " - https://dallery.gallery/the-dalle-2-prompt-book/\n"
221 | ]
222 | },
223 | {
224 | "cell_type": "code",
225 | "execution_count": null,
226 | "metadata": {},
227 | "outputs": [],
228 | "source": [
229 | "response = client.images.generate(\n",
230 | " model=\"dall-e-3\",\n",
231 | " prompt=\"A sunlit indoor lounge area with a pool with clear water\"\n",
232 | " \"and another pool with translucent pastel pink water, next\"\n",
233 | " \" to a big window, digital art\",\n",
234 | " size=\"1024x1024\",\n",
235 | " quality=\"standard\",\n",
236 | " n=1,\n",
237 | ")\n",
238 | "\n",
239 | "image_url = response.data[0].url"
240 | ]
241 | },
242 | {
243 | "cell_type": "markdown",
244 | "metadata": {},
245 | "source": [
246 | "생성된 이미지를 출력합니다.\n"
247 | ]
248 | },
249 | {
250 | "cell_type": "code",
251 | "execution_count": null,
252 | "metadata": {},
253 | "outputs": [],
254 | "source": [
255 | "print(image_url)"
256 | ]
257 | },
258 | {
259 | "cell_type": "code",
260 | "execution_count": null,
261 | "metadata": {},
262 | "outputs": [],
263 | "source": [
264 | "# 생성된 이미지를 출력합니다.\n",
265 | "Image(url=image_url, width=500)"
266 | ]
267 | },
268 | {
269 | "cell_type": "code",
270 | "execution_count": null,
271 | "metadata": {},
272 | "outputs": [],
273 | "source": [
274 | "# 생성된 이미지를 URL로부터 다운로드하여 저장합니다.\n",
275 | "urllib.request.urlretrieve(image_url, \"generated_image2.jpg\")"
276 | ]
277 | },
278 | {
279 | "cell_type": "markdown",
280 | "metadata": {},
281 | "source": [
282 | "## ② 이미지 수정(Image Edit)\n",
283 | "\n",
284 | "- 도큐먼트: https://platform.openai.com/docs/api-reference/images/createEdit\n",
285 | "\n",
286 | "**주요 파라미터**\n",
287 | "\n",
288 | "- `mask`:\n",
289 | " - 마스킹 영역은 완전히 투명한 영역(예: 알파가 0인 곳)이 이미지를 편집할 위치를 나타내는 추가 이미지입니다.\n",
290 | " - 4MB 미만의 유효한 PNG 파일이어야 하며 이미지와 크기가 같아야 합니다.\n",
291 | " - 마스킹한 영역에 대하여 다양한 버전의 이미지를 생성합니다.\n",
292 | "- `model`: 이미지 생성에 사용할 모델입니다. 현재 `dall-e-2` 만 지원됩니다.\n",
293 | "- `n`: 생성할 이미지의 개수입니다.\n",
294 | "- `size`: `256x256`, `512x512`, or `1024x1024`. 기본값은 `1024x1024` 입니다.\n"
295 | ]
296 | },
297 | {
298 | "cell_type": "code",
299 | "execution_count": null,
300 | "metadata": {},
301 | "outputs": [],
302 | "source": [
303 | "from openai import OpenAI\n",
304 | "\n",
305 | "client = OpenAI()\n",
306 | "\n",
307 | "response = client.images.edit(\n",
308 | " model=\"dall-e-2\",\n",
309 | " image=open(\"data/sample.png\", \"rb\"),\n",
310 | " mask=open(\"data/sample-mask.png\", \"rb\"),\n",
311 | " prompt=\"add a Christmas tree\",\n",
312 | " n=1,\n",
313 | " size=\"1024x1024\",\n",
314 | ")\n",
315 | "\n",
316 | "image_url = response.data[0].url"
317 | ]
318 | },
319 | {
320 | "cell_type": "markdown",
321 | "metadata": {},
322 | "source": [
323 | "이전의 코드에서 작성한 프롬프트는 마치 사진과 같은 Photorealistic 이미지를 생성하기 위하여 카메라 렌즈 정보를 추가해 주었습니다. 이렇게 카메라 렌즈, 화각, 조리개 값등을 넣어 마치 사진으로 촬영한 듯한 이미지를 생성할 수 있습니다.\n"
324 | ]
325 | },
326 | {
327 | "cell_type": "markdown",
328 | "metadata": {},
329 | "source": [
330 | "원본 이미지는 다음과 같습니다.\n"
331 | ]
332 | },
333 | {
334 | "cell_type": "code",
335 | "execution_count": null,
336 | "metadata": {},
337 | "outputs": [],
338 | "source": [
339 | "# 원본 이미지를 출력합니다.\n",
340 | "Image(url=\"data/sample.png\")"
341 | ]
342 | },
343 | {
344 | "cell_type": "markdown",
345 | "metadata": {},
346 | "source": [
347 | "다음은 마스킹한 이미지입니다. 마스킹은 photopea 에서 쉽게 진행할 수 있습니다.\n",
348 | "\n",
349 | "- [photopea 링크](https://photopea.com/)\n"
350 | ]
351 | },
352 | {
353 | "cell_type": "code",
354 | "execution_count": null,
355 | "metadata": {},
356 | "outputs": [],
357 | "source": [
358 | "# 마스킹된 이미지를 출력합니다.\n",
359 | "Image(url=\"data/sample-mask.png\")"
360 | ]
361 | },
362 | {
363 | "cell_type": "markdown",
364 | "metadata": {},
365 | "source": [
366 | "마지막으로 마스킹된 영역을 크리스마스 트리로 채운 결과 이미지 입니다.\n"
367 | ]
368 | },
369 | {
370 | "cell_type": "code",
371 | "execution_count": null,
372 | "metadata": {},
373 | "outputs": [],
374 | "source": [
375 | "# 생성된 이미지를 URL로부터 다운로드하여 저장합니다.\n",
376 | "urllib.request.urlretrieve(image_url, \"edited_output.png\")\n",
377 | "\n",
378 | "# 생성된 이미지를 출력합니다.\n",
379 | "Image(url=\"edited_output.png\")"
380 | ]
381 | },
382 | {
383 | "cell_type": "markdown",
384 | "metadata": {},
385 | "source": [
386 | "## ③ 다양한 버전의 이미지 생성(Image Variation)\n",
387 | "\n",
388 | "주어진 이미지의 변형을 생성합니다.\n",
389 | "\n",
390 | "- 도큐먼트: https://platform.openai.com/docs/api-reference/images/createVariation\n",
391 | "\n",
392 | "주요 파라미터\n",
393 | "\n",
394 | "- `image`: 변형의 기준으로 사용할 이미지입니다. 4MB 미만의 유효한 `PNG` 파일이어야 하며 `정사각형` 이어야 합니다.\n",
395 | "- `model`: 이미지 생성에 사용할 모델입니다. 현재 `dall-e-2` 만 지원됩니다.\n",
396 | "- `n`: 생성할 이미지의 개수입니다.\n",
397 | "- `size`: `256x256`, `512x512`, or `1024x1024`. 기본값은 `1024x1024` 입니다.\n"
398 | ]
399 | },
400 | {
401 | "cell_type": "code",
402 | "execution_count": null,
403 | "metadata": {},
404 | "outputs": [],
405 | "source": [
406 | "number_of_variations = 2\n",
407 | "image_size = \"512x512\"\n",
408 | "\n",
409 | "response = client.images.create_variation(\n",
410 | " image=open(\"data/generated_image_porche.png\", \"rb\"), # 기준 이미지\n",
411 | " n=number_of_variations, # 생성할 이미지의 개수\n",
412 | " size=image_size, # 생성할 이미지의 크기\n",
413 | ")\n",
414 | "\n",
415 | "image_url = response.data[0].url"
416 | ]
417 | },
418 | {
419 | "cell_type": "markdown",
420 | "metadata": {},
421 | "source": [
422 | "생성된 이미지를 출력합니다.\n"
423 | ]
424 | },
425 | {
426 | "cell_type": "code",
427 | "execution_count": null,
428 | "metadata": {},
429 | "outputs": [],
430 | "source": [
431 | "import matplotlib.pyplot as plt\n",
432 | "from matplotlib.image import imread\n",
433 | "\n",
434 | "\n",
435 | "fig, ax = plt.subplots(1, number_of_variations, figsize=(8, 8 * number_of_variations))\n",
436 | "\n",
437 | "for i in range(1, number_of_variations + 1):\n",
438 | " filename = f\"variated_image_{i}.jpg\"\n",
439 | " i -= 1\n",
440 | " urllib.request.urlretrieve(response.data[i].url, filename)\n",
441 | " img = imread(filename)\n",
442 | " ax[i].imshow(img)\n",
443 | " ax[i].axis(\"off\")\n",
444 | " ax[i].set_title(f\"Variation {i+1}\")\n",
445 | "\n",
446 | "plt.tight_layout()\n",
447 | "plt.show()"
448 | ]
449 | },
450 | {
451 | "cell_type": "code",
452 | "execution_count": null,
453 | "metadata": {},
454 | "outputs": [],
455 | "source": []
456 | }
457 | ],
458 | "metadata": {
459 | "kernelspec": {
460 | "display_name": "base",
461 | "language": "python",
462 | "name": "python3"
463 | },
464 | "language_info": {
465 | "codemirror_mode": {
466 | "name": "ipython",
467 | "version": 3
468 | },
469 | "file_extension": ".py",
470 | "mimetype": "text/x-python",
471 | "name": "python",
472 | "nbconvert_exporter": "python",
473 | "pygments_lexer": "ipython3",
474 | "version": "3.10.13"
475 | }
476 | },
477 | "nbformat": 4,
478 | "nbformat_minor": 2
479 | }
480 |
--------------------------------------------------------------------------------
/03-TTS-and-STT.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "# 토큰 정보로드를 위한 라이브러리\n",
10 | "# 설치: pip install python-dotenv\n",
11 | "from dotenv import load_dotenv\n",
12 | "\n",
13 | "# 토큰 정보로드\n",
14 | "load_dotenv()"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "## Client 생성\n",
22 | "\n",
23 | "- `client` 는 OpenAI 모듈로 생성된 인스턴스 입니다.\n",
24 | "\n",
25 | "[주의] 아래의 코드에서 오류가 난다면 API 키의 오류일 가능성이 높습니다.\n"
26 | ]
27 | },
28 | {
29 | "cell_type": "code",
30 | "execution_count": null,
31 | "metadata": {},
32 | "outputs": [],
33 | "source": [
34 | "from openai import OpenAI\n",
35 | "\n",
36 | "client = OpenAI()"
37 | ]
38 | },
39 | {
40 | "cell_type": "markdown",
41 | "metadata": {},
42 | "source": [
43 | "## Text To Speech(TTS)\n",
44 | "\n",
45 | "- TTS는 컴퓨터 프로그램이나 기기가 텍스트를 인간의 음성처럼 들리는 오디오로 변환하는 과정입니다.\n",
46 | "- 이 기술은 음성 합성을 통해 텍스트 데이터를 자연스러운 음성으로 바꿉니다.\n",
47 | "- 사용 예시: 오디오북, 음성 안내 시스템, 음성 기반 가상 어시스턴트 등.\n",
48 | "\n",
49 | "**[참고]**\n",
50 | "\n",
51 | "- 공식문서: https://platform.openai.com/docs/guides/text-to-speech\n"
52 | ]
53 | },
54 | {
55 | "cell_type": "markdown",
56 | "metadata": {},
57 | "source": [
58 | "**주요 파라미터**\n",
59 | "\n",
60 | "- `model`: 사용 가능한 TTS 모델 중 하나를 지정합니다. `tts-1` 또는 `tts-1-hd`.\n",
61 | " - 최신 지원모델 확인: https://platform.openai.com/docs/models/tts\n",
62 | "- `input`: 오디오를 생성할 텍스트입니다. 최대 길이는 4096자입니다.\n",
63 | "- `voice`: 오디오를 생성할 때 사용할 음성입니다. 지원되는 음성은 `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer` 입니다. 음성의 미리듣기는 [여기](https://platform.openai.com/docs/guides/text-to-speech/voice-options) 에서 확인할 수 있습니다.\n",
64 | "- `response_format`: 오디오를 입력할 형식입니다. 지원되는 형식은 `mp3`, `opus`, `aac` 및 `flac` 입니다.\n",
65 | "- `speed`: 생성된 오디오의 속도입니다. `0.25` 에서 `4.0` 사이의 값을 선택합니다. 기본값은 `1.0` 입니다.\n"
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": null,
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "speech_file_path = \"tts_audio.mp3\"\n",
75 | "\n",
76 | "response = client.audio.speech.create(\n",
77 | " model=\"tts-1\",\n",
78 | " input=\"아~ 오늘 파이썬 배우기 정말 좋은 날이네~\",\n",
79 | " voice=\"shimmer\",\n",
80 | " response_format=\"mp3\",\n",
81 | " speed=2.0,\n",
82 | ")\n",
83 | "\n",
84 | "response.stream_to_file(speech_file_path)"
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "저장한 오디오 파일을 재생합니다.\n"
92 | ]
93 | },
94 | {
95 | "cell_type": "code",
96 | "execution_count": null,
97 | "metadata": {},
98 | "outputs": [],
99 | "source": [
100 | "from IPython.display import Audio\n",
101 | "\n",
102 | "Audio(speech_file_path)"
103 | ]
104 | },
105 | {
106 | "cell_type": "markdown",
107 | "metadata": {},
108 | "source": [
109 | "## Speech To Text(STT)\n",
110 | "\n",
111 | "- STT는 사람의 말소리를 텍스트로 변환하는 기술입니다.\n",
112 | "- 이는 음성 인식을 통해 구어체 언어를 캡처하고 이를 기록 가능한 형태의 텍스트로 변환합니다.\n",
113 | "- 사용예시: 음성 명령 입력, 자동 회의록 작성, 음성 기반 검색 시스템 등.\n",
114 | "\n",
115 | "**[참고]**\n",
116 | "\n",
117 | "- 공식문서: https://platform.openai.com/docs/guides/speech-to-text\n",
118 | "- 파일 업로드는 현재 25MB로 제한되어 있으며, 지원되는 입력 파일 형식은 `mp3`, `MP4`, `MPEG`, `MPGA`, `M4A`, `WAV`, `WEBM` 입니다.\n",
119 | "- 지원언어\n",
120 | " - 아프리칸스어, 아랍어, 아르메니아어, 아제르바이잔어, 벨라루스어, 보스니아어, 불가리아어, 카탈로니아어, 중국어, 크로아티아어, 체코어, 덴마크어, 네덜란드어, 영어, 에스토니아어, 핀란드어, 프랑스어, 갈리시아어, 독일어, 그리스어, 히브리어, 힌디어, 헝가리어, 아이슬란드어, 인도네시아어, 이탈리아어, 일본어, 인도네시아어, 칸나다어, 카자흐어, 한국어, 라트비아어, 리투아니아어, 마케도니아어, 말레이어, 마라티어, 마오리어, 네팔어, 노르웨이어, 페르시아어, 폴란드어, 포르투갈어, 루마니아어, 러시아어, 세르비아어, 슬로바키아어, 슬로베니아어, 스페인어, 스와힐리어, 스웨덴어, 타갈로그어, 타밀어, 태국어, 터키어, 우크라이나어, 우르두어, 베트남어 및 웨일스어.\n"
121 | ]
122 | },
123 | {
124 | "cell_type": "markdown",
125 | "metadata": {},
126 | "source": [
127 | "**주요 파라미터**\n",
128 | "\n",
129 | "- `file`: 변환할 오디오 파일 개체(파일 이름이 아님)로, 다음 형식 중 하나입니다: `FLAC`, `MP3`, `MP4`, `MPEG`, `MPGA`, `M4A`, `OGG`, `WAV` 또는 `WEBM`.\n",
130 | "- `model`: 현재는 `whisper-1` 모델만 지정 가능합니다.\n",
131 | "- `language`: 입력 오디오의 언어입니다. 입력 언어를 ISO-639-1 형식으로 제공하면 정확도와 지연 시간이 개선됩니다.\n",
132 | " - [ISO-639-1 형식](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)\n",
133 | "- `prompt`: (선택 사항) 모델의 스타일을 안내하거나 이전 오디오 세그먼트를 계속하기 위한 텍스트입니다. 프롬프트는 오디오 언어와 일치해야 합니다.\n",
134 | "- `response_format`: 변환된 결과물 출력 형식입니다. 가능한 지정 옵션은 `json`, `text`, `srt`, `verbose_json` 또는 `vtt` 입니다.\n",
135 | "- `temperature`: 0에서 1 사이의 샘플링 `temperature` 입니다. 0.8과 같이 값이 높을수록 출력은 더 무작위적이고, 0.2와 같이 값이 낮을수록 출력은 더 집중적이고 결정론적입니다. 0으로 설정하면 모델은 로그 확률을 사용하여 특정 임계값에 도달할 때까지 자동으로 `temperature` 을 높입니다.\n"
136 | ]
137 | },
138 | {
139 | "cell_type": "code",
140 | "execution_count": null,
141 | "metadata": {},
142 | "outputs": [],
143 | "source": [
144 | "audio_file = open(\"data/채용면접_샘플_01.wav\", \"rb\")\n",
145 | "transcript = client.audio.transcriptions.create(\n",
146 | " file=audio_file,\n",
147 | " model=\"whisper-1\",\n",
148 | " language=\"ko\",\n",
149 | " response_format=\"text\",\n",
150 | " temperature=0.0,\n",
151 | ")"
152 | ]
153 | },
154 | {
155 | "cell_type": "code",
156 | "execution_count": null,
157 | "metadata": {},
158 | "outputs": [],
159 | "source": [
160 | "# 결과물 출력\n",
161 | "print(transcript)"
162 | ]
163 | },
164 | {
165 | "cell_type": "markdown",
166 | "metadata": {},
167 | "source": [
168 | "## 더욱 긴 오디오 입력 대한 처리\n",
169 | "\n",
170 | "기본적으로 Whisper API는 **25MB 미만의 파일** 만 지원합니다.\n",
171 | "\n",
172 | "이보다 긴 오디오 파일이 있는 경우 **25MB 이하의 청크로 나누거나 압축된 오디오 형식을 사용** 해야 합니다.\n",
173 | "\n",
174 | "최상의 성능을 얻으려면 문장 중간에 오디오를 분할하면 일부 문맥이 손실될 수 있으므로 분할을 피하는 것이 좋습니다.\n",
175 | "\n",
176 | "이를 처리하는 한 가지 방법은 `PyDub` 오픈 소스 Python 패키지를 사용하여 **오디오를 분할** 하는 것입니다.\n"
177 | ]
178 | },
179 | {
180 | "cell_type": "markdown",
181 | "metadata": {},
182 | "source": [
183 | "**샘플 데이터셋(채용면접 인터뷰 데이터)**\n",
184 | "\n",
185 | "- 링크: https://aihub.or.kr/aihubdata/data/view.do?currMenu=115&topMenu=100&aihubDataSe=data&dataSetSn=71592\n"
186 | ]
187 | },
188 | {
189 | "cell_type": "markdown",
190 | "metadata": {},
191 | "source": [
192 | "아래의 코드는 오디오 파일을 정해진 시간에 따라 분절하여 별도의 파일로 저장하는 코드입니다.\n"
193 | ]
194 | },
195 | {
196 | "cell_type": "code",
197 | "execution_count": null,
198 | "metadata": {},
199 | "outputs": [],
200 | "source": [
201 | "# !pip install pydub"
202 | ]
203 | },
204 | {
205 | "cell_type": "code",
206 | "execution_count": null,
207 | "metadata": {},
208 | "outputs": [],
209 | "source": [
210 | "from pydub import AudioSegment\n",
211 | "\n",
212 | "filename = \"data/채용면접_샘플_02.wav\"\n",
213 | "myaudio = AudioSegment.from_mp3(filename)\n",
214 | "\n",
215 | "# PyDub 는 밀리초 단위로 시간을 계산합니다.\n",
216 | "thirty_seconds = 1 * 30 * 1000 # (1초 * 30) * 1000\n",
217 | "total_milliseconds = myaudio.duration_seconds * 1000 # 전체 길이를 밀리초로 변환"
218 | ]
219 | },
220 | {
221 | "cell_type": "code",
222 | "execution_count": null,
223 | "metadata": {},
224 | "outputs": [],
225 | "source": [
226 | "# 전체 길이를 30초로 나누어서 반복할 횟수를 계산합니다.\n",
227 | "total_iterations = int(total_milliseconds // thirty_seconds + 1)\n",
228 | "total_iterations"
229 | ]
230 | },
231 | {
232 | "cell_type": "code",
233 | "execution_count": null,
234 | "metadata": {},
235 | "outputs": [],
236 | "source": [
237 | "# 생성된 파일명을 저장할 리스트\n",
238 | "output_filenames = []\n",
239 | "\n",
240 | "for i in range(total_iterations):\n",
241 | " if i < total_iterations - 1:\n",
242 | " # 30초 단위로 오디오를 분할합니다.\n",
243 | " part_of_audio = myaudio[thirty_seconds * i: thirty_seconds * (i + 1)]\n",
244 | " else:\n",
245 | " # 마지막은 나머지 전체를 분할합니다.\n",
246 | " part_of_audio = myaudio[thirty_seconds * i:]\n",
247 | "\n",
248 | " output_filename = (\n",
249 | " # 예시: 채용면접_샘플_02-(1).mp3, 채용면접_샘플_02-(2).mp3 ...\n",
250 | " f\"{filename[:-4]}-({i+1}).mp3\"\n",
251 | " )\n",
252 | "\n",
253 | " # 분할된 오디오를 저장합니다.\n",
254 | " part_of_audio.export(output_filename, format=\"mp3\")\n",
255 | " output_filenames.append(output_filename)"
256 | ]
257 | },
258 | {
259 | "cell_type": "code",
260 | "execution_count": null,
261 | "metadata": {},
262 | "outputs": [],
263 | "source": [
264 | "# 결과물(파일명) 출력\n",
265 | "output_filenames"
266 | ]
267 | },
268 | {
269 | "cell_type": "code",
270 | "execution_count": null,
271 | "metadata": {},
272 | "outputs": [],
273 | "source": [
274 | "transcripts = []\n",
275 | "\n",
276 | "for audio_filename in output_filenames:\n",
277 | " audio_file = open(audio_filename, \"rb\") # audio file 을 읽어옵니다.\n",
278 | "\n",
279 | " # transcript 를 생성합니다.\n",
280 | " transcript = client.audio.transcriptions.create(\n",
281 | " file=audio_file,\n",
282 | " model=\"whisper-1\", # 모델은 whisper-1 을 사용\n",
283 | " language=\"ko\", # 한국어를 사용\n",
284 | " response_format=\"text\", # 결과물은 text 로 출력\n",
285 | " temperature=0.0,\n",
286 | " )\n",
287 | "\n",
288 | " # 생성된 transcript 를 리스트에 추가합니다.\n",
289 | " transcripts.append(transcript)\n",
290 | "\n",
291 | "# 전체 transcript 출력(리스트를 문자열로 변환)\n",
292 | "final_output = \"---- 분할 ---- \\n\".join(transcripts)\n",
293 | "print(final_output)"
294 | ]
295 | },
296 | {
297 | "cell_type": "code",
298 | "execution_count": null,
299 | "metadata": {},
300 | "outputs": [],
301 | "source": [
302 | "example_prompt = \"\"\"\n",
303 | "당신은 채용 담당관입니다.\n",
304 | "주어진 내용을 바탕으로, 면접자의 긍정적인 면과 부정적인 면을 나누어서 정리해 주세요.\n",
305 | "결과물은 요약된 불렛포인트로 정리해 주세요.\n",
306 | "한글로 작성해 주세요.\n",
307 | "(예시)\n",
308 | "#긍정적인면\n",
309 | "- \n",
310 | "- \n",
311 | "-\n",
312 | "#부정정인면\n",
313 | "-\n",
314 | "- \n",
315 | "\"\"\"\n",
316 | "\n",
317 | "\n",
318 | "def generate_HR_opinion(temperature, prompt, transcript):\n",
319 | " response = client.chat.completions.create(\n",
320 | " model=\"gpt-4\",\n",
321 | " temperature=temperature,\n",
322 | " messages=[\n",
323 | " {\"role\": \"system\", \"content\": prompt},\n",
324 | " {\"role\": \"user\", \"content\": transcript},\n",
325 | " ],\n",
326 | " stream=True,\n",
327 | " )\n",
328 | " final_answer = []\n",
329 | "\n",
330 | " # 스트림 모드에서는 completion.choices 를 반복문으로 순회\n",
331 | " for chunk in response:\n",
332 | " # chunk 를 저장\n",
333 | " chunk_content = chunk.choices[0].delta.content\n",
334 | " # chunk 가 문자열이면 final_answer 에 추가\n",
335 | " if isinstance(chunk_content, str):\n",
336 | " final_answer.append(chunk_content)\n",
337 | " # 토큰 단위로 실시간 답변 출력\n",
338 | " print(chunk_content, end=\"\")\n",
339 | " return \"\".join(final_answer)\n",
340 | "\n",
341 | "\n",
342 | "hr_opinion = generate_HR_opinion(0, example_prompt, final_output)"
343 | ]
344 | }
345 | ],
346 | "metadata": {
347 | "kernelspec": {
348 | "display_name": "base",
349 | "language": "python",
350 | "name": "python3"
351 | },
352 | "language_info": {
353 | "codemirror_mode": {
354 | "name": "ipython",
355 | "version": 3
356 | },
357 | "file_extension": ".py",
358 | "mimetype": "text/x-python",
359 | "name": "python",
360 | "nbconvert_exporter": "python",
361 | "pygments_lexer": "ipython3",
362 | "version": "3.10.13"
363 | }
364 | },
365 | "nbformat": 4,
366 | "nbformat_minor": 2
367 | }
368 |
--------------------------------------------------------------------------------
/04-Creating-Transcripts.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## OpenAI API 키 발급 및 설정\n",
8 | "\n",
9 | "### 1. OpenAI API 키 발급\n",
10 | "\n",
11 | "[OpenAI API 키 발급방법](https://teddylee777.github.io/openai/openai-api-key/) 글을 참고해 주세요.\n",
12 | "\n",
13 | "### 2. `.env` 파일 설정\n",
14 | "\n",
15 | "- 프로젝트 루트 디렉토리에 `.env` 파일을 생성합니다.\n",
16 | "- 파일에 API 키를 다음 형식으로 저장합니다:\n",
17 | " `OPENAI_API_KEY` 에 발급받은 API KEY 를 입력합니다.\n",
18 | "\n",
19 | "- `.env` 파일에 발급한 API KEY 를 입력합니다.\n"
20 | ]
21 | },
22 | {
23 | "cell_type": "code",
24 | "execution_count": 2,
25 | "metadata": {},
26 | "outputs": [
27 | {
28 | "data": {
29 | "text/plain": [
30 | "True"
31 | ]
32 | },
33 | "execution_count": 2,
34 | "metadata": {},
35 | "output_type": "execute_result"
36 | }
37 | ],
38 | "source": [
39 | "# 토큰 정보로드를 위한 라이브러리\n",
40 | "# 설치: pip install python-dotenv\n",
41 | "from dotenv import load_dotenv\n",
42 | "\n",
43 | "# 토큰 정보로드\n",
44 | "load_dotenv()"
45 | ]
46 | },
47 | {
48 | "cell_type": "markdown",
49 | "metadata": {},
50 | "source": [
51 | "## 자막생성\n"
52 | ]
53 | },
54 | {
55 | "cell_type": "code",
56 | "execution_count": 3,
57 | "metadata": {},
58 | "outputs": [],
59 | "source": [
60 | "from openai import OpenAI\n",
61 | "\n",
62 | "client = OpenAI()"
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": 6,
68 | "metadata": {},
69 | "outputs": [],
70 | "source": [
71 | "audio_file = open(\"data/채용면접_샘플_01.wav\", \"rb\")\n",
72 | "transcript = client.audio.transcriptions.create(\n",
73 | " file=audio_file,\n",
74 | " model=\"whisper-1\",\n",
75 | " language=\"ko\",\n",
76 | " response_format=\"srt\", # 자막 포맷\n",
77 | " temperature=0.0,\n",
78 | ")"
79 | ]
80 | },
81 | {
82 | "cell_type": "code",
83 | "execution_count": 7,
84 | "metadata": {},
85 | "outputs": [
86 | {
87 | "name": "stdout",
88 | "output_type": "stream",
89 | "text": [
90 | "1\n",
91 | "00:00:00,000 --> 00:00:07,000\n",
92 | "지금 생각해보면 가장 기억에 남는 것이 외환위기 때의 경험입니다.\n",
93 | "\n",
94 | "2\n",
95 | "00:00:07,000 --> 00:00:13,000\n",
96 | "외환위기 때 나라뿐 아니라 회사에서는 달러가 많이 부족했고\n",
97 | "\n",
98 | "3\n",
99 | "00:00:13,000 --> 00:00:19,000\n",
100 | "우리는 수출을 하기 위해서 원자재라든지 대금지급\n",
101 | "\n",
102 | "4\n",
103 | "00:00:19,000 --> 00:00:23,000\n",
104 | "혹은 또 우리가 수출한 물건에 대한 대금을 받아야 되는 상황이었습니다.\n",
105 | "\n",
106 | "5\n",
107 | "00:00:23,000 --> 00:00:29,000\n",
108 | "일단은 우리가 해외로부터 받아야 될 때는 최대한 그것을 달러로 받았고\n",
109 | "\n",
110 | "6\n",
111 | "00:00:29,000 --> 00:00:36,000\n",
112 | "반대로 우리가 지불해야 될 것은 가능한 한 원자재를 통해서 지급을 했습니다.\n",
113 | "\n",
114 | "7\n",
115 | "00:00:36,000 --> 00:00:40,000\n",
116 | "그 원자재라는 것이 결국은 반도체 쪽이었는데\n",
117 | "\n",
118 | "8\n",
119 | "00:00:40,000 --> 00:00:46,000\n",
120 | "우리나라에서 가장 나름 손쉽게 구하면서도 꼭 필요한 제품인 반도체를\n",
121 | "\n",
122 | "9\n",
123 | "00:00:46,000 --> 00:00:48,000\n",
124 | "원자재값 대응으로 물건을 주면서\n",
125 | "\n",
126 | "10\n",
127 | "00:00:48,000 --> 00:00:53,000\n",
128 | "반대로 해외에서 우리가 받아야 될 것은 달러로 받으면서\n",
129 | "\n",
130 | "11\n",
131 | "00:00:53,000 --> 00:00:57,000\n",
132 | "그 환율차를 가장 줄일 수가 있었습니다.\n",
133 | "\n",
134 | "12\n",
135 | "00:00:57,000 --> 00:01:06,000\n",
136 | "그것으로 인해서 약 6개월 동안에 나름 회사에서는 달러 지출을 막을 수 있었고\n",
137 | "\n",
138 | "13\n",
139 | "00:01:06,000 --> 00:01:15,000\n",
140 | "그때 그나마 달러를 회사에서 확보를 해서 나름의 위기를 극복할 수 있었던 것으로 생각합니다.\n",
141 | "\n",
142 | "\n",
143 | "\n"
144 | ]
145 | }
146 | ],
147 | "source": [
148 | "print(transcript)"
149 | ]
150 | },
151 | {
152 | "cell_type": "markdown",
153 | "metadata": {},
154 | "source": [
155 | "## YouTube\n"
156 | ]
157 | },
158 | {
159 | "cell_type": "code",
160 | "execution_count": 8,
161 | "metadata": {},
162 | "outputs": [],
163 | "source": [
164 | "from pytube import YouTube\n",
165 | "import os\n",
166 | "\n",
167 | "link = \"https://youtu.be/LQS3y7Tckhc?si=pEJdAfSq3On_Uvou\"\n",
168 | "\n",
169 | "yt = YouTube(link)\n",
170 | "filename = yt.streams.filter(only_audio=True).first().download()\n",
171 | "renamed_file = filename.replace(\".mp4\", \".mp3\")\n",
172 | "os.rename(filename, renamed_file)"
173 | ]
174 | },
175 | {
176 | "cell_type": "code",
177 | "execution_count": 9,
178 | "metadata": {},
179 | "outputs": [
180 | {
181 | "name": "stdout",
182 | "output_type": "stream",
183 | "text": [
184 | "/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화.mp3\n"
185 | ]
186 | }
187 | ],
188 | "source": [
189 | "print(renamed_file)"
190 | ]
191 | },
192 | {
193 | "cell_type": "markdown",
194 | "metadata": {},
195 | "source": [
196 | "## MP3 -> WAV 변환\n"
197 | ]
198 | },
199 | {
200 | "cell_type": "code",
201 | "execution_count": 10,
202 | "metadata": {},
203 | "outputs": [],
204 | "source": [
205 | "from moviepy.editor import AudioFileClip\n",
206 | "\n",
207 | "\n",
208 | "def convert_mp3_to_wav(filepath):\n",
209 | " # WAV 파일 경로\n",
210 | " wav_file_path = filepath.replace(\".mp3\", \".wav\")\n",
211 | "\n",
212 | " # MP4 파일 로드\n",
213 | " audio_clip = AudioFileClip(filepath)\n",
214 | "\n",
215 | " # WAV 형식으로 오디오 추출 및 저장\n",
216 | " audio_clip.write_audiofile(wav_file_path, fps=44100, nbytes=2, codec=\"pcm_s16le\")\n",
217 | " return wav_file_path"
218 | ]
219 | },
220 | {
221 | "cell_type": "code",
222 | "execution_count": 11,
223 | "metadata": {},
224 | "outputs": [
225 | {
226 | "name": "stdout",
227 | "output_type": "stream",
228 | "text": [
229 | "MoviePy - Writing audio in /Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화.wav\n"
230 | ]
231 | },
232 | {
233 | "name": "stderr",
234 | "output_type": "stream",
235 | "text": [
236 | " "
237 | ]
238 | },
239 | {
240 | "name": "stdout",
241 | "output_type": "stream",
242 | "text": [
243 | "MoviePy - Done.\n"
244 | ]
245 | },
246 | {
247 | "name": "stderr",
248 | "output_type": "stream",
249 | "text": [
250 | "\r"
251 | ]
252 | }
253 | ],
254 | "source": [
255 | "wav_file = convert_mp3_to_wav(renamed_file)"
256 | ]
257 | },
258 | {
259 | "cell_type": "code",
260 | "execution_count": 13,
261 | "metadata": {},
262 | "outputs": [],
263 | "source": [
264 | "from pydub import AudioSegment\n",
265 | "\n",
266 | "# 오디오 파일 불러오기\n",
267 | "audio = AudioSegment.from_file(wav_file, format=\"wav\")\n",
268 | "\n",
269 | "total_length = len(audio)\n",
270 | "length_per_chunk = 60 * 1000 # 60초\n",
271 | "\n",
272 | "if not os.path.exists(\".tmp\"):\n",
273 | " os.mkdir(\".tmp\")\n",
274 | "\n",
275 | "folder_path = os.path.join(\".tmp\", wav_file[:-4])\n",
276 | "\n",
277 | "if not os.path.exists(folder_path):\n",
278 | " os.mkdir(folder_path)\n",
279 | "\n",
280 | "chunks = []\n",
281 | "for i in range(0, total_length, length_per_chunk):\n",
282 | " chunk_file_path = os.path.join(folder_path, f\"{i}.wav\")\n",
283 | " audio[i : i + length_per_chunk].export(chunk_file_path, format=\"wav\")\n",
284 | " chunks.append(chunk_file_path)"
285 | ]
286 | },
287 | {
288 | "cell_type": "code",
289 | "execution_count": 14,
290 | "metadata": {},
291 | "outputs": [
292 | {
293 | "data": {
294 | "text/plain": [
295 | "['/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/0.wav',\n",
296 | " '/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/60000.wav',\n",
297 | " '/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/120000.wav',\n",
298 | " '/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/180000.wav',\n",
299 | " '/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/240000.wav',\n",
300 | " '/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/300000.wav',\n",
301 | " '/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/360000.wav']"
302 | ]
303 | },
304 | "execution_count": 14,
305 | "metadata": {},
306 | "output_type": "execute_result"
307 | }
308 | ],
309 | "source": [
310 | "chunks"
311 | ]
312 | },
313 | {
314 | "cell_type": "code",
315 | "execution_count": 16,
316 | "metadata": {},
317 | "outputs": [],
318 | "source": [
319 | "from datetime import datetime, timedelta\n",
320 | "import re\n",
321 | "\n",
322 | "\n",
323 | "def adjust_timestamps(transcript, minutes=1):\n",
324 | " # Define the regular expression pattern for timestamps\n",
325 | " timestamp_pattern = re.compile(r\"(\\d{2}:\\d{2}:\\d{2},\\d{3})\")\n",
326 | "\n",
327 | " # Function to add minutes to a timestamp\n",
328 | " def add_minutes(timestamp_str, minutes):\n",
329 | " timestamp = datetime.strptime(timestamp_str, \"%H:%M:%S,%f\")\n",
330 | " adjusted_timestamp = timestamp + timedelta(minutes=minutes)\n",
331 | " return adjusted_timestamp.strftime(\"%H:%M:%S,%f\")[:-3]\n",
332 | "\n",
333 | " # Replace timestamps in the transcript\n",
334 | " adjusted_transcript = timestamp_pattern.sub(\n",
335 | " lambda match: add_minutes(match.group(1), minutes), transcript\n",
336 | " )\n",
337 | " return adjusted_transcript"
338 | ]
339 | },
340 | {
341 | "cell_type": "code",
342 | "execution_count": 17,
343 | "metadata": {},
344 | "outputs": [
345 | {
346 | "name": "stdout",
347 | "output_type": "stream",
348 | "text": [
349 | "/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/0.wav\n",
350 | "/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/60000.wav\n",
351 | "/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/120000.wav\n",
352 | "/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/180000.wav\n",
353 | "/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/240000.wav\n",
354 | "/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/300000.wav\n",
355 | "/Users/teddy/Dev/github/openai-api-kr/[GPTs로 꿀빨기] PPT 제작 자동화/360000.wav\n"
356 | ]
357 | }
358 | ],
359 | "source": [
360 | "transcripts = []\n",
361 | "for i, chunk in enumerate(chunks):\n",
362 | " print(chunk)\n",
363 | " audio_file = open(chunk, \"rb\")\n",
364 | " transcript = client.audio.transcriptions.create(\n",
365 | " file=audio_file,\n",
366 | " model=\"whisper-1\",\n",
367 | " language=\"ko\",\n",
368 | " response_format=\"srt\",\n",
369 | " temperature=0.01,\n",
370 | " )\n",
371 | " transcripts.append(adjust_timestamps(transcript, minutes=i))"
372 | ]
373 | },
374 | {
375 | "cell_type": "code",
376 | "execution_count": 19,
377 | "metadata": {},
378 | "outputs": [],
379 | "source": [
380 | "def merge_transcripts(*transcripts):\n",
381 | " merged_transcript = \"\"\n",
382 | " current_number = 1\n",
383 | "\n",
384 | " for transcript in transcripts:\n",
385 | " # Split the transcript into segments\n",
386 | " segments = transcript.strip().split(\"\\n\\n\")\n",
387 | " for segment in segments:\n",
388 | " # Split each segment into lines\n",
389 | " lines = segment.split(\"\\n\")\n",
390 | " # Replace the number at the beginning of each segment with the correct sequence number\n",
391 | " lines[0] = str(current_number)\n",
392 | " # Increment the sequence number\n",
393 | " current_number += 1\n",
394 | " # Reassemble the segment\n",
395 | " merged_transcript += \"\\n\".join(lines) + \"\\n\\n\"\n",
396 | "\n",
397 | " return merged_transcript.strip()"
398 | ]
399 | },
400 | {
401 | "cell_type": "code",
402 | "execution_count": 20,
403 | "metadata": {},
404 | "outputs": [
405 | {
406 | "name": "stdout",
407 | "output_type": "stream",
408 | "text": [
409 | "1\n",
410 | "00:00:00,000 --> 00:00:07,760\n",
411 | "여기 있는 내용들을 쭉 드래그를 합니다 복사를 하신 다음에 ppt 제작 전문가 gptsbot한테 붙여넣기를 해주는 거예요\n",
412 | "\n",
413 | "2\n",
414 | "00:00:07,760 --> 00:00:16,639\n",
415 | "얘가 ppt를 작성을 해주는 것을 볼 수가 있어요 ppt의 제목을 알아서 뽑아주고요 그 안에 포함될 블랙포인트들을 구성을 해줍니다\n",
416 | "\n",
417 | "3\n",
418 | "00:00:16,639 --> 00:00:25,920\n",
419 | "마지막으로 발표 스크립트도 얘가 자동으로 작성을 해주거든요 에디터 영역에다가 붙여넣기를 해주시면은 오른쪽에 깔끔하게 장표가 완성이 되는 것을 볼 수가 있어요\n",
420 | "\n",
421 | "4\n",
422 | "00:00:25,920 --> 00:00:27,360\n",
423 | "굉장히 빠르게 완성이 되죠\n",
424 | "\n",
425 | "5\n",
426 | "00:00:30,000 --> 00:00:38,160\n",
427 | "안녕하세요 오늘은 채치 pt의 새로운 기능 중에 하나인 gpts에 대해서 알아보도록 하겠는데요\n",
428 | "\n",
429 | "6\n",
430 | "00:00:38,160 --> 00:00:42,639\n",
431 | "제가 최근에 이 gpts를 활용하면서 정말 놀라움을 금치 못하고 있습니다\n",
432 | "\n",
433 | "7\n",
434 | "00:00:42,639 --> 00:00:48,240\n",
435 | "생산성을 극대화 해주는 게 바로 gpts 인데요 관심 있으신 분들은 한번씩 써보고 계실 것 같아요\n",
436 | "\n",
437 | "8\n",
438 | "00:00:48,240 --> 00:00:52,560\n",
439 | "제가 평소에 너무 싫어하는 게 이 ppt를 제작하는 것을 너무 귀찮아해요\n",
440 | "\n",
441 | "9\n",
442 | "00:00:52,560 --> 00:00:54,160\n",
443 | "문서 하는 것도 너무 귀찮아하고요\n",
444 | "\n",
445 | "10\n",
446 | "00:00:54,160 --> 00:00:56,560\n",
447 | "이 ppt를 어떻게 하면 좀 쉽게 만들 수 있을까\n",
448 | "\n",
449 | "11\n",
450 | "00:00:56,560 --> 00:01:00,720\n",
451 | "요즘에는 채치 pt를 사용해서 귀찮은 부분들을 많이 해소를 하고 있습니다\n",
452 | "\n",
453 | "12\n",
454 | "00:01:00,000 --> 00:01:03,880\n",
455 | "제가 이렇게 PPT 제작 전문가라는 GPTS를 만들어 봤어요\n",
456 | "\n",
457 | "13\n",
458 | "00:01:03,880 --> 00:01:06,080\n",
459 | "먼저 이 기능에 대해서 간단히 소개를 해드릴게요\n",
460 | "\n",
461 | "14\n",
462 | "00:01:06,080 --> 00:01:08,780\n",
463 | "웹사이트에 링크나 아니면 글을 넣어주게 되면은\n",
464 | "\n",
465 | "15\n",
466 | "00:01:08,780 --> 00:01:11,180\n",
467 | "그 내용을 기반으로 PPT를 만들어주는\n",
468 | "\n",
469 | "16\n",
470 | "00:01:11,180 --> 00:01:12,980\n",
471 | "그런 채집 PT라고 보시면 돼요\n",
472 | "\n",
473 | "17\n",
474 | "00:01:12,980 --> 00:01:14,080\n",
475 | "예시를 들어볼게요\n",
476 | "\n",
477 | "18\n",
478 | "00:01:14,080 --> 00:01:17,180\n",
479 | "오늘자 신문 기사를 하나 랜덤하게 발췌를 했습니다\n",
480 | "\n",
481 | "19\n",
482 | "00:01:17,180 --> 00:01:19,120\n",
483 | "라이폰 통화 녹음 굿, 워치 날림은 아쉽\n",
484 | "\n",
485 | "20\n",
486 | "00:01:19,120 --> 00:01:22,600\n",
487 | "화제의 SKT A. 써보니 라는 제목의 기사이고요\n",
488 | "\n",
489 | "21\n",
490 | "00:01:22,600 --> 00:01:25,900\n",
491 | "자 이 내용들을 가지고 제가 PPT를 만들고 싶어요\n",
492 | "\n",
493 | "22\n",
494 | "00:01:25,900 --> 00:01:28,059\n",
495 | "여기 있는 내용들을 쭉 드래그를 합니다\n",
496 | "\n",
497 | "23\n",
498 | "00:01:28,120 --> 00:01:31,299\n",
499 | "자 이렇게 드래그를 해서 내용을 가져오는 거죠\n",
500 | "\n",
501 | "24\n",
502 | "00:01:31,299 --> 00:01:33,060\n",
503 | "복사를 하신 다음에\n",
504 | "\n",
505 | "25\n",
506 | "00:01:33,060 --> 00:01:35,639\n",
507 | "PPT 제작 전문가 GPTS 보트한테\n",
508 | "\n",
509 | "26\n",
510 | "00:01:35,639 --> 00:01:37,000\n",
511 | "붙여넣기를 해주는 거예요\n",
512 | "\n",
513 | "27\n",
514 | "00:01:37,000 --> 00:01:38,599\n",
515 | "자 이렇게 내용을 붙여 넣었습니다\n",
516 | "\n",
517 | "28\n",
518 | "00:01:38,599 --> 00:01:39,840\n",
519 | "엔터키를 입력해 볼게요\n",
520 | "\n",
521 | "29\n",
522 | "00:01:39,840 --> 00:01:43,380\n",
523 | "얘가 PPT를 작성을 해주는 것을 볼 수가 있어요\n",
524 | "\n",
525 | "30\n",
526 | "00:01:43,380 --> 00:01:45,740\n",
527 | "PPT의 제목을 알아서 뽑아주고요\n",
528 | "\n",
529 | "31\n",
530 | "00:01:45,740 --> 00:01:48,740\n",
531 | "그 안에 포함될 블랙 포인트들을 구성을 해줍니다\n",
532 | "\n",
533 | "32\n",
534 | "00:01:48,740 --> 00:01:52,419\n",
535 | "제가 여기 안에 내용은 아주 간략하게 구성을 해달라고 했기 때문에\n",
536 | "\n",
537 | "33\n",
538 | "00:01:52,419 --> 00:01:54,860\n",
539 | "구체적인 내용보다는 핵심 위주로 이렇게 뽑아내서\n",
540 | "\n",
541 | "34\n",
542 | "00:01:54,860 --> 00:01:56,060\n",
543 | "넣어주는 것을 볼 수가 있죠\n",
544 | "\n",
545 | "35\n",
546 | "00:01:56,060 --> 00:01:57,759\n",
547 | "처음에 핵심 내용을 뽑아주고요\n",
548 | "\n",
549 | "36\n",
550 | "00:01:57,759 --> 00:02:00,119\n",
551 | "다음으로는 슬라이드 구성 부분에서\n",
552 | "\n",
553 | "37\n",
554 | "00:02:00,000 --> 00:02:02,320\n",
555 | "슬라이드 1에는 제목은 뭐가 들어가고\n",
556 | "\n",
557 | "38\n",
558 | "00:02:02,320 --> 00:02:04,540\n",
559 | "장표 안에 들어가는 블랙 포인트는 뭐가 들어가고\n",
560 | "\n",
561 | "39\n",
562 | "00:02:04,540 --> 00:02:06,040\n",
563 | "이런 식으로 구성을 해주고 있어요\n",
564 | "\n",
565 | "40\n",
566 | "00:02:06,040 --> 00:02:09,520\n",
567 | "마지막으로 발표 스크립트도 얘가 자동으로 작성을 해주거든요\n",
568 | "\n",
569 | "41\n",
570 | "00:02:09,520 --> 00:02:13,080\n",
571 | "제가 발표할 내용들을 알아서 작성을 해주는 것을 볼 수가 있고요\n",
572 | "\n",
573 | "42\n",
574 | "00:02:13,080 --> 00:02:14,860\n",
575 | "3장의 슬라이드로 구성이 됐는데\n",
576 | "\n",
577 | "43\n",
578 | "00:02:14,860 --> 00:02:16,260\n",
579 | "중간에 길어서 끊어졌어요\n",
580 | "\n",
581 | "44\n",
582 | "00:02:16,260 --> 00:02:19,059\n",
583 | "그러면 오른쪽에 Continue Generating을 눌러주시면 됩니다\n",
584 | "\n",
585 | "45\n",
586 | "00:02:19,059 --> 00:02:22,559\n",
587 | "이렇게 발표 스크립트까지 완성을 해줬고요\n",
588 | "\n",
589 | "46\n",
590 | "00:02:22,559 --> 00:02:26,200\n",
591 | "다음으로는 MARF 형식의 슬라이드라는 것을 작성해주는 것을 볼 수가 있어요\n",
592 | "\n",
593 | "47\n",
594 | "00:02:26,200 --> 00:02:27,400\n",
595 | "위에 내용까지는 알겠는데\n",
596 | "\n",
597 | "48\n",
598 | "00:02:27,400 --> 00:02:30,000\n",
599 | "갑자기 여기에서 MARF라는 게 툭 튀어나왔죠\n",
600 | "\n",
601 | "49\n",
602 | "00:02:30,000 --> 00:02:31,900\n",
603 | "이거는 어떻게 쓰는 건지 제가 보여드릴게요\n",
604 | "\n",
605 | "50\n",
606 | "00:02:31,900 --> 00:02:33,740\n",
607 | "이렇게 구성을 해주는 것까지도 좋은데요\n",
608 | "\n",
609 | "51\n",
610 | "00:02:33,740 --> 00:02:36,639\n",
611 | "저는 장표를 만드는 것까지도 자동화를 하고 싶었던 거예요\n",
612 | "\n",
613 | "52\n",
614 | "00:02:36,639 --> 00:02:38,880\n",
615 | "여기 보시면 Copy Code라는 버튼이 보이실 거예요\n",
616 | "\n",
617 | "53\n",
618 | "00:02:38,880 --> 00:02:40,919\n",
619 | "이거를 눌러서 코드를 복사를 합니다\n",
620 | "\n",
621 | "54\n",
622 | "00:02:40,919 --> 00:02:44,520\n",
623 | "다음으로는 Mark Slides라는 웹사이트로 오시면 되고요\n",
624 | "\n",
625 | "55\n",
626 | "00:02:44,520 --> 00:02:47,880\n",
627 | "markslides.ai 여기 주소로 오시면 돼요\n",
628 | "\n",
629 | "56\n",
630 | "00:02:47,880 --> 00:02:50,360\n",
631 | "에디터 영역에다가 붙여넣기를 해주시면\n",
632 | "\n",
633 | "57\n",
634 | "00:02:50,360 --> 00:02:53,799\n",
635 | "오른쪽에 깔끔하게 장표가 완성이 되는 것을 볼 수가 있어요\n",
636 | "\n",
637 | "58\n",
638 | "00:02:53,799 --> 00:02:55,099\n",
639 | "굉장히 빠르게 완성이 됐죠\n",
640 | "\n",
641 | "59\n",
642 | "00:02:55,160 --> 00:02:58,540\n",
643 | "바로 슬라이드 표시 진행을 하실 수도 있고\n",
644 | "\n",
645 | "60\n",
646 | "00:02:58,540 --> 00:03:00,540\n",
647 | "Export as PDF라는 것들도 있어요\n",
648 | "\n",
649 | "61\n",
650 | "00:03:00,000 --> 00:03:02,560\n",
651 | "버튼으로 pdf로 내려받으실 수도 있어요\n",
652 | "\n",
653 | "62\n",
654 | "00:03:02,560 --> 00:03:06,840\n",
655 | "물론 여기 있는 ppt 장표가 최종 버전이라고 하기엔\n",
656 | "\n",
657 | "63\n",
658 | "00:03:06,840 --> 00:03:08,200\n",
659 | "좀 어려움이 있을 수 있겠죠\n",
660 | "\n",
661 | "64\n",
662 | "00:03:08,200 --> 00:03:09,540\n",
663 | "내용 보충이 필요할 수도 있고요\n",
664 | "\n",
665 | "65\n",
666 | "00:03:09,540 --> 00:03:11,900\n",
667 | "하지만 기본 골격을 잡는 데에는\n",
668 | "\n",
669 | "66\n",
670 | "00:03:11,900 --> 00:03:14,680\n",
671 | "굉장히 빠른 속도로 잡으실 수가 있기 때문에\n",
672 | "\n",
673 | "67\n",
674 | "00:03:14,680 --> 00:03:16,340\n",
675 | "생산성을 높일 수가 있습니다\n",
676 | "\n",
677 | "68\n",
678 | "00:03:16,340 --> 00:03:19,480\n",
679 | "그런데 여기 있는 내용을 복사 붙여넣기 하는 것도\n",
680 | "\n",
681 | "69\n",
682 | "00:03:19,480 --> 00:03:20,719\n",
683 | "귀찮은 일일 수가 있어요\n",
684 | "\n",
685 | "70\n",
686 | "00:03:20,719 --> 00:03:22,879\n",
687 | "그래서 지금부터 보여드릴 내용은\n",
688 | "\n",
689 | "71\n",
690 | "00:03:22,879 --> 00:03:25,920\n",
691 | "여기에 단순하게 링크를 넣는 방법이에요\n",
692 | "\n",
693 | "72\n",
694 | "00:03:25,920 --> 00:03:28,200\n",
695 | "이번에는 해외 기사도 한번 가져와 볼게요\n",
696 | "\n",
697 | "73\n",
698 | "00:03:28,200 --> 00:03:30,700\n",
699 | "이번엔 이렇게 드래그해서 가져오는 게 아니라\n",
700 | "\n",
701 | "74\n",
702 | "00:03:30,700 --> 00:03:33,740\n",
703 | "단순하게 이 신문기사의 링크를 복사를 해서\n",
704 | "\n",
705 | "75\n",
706 | "00:03:33,740 --> 00:03:37,980\n",
707 | "ppt 제작 전문가 보드한테 링크를 알려주도록 하겠습니다\n",
708 | "\n",
709 | "76\n",
710 | "00:03:37,980 --> 00:03:40,180\n",
711 | "이렇게 링크를 알려주면 제목과 함께\n",
712 | "\n",
713 | "77\n",
714 | "00:03:40,180 --> 00:03:42,540\n",
715 | "본문의 내용을 얘가 알아서 가져오게끔\n",
716 | "\n",
717 | "78\n",
718 | "00:03:42,540 --> 00:03:44,279\n",
719 | "프럼프트가 짜져 있어요\n",
720 | "\n",
721 | "79\n",
722 | "00:03:44,279 --> 00:03:48,380\n",
723 | "자 이렇게 내용을 가져와서 슬라이드로 변형을 하고 있고요\n",
724 | "\n",
725 | "80\n",
726 | "00:03:48,380 --> 00:03:51,380\n",
727 | "여기에 나와 있는 내용들은 해외 기사임에도 불구하고\n",
728 | "\n",
729 | "81\n",
730 | "00:03:51,380 --> 00:03:53,259\n",
731 | "한글로 잘 쓰고 있는 것을 볼 수가 있죠\n",
732 | "\n",
733 | "82\n",
734 | "00:03:53,259 --> 00:03:55,820\n",
735 | "제가 무조건 한글로 번역하게끔 프럼프트를 넣어놨어요\n",
736 | "\n",
737 | "83\n",
738 | "00:03:55,820 --> 00:03:57,720\n",
739 | "그렇기 때문에 해외 기사를 넣더라도\n",
740 | "\n",
741 | "84\n",
742 | "00:03:57,720 --> 00:04:00,580\n",
743 | "이렇게 한글로 잘 번역해서 슬라이드 구성을 해주시면 됩니다\n",
744 | "\n",
745 | "85\n",
746 | "00:04:00,000 --> 00:04:02,680\n",
747 | "마지막으로 슬라이드 발표 스크립트까지\n",
748 | "\n",
749 | "86\n",
750 | "00:04:02,680 --> 00:04:05,080\n",
751 | "이렇게 잘 작성하는 것을 볼 수가 있죠\n",
752 | "\n",
753 | "87\n",
754 | "00:04:05,080 --> 00:04:09,680\n",
755 | "그런데 무조건 링크 붙여넣기 기능은 잘 되는 것은 아니에요\n",
756 | "\n",
757 | "88\n",
758 | "00:04:09,680 --> 00:04:13,800\n",
759 | "가끔 가다가 이렇게 중간에 에러가 나타나기도 하고요\n",
760 | "\n",
761 | "89\n",
762 | "00:04:13,800 --> 00:04:18,440\n",
763 | "때로는 이렇게 regenerate를 눌러서 다시 시도를 하는데\n",
764 | "\n",
765 | "90\n",
766 | "00:04:18,440 --> 00:04:22,280\n",
767 | "이런 식으로 웹사이트 접근하는 데에 문제가 있다고 하면서\n",
768 | "\n",
769 | "91\n",
770 | "00:04:22,280 --> 00:04:24,400\n",
771 | "정보를 가져오는데 좀 어려움이 있는 것 같아요\n",
772 | "\n",
773 | "92\n",
774 | "00:04:24,400 --> 00:04:27,480\n",
775 | "이유는 로봇이 정보를 자동으로 긁어가지 못하게끔\n",
776 | "\n",
777 | "93\n",
778 | "00:04:27,480 --> 00:04:28,480\n",
779 | "블록을 하고 있는데\n",
780 | "\n",
781 | "94\n",
782 | "00:04:28,480 --> 00:04:32,080\n",
783 | "GPTS를 쓰게 되면은 이러한 문제점이 종종 발생을 하는 것 같습니다\n",
784 | "\n",
785 | "95\n",
786 | "00:04:32,080 --> 00:04:34,720\n",
787 | "현재로서는 좀 번거로울 수 있겠지만\n",
788 | "\n",
789 | "96\n",
790 | "00:04:34,720 --> 00:04:38,480\n",
791 | "추천드리는 방법은 웹사이트에 가서 이 전체 내용을 복사를 해서\n",
792 | "\n",
793 | "97\n",
794 | "00:04:38,480 --> 00:04:41,080\n",
795 | "붙여넣기 하는 방식을 가장 먼저 추천을 드리고요\n",
796 | "\n",
797 | "98\n",
798 | "00:04:41,080 --> 00:04:44,040\n",
799 | "슬라이드 구성을 하실 때에도 붙여넣기를 할 때\n",
800 | "\n",
801 | "99\n",
802 | "00:04:44,040 --> 00:04:46,040\n",
803 | "전체 내용을 붙여넣기를 하지 마시고요\n",
804 | "\n",
805 | "100\n",
806 | "00:04:46,040 --> 00:04:48,279\n",
807 | "큰 단락 위주로 붙여넣기 하시면 더욱 좋습니다\n",
808 | "\n",
809 | "101\n",
810 | "00:04:48,279 --> 00:04:50,919\n",
811 | "PPT에 큰 주제가 있고\n",
812 | "\n",
813 | "102\n",
814 | "00:04:50,919 --> 00:04:54,160\n",
815 | "이걸 관통하는 소 주제를 여러 개를 구성을 했어요\n",
816 | "\n",
817 | "103\n",
818 | "00:04:54,160 --> 00:04:56,919\n",
819 | "1번 주제가 있고 2번 주제가 있고 3번 주제가 있고요\n",
820 | "\n",
821 | "104\n",
822 | "00:04:56,919 --> 00:04:59,240\n",
823 | "내용을 그냥 다 때려넣고 얘가 잘해줄게요\n",
824 | "\n",
825 | "105\n",
826 | "00:05:00,000 --> 00:05:01,340\n",
827 | "라고 하지 마시고요\n",
828 | "\n",
829 | "106\n",
830 | "00:05:01,340 --> 00:05:03,300\n",
831 | "먼저 1번 주제에 해당한 내용을 붙여 넣고\n",
832 | "\n",
833 | "107\n",
834 | "00:05:03,300 --> 00:05:04,440\n",
835 | "슬라이드 구성을 하시고\n",
836 | "\n",
837 | "108\n",
838 | "00:05:04,440 --> 00:05:06,200\n",
839 | "2번 주제 넣고 구성하시고\n",
840 | "\n",
841 | "109\n",
842 | "00:05:06,200 --> 00:05:07,900\n",
843 | "3번 주제 넣고 구성하시는 게\n",
844 | "\n",
845 | "110\n",
846 | "00:05:07,900 --> 00:05:09,680\n",
847 | "가장 결과물이 좋았던 것 같습니다\n",
848 | "\n",
849 | "111\n",
850 | "00:05:09,680 --> 00:05:11,500\n",
851 | "제가 만든 이 PPT 제작 전문가는\n",
852 | "\n",
853 | "112\n",
854 | "00:05:11,500 --> 00:05:14,340\n",
855 | "어떻게 하면 효율적으로 써볼 수 있을까 해서\n",
856 | "\n",
857 | "113\n",
858 | "00:05:14,340 --> 00:05:16,180\n",
859 | "처음으로 간단하게 한번 만들어 봤고요\n",
860 | "\n",
861 | "114\n",
862 | "00:05:16,180 --> 00:05:18,400\n",
863 | "최대 슬라이드 3장만 만들게끔 넣어 놨거든요\n",
864 | "\n",
865 | "115\n",
866 | "00:05:18,400 --> 00:05:20,780\n",
867 | "나중에 여러분들이 프롬프트 튜닝을 하시게 되면\n",
868 | "\n",
869 | "116\n",
870 | "00:05:20,780 --> 00:05:22,480\n",
871 | "5장 7장 이렇게 늘리거나\n",
872 | "\n",
873 | "117\n",
874 | "00:05:22,480 --> 00:05:24,639\n",
875 | "안에 들어가는 내용 구성하는 방법도\n",
876 | "\n",
877 | "118\n",
878 | "00:05:24,639 --> 00:05:25,700\n",
879 | "달리 하실 수가 있습니다\n",
880 | "\n",
881 | "119\n",
882 | "00:05:25,700 --> 00:05:26,780\n",
883 | "오늘 영상에서는\n",
884 | "\n",
885 | "120\n",
886 | "00:05:26,780 --> 00:05:29,280\n",
887 | "제가 이 PPT 제작 전문가를 어떻게 활용하고 있는지\n",
888 | "\n",
889 | "121\n",
890 | "00:05:29,280 --> 00:05:32,619\n",
891 | "이것을 활용해서 어떻게 슬라이드를 좀 빠르게 만드는지\n",
892 | "\n",
893 | "122\n",
894 | "00:05:32,619 --> 00:05:34,320\n",
895 | "그 방법에 대해서 공유를 해드렸고요\n",
896 | "\n",
897 | "123\n",
898 | "00:05:34,320 --> 00:05:36,119\n",
899 | "만약에 이 영상이 반응이 좋다면\n",
900 | "\n",
901 | "124\n",
902 | "00:05:36,119 --> 00:05:38,520\n",
903 | "PPT 제작 전문가를 어떻게 구성을 했는지\n",
904 | "\n",
905 | "125\n",
906 | "00:05:38,520 --> 00:05:40,619\n",
907 | "제가 어떠한 프롬프트를 썼는지도\n",
908 | "\n",
909 | "126\n",
910 | "00:05:40,619 --> 00:05:42,060\n",
911 | "공유를 해드리도록 하겠습니다\n",
912 | "\n",
913 | "127\n",
914 | "00:05:42,060 --> 00:05:44,060\n",
915 | "그리고 이 GPTS를 만들 때\n",
916 | "\n",
917 | "128\n",
918 | "00:05:44,060 --> 00:05:45,980\n",
919 | "좀 좋은 결과물을 내기 위해서는\n",
920 | "\n",
921 | "129\n",
922 | "00:05:45,980 --> 00:05:47,919\n",
923 | "어떤 식으로 구성을 하면 되는지도\n",
924 | "\n",
925 | "130\n",
926 | "00:05:47,919 --> 00:05:49,279\n",
927 | "영상으로 담아보도록 할게요\n",
928 | "\n",
929 | "131\n",
930 | "00:05:49,279 --> 00:05:52,880\n",
931 | "이 PPT 제작 전문가를 체험해 보고 싶으신 분들을 위해서\n",
932 | "\n",
933 | "132\n",
934 | "00:05:52,880 --> 00:05:55,279\n",
935 | "더보기란에 링크 넣어두도록 하겠습니다\n",
936 | "\n",
937 | "133\n",
938 | "00:05:55,279 --> 00:05:56,580\n",
939 | "오늘 영상은 여기까지였습니다\n",
940 | "\n",
941 | "134\n",
942 | "00:05:56,580 --> 00:05:57,520\n",
943 | "감사합니다\n",
944 | "\n",
945 | "135\n",
946 | "00:06:00,000 --> 00:06:11,470\n",
947 | "아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아\n"
948 | ]
949 | }
950 | ],
951 | "source": [
952 | "print(merge_transcripts(*transcripts))"
953 | ]
954 | },
955 | {
956 | "cell_type": "code",
957 | "execution_count": 21,
958 | "metadata": {},
959 | "outputs": [
960 | {
961 | "name": "stdout",
962 | "output_type": "stream",
963 | "text": [
964 | "1\n",
965 | "00:00:00,000 --> 00:00:07,760\n",
966 | "여기 있는 내용들을 쭉 드래그를 합니다 복사를 하신 다음에 ppt 제작 전문가 gptsbot한테 붙여넣기를 해주는 거예요\n",
967 | "\n",
968 | "2\n",
969 | "00:00:07,760 --> 00:00:16,639\n",
970 | "얘가 ppt를 작성을 해주는 것을 볼 수가 있어요 ppt의 제목을 알아서 뽑아주고요 그 안에 포함될 블랙포인트들을 구성을 해줍니다\n",
971 | "\n",
972 | "3\n",
973 | "00:00:16,639 --> 00:00:25,920\n",
974 | "마지막으로 발표 스크립트도 얘가 자동으로 작성을 해주거든요 에디터 영역에다가 붙여넣기를 해주시면은 오른쪽에 깔끔하게 장표가 완성이 되는 것을 볼 수가 있어요\n",
975 | "\n",
976 | "4\n",
977 | "00:00:25,920 --> 00:00:27,360\n",
978 | "굉장히 빠르게 완성이 되죠\n",
979 | "\n",
980 | "5\n",
981 | "00:00:30,000 --> 00:00:38,160\n",
982 | "안녕하세요 오늘은 채치 pt의 새로운 기능 중에 하나인 gpts에 대해서 알아보도록 하겠는데요\n",
983 | "\n",
984 | "6\n",
985 | "00:00:38,160 --> 00:00:42,639\n",
986 | "제가 최근에 이 gpts를 활용하면서 정말 놀라움을 금치 못하고 있습니다\n",
987 | "\n",
988 | "7\n",
989 | "00:00:42,639 --> 00:00:48,240\n",
990 | "생산성을 극대화 해주는 게 바로 gpts 인데요 관심 있으신 분들은 한번씩 써보고 계실 것 같아요\n",
991 | "\n",
992 | "8\n",
993 | "00:00:48,240 --> 00:00:52,560\n",
994 | "제가 평소에 너무 싫어하는 게 이 ppt를 제작하는 것을 너무 귀찮아해요\n",
995 | "\n",
996 | "9\n",
997 | "00:00:52,560 --> 00:00:54,160\n",
998 | "문서 하는 것도 너무 귀찮아하고요\n",
999 | "\n",
1000 | "10\n",
1001 | "00:00:54,160 --> 00:00:56,560\n",
1002 | "이 ppt를 어떻게 하면 좀 쉽게 만들 수 있을까\n",
1003 | "\n",
1004 | "11\n",
1005 | "00:00:56,560 --> 00:01:00,720\n",
1006 | "요즘에는 채치 pt를 사용해서 귀찮은 부분들을 많이 해소를 하고 있습니다\n",
1007 | "\n",
1008 | "12\n",
1009 | "00:01:00,000 --> 00:01:03,880\n",
1010 | "제가 이렇게 PPT 제작 전문가라는 GPTS를 만들어 봤어요\n",
1011 | "\n",
1012 | "13\n",
1013 | "00:01:03,880 --> 00:01:06,080\n",
1014 | "먼저 이 기능에 대해서 간단히 소개를 해드릴게요\n",
1015 | "\n",
1016 | "14\n",
1017 | "00:01:06,080 --> 00:01:08,780\n",
1018 | "웹사이트에 링크나 아니면 글을 넣어주게 되면은\n",
1019 | "\n",
1020 | "15\n",
1021 | "00:01:08,780 --> 00:01:11,180\n",
1022 | "그 내용을 기반으로 PPT를 만들어주는\n",
1023 | "\n",
1024 | "16\n",
1025 | "00:01:11,180 --> 00:01:12,980\n",
1026 | "그런 채집 PT라고 보시면 돼요\n",
1027 | "\n",
1028 | "17\n",
1029 | "00:01:12,980 --> 00:01:14,080\n",
1030 | "예시를 들어볼게요\n",
1031 | "\n",
1032 | "18\n",
1033 | "00:01:14,080 --> 00:01:17,180\n",
1034 | "오늘자 신문 기사를 하나 랜덤하게 발췌를 했습니다\n",
1035 | "\n",
1036 | "19\n",
1037 | "00:01:17,180 --> 00:01:19,120\n",
1038 | "라이폰 통화 녹음 굿, 워치 날림은 아쉽\n",
1039 | "\n",
1040 | "20\n",
1041 | "00:01:19,120 --> 00:01:22,600\n",
1042 | "화제의 SKT A. 써보니 라는 제목의 기사이고요\n",
1043 | "\n",
1044 | "21\n",
1045 | "00:01:22,600 --> 00:01:25,900\n",
1046 | "자 이 내용들을 가지고 제가 PPT를 만들고 싶어요\n",
1047 | "\n",
1048 | "22\n",
1049 | "00:01:25,900 --> 00:01:28,059\n",
1050 | "여기 있는 내용들을 쭉 드래그를 합니다\n",
1051 | "\n",
1052 | "23\n",
1053 | "00:01:28,120 --> 00:01:31,299\n",
1054 | "자 이렇게 드래그를 해서 내용을 가져오는 거죠\n",
1055 | "\n",
1056 | "24\n",
1057 | "00:01:31,299 --> 00:01:33,060\n",
1058 | "복사를 하신 다음에\n",
1059 | "\n",
1060 | "25\n",
1061 | "00:01:33,060 --> 00:01:35,639\n",
1062 | "PPT 제작 전문가 GPTS 보트한테\n",
1063 | "\n",
1064 | "26\n",
1065 | "00:01:35,639 --> 00:01:37,000\n",
1066 | "붙여넣기를 해주는 거예요\n",
1067 | "\n",
1068 | "27\n",
1069 | "00:01:37,000 --> 00:01:38,599\n",
1070 | "자 이렇게 내용을 붙여 넣었습니다\n",
1071 | "\n",
1072 | "28\n",
1073 | "00:01:38,599 --> 00:01:39,840\n",
1074 | "엔터키를 입력해 볼게요\n",
1075 | "\n",
1076 | "29\n",
1077 | "00:01:39,840 --> 00:01:43,380\n",
1078 | "얘가 PPT를 작성을 해주는 것을 볼 수가 있어요\n",
1079 | "\n",
1080 | "30\n",
1081 | "00:01:43,380 --> 00:01:45,740\n",
1082 | "PPT의 제목을 알아서 뽑아주고요\n",
1083 | "\n",
1084 | "31\n",
1085 | "00:01:45,740 --> 00:01:48,740\n",
1086 | "그 안에 포함될 블랙 포인트들을 구성을 해줍니다\n",
1087 | "\n",
1088 | "32\n",
1089 | "00:01:48,740 --> 00:01:52,419\n",
1090 | "제가 여기 안에 내용은 아주 간략하게 구성을 해달라고 했기 때문에\n",
1091 | "\n",
1092 | "33\n",
1093 | "00:01:52,419 --> 00:01:54,860\n",
1094 | "구체적인 내용보다는 핵심 위주로 이렇게 뽑아내서\n",
1095 | "\n",
1096 | "34\n",
1097 | "00:01:54,860 --> 00:01:56,060\n",
1098 | "넣어주는 것을 볼 수가 있죠\n",
1099 | "\n",
1100 | "35\n",
1101 | "00:01:56,060 --> 00:01:57,759\n",
1102 | "처음에 핵심 내용을 뽑아주고요\n",
1103 | "\n",
1104 | "36\n",
1105 | "00:01:57,759 --> 00:02:00,119\n",
1106 | "다음으로는 슬라이드 구성 부분에서\n",
1107 | "\n",
1108 | "37\n",
1109 | "00:02:00,000 --> 00:02:02,320\n",
1110 | "슬라이드 1에는 제목은 뭐가 들어가고\n",
1111 | "\n",
1112 | "38\n",
1113 | "00:02:02,320 --> 00:02:04,540\n",
1114 | "장표 안에 들어가는 블랙 포인트는 뭐가 들어가고\n",
1115 | "\n",
1116 | "39\n",
1117 | "00:02:04,540 --> 00:02:06,040\n",
1118 | "이런 식으로 구성을 해주고 있어요\n",
1119 | "\n",
1120 | "40\n",
1121 | "00:02:06,040 --> 00:02:09,520\n",
1122 | "마지막으로 발표 스크립트도 얘가 자동으로 작성을 해주거든요\n",
1123 | "\n",
1124 | "41\n",
1125 | "00:02:09,520 --> 00:02:13,080\n",
1126 | "제가 발표할 내용들을 알아서 작성을 해주는 것을 볼 수가 있고요\n",
1127 | "\n",
1128 | "42\n",
1129 | "00:02:13,080 --> 00:02:14,860\n",
1130 | "3장의 슬라이드로 구성이 됐는데\n",
1131 | "\n",
1132 | "43\n",
1133 | "00:02:14,860 --> 00:02:16,260\n",
1134 | "중간에 길어서 끊어졌어요\n",
1135 | "\n",
1136 | "44\n",
1137 | "00:02:16,260 --> 00:02:19,059\n",
1138 | "그러면 오른쪽에 Continue Generating을 눌러주시면 됩니다\n",
1139 | "\n",
1140 | "45\n",
1141 | "00:02:19,059 --> 00:02:22,559\n",
1142 | "이렇게 발표 스크립트까지 완성을 해줬고요\n",
1143 | "\n",
1144 | "46\n",
1145 | "00:02:22,559 --> 00:02:26,200\n",
1146 | "다음으로는 MARF 형식의 슬라이드라는 것을 작성해주는 것을 볼 수가 있어요\n",
1147 | "\n",
1148 | "47\n",
1149 | "00:02:26,200 --> 00:02:27,400\n",
1150 | "위에 내용까지는 알겠는데\n",
1151 | "\n",
1152 | "48\n",
1153 | "00:02:27,400 --> 00:02:30,000\n",
1154 | "갑자기 여기에서 MARF라는 게 툭 튀어나왔죠\n",
1155 | "\n",
1156 | "49\n",
1157 | "00:02:30,000 --> 00:02:31,900\n",
1158 | "이거는 어떻게 쓰는 건지 제가 보여드릴게요\n",
1159 | "\n",
1160 | "50\n",
1161 | "00:02:31,900 --> 00:02:33,740\n",
1162 | "이렇게 구성을 해주는 것까지도 좋은데요\n",
1163 | "\n",
1164 | "51\n",
1165 | "00:02:33,740 --> 00:02:36,639\n",
1166 | "저는 장표를 만드는 것까지도 자동화를 하고 싶었던 거예요\n",
1167 | "\n",
1168 | "52\n",
1169 | "00:02:36,639 --> 00:02:38,880\n",
1170 | "여기 보시면 Copy Code라는 버튼이 보이실 거예요\n",
1171 | "\n",
1172 | "53\n",
1173 | "00:02:38,880 --> 00:02:40,919\n",
1174 | "이거를 눌러서 코드를 복사를 합니다\n",
1175 | "\n",
1176 | "54\n",
1177 | "00:02:40,919 --> 00:02:44,520\n",
1178 | "다음으로는 Mark Slides라는 웹사이트로 오시면 되고요\n",
1179 | "\n",
1180 | "55\n",
1181 | "00:02:44,520 --> 00:02:47,880\n",
1182 | "markslides.ai 여기 주소로 오시면 돼요\n",
1183 | "\n",
1184 | "56\n",
1185 | "00:02:47,880 --> 00:02:50,360\n",
1186 | "에디터 영역에다가 붙여넣기를 해주시면\n",
1187 | "\n",
1188 | "57\n",
1189 | "00:02:50,360 --> 00:02:53,799\n",
1190 | "오른쪽에 깔끔하게 장표가 완성이 되는 것을 볼 수가 있어요\n",
1191 | "\n",
1192 | "58\n",
1193 | "00:02:53,799 --> 00:02:55,099\n",
1194 | "굉장히 빠르게 완성이 됐죠\n",
1195 | "\n",
1196 | "59\n",
1197 | "00:02:55,160 --> 00:02:58,540\n",
1198 | "바로 슬라이드 표시 진행을 하실 수도 있고\n",
1199 | "\n",
1200 | "60\n",
1201 | "00:02:58,540 --> 00:03:00,540\n",
1202 | "Export as PDF라는 것들도 있어요\n",
1203 | "\n",
1204 | "61\n",
1205 | "00:03:00,000 --> 00:03:02,560\n",
1206 | "버튼으로 pdf로 내려받으실 수도 있어요\n",
1207 | "\n",
1208 | "62\n",
1209 | "00:03:02,560 --> 00:03:06,840\n",
1210 | "물론 여기 있는 ppt 장표가 최종 버전이라고 하기엔\n",
1211 | "\n",
1212 | "63\n",
1213 | "00:03:06,840 --> 00:03:08,200\n",
1214 | "좀 어려움이 있을 수 있겠죠\n",
1215 | "\n",
1216 | "64\n",
1217 | "00:03:08,200 --> 00:03:09,540\n",
1218 | "내용 보충이 필요할 수도 있고요\n",
1219 | "\n",
1220 | "65\n",
1221 | "00:03:09,540 --> 00:03:11,900\n",
1222 | "하지만 기본 골격을 잡는 데에는\n",
1223 | "\n",
1224 | "66\n",
1225 | "00:03:11,900 --> 00:03:14,680\n",
1226 | "굉장히 빠른 속도로 잡으실 수가 있기 때문에\n",
1227 | "\n",
1228 | "67\n",
1229 | "00:03:14,680 --> 00:03:16,340\n",
1230 | "생산성을 높일 수가 있습니다\n",
1231 | "\n",
1232 | "68\n",
1233 | "00:03:16,340 --> 00:03:19,480\n",
1234 | "그런데 여기 있는 내용을 복사 붙여넣기 하는 것도\n",
1235 | "\n",
1236 | "69\n",
1237 | "00:03:19,480 --> 00:03:20,719\n",
1238 | "귀찮은 일일 수가 있어요\n",
1239 | "\n",
1240 | "70\n",
1241 | "00:03:20,719 --> 00:03:22,879\n",
1242 | "그래서 지금부터 보여드릴 내용은\n",
1243 | "\n",
1244 | "71\n",
1245 | "00:03:22,879 --> 00:03:25,920\n",
1246 | "여기에 단순하게 링크를 넣는 방법이에요\n",
1247 | "\n",
1248 | "72\n",
1249 | "00:03:25,920 --> 00:03:28,200\n",
1250 | "이번에는 해외 기사도 한번 가져와 볼게요\n",
1251 | "\n",
1252 | "73\n",
1253 | "00:03:28,200 --> 00:03:30,700\n",
1254 | "이번엔 이렇게 드래그해서 가져오는 게 아니라\n",
1255 | "\n",
1256 | "74\n",
1257 | "00:03:30,700 --> 00:03:33,740\n",
1258 | "단순하게 이 신문기사의 링크를 복사를 해서\n",
1259 | "\n",
1260 | "75\n",
1261 | "00:03:33,740 --> 00:03:37,980\n",
1262 | "ppt 제작 전문가 보드한테 링크를 알려주도록 하겠습니다\n",
1263 | "\n",
1264 | "76\n",
1265 | "00:03:37,980 --> 00:03:40,180\n",
1266 | "이렇게 링크를 알려주면 제목과 함께\n",
1267 | "\n",
1268 | "77\n",
1269 | "00:03:40,180 --> 00:03:42,540\n",
1270 | "본문의 내용을 얘가 알아서 가져오게끔\n",
1271 | "\n",
1272 | "78\n",
1273 | "00:03:42,540 --> 00:03:44,279\n",
1274 | "프럼프트가 짜져 있어요\n",
1275 | "\n",
1276 | "79\n",
1277 | "00:03:44,279 --> 00:03:48,380\n",
1278 | "자 이렇게 내용을 가져와서 슬라이드로 변형을 하고 있고요\n",
1279 | "\n",
1280 | "80\n",
1281 | "00:03:48,380 --> 00:03:51,380\n",
1282 | "여기에 나와 있는 내용들은 해외 기사임에도 불구하고\n",
1283 | "\n",
1284 | "81\n",
1285 | "00:03:51,380 --> 00:03:53,259\n",
1286 | "한글로 잘 쓰고 있는 것을 볼 수가 있죠\n",
1287 | "\n",
1288 | "82\n",
1289 | "00:03:53,259 --> 00:03:55,820\n",
1290 | "제가 무조건 한글로 번역하게끔 프럼프트를 넣어놨어요\n",
1291 | "\n",
1292 | "83\n",
1293 | "00:03:55,820 --> 00:03:57,720\n",
1294 | "그렇기 때문에 해외 기사를 넣더라도\n",
1295 | "\n",
1296 | "84\n",
1297 | "00:03:57,720 --> 00:04:00,580\n",
1298 | "이렇게 한글로 잘 번역해서 슬라이드 구성을 해주시면 됩니다\n",
1299 | "\n",
1300 | "85\n",
1301 | "00:04:00,000 --> 00:04:02,680\n",
1302 | "마지막으로 슬라이드 발표 스크립트까지\n",
1303 | "\n",
1304 | "86\n",
1305 | "00:04:02,680 --> 00:04:05,080\n",
1306 | "이렇게 잘 작성하는 것을 볼 수가 있죠\n",
1307 | "\n",
1308 | "87\n",
1309 | "00:04:05,080 --> 00:04:09,680\n",
1310 | "그런데 무조건 링크 붙여넣기 기능은 잘 되는 것은 아니에요\n",
1311 | "\n",
1312 | "88\n",
1313 | "00:04:09,680 --> 00:04:13,800\n",
1314 | "가끔 가다가 이렇게 중간에 에러가 나타나기도 하고요\n",
1315 | "\n",
1316 | "89\n",
1317 | "00:04:13,800 --> 00:04:18,440\n",
1318 | "때로는 이렇게 regenerate를 눌러서 다시 시도를 하는데\n",
1319 | "\n",
1320 | "90\n",
1321 | "00:04:18,440 --> 00:04:22,280\n",
1322 | "이런 식으로 웹사이트 접근하는 데에 문제가 있다고 하면서\n",
1323 | "\n",
1324 | "91\n",
1325 | "00:04:22,280 --> 00:04:24,400\n",
1326 | "정보를 가져오는데 좀 어려움이 있는 것 같아요\n",
1327 | "\n",
1328 | "92\n",
1329 | "00:04:24,400 --> 00:04:27,480\n",
1330 | "이유는 로봇이 정보를 자동으로 긁어가지 못하게끔\n",
1331 | "\n",
1332 | "93\n",
1333 | "00:04:27,480 --> 00:04:28,480\n",
1334 | "블록을 하고 있는데\n",
1335 | "\n",
1336 | "94\n",
1337 | "00:04:28,480 --> 00:04:32,080\n",
1338 | "GPTS를 쓰게 되면은 이러한 문제점이 종종 발생을 하는 것 같습니다\n",
1339 | "\n",
1340 | "95\n",
1341 | "00:04:32,080 --> 00:04:34,720\n",
1342 | "현재로서는 좀 번거로울 수 있겠지만\n",
1343 | "\n",
1344 | "96\n",
1345 | "00:04:34,720 --> 00:04:38,480\n",
1346 | "추천드리는 방법은 웹사이트에 가서 이 전체 내용을 복사를 해서\n",
1347 | "\n",
1348 | "97\n",
1349 | "00:04:38,480 --> 00:04:41,080\n",
1350 | "붙여넣기 하는 방식을 가장 먼저 추천을 드리고요\n",
1351 | "\n",
1352 | "98\n",
1353 | "00:04:41,080 --> 00:04:44,040\n",
1354 | "슬라이드 구성을 하실 때에도 붙여넣기를 할 때\n",
1355 | "\n",
1356 | "99\n",
1357 | "00:04:44,040 --> 00:04:46,040\n",
1358 | "전체 내용을 붙여넣기를 하지 마시고요\n",
1359 | "\n",
1360 | "100\n",
1361 | "00:04:46,040 --> 00:04:48,279\n",
1362 | "큰 단락 위주로 붙여넣기 하시면 더욱 좋습니다\n",
1363 | "\n",
1364 | "101\n",
1365 | "00:04:48,279 --> 00:04:50,919\n",
1366 | "PPT에 큰 주제가 있고\n",
1367 | "\n",
1368 | "102\n",
1369 | "00:04:50,919 --> 00:04:54,160\n",
1370 | "이걸 관통하는 소 주제를 여러 개를 구성을 했어요\n",
1371 | "\n",
1372 | "103\n",
1373 | "00:04:54,160 --> 00:04:56,919\n",
1374 | "1번 주제가 있고 2번 주제가 있고 3번 주제가 있고요\n",
1375 | "\n",
1376 | "104\n",
1377 | "00:04:56,919 --> 00:04:59,240\n",
1378 | "내용을 그냥 다 때려넣고 얘가 잘해줄게요\n",
1379 | "\n",
1380 | "105\n",
1381 | "00:05:00,000 --> 00:05:01,340\n",
1382 | "라고 하지 마시고요\n",
1383 | "\n",
1384 | "106\n",
1385 | "00:05:01,340 --> 00:05:03,300\n",
1386 | "먼저 1번 주제에 해당한 내용을 붙여 넣고\n",
1387 | "\n",
1388 | "107\n",
1389 | "00:05:03,300 --> 00:05:04,440\n",
1390 | "슬라이드 구성을 하시고\n",
1391 | "\n",
1392 | "108\n",
1393 | "00:05:04,440 --> 00:05:06,200\n",
1394 | "2번 주제 넣고 구성하시고\n",
1395 | "\n",
1396 | "109\n",
1397 | "00:05:06,200 --> 00:05:07,900\n",
1398 | "3번 주제 넣고 구성하시는 게\n",
1399 | "\n",
1400 | "110\n",
1401 | "00:05:07,900 --> 00:05:09,680\n",
1402 | "가장 결과물이 좋았던 것 같습니다\n",
1403 | "\n",
1404 | "111\n",
1405 | "00:05:09,680 --> 00:05:11,500\n",
1406 | "제가 만든 이 PPT 제작 전문가는\n",
1407 | "\n",
1408 | "112\n",
1409 | "00:05:11,500 --> 00:05:14,340\n",
1410 | "어떻게 하면 효율적으로 써볼 수 있을까 해서\n",
1411 | "\n",
1412 | "113\n",
1413 | "00:05:14,340 --> 00:05:16,180\n",
1414 | "처음으로 간단하게 한번 만들어 봤고요\n",
1415 | "\n",
1416 | "114\n",
1417 | "00:05:16,180 --> 00:05:18,400\n",
1418 | "최대 슬라이드 3장만 만들게끔 넣어 놨거든요\n",
1419 | "\n",
1420 | "115\n",
1421 | "00:05:18,400 --> 00:05:20,780\n",
1422 | "나중에 여러분들이 프롬프트 튜닝을 하시게 되면\n",
1423 | "\n",
1424 | "116\n",
1425 | "00:05:20,780 --> 00:05:22,480\n",
1426 | "5장 7장 이렇게 늘리거나\n",
1427 | "\n",
1428 | "117\n",
1429 | "00:05:22,480 --> 00:05:24,639\n",
1430 | "안에 들어가는 내용 구성하는 방법도\n",
1431 | "\n",
1432 | "118\n",
1433 | "00:05:24,639 --> 00:05:25,700\n",
1434 | "달리 하실 수가 있습니다\n",
1435 | "\n",
1436 | "119\n",
1437 | "00:05:25,700 --> 00:05:26,780\n",
1438 | "오늘 영상에서는\n",
1439 | "\n",
1440 | "120\n",
1441 | "00:05:26,780 --> 00:05:29,280\n",
1442 | "제가 이 PPT 제작 전문가를 어떻게 활용하고 있는지\n",
1443 | "\n",
1444 | "121\n",
1445 | "00:05:29,280 --> 00:05:32,619\n",
1446 | "이것을 활용해서 어떻게 슬라이드를 좀 빠르게 만드는지\n",
1447 | "\n",
1448 | "122\n",
1449 | "00:05:32,619 --> 00:05:34,320\n",
1450 | "그 방법에 대해서 공유를 해드렸고요\n",
1451 | "\n",
1452 | "123\n",
1453 | "00:05:34,320 --> 00:05:36,119\n",
1454 | "만약에 이 영상이 반응이 좋다면\n",
1455 | "\n",
1456 | "124\n",
1457 | "00:05:36,119 --> 00:05:38,520\n",
1458 | "PPT 제작 전문가를 어떻게 구성을 했는지\n",
1459 | "\n",
1460 | "125\n",
1461 | "00:05:38,520 --> 00:05:40,619\n",
1462 | "제가 어떠한 프롬프트를 썼는지도\n",
1463 | "\n",
1464 | "126\n",
1465 | "00:05:40,619 --> 00:05:42,060\n",
1466 | "공유를 해드리도록 하겠습니다\n",
1467 | "\n",
1468 | "127\n",
1469 | "00:05:42,060 --> 00:05:44,060\n",
1470 | "그리고 이 GPTS를 만들 때\n",
1471 | "\n",
1472 | "128\n",
1473 | "00:05:44,060 --> 00:05:45,980\n",
1474 | "좀 좋은 결과물을 내기 위해서는\n",
1475 | "\n",
1476 | "129\n",
1477 | "00:05:45,980 --> 00:05:47,919\n",
1478 | "어떤 식으로 구성을 하면 되는지도\n",
1479 | "\n",
1480 | "130\n",
1481 | "00:05:47,919 --> 00:05:49,279\n",
1482 | "영상으로 담아보도록 할게요\n",
1483 | "\n",
1484 | "131\n",
1485 | "00:05:49,279 --> 00:05:52,880\n",
1486 | "이 PPT 제작 전문가를 체험해 보고 싶으신 분들을 위해서\n",
1487 | "\n",
1488 | "132\n",
1489 | "00:05:52,880 --> 00:05:55,279\n",
1490 | "더보기란에 링크 넣어두도록 하겠습니다\n",
1491 | "\n",
1492 | "133\n",
1493 | "00:05:55,279 --> 00:05:56,580\n",
1494 | "오늘 영상은 여기까지였습니다\n",
1495 | "\n",
1496 | "134\n",
1497 | "00:05:56,580 --> 00:05:57,520\n",
1498 | "감사합니다\n",
1499 | "\n",
1500 | "135\n",
1501 | "00:06:00,000 --> 00:06:11,470\n",
1502 | "아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아 아\n"
1503 | ]
1504 | }
1505 | ],
1506 | "source": [
1507 | "merged_transcript = merge_transcripts(*transcripts)\n",
1508 | "print(merged_transcript)"
1509 | ]
1510 | },
1511 | {
1512 | "cell_type": "code",
1513 | "execution_count": 22,
1514 | "metadata": {},
1515 | "outputs": [],
1516 | "source": [
1517 | "with open(\"sample.srt\", \"w\") as f:\n",
1518 | " f.write(merged_transcript)"
1519 | ]
1520 | },
1521 | {
1522 | "cell_type": "code",
1523 | "execution_count": 23,
1524 | "metadata": {},
1525 | "outputs": [],
1526 | "source": [
1527 | "# define a function for GPT to generate fictitious prompts\n",
1528 | "def post_processing(context: str) -> str:\n",
1529 | " \"\"\"Given an instruction, generate a prompt.\"\"\"\n",
1530 | " # system_prompt = instruction\n",
1531 | " # user_prompt = f\"Give me a summary of this video: {context}\"\n",
1532 | " response = client.chat.completions.create(\n",
1533 | " model=\"gpt-4-turbo-preview\",\n",
1534 | " temperature=0.1,\n",
1535 | " messages=[\n",
1536 | " {\n",
1537 | " \"role\": \"system\",\n",
1538 | " \"content\": \"당신은 자막 정보를 바탕으로 요약을 작성하는 인공지능입니다.\",\n",
1539 | " # we pick an example topic (friends talking about a vacation) so that GPT does not refuse or ask clarifying questions\n",
1540 | " },\n",
1541 | " {\"role\": \"user\", \"content\": context},\n",
1542 | " ],\n",
1543 | " stream=True,\n",
1544 | " )\n",
1545 | "\n",
1546 | " final_answer = []\n",
1547 | " # 스트림 모드에서는 completion.choices 를 반복문으로 순회\n",
1548 | " for chunk in response:\n",
1549 | " # chunk 를 저장\n",
1550 | " chunk_content = chunk.choices[0].delta.content\n",
1551 | " # chunk 가 문자열이면 final_answer 에 추가\n",
1552 | " if isinstance(chunk_content, str):\n",
1553 | " final_answer.append(chunk_content)\n",
1554 | " # 토큰 단위로 실시간 답변 출력\n",
1555 | " print(chunk_content, end=\"\")\n",
1556 | " return \"\".join(final_answer)"
1557 | ]
1558 | },
1559 | {
1560 | "cell_type": "code",
1561 | "execution_count": 24,
1562 | "metadata": {},
1563 | "outputs": [
1564 | {
1565 | "name": "stdout",
1566 | "output_type": "stream",
1567 | "text": [
1568 | "00:30 🌟 GPTS의 새로운 기능 소개 시작해요 \n",
1569 | "00:52 🛠️ PPT 제작의 귀찮음을 해결하는 GPTS의 역할에 대해 설명해요 \n",
1570 | "01:14 📝 웹사이트 링크나 글을 넣어 PPT를 자동으로 만들어주는 과정을 보여줘요 \n",
1571 | "02:26 🔄 MARF 형식의 슬라이드 작성과 자동화된 장표 만들기 과정을 소개해요 \n",
1572 | "03:25 🔗 해외 기사 링크를 이용한 PPT 제작 방법을 설명해요 \n",
1573 | "04:09 ❗ 링크 붙여넣기 기능의 한계와 해결 방안에 대해 이야기해요 \n",
1574 | "05:11 📊 효율적인 PPT 제작 전문가 사용법과 프롬프트 튜닝 팁을 공유해요 "
1575 | ]
1576 | }
1577 | ],
1578 | "source": [
1579 | "instruction = f\"\"\"주어진 비디오 \"자막정보\" 를 바탕으로 [요청사항]을 차례대로 수행해주세요.\n",
1580 | "[자막정보]\n",
1581 | "{merged_transcript}\n",
1582 | "\n",
1583 | "[요청사항]\n",
1584 | "1. 주어진 [자막정보]에서 중요한 주제를 시간 순서에 맞게 선정하고, 주제가 시작되는 시간을 기록해주세요.\n",
1585 | "2. 주제는 한 줄 요약을 작성하고, 자막에서 주제가 시작되는 시간을 mm:ss(분:초) 형식으로 작성하세요. (예: 00:05 👋 자막 생성 기능에 대한 소개)\n",
1586 | "3. 요약은 한글로 작성해주세요.\n",
1587 | "4. 각 문장에 적합한 emoji를 최대한 활용해 주세요\n",
1588 | "5. 한글로 번역해줘.\n",
1589 | "\n",
1590 | "[출력예시]\n",
1591 | "00:12 👋 GPTs 의 주요 개념에 대하여 소개해요\n",
1592 | "03:13 👀 GPTs 의 장단점과 활용 사례에 대하여 자세히 알아봐요\n",
1593 | "\n",
1594 | "[주의사항]\n",
1595 | "- 주제는 최대한 많이 추출해 주세요.\n",
1596 | "- 시간표기에 오류가 없도록 주의해 주세요. 분:초 형식으로 작성합니다. (예: 00:12)\n",
1597 | "\n",
1598 | "run step-by-step. Take a deep breath. You can do it!\n",
1599 | "\"\"\"\n",
1600 | "summary_output = post_processing(instruction)"
1601 | ]
1602 | }
1603 | ],
1604 | "metadata": {
1605 | "kernelspec": {
1606 | "display_name": "py-test",
1607 | "language": "python",
1608 | "name": "python3"
1609 | },
1610 | "language_info": {
1611 | "codemirror_mode": {
1612 | "name": "ipython",
1613 | "version": 3
1614 | },
1615 | "file_extension": ".py",
1616 | "mimetype": "text/x-python",
1617 | "name": "python",
1618 | "nbconvert_exporter": "python",
1619 | "pygments_lexer": "ipython3",
1620 | "version": "3.10.13"
1621 | }
1622 | },
1623 | "nbformat": 4,
1624 | "nbformat_minor": 2
1625 | }
1626 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 📘 OpenAI API 한국어 튜토리얼
2 |
3 | 🌟 **OpenAI 공식 Document, Cookbook, 그 밖의 실용 예제**를 바탕으로 작성한 한국어 튜토리얼입니다.
4 |
5 | 본 튜토리얼을 통해 Python OpenAI API 를 더 쉽고 효과적으로 사용하는 방법을 배울 수 있습니다.
6 |
7 | 공개된 [LangChain 한국어 튜토리얼](https://github.com/teddylee777/langchain-kr) 도 있으니, 같이 살펴 보시면 좋습니다.
8 |
9 | ## YouTube 튜토리얼
10 |
11 | 아래의 영상을 시청하시면서 따라서 진행하세요.
12 |
13 | [](https://youtu.be/VmB_bSa8Jf4)
14 |
15 | ## 📁 추가 실습파일 목록
16 |
17 | - [SPRi AI Brief 인공지능 산업의 최신 동향 2023년 12월호](https://spri.kr/posts/view/23669)
18 |
19 | - [The DALL·E Prompt Book](https://dallery.gallery/wp-content/uploads/2022/07/The-DALL%C2%B7E-2-prompt-book-v1.02.pdf)
20 |
21 | - [논문 - Language Models are Unsupervised Multitask Learners](https://d4mucfpksywv.cloudfront.net/better-language-models/language_models_are_unsupervised_multitask_learners.pdf)
22 |
23 |
24 |
25 | ## ✏️ 블로그 글 목록
26 |
27 | ### General
28 |
29 | - [OpenAI API 모델 리스트 / 요금표](https://teddylee777.github.io/openai/openai-models/)
30 |
31 | ### OpenAI Python API
32 |
33 | - [OpenAI Python API 키 발급방법, 요금체계](https://teddylee777.github.io/openai/openai-api-key/)
34 | - [채팅(chat) 함수 사용하기(1)](https://teddylee777.github.io/openai/openai-api-tutorial-01/)
35 | - [DALL·E를 사용하여 이미지 생성, 수정, 다양화하기(2)](https://teddylee777.github.io/openai/openai-api-tutorial-02/)
36 | - [Whisper API를 사용하여 TTS, STT 구현하기(3)](https://teddylee777.github.io/openai/openai-api-tutorial-03/)
37 |
38 | ## 🎬 YouTube
39 | - [OpenAI 의 새로운 기능 Assistant API 완벽히 이해해보기](https://youtu.be/-Wne4a-8RlY)
40 | - [OpenAI 의 새로운 기능 Assistant API 3가지 도구 활용법](https://youtu.be/BMW1NJkL7Ks)
41 |
42 |
43 | ## 📜 라이선스
44 |
45 | 본 프로젝트는 [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)에 따라 라이선스가 부여됩니다.
46 |
47 | ### 🚫 라이선스 고지
48 |
49 | 🔒 본 내용의 저작권은 2024년 [테디노트](https://teddylee777.github.io)에 있습니다. 모든 권리는 저작권자에게 있으며, teddylee777@gmail.com 으로 문의할 수 있습니다.
50 |
51 | 본 내용의 무단 전재 및 재배포를 금지합니다. 본 내용의 전체 혹은 일부를 인용할 경우, 출처를 명확히 밝혀주시기 바랍니다.
52 |
53 | 본 문서는 다른 문서의 내용을 참고하여 작성되었을 수 있습니다. 참고 자료는 본 문서 하단의 출처 목록에서 확인하실 수 있습니다.
54 |
55 | ## 📚 출처
56 |
57 | - [OpenAI Cookbook](https://cookbook.openai.com/) 📖
58 | - [OpenAI API Reference](https://platform.openai.com/docs/introduction) 🤖
59 |
60 | ## 🌐 추가 자료
61 |
62 | - **유튜브 채널**: [YouTube 테디노트](https://www.youtube.com/channel/UCt2wAAXgm87ACiQnDHQEW6Q) 🎥
63 | - **블로그**: [테디노트](https://teddylee777.github.io) 📝
64 | - **Playground**: [OpenAI Playground](https://platform.openai.com/playground)
65 |
66 | ## 💡 컨트리뷰션
67 |
68 | 본 튜토리얼에 기여하고자 하는 분들은 언제든지 풀 리퀘스트를 보내주시거나, 이슈를 등록하여 의견을 공유해 주시기 바랍니다. 모든 기여는 본 프로젝트의 발전에 큰 도움이 됩니다. 💖
69 |
70 |
71 |
72 | 
73 |
--------------------------------------------------------------------------------
/audio_utils.py:
--------------------------------------------------------------------------------
1 | import re
2 | import os
3 | from pytube import YouTube
4 | from moviepy.editor import AudioFileClip, VideoFileClip
5 |
6 |
7 | def extract_abr(abr):
8 | youtube_audio_pattern = re.compile(r"\d+")
9 | kbps = youtube_audio_pattern.search(abr)
10 | if kbps:
11 | kbps = kbps.group()
12 | return int(kbps)
13 | else:
14 | return 0
15 |
16 |
17 | def get_audio_filepath(filename):
18 | # audio 폴더가 없으면 생성
19 | if not os.path.isdir("audio"):
20 | os.mkdir("audio")
21 |
22 | # 현재 스크립트의 절대 경로 얻기
23 | current_directory = os.path.abspath("")
24 |
25 | # 파일 경로 생성
26 | audio_file_path = os.path.join(current_directory, "audio", filename)
27 |
28 | return audio_file_path
29 |
30 |
31 | def convert_mp4_to_wav(mp4_file_path, wav_file_path):
32 | # MP4 파일 로드
33 | audio_clip = AudioFileClip(mp4_file_path)
34 |
35 | # WAV 형식으로 오디오 추출 및 저장
36 | audio_clip.write_audiofile(wav_file_path, fps=44100, nbytes=2, codec="pcm_s16le")
37 |
38 |
39 | def download_audio_from_youtube(link):
40 | # YouTube 객체 생성
41 | yt = YouTube(link)
42 |
43 | # mp4 오디오만 필터링
44 | mp4_files = dict()
45 |
46 | # "audio/mp4" 타입의 스트림만 필터링
47 | for stream in yt.streams.filter(only_audio=True):
48 | mime_type = stream.mime_type
49 | abr = stream.abr
50 | if mime_type == "audio/mp4":
51 | abr = extract_abr(abr)
52 | mp4_files[abr] = stream
53 |
54 | # 키를 기준으로 정렬
55 | sorted_keys = sorted(mp4_files.keys())
56 | # 가장 큰 키를 사용하여 값 가져오기
57 | largest_value = mp4_files[sorted_keys[-1]]
58 | filename = largest_value.download()
59 |
60 | # 현재 스크립트의 절대 경로 얻기
61 | current_directory = os.path.abspath("")
62 |
63 | new_filename = os.path.basename(filename.replace(".mp4", ".wav"))
64 |
65 | new_filepath = os.path.join(current_directory, "audio", new_filename)
66 |
67 | # mp4 파일을 wav 파일로 변환
68 | convert_mp4_to_wav(filename, new_filepath)
69 |
70 | # mp4 파일 삭제
71 | os.remove(filename)
72 | return new_filepath
73 |
74 |
75 | def extract_audio_from_video(video_filepath):
76 | # MP4 파일 로드
77 | video = VideoFileClip(video_filepath)
78 | audio_filepath = get_audio_filepath(video_filepath.replace(".mp4", ".wav"))
79 | video.audio.write_audiofile(audio_filepath)
80 | return audio_filepath
81 |
--------------------------------------------------------------------------------
/data/edited_image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/edited_image.jpg
--------------------------------------------------------------------------------
/data/generated_image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/generated_image1.jpg
--------------------------------------------------------------------------------
/data/generated_image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/generated_image2.jpg
--------------------------------------------------------------------------------
/data/generated_image_porche.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/generated_image_porche.png
--------------------------------------------------------------------------------
/data/porche_911.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/porche_911.jpg
--------------------------------------------------------------------------------
/data/sample-mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/sample-mask.png
--------------------------------------------------------------------------------
/data/sample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/sample.png
--------------------------------------------------------------------------------
/data/오디오샘플_01.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/오디오샘플_01.wav
--------------------------------------------------------------------------------
/data/채용면접_샘플_01.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/채용면접_샘플_01.wav
--------------------------------------------------------------------------------
/data/채용면접_샘플_02.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/data/채용면접_샘플_02.wav
--------------------------------------------------------------------------------
/images/NotRealCorp_chart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/NotRealCorp_chart.png
--------------------------------------------------------------------------------
/images/assistant-code-interpreter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-code-interpreter.png
--------------------------------------------------------------------------------
/images/assistant-create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-create.png
--------------------------------------------------------------------------------
/images/assistant-file-id.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-file-id.png
--------------------------------------------------------------------------------
/images/assistant-file-upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-file-upload.png
--------------------------------------------------------------------------------
/images/assistant-function1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-function1.png
--------------------------------------------------------------------------------
/images/assistant-function2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-function2.png
--------------------------------------------------------------------------------
/images/assistant-lists.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-lists.png
--------------------------------------------------------------------------------
/images/assistant-math-tutor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-math-tutor.png
--------------------------------------------------------------------------------
/images/assistant-retrieval.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistant-retrieval.png
--------------------------------------------------------------------------------
/images/assistants_overview_assistants_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistants_overview_assistants_dashboard.png
--------------------------------------------------------------------------------
/images/assistants_overview_assistants_playground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistants_overview_assistants_playground.png
--------------------------------------------------------------------------------
/images/assistants_overview_diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistants_overview_diagram.png
--------------------------------------------------------------------------------
/images/assistants_overview_enable_code_interpreter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistants_overview_enable_code_interpreter.png
--------------------------------------------------------------------------------
/images/assistants_overview_enable_function.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistants_overview_enable_function.png
--------------------------------------------------------------------------------
/images/assistants_overview_enable_retrieval.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistants_overview_enable_retrieval.png
--------------------------------------------------------------------------------
/images/assistants_overview_new_assistant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/assistants_overview_new_assistant.png
--------------------------------------------------------------------------------
/images/chain_of_thought_fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/chain_of_thought_fig1.png
--------------------------------------------------------------------------------
/images/chain_of_thought_fig11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/chain_of_thought_fig11.png
--------------------------------------------------------------------------------
/images/chain_of_thought_fig3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/chain_of_thought_fig3.png
--------------------------------------------------------------------------------
/images/chain_of_thought_fig5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/chain_of_thought_fig5.png
--------------------------------------------------------------------------------
/images/dalle_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/dalle_image.png
--------------------------------------------------------------------------------
/images/data_vis_slide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/data_vis_slide.png
--------------------------------------------------------------------------------
/images/faithful-reasoning_fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/faithful-reasoning_fig1.png
--------------------------------------------------------------------------------
/images/faithful-reasoning_fig2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/faithful-reasoning_fig2.png
--------------------------------------------------------------------------------
/images/faithful-reasoning_fig3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/faithful-reasoning_fig3.png
--------------------------------------------------------------------------------
/images/faithful-reasoning_fig4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/faithful-reasoning_fig4.png
--------------------------------------------------------------------------------
/images/faithful-reasoning_fig5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/faithful-reasoning_fig5.png
--------------------------------------------------------------------------------
/images/faithful-reasoning_fig7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/faithful-reasoning_fig7.png
--------------------------------------------------------------------------------
/images/faithful-reasoning_tab2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/faithful-reasoning_tab2.png
--------------------------------------------------------------------------------
/images/faithful-reasoning_tab5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/faithful-reasoning_tab5.png
--------------------------------------------------------------------------------
/images/least-to-most_fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/least-to-most_fig1.png
--------------------------------------------------------------------------------
/images/least-to-most_tab11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/least-to-most_tab11.png
--------------------------------------------------------------------------------
/images/least-to-most_tab4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/least-to-most_tab4.png
--------------------------------------------------------------------------------
/images/least-to-most_tab9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/least-to-most_tab9.png
--------------------------------------------------------------------------------
/images/llamaindex_rag_overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/llamaindex_rag_overview.png
--------------------------------------------------------------------------------
/images/lm_cascades_fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/lm_cascades_fig1.png
--------------------------------------------------------------------------------
/images/lm_cascades_fig3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/lm_cascades_fig3.png
--------------------------------------------------------------------------------
/images/lm_cascades_fig4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/lm_cascades_fig4.png
--------------------------------------------------------------------------------
/images/lm_cascades_fig5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/lm_cascades_fig5.png
--------------------------------------------------------------------------------
/images/lm_cascades_fig6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/lm_cascades_fig6.png
--------------------------------------------------------------------------------
/images/maieutic_fig2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/maieutic_fig2.png
--------------------------------------------------------------------------------
/images/maieutic_fig6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/maieutic_fig6.png
--------------------------------------------------------------------------------
/images/maieutic_tab1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/maieutic_tab1.png
--------------------------------------------------------------------------------
/images/openai-cookbook-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/openai-cookbook-white.png
--------------------------------------------------------------------------------
/images/openai-cookbook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/openai-cookbook.png
--------------------------------------------------------------------------------
/images/search_rerank_answer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/search_rerank_answer.png
--------------------------------------------------------------------------------
/images/selection-inference_fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/selection-inference_fig1.png
--------------------------------------------------------------------------------
/images/selection-inference_fig4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/selection-inference_fig4.png
--------------------------------------------------------------------------------
/images/self-consistency_fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/self-consistency_fig1.png
--------------------------------------------------------------------------------
/images/self-consistency_fig3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/self-consistency_fig3.png
--------------------------------------------------------------------------------
/images/star_fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/star_fig1.png
--------------------------------------------------------------------------------
/images/star_tab1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/star_tab1.png
--------------------------------------------------------------------------------
/images/structures.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/structures.png
--------------------------------------------------------------------------------
/images/title_slide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/title_slide.png
--------------------------------------------------------------------------------
/images/verifiers_fig3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/verifiers_fig3.png
--------------------------------------------------------------------------------
/images/verifiers_fig5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/verifiers_fig5.png
--------------------------------------------------------------------------------
/images/zero-shot_reasoners_fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/zero-shot_reasoners_fig1.png
--------------------------------------------------------------------------------
/images/zero-shot_reasoners_fig2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/zero-shot_reasoners_fig2.png
--------------------------------------------------------------------------------
/images/zero-shot_reasoners_tab1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/zero-shot_reasoners_tab1.png
--------------------------------------------------------------------------------
/images/zero-shot_reasoners_tab5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddylee777/openai-api-kr/f22d26a7cc157e6a60a2fd6117fe2ddf675e7bc4/images/zero-shot_reasoners_tab5.png
--------------------------------------------------------------------------------
/requirements_mac.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.9.1
2 | aiosignal==1.3.1
3 | altair==5.2.0
4 | amazon-textract-caller==0.2.1
5 | amazon-textract-response-parser==1.0.2
6 | annotated-types==0.6.0
7 | anyio==3.7.1
8 | argon2-cffi==23.1.0
9 | argon2-cffi-bindings==21.2.0
10 | arrow==1.3.0
11 | asgiref==3.7.2
12 | asttokens==2.4.1
13 | async-lru==2.0.4
14 | async-timeout==4.0.3
15 | attrs==23.1.0
16 | Babel==2.14.0
17 | backoff==2.2.1
18 | bcrypt==4.1.2
19 | beautifulsoup4==4.12.2
20 | bleach==6.1.0
21 | blinker==1.7.0
22 | boto3==1.34.5
23 | botocore==1.34.5
24 | cachetools==5.3.2
25 | certifi==2023.11.17
26 | cffi==1.16.0
27 | chardet==5.2.0
28 | charset-normalizer==3.3.2
29 | chroma-hnswlib==0.7.3
30 | chromadb==0.4.21
31 | click==8.1.7
32 | colorama==0.4.6
33 | coloredlogs==15.0.1
34 | comm==0.2.0
35 | contourpy==1.2.0
36 | cryptography==41.0.7
37 | curl-cffi==0.5.10
38 | cycler==0.12.1
39 | dataclasses-json==0.6.3
40 | datasets==2.15.0
41 | debugpy==1.8.0
42 | decorator==5.1.1
43 | defusedxml==0.7.1
44 | Deprecated==1.2.14
45 | deprecation==2.1.0
46 | dill==0.3.7
47 | distro==1.8.0
48 | duckdb==0.9.2
49 | duckduckgo-search==4.1.0
50 | emoji==2.9.0
51 | et-xmlfile==1.1.0
52 | exceptiongroup==1.2.0
53 | executing==2.0.1
54 | faiss-cpu==1.7.4
55 | fastapi==0.105.0
56 | fastjsonschema==2.19.0
57 | filelock==3.13.1
58 | filetype==1.2.0
59 | flatbuffers==23.5.26
60 | fonttools==4.47.0
61 | fqdn==1.5.1
62 | frozenlist==1.4.1
63 | fsspec==2023.10.0
64 | gitdb==4.0.11
65 | GitPython==3.1.40
66 | google-auth==2.25.2
67 | google-search-results==2.4.2
68 | googleapis-common-protos==1.62.0
69 | greenlet==3.0.2
70 | grpcio==1.60.0
71 | h11==0.14.0
72 | httpcore==1.0.2
73 | httptools==0.6.1
74 | httpx==0.26.0
75 | huggingface-hub==0.20.1
76 | humanfriendly==10.0
77 | idna==3.6
78 | importlib-metadata==6.11.0
79 | importlib-resources==6.1.1
80 | ipykernel==6.27.1
81 | ipython==8.18.1
82 | ipywidgets==8.1.1
83 | isoduration==20.11.0
84 | jedi==0.19.1
85 | Jinja2==3.1.2
86 | jmespath==1.0.1
87 | joblib==1.3.2
88 | json5==0.9.14
89 | jsonpatch==1.33
90 | jsonpath-python==1.0.6
91 | jsonpointer==2.4
92 | jsonschema==4.20.0
93 | jsonschema-specifications==2023.11.2
94 | jupyter==1.0.0
95 | jupyter_client==8.6.0
96 | jupyter-console==6.6.3
97 | jupyter_core==5.5.1
98 | jupyter-events==0.9.0
99 | jupyter-lsp==2.2.1
100 | jupyter_server==2.12.1
101 | jupyter_server_terminals==0.5.0
102 | jupyterlab==4.0.9
103 | jupyterlab_pygments==0.3.0
104 | jupyterlab_server==2.25.2
105 | jupyterlab-widgets==3.0.9
106 | kiwisolver==1.4.5
107 | kubernetes==28.1.0
108 | lancedb==0.4.0
109 | langchain==0.0.352
110 | langchain-community==0.0.5
111 | langchain-core==0.1.2
112 | langdetect==1.0.9
113 | langsmith==0.0.73
114 | lxml==4.9.4
115 | markdown-it-py==3.0.0
116 | MarkupSafe==2.1.3
117 | marshmallow==3.20.1
118 | matplotlib==3.8.2
119 | matplotlib-inline==0.1.6
120 | mdurl==0.1.2
121 | mistune==3.0.2
122 | mmh3==4.0.1
123 | monotonic==1.6
124 | mpmath==1.3.0
125 | multidict==6.0.4
126 | multiprocess==0.70.15
127 | mypy-extensions==1.0.0
128 | nbclient==0.9.0
129 | nbconvert==7.13.0
130 | nbformat==5.9.2
131 | nest-asyncio==1.5.8
132 | networkx==3.0
133 | nltk==3.8.1
134 | notebook==7.0.6
135 | notebook_shim==0.2.3
136 | numpy==1.26.2
137 | oauthlib==3.2.2
138 | onnxruntime==1.16.3
139 | openai==1.6.0
140 | openpyxl==3.1.2
141 | opentelemetry-api==1.22.0
142 | opentelemetry-exporter-otlp-proto-common==1.22.0
143 | opentelemetry-exporter-otlp-proto-grpc==1.22.0
144 | opentelemetry-instrumentation==0.43b0
145 | opentelemetry-instrumentation-asgi==0.43b0
146 | opentelemetry-instrumentation-fastapi==0.43b0
147 | opentelemetry-proto==1.22.0
148 | opentelemetry-sdk==1.22.0
149 | opentelemetry-semantic-conventions==0.43b0
150 | opentelemetry-util-http==0.43b0
151 | overrides==7.4.0
152 | packaging==23.2
153 | pandas==1.5.3
154 | pandocfilters==1.5.0
155 | parso==0.8.3
156 | pdf2image==1.16.3
157 | pdfminer==20191125
158 | pdfminer.six==20221105
159 | pdfplumber==0.10.3
160 | Pillow==10.1.0
161 | pip==23.3.1
162 | platformdirs==4.1.0
163 | posthog==3.1.0
164 | prometheus-client==0.19.0
165 | prompt-toolkit==3.0.43
166 | protobuf==4.25.1
167 | psutil==5.9.7
168 | pulsar-client==3.3.0
169 | pure-eval==0.2.2
170 | py==1.11.0
171 | pyarrow==14.0.2
172 | pyarrow-hotfix==0.6
173 | pyasn1==0.5.1
174 | pyasn1-modules==0.3.0
175 | pycparser==2.21
176 | pycryptodome==3.19.0
177 | pydantic==2.5.2
178 | pydantic_core==2.14.5
179 | pydeck==0.8.1b0
180 | Pygments==2.17.2
181 | pylance==0.9.0
182 | PyMuPDF==1.23.8
183 | PyMuPDFb==1.23.7
184 | PyMySQL==1.1.0
185 | pyparsing==3.1.1
186 | pypdf==3.17.3
187 | pypdfium2==4.25.0
188 | PyPika==0.48.9
189 | pyreadline3==3.4.1
190 | python-dateutil==2.8.2
191 | python-dotenv==1.0.0
192 | python-iso639==2023.12.11
193 | python-json-logger==2.0.7
194 | python-magic==0.4.27
195 | pytz==2023.3.post1
196 | PyYAML==6.0.1
197 | pyzmq==25.1.2
198 | qtconsole==5.5.1
199 | QtPy==2.4.1
200 | rapidfuzz==3.5.2
201 | ratelimiter==1.2.0.post0
202 | referencing==0.32.0
203 | regex==2023.10.3
204 | requests==2.31.0
205 | requests-oauthlib==1.3.1
206 | retry==0.9.2
207 | rfc3339-validator==0.1.4
208 | rfc3986-validator==0.1.1
209 | rich==13.7.0
210 | rpds-py==0.15.2
211 | rsa==4.9
212 | s3transfer==0.9.0
213 | safetensors==0.4.1
214 | scikit-learn==1.3.2
215 | scipy==1.11.4
216 | seaborn==0.13.0
217 | semver==3.0.2
218 | Send2Trash==1.8.2
219 | setuptools==68.2.2
220 | six==1.16.0
221 | smmap==5.0.1
222 | sniffio==1.3.0
223 | soupsieve==2.5
224 | SQLAlchemy==2.0.23
225 | stack-data==0.6.3
226 | starlette==0.27.0
227 | streamlit==1.29.0
228 | sympy==1.12
229 | tabulate==0.9.0
230 | tenacity==8.2.3
231 | terminado==0.18.0
232 | threadpoolctl==3.2.0
233 | tiktoken==0.5.2
234 | tinycss2==1.2.1
235 | tokenizers==0.15.0
236 | toml==0.10.2
237 | tomli==2.0.1
238 | toolz==0.12.0
239 | torch==2.1.2
240 | torchaudio==2.1.2
241 | torchvision==0.16.2
242 | tornado==6.4
243 | tqdm==4.66.1
244 | traitlets==5.14.0
245 | transformers==4.36.2
246 | typer==0.9.0
247 | types-python-dateutil==2.8.19.14
248 | typing_extensions==4.9.0
249 | typing-inspect==0.9.0
250 | tzdata==2023.3
251 | tzlocal==5.2
252 | unstructured==0.11.6
253 | unstructured-client==0.15.0
254 | uri-template==1.3.0
255 | urllib3==1.26.18
256 | uvicorn==0.25.0
257 | validators==0.22.0
258 | watchdog==3.0.0
259 | watchfiles==0.21.0
260 | wcwidth==0.2.12
261 | webcolors==1.13
262 | webencodings==0.5.1
263 | websocket-client==1.7.0
264 | websockets==12.0
265 | wheel==0.41.2
266 | widgetsnbextension==4.0.9
267 | wrapt==1.16.0
268 | xxhash==3.4.1
269 | yarl==1.9.4
270 | zipp==3.17.0
271 |
--------------------------------------------------------------------------------
/requirements_windows.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.9.1
2 | aiosignal==1.3.1
3 | altair==5.2.0
4 | amazon-textract-caller==0.2.1
5 | amazon-textract-response-parser==1.0.2
6 | annotated-types==0.6.0
7 | anyio==3.7.1
8 | argon2-cffi==23.1.0
9 | argon2-cffi-bindings==21.2.0
10 | arrow==1.3.0
11 | asgiref==3.7.2
12 | asttokens==2.4.1
13 | async-lru==2.0.4
14 | async-timeout==4.0.3
15 | attrs==23.1.0
16 | Babel==2.14.0
17 | backoff==2.2.1
18 | bcrypt==4.1.2
19 | beautifulsoup4==4.12.2
20 | bleach==6.1.0
21 | blinker==1.7.0
22 | boto3==1.34.5
23 | botocore==1.34.5
24 | cachetools==5.3.2
25 | certifi==2023.11.17
26 | cffi==1.16.0
27 | chardet==5.2.0
28 | charset-normalizer==3.3.2
29 | chroma-hnswlib==0.7.3
30 | chromadb==0.4.21
31 | click==8.1.7
32 | colorama==0.4.6
33 | coloredlogs==15.0.1
34 | comm==0.2.0
35 | contourpy==1.2.0
36 | cryptography==41.0.7
37 | curl-cffi==0.5.10
38 | cycler==0.12.1
39 | dataclasses-json==0.6.3
40 | datasets==2.15.0
41 | debugpy==1.8.0
42 | decorator==5.1.1
43 | defusedxml==0.7.1
44 | Deprecated==1.2.14
45 | deprecation==2.1.0
46 | dill==0.3.7
47 | distro==1.8.0
48 | duckdb==0.9.2
49 | duckduckgo-search==4.1.0
50 | emoji==2.9.0
51 | et-xmlfile==1.1.0
52 | exceptiongroup==1.2.0
53 | executing==2.0.1
54 | faiss-cpu==1.7.4
55 | fastapi==0.105.0
56 | fastjsonschema==2.19.0
57 | filelock==3.13.1
58 | filetype==1.2.0
59 | flatbuffers==23.5.26
60 | fonttools==4.47.0
61 | fqdn==1.5.1
62 | frozenlist==1.4.1
63 | fsspec==2023.10.0
64 | gitdb==4.0.11
65 | GitPython==3.1.40
66 | google-auth==2.25.2
67 | google-search-results==2.4.2
68 | googleapis-common-protos==1.62.0
69 | greenlet==3.0.2
70 | grpcio==1.60.0
71 | h11==0.14.0
72 | httpcore==1.0.2
73 | httptools==0.6.1
74 | httpx==0.26.0
75 | huggingface-hub==0.20.1
76 | humanfriendly==10.0
77 | idna==3.6
78 | importlib-metadata==6.11.0
79 | importlib-resources==6.1.1
80 | ipykernel==6.27.1
81 | ipython==8.18.1
82 | ipywidgets==8.1.1
83 | isoduration==20.11.0
84 | jedi==0.19.1
85 | Jinja2==3.1.2
86 | jmespath==1.0.1
87 | joblib==1.3.2
88 | json5==0.9.14
89 | jsonpatch==1.33
90 | jsonpath-python==1.0.6
91 | jsonpointer==2.4
92 | jsonschema==4.20.0
93 | jsonschema-specifications==2023.11.2
94 | jupyter==1.0.0
95 | jupyter_client==8.6.0
96 | jupyter-console==6.6.3
97 | jupyter_core==5.5.1
98 | jupyter-events==0.9.0
99 | jupyter-lsp==2.2.1
100 | jupyter_server==2.12.1
101 | jupyter_server_terminals==0.5.0
102 | jupyterlab==4.0.9
103 | jupyterlab_pygments==0.3.0
104 | jupyterlab_server==2.25.2
105 | jupyterlab-widgets==3.0.9
106 | kiwisolver==1.4.5
107 | kubernetes==28.1.0
108 | lancedb==0.4.0
109 | langchain==0.0.352
110 | langchain-community==0.0.5
111 | langchain-core==0.1.2
112 | langdetect==1.0.9
113 | langsmith==0.0.73
114 | lxml==4.9.4
115 | markdown-it-py==3.0.0
116 | MarkupSafe==2.1.3
117 | marshmallow==3.20.1
118 | matplotlib==3.8.2
119 | matplotlib-inline==0.1.6
120 | mdurl==0.1.2
121 | mistune==3.0.2
122 | mmh3==4.0.1
123 | monotonic==1.6
124 | mpmath==1.3.0
125 | multidict==6.0.4
126 | multiprocess==0.70.15
127 | mypy-extensions==1.0.0
128 | nbclient==0.9.0
129 | nbconvert==7.13.0
130 | nbformat==5.9.2
131 | nest-asyncio==1.5.8
132 | networkx==3.0
133 | nltk==3.8.1
134 | notebook==7.0.6
135 | notebook_shim==0.2.3
136 | numpy==1.26.2
137 | oauthlib==3.2.2
138 | onnxruntime==1.16.3
139 | openai==1.6.0
140 | openpyxl==3.1.2
141 | opentelemetry-api==1.22.0
142 | opentelemetry-exporter-otlp-proto-common==1.22.0
143 | opentelemetry-exporter-otlp-proto-grpc==1.22.0
144 | opentelemetry-instrumentation==0.43b0
145 | opentelemetry-instrumentation-asgi==0.43b0
146 | opentelemetry-instrumentation-fastapi==0.43b0
147 | opentelemetry-proto==1.22.0
148 | opentelemetry-sdk==1.22.0
149 | opentelemetry-semantic-conventions==0.43b0
150 | opentelemetry-util-http==0.43b0
151 | overrides==7.4.0
152 | packaging==23.2
153 | pandas==1.5.3
154 | pandocfilters==1.5.0
155 | parso==0.8.3
156 | pdf2image==1.16.3
157 | pdfminer==20191125
158 | pdfminer.six==20221105
159 | pdfplumber==0.10.3
160 | Pillow==10.1.0
161 | pip==23.3.1
162 | platformdirs==4.1.0
163 | posthog==3.1.0
164 | prometheus-client==0.19.0
165 | prompt-toolkit==3.0.43
166 | protobuf==4.25.1
167 | psutil==5.9.7
168 | pulsar-client==3.3.0
169 | pure-eval==0.2.2
170 | py==1.11.0
171 | pyarrow==14.0.2
172 | pyarrow-hotfix==0.6
173 | pyasn1==0.5.1
174 | pyasn1-modules==0.3.0
175 | pycparser==2.21
176 | pycryptodome==3.19.0
177 | pydantic==2.5.2
178 | pydantic_core==2.14.5
179 | pydeck==0.8.1b0
180 | Pygments==2.17.2
181 | pylance==0.9.0
182 | PyMuPDF==1.23.8
183 | PyMuPDFb==1.23.7
184 | PyMySQL==1.1.0
185 | pyparsing==3.1.1
186 | pypdf==3.17.3
187 | pypdfium2==4.25.0
188 | PyPika==0.48.9
189 | pyreadline3==3.4.1
190 | python-dateutil==2.8.2
191 | python-dotenv==1.0.0
192 | python-iso639==2023.12.11
193 | python-json-logger==2.0.7
194 | python-magic==0.4.27
195 | pytz==2023.3.post1
196 | pywin32==306
197 | pywinpty==2.0.12
198 | PyYAML==6.0.1
199 | pyzmq==25.1.2
200 | qtconsole==5.5.1
201 | QtPy==2.4.1
202 | rapidfuzz==3.5.2
203 | ratelimiter==1.2.0.post0
204 | referencing==0.32.0
205 | regex==2023.10.3
206 | requests==2.31.0
207 | requests-oauthlib==1.3.1
208 | retry==0.9.2
209 | rfc3339-validator==0.1.4
210 | rfc3986-validator==0.1.1
211 | rich==13.7.0
212 | rpds-py==0.15.2
213 | rsa==4.9
214 | s3transfer==0.9.0
215 | safetensors==0.4.1
216 | scikit-learn==1.3.2
217 | scipy==1.11.4
218 | seaborn==0.13.0
219 | semver==3.0.2
220 | Send2Trash==1.8.2
221 | setuptools==68.2.2
222 | six==1.16.0
223 | smmap==5.0.1
224 | sniffio==1.3.0
225 | soupsieve==2.5
226 | SQLAlchemy==2.0.23
227 | stack-data==0.6.3
228 | starlette==0.27.0
229 | streamlit==1.29.0
230 | sympy==1.12
231 | tabulate==0.9.0
232 | tenacity==8.2.3
233 | terminado==0.18.0
234 | threadpoolctl==3.2.0
235 | tiktoken==0.5.2
236 | tinycss2==1.2.1
237 | tokenizers==0.15.0
238 | toml==0.10.2
239 | tomli==2.0.1
240 | toolz==0.12.0
241 | torch==2.1.2
242 | torchaudio==2.1.2
243 | torchvision==0.16.2
244 | tornado==6.4
245 | tqdm==4.66.1
246 | traitlets==5.14.0
247 | transformers==4.36.2
248 | typer==0.9.0
249 | types-python-dateutil==2.8.19.14
250 | typing_extensions==4.9.0
251 | typing-inspect==0.9.0
252 | tzdata==2023.3
253 | tzlocal==5.2
254 | unstructured==0.11.6
255 | unstructured-client==0.15.0
256 | uri-template==1.3.0
257 | urllib3==1.26.18
258 | uvicorn==0.25.0
259 | validators==0.22.0
260 | watchdog==3.0.0
261 | watchfiles==0.21.0
262 | wcwidth==0.2.12
263 | webcolors==1.13
264 | webencodings==0.5.1
265 | websocket-client==1.7.0
266 | websockets==12.0
267 | wheel==0.41.2
268 | widgetsnbextension==4.0.9
269 | wrapt==1.16.0
270 | xxhash==3.4.1
271 | yarl==1.9.4
272 | zipp==3.17.0
273 |
--------------------------------------------------------------------------------