├── .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 | " \"Generated\n", 162 | "
\n", 163 | "
\n", 164 | " \"Generated\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://img.youtube.com/vi/VmB_bSa8Jf4/0.jpg)](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 |

teddylee777

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 | --------------------------------------------------------------------------------