{
    "componentChunkName": "component---src-templates-post-tsx",
    "path": "/streamlit-chatgpt/",
    "result": {"data":{"logo":null,"markdownRemark":{"html":"<h1>단 30줄로 ChatGPT 웹페이지 만들기 (Streamlit chat_message)</h1>\n<p><a href=\"https://github.com/streamlit/streamlit\">Streamlit</a>은 파이썬 기반의 오픈소스 웹 UI 라이브러리입니다. 매우 간단한 코드로 손쉽게 웹페이지를 띄울 수 있어서 간단한 데모나 PoC 제품을 빠르게 만들어볼때 굉장히 유용합니다. 실제로 개인적으로 간단한 데모를 만들때 <a href=\"https://github.com/gradio-app/gradio\">Gradio</a>와 함께 가장 많이 쓰는 라이브러리입니다.</p>\n<img width=\"400\" alt=\"image\" src=\"https://github.com/sooftware/sooftware.io/assets/42150335/134118d0-c4b2-4689-bc85-4c805b8c7154\">\n<p>두 라이브러리 모두 간단하게 웹페이지를 띄울 수 있다는 장점이 있지만, 제 경험상 streamlit으로 코드를 작성했을 때 보다 간편헀던 것 같습니다. 그래서 이번 포스트에서는 streamlit에서 제공하는 <strong>chat_message</strong> 메서드와 OpenAI API를 이용해서 <strong>단 30줄의 코드</strong>로 ChatGPT를 웹페이지에 띄워보려고 합니다! (chat_message 외의 사용법을 알고싶으신 분들은 <a href=\"https://sooftware.github.io/streamlit/\">이전 streamlit 포스트</a>를 참고하세요!)</p>\n<h2>Installation</h2>\n<p>먼저 스트림릿 설치를 위해서 아래 커먼드롤 입력합니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ pip install streamlit</code></pre></div>\n<p>그리고 OpenAI API 사용을 위해서 아래 커맨드로 openai 라이브러리도 설치해줍니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ pip install openai==1.2.0</code></pre></div>\n<p>참고로 openai 버전은 꼭 1.2.0이 아니여도 되지만, 버전마다 사용법이 조금씩 다를 수 있기 때문에, 이번 포스트에서는 버전을 고정해줬습니다.</p>\n<h2>Build Streamlit ChatGPT Page</h2>\n<p>이 섹션에서는 Streamlit을 처음 사용해보신다고 가정하고 하나하나 자세하게 보고 넘어가겠습니다. 이미 Streamlit에 익숙해서 전체 코드만 필요하신 분은 아래로 내리시면 코드가 있으니 해당 부분 참고하시면 되겠습니다. :)</p>\n<h3>Step 1: import libraries</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> streamlit <span class=\"token keyword\">as</span> st  \n<span class=\"token keyword\">import</span> os  \n<span class=\"token keyword\">from</span> openai <span class=\"token keyword\">import</span> OpenAI</code></pre></div>\n<p>먼저, 필요한 라이브러리들을 import 해줍니다. 앞에서 설치해준 streamlit, openai와 openai API 키 등록을 위해 기본 내장 라이브러리인 os를 import 해줍니다.</p>\n<h3>Step 2: OpenAI API 세팅</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\">os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">[</span><span class=\"token string\">\"OPENAI_API_KEY\"</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"YOUR_OPENAI_API_KEY\"</span>  \nclient <span class=\"token operator\">=</span> OpenAI<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>환경에 OpenAI API 키를 등록하고, API 사용을 위한 client를 생성합니다. OpenAI API 키는 <a href=\"https://platform.openai.com\">https://platform.openai.com</a> 에서 회원가입 및 결제카드를 등록하면 받을 수 있습니다.</p>\n<h3>Step 3: Streamlit 코드 작성</h3>\n<p>이제 본격적으로 Streamlit 코드를 작성해주면 됩니다!</p>\n<p>먼저 생성할 페이지의 타이틀과 ChatGPT와 주고받을 메세지를 저장할 리스트를 생성해줍니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\">st<span class=\"token punctuation\">.</span>title<span class=\"token punctuation\">(</span><span class=\"token string\">\"Streamlit ChatGPT\"</span><span class=\"token punctuation\">)</span>  \n  \n<span class=\"token keyword\">if</span> <span class=\"token string\">'messages'</span> <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">:</span>  \n    st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>  </code></pre></div>\n<p>Streamlit은 기본적으로 매 event가 발생할때마다 페이지를 새로 로드하는 방식입니다. 그래서 <strong>st.session_state</strong>가 아닌 새로 변수를 생성하게 되면 이벤트가 발생할대마다 해당 변수가 초기화되어 버립니다. 그래서 스트림릿에서 변수들을 기록할때는 <strong>st.session_state</strong>에 위와 같은 형식으로 저장하는 것을 추천드립니다.</p>\n<p>다음으로는 사용자로부터 텍스트를 입력받을 창과 텍스트를 전송할 버튼을 만들어 보겠습니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\">user_message <span class=\"token operator\">=</span> st<span class=\"token punctuation\">.</span>text_input<span class=\"token punctuation\">(</span><span class=\"token string\">\"User:\"</span><span class=\"token punctuation\">)</span>  \n  \n<span class=\"token keyword\">if</span> st<span class=\"token punctuation\">.</span>button<span class=\"token punctuation\">(</span><span class=\"token string\">\"Send\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>  \n    st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"role\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"user\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"content\"</span><span class=\"token punctuation\">:</span> user_message<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>스트림릿에서 텍스트를 입력받을 때는 <strong>st.text_input</strong> 메서드를 사용합니다. 버튼은 <strong>st.button</strong> 메서드를 이용하면 되는데, 저희는 버튼이 눌렸을때의 동작이 필요하므로 <strong>if st.button(“Send”)</strong> 와 같이 작성했습니다. 그리고 유저 메세지를 ChatGPT에게 보내기 위해 기존에 초기화를 해둔 <strong>st.session_state.messages</strong>에 ChatGPT에서 요구하는 형식에 맞게 append를 해주겠습니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">if</span> st<span class=\"token punctuation\">.</span>button<span class=\"token punctuation\">(</span><span class=\"token string\">\"Send\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>  \n    st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"role\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"user\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"content\"</span><span class=\"token punctuation\">:</span> user_message<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>  \n  \n    completion <span class=\"token operator\">=</span> client<span class=\"token punctuation\">.</span>chat<span class=\"token punctuation\">.</span>completions<span class=\"token punctuation\">.</span>create<span class=\"token punctuation\">(</span>  \n        model<span class=\"token operator\">=</span><span class=\"token string\">\"gpt-3.5-turbo\"</span><span class=\"token punctuation\">,</span>  \n        messages<span class=\"token operator\">=</span>st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">,</span>  \n    <span class=\"token punctuation\">)</span>  \n    response <span class=\"token operator\">=</span> completion<span class=\"token punctuation\">.</span>choices<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>message<span class=\"token punctuation\">.</span>content  \n    st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"role\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"assistant\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"content\"</span><span class=\"token punctuation\">:</span> response<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> </code></pre></div>\n<p>입력받은 유저 메세지를 ChatGPT에게 전송해서 응답을 받아옵니다! 이전 세팅에서 생성한 openai client의 <strong>chat.completions.create</strong> 메서드를 이용하여 응답을 받아오고, ChatGPT의 응답을 유저 메세지 같이 <strong>st.session_state.messages</strong>에 append 해줍니다. 여기까지 코드작성이 됐다면 아래와 같은 플로우가 완성됩니다!</p>\n<ol>\n<li>유저 메세지 입력</li>\n<li>messages에 유저 메세지 추가</li>\n<li>messages 기반으로 ChatGPT 응답 생성</li>\n<li>ChatGPT 응답 messages에 추가</li>\n<li>1로 돌아가서 반복하며 messages에는 [유저, ChatGPT, 유저, ChatGPT, …] 순서로 주고받은 대화 내역이 저장됨</li>\n</ol>\n<h3>Step 4: chat_message 메서드로 대화 display</h3>\n<p>주고받은 대화들을 시각적으로 볼 수 있게 하기 위해 주고받는 대화들을 streamlit의 <strong>chat_message</strong> 메서드로 display 해줍니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">for</span> message <span class=\"token keyword\">in</span> <span class=\"token builtin\">reversed</span><span class=\"token punctuation\">(</span>st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>  \n    <span class=\"token keyword\">with</span> st<span class=\"token punctuation\">.</span>chat_message<span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">[</span><span class=\"token string\">'role'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>  \n        <span class=\"token keyword\">if</span> message<span class=\"token punctuation\">[</span><span class=\"token string\">'role'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">==</span> <span class=\"token string\">'user'</span><span class=\"token punctuation\">:</span>  \n            st<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">[</span><span class=\"token string\">'content'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>  \n        <span class=\"token keyword\">else</span><span class=\"token punctuation\">:</span>  \n            st<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">[</span><span class=\"token string\">'content'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> avatar<span class=\"token operator\">=</span>st<span class=\"token punctuation\">.</span>image<span class=\"token punctuation\">(</span><span class=\"token string\">'assets/openai-logo.png'</span><span class=\"token punctuation\">,</span> width<span class=\"token operator\">=</span><span class=\"token number\">30</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>위에서 저장한 <strong>st.session_state.messages</strong>를 for 문을 돌면서 하나씩 가져와서 사용자인지 ChatGPT인지를 판별하고, display 해줍니다. (최근 대화가 위에 오도록 하기 위하여 reversed 메서드를 사용합니다) 조금 더 명확하게 표시를 해주기 위해 ChatGPT의 경우 미리 저장해둔 OpenAI logo로 아바타를 표시해줬습니다.</p>\n<h2>\bStep 5: Run Streamlit</h2>\n<p>Streamlit 기반 웹페이지를 실행할때는 아래와 같이 <strong>streamlit run ***.py</strong> 형식으로 입력해주시면 됩니다. 저는 파이썬 파일명을 app.py로 했으니 아래와 같이 실행했습니다.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ streamlit run app.py</code></pre></div>\n<p>위 명령어를 실행하면 아래와 같이 Streamlit으로 만든 ChatGPT 페이지를 사용해볼 수 있습니다!</p>\n<img width=\"500\" alt=\"image\" src=\"https://github.com/sooftware/sooftware.io/assets/42150335/2dff5ff4-2ee5-49b2-a3eb-3fadd1ab51e0\">\n이렇게 총 31줄의 코드로 AI와 대화하는 웹페이지를 만들 수 있다니 세상 좋아졌다는게 체감이 됩니다. 😎   \n<p>이번 포스트에서는 간단하게 ChatGPT와 대화하는 정도의 페이지만 만들었지만 스트림릿에서 제공하는 더 많은 기능들을 활용하면 보다 복잡한 어플리케이션도 빠르게 제작할 수 있습니다. 아래는 제가 운영하는 서비스인 <a href=\"https://dearmate.ai/\">Dearmate</a> 케릭터들과의 대화를 Streamlit으로 만들어본 예시입니다.</p>\n<img src=\"https://github.com/sooftware/sooftware.io/assets/42150335/236e96dd-c65f-4489-9c06-154c92702c95\" width=\"400\">\n<p>이렇게 Streamlit을 활용하면 내부 데모페이지, PoC 정도의 페이지를 손쉽게 구성할 수 있습니다. 저도 일하면서 반복적으로 손이 가는 업무들은 스트림릿을 이용해서 웹페이지를 하나 띄워두고 즐겨찾기 해두고 일을 하는데, 상당히 편리하고 일의 능률도 많이 올라갑니다. 😎 이 포스트를 읽는 여러분들도 스트림릿을 적극적으로 활용해보시는 것을 추천합니다!</p>\n<h3>전체 코드</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> streamlit <span class=\"token keyword\">as</span> st  \n<span class=\"token keyword\">import</span> os  \n<span class=\"token keyword\">from</span> openai <span class=\"token keyword\">import</span> OpenAI  \n  \nos<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">[</span><span class=\"token string\">\"OPENAI_API_KEY\"</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"YOUR_OPENAI_API_KEY\"</span>  \nclient <span class=\"token operator\">=</span> OpenAI<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>  \n  \nst<span class=\"token punctuation\">.</span>title<span class=\"token punctuation\">(</span><span class=\"token string\">\"Streamlit ChatGPT\"</span><span class=\"token punctuation\">)</span>  \n  \n<span class=\"token keyword\">if</span> <span class=\"token string\">'messages'</span> <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">:</span>  \n    st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>  \n  \nuser_message <span class=\"token operator\">=</span> st<span class=\"token punctuation\">.</span>text_input<span class=\"token punctuation\">(</span><span class=\"token string\">\"User:\"</span><span class=\"token punctuation\">)</span>  \n  \n<span class=\"token keyword\">if</span> st<span class=\"token punctuation\">.</span>button<span class=\"token punctuation\">(</span><span class=\"token string\">\"Send\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>  \n    st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"role\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"user\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"content\"</span><span class=\"token punctuation\">:</span> user_message<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>  \n  \n    completion <span class=\"token operator\">=</span> client<span class=\"token punctuation\">.</span>chat<span class=\"token punctuation\">.</span>completions<span class=\"token punctuation\">.</span>create<span class=\"token punctuation\">(</span>  \n        model<span class=\"token operator\">=</span><span class=\"token string\">\"gpt-3.5-turbo\"</span><span class=\"token punctuation\">,</span>  \n        messages<span class=\"token operator\">=</span>st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">,</span>  \n    <span class=\"token punctuation\">)</span>  \n    response <span class=\"token operator\">=</span> completion<span class=\"token punctuation\">.</span>choices<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>message<span class=\"token punctuation\">.</span>content  \n    st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"role\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"assistant\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"content\"</span><span class=\"token punctuation\">:</span> response<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>  \n  \n<span class=\"token keyword\">for</span> message <span class=\"token keyword\">in</span> <span class=\"token builtin\">reversed</span><span class=\"token punctuation\">(</span>st<span class=\"token punctuation\">.</span>session_state<span class=\"token punctuation\">.</span>messages<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>  \n    <span class=\"token keyword\">with</span> st<span class=\"token punctuation\">.</span>chat_message<span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">[</span><span class=\"token string\">'role'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>  \n        <span class=\"token keyword\">if</span> message<span class=\"token punctuation\">[</span><span class=\"token string\">'role'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">==</span> <span class=\"token string\">'user'</span><span class=\"token punctuation\">:</span>  \n            st<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">[</span><span class=\"token string\">'content'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>  \n        <span class=\"token keyword\">else</span><span class=\"token punctuation\">:</span>  \n            st<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">[</span><span class=\"token string\">'content'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> avatar<span class=\"token operator\">=</span>st<span class=\"token punctuation\">.</span>image<span class=\"token punctuation\">(</span><span class=\"token string\">'assets/openai-logo.png'</span><span class=\"token punctuation\">,</span> width<span class=\"token operator\">=</span><span class=\"token number\">30</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>","htmlAst":{"type":"root","children":[{"type":"element","tagName":"h1","properties":{},"children":[{"type":"text","value":"단 30줄로 ChatGPT 웹페이지 만들기 (Streamlit chat_message)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://github.com/streamlit/streamlit"},"children":[{"type":"text","value":"Streamlit"}]},{"type":"text","value":"은 파이썬 기반의 오픈소스 웹 UI 라이브러리입니다. 매우 간단한 코드로 손쉽게 웹페이지를 띄울 수 있어서 간단한 데모나 PoC 제품을 빠르게 만들어볼때 굉장히 유용합니다. 실제로 개인적으로 간단한 데모를 만들때 "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/gradio-app/gradio"},"children":[{"type":"text","value":"Gradio"}]},{"type":"text","value":"와 함께 가장 많이 쓰는 라이브러리입니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"width":400,"alt":"image","src":"https://github.com/sooftware/sooftware.io/assets/42150335/134118d0-c4b2-4689-bc85-4c805b8c7154"},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"두 라이브러리 모두 간단하게 웹페이지를 띄울 수 있다는 장점이 있지만, 제 경험상 streamlit으로 코드를 작성했을 때 보다 간편헀던 것 같습니다. 그래서 이번 포스트에서는 streamlit에서 제공하는 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"chat_message"}]},{"type":"text","value":" 메서드와 OpenAI API를 이용해서 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"단 30줄의 코드"}]},{"type":"text","value":"로 ChatGPT를 웹페이지에 띄워보려고 합니다! (chat_message 외의 사용법을 알고싶으신 분들은 "},{"type":"element","tagName":"a","properties":{"href":"https://sooftware.github.io/streamlit/"},"children":[{"type":"text","value":"이전 streamlit 포스트"}]},{"type":"text","value":"를 참고하세요!)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h2","properties":{},"children":[{"type":"text","value":"Installation"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"먼저 스트림릿 설치를 위해서 아래 커먼드롤 입력합니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"$ pip install streamlit"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"그리고 OpenAI API 사용을 위해서 아래 커맨드로 openai 라이브러리도 설치해줍니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"$ pip install openai==1.2.0"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"참고로 openai 버전은 꼭 1.2.0이 아니여도 되지만, 버전마다 사용법이 조금씩 다를 수 있기 때문에, 이번 포스트에서는 버전을 고정해줬습니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h2","properties":{},"children":[{"type":"text","value":"Build Streamlit ChatGPT Page"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"이 섹션에서는 Streamlit을 처음 사용해보신다고 가정하고 하나하나 자세하게 보고 넘어가겠습니다. 이미 Streamlit에 익숙해서 전체 코드만 필요하신 분은 아래로 내리시면 코드가 있으니 해당 부분 참고하시면 되겠습니다. :)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{},"children":[{"type":"text","value":"Step 1: import libraries"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"python"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"import"}]},{"type":"text","value":" streamlit "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"as"}]},{"type":"text","value":" st  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"import"}]},{"type":"text","value":" os  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"from"}]},{"type":"text","value":" openai "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"import"}]},{"type":"text","value":" OpenAI"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"먼저, 필요한 라이브러리들을 import 해줍니다. 앞에서 설치해준 streamlit, openai와 openai API 키 등록을 위해 기본 내장 라이브러리인 os를 import 해줍니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{},"children":[{"type":"text","value":"Step 2: OpenAI API 세팅"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"python"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-python"]},"children":[{"type":"text","value":"os"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"environ"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"OPENAI_API_KEY\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"YOUR_OPENAI_API_KEY\""}]},{"type":"text","value":"  \nclient "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" OpenAI"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"환경에 OpenAI API 키를 등록하고, API 사용을 위한 client를 생성합니다. OpenAI API 키는 "},{"type":"element","tagName":"a","properties":{"href":"https://platform.openai.com"},"children":[{"type":"text","value":"https://platform.openai.com"}]},{"type":"text","value":" 에서 회원가입 및 결제카드를 등록하면 받을 수 있습니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{},"children":[{"type":"text","value":"Step 3: Streamlit 코드 작성"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"이제 본격적으로 Streamlit 코드를 작성해주면 됩니다!"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"먼저 생성할 페이지의 타이틀과 ChatGPT와 주고받을 메세지를 저장할 리스트를 생성해줍니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"python"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-python"]},"children":[{"type":"text","value":"st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"title"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"Streamlit ChatGPT\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"if"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'messages'"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"not"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"in"}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n    st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"text","value":"  "}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Streamlit은 기본적으로 매 event가 발생할때마다 페이지를 새로 로드하는 방식입니다. 그래서 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"st.session_state"}]},{"type":"text","value":"가 아닌 새로 변수를 생성하게 되면 이벤트가 발생할대마다 해당 변수가 초기화되어 버립니다. 그래서 스트림릿에서 변수들을 기록할때는 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"st.session_state"}]},{"type":"text","value":"에 위와 같은 형식으로 저장하는 것을 추천드립니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"다음으로는 사용자로부터 텍스트를 입력받을 창과 텍스트를 전송할 버튼을 만들어 보겠습니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"python"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-python"]},"children":[{"type":"text","value":"user_message "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"text_input"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"User:\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"if"}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"button"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"Send\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n    st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"append"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"role\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"user\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"content\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" user_message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"스트림릿에서 텍스트를 입력받을 때는 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"st.text_input"}]},{"type":"text","value":" 메서드를 사용합니다. 버튼은 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"st.button"}]},{"type":"text","value":" 메서드를 이용하면 되는데, 저희는 버튼이 눌렸을때의 동작이 필요하므로 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"if st.button(“Send”)"}]},{"type":"text","value":" 와 같이 작성했습니다. 그리고 유저 메세지를 ChatGPT에게 보내기 위해 기존에 초기화를 해둔 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"st.session_state.messages"}]},{"type":"text","value":"에 ChatGPT에서 요구하는 형식에 맞게 append를 해주겠습니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"python"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"if"}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"button"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"Send\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n    st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"append"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"role\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"user\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"content\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" user_message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n  \n    completion "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" client"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"chat"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"completions"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"create"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"  \n        model"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"gpt-3.5-turbo\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"  \n        messages"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":"st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"  \n    "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n    response "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" completion"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"choices"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","number"]},"children":[{"type":"text","value":"0"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"content  \n    st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"append"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"role\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"assistant\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"content\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" response"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":" "}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"입력받은 유저 메세지를 ChatGPT에게 전송해서 응답을 받아옵니다! 이전 세팅에서 생성한 openai client의 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"chat.completions.create"}]},{"type":"text","value":" 메서드를 이용하여 응답을 받아오고, ChatGPT의 응답을 유저 메세지 같이 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"st.session_state.messages"}]},{"type":"text","value":"에 append 해줍니다. 여기까지 코드작성이 됐다면 아래와 같은 플로우가 완성됩니다!"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"유저 메세지 입력"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"messages에 유저 메세지 추가"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"messages 기반으로 ChatGPT 응답 생성"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"ChatGPT 응답 messages에 추가"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"1로 돌아가서 반복하며 messages에는 [유저, ChatGPT, 유저, ChatGPT, …] 순서로 주고받은 대화 내역이 저장됨"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{},"children":[{"type":"text","value":"Step 4: chat_message 메서드로 대화 display"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"주고받은 대화들을 시각적으로 볼 수 있게 하기 위해 주고받는 대화들을 streamlit의 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"chat_message"}]},{"type":"text","value":" 메서드로 display 해줍니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"python"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"for"}]},{"type":"text","value":" message "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"in"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","builtin"]},"children":[{"type":"text","value":"reversed"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n    "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"with"}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"chat_message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'role'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n        "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"if"}]},{"type":"text","value":" message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'role'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'user'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n            st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"write"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'content'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n        "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"else"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n            st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"write"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'content'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" avatar"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":"st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"image"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'assets/openai-logo.png'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" width"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"element","tagName":"span","properties":{"className":["token","number"]},"children":[{"type":"text","value":"30"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"위에서 저장한 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"st.session_state.messages"}]},{"type":"text","value":"를 for 문을 돌면서 하나씩 가져와서 사용자인지 ChatGPT인지를 판별하고, display 해줍니다. (최근 대화가 위에 오도록 하기 위하여 reversed 메서드를 사용합니다) 조금 더 명확하게 표시를 해주기 위해 ChatGPT의 경우 미리 저장해둔 OpenAI logo로 아바타를 표시해줬습니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h2","properties":{},"children":[{"type":"text","value":"\bStep 5: Run Streamlit"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Streamlit 기반 웹페이지를 실행할때는 아래와 같이 "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"streamlit run ***.py"}]},{"type":"text","value":" 형식으로 입력해주시면 됩니다. 저는 파이썬 파일명을 app.py로 했으니 아래와 같이 실행했습니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"$ streamlit run app.py"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"위 명령어를 실행하면 아래와 같이 Streamlit으로 만든 ChatGPT 페이지를 사용해볼 수 있습니다!"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"width":500,"alt":"image","src":"https://github.com/sooftware/sooftware.io/assets/42150335/2dff5ff4-2ee5-49b2-a3eb-3fadd1ab51e0"},"children":[]},{"type":"text","value":"\n이렇게 총 31줄의 코드로 AI와 대화하는 웹페이지를 만들 수 있다니 세상 좋아졌다는게 체감이 됩니다. 😎   \n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"이번 포스트에서는 간단하게 ChatGPT와 대화하는 정도의 페이지만 만들었지만 스트림릿에서 제공하는 더 많은 기능들을 활용하면 보다 복잡한 어플리케이션도 빠르게 제작할 수 있습니다. 아래는 제가 운영하는 서비스인 "},{"type":"element","tagName":"a","properties":{"href":"https://dearmate.ai/"},"children":[{"type":"text","value":"Dearmate"}]},{"type":"text","value":" 케릭터들과의 대화를 Streamlit으로 만들어본 예시입니다."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://github.com/sooftware/sooftware.io/assets/42150335/236e96dd-c65f-4489-9c06-154c92702c95","width":400},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"이렇게 Streamlit을 활용하면 내부 데모페이지, PoC 정도의 페이지를 손쉽게 구성할 수 있습니다. 저도 일하면서 반복적으로 손이 가는 업무들은 스트림릿을 이용해서 웹페이지를 하나 띄워두고 즐겨찾기 해두고 일을 하는데, 상당히 편리하고 일의 능률도 많이 올라갑니다. 😎 이 포스트를 읽는 여러분들도 스트림릿을 적극적으로 활용해보시는 것을 추천합니다!"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{},"children":[{"type":"text","value":"전체 코드"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"python"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-python"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"import"}]},{"type":"text","value":" streamlit "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"as"}]},{"type":"text","value":" st  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"import"}]},{"type":"text","value":" os  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"from"}]},{"type":"text","value":" openai "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"import"}]},{"type":"text","value":" OpenAI  \n  \nos"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"environ"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"OPENAI_API_KEY\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"YOUR_OPENAI_API_KEY\""}]},{"type":"text","value":"  \nclient "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" OpenAI"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n  \nst"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"title"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"Streamlit ChatGPT\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"if"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'messages'"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"not"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"in"}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n    st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"text","value":"  \n  \nuser_message "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"text_input"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"User:\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"if"}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"button"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"Send\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n    st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"append"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"role\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"user\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"content\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" user_message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n  \n    completion "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" client"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"chat"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"completions"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"create"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"  \n        model"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"gpt-3.5-turbo\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"  \n        messages"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":"st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"  \n    "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n    response "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" completion"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"choices"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","number"]},"children":[{"type":"text","value":"0"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"content  \n    st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"append"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"role\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"assistant\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"content\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" response"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n  \n"},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"for"}]},{"type":"text","value":" message "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"in"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","builtin"]},"children":[{"type":"text","value":"reversed"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"session_state"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"messages"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n    "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"with"}]},{"type":"text","value":" st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"chat_message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'role'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n        "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"if"}]},{"type":"text","value":" message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'role'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'user'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n            st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"write"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'content'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"  \n        "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"else"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":"  \n            st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"write"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'content'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" avatar"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":"st"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"image"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'assets/openai-logo.png'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" width"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"element","tagName":"span","properties":{"className":["token","number"]},"children":[{"type":"text","value":"30"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]}]}]}]}],"data":{"quirksMode":false}},"excerpt":"단 30줄로 ChatGPT 웹페이지 만들기 (Streamlit chat_message) Streamlit은 파이썬 기반의 오픈소스 웹 UI 라이브러리입니다. 매우 간단한 코드로 손쉽게 웹페이지를 띄울 수 있어서 간단한 데모나 PoC…","fields":{"readingTime":{"text":"9 min read"}},"frontmatter":{"title":"단 30줄로 ChatGPT 웹페이지 만들기 (Streamlit chat_message)","userDate":"1 May 2024","date":"2024-05-01T10:00:00.000Z","tags":["toolkit","web","chatgpt"],"excerpt":null,"image":{"childImageSharp":{"gatsbyImageData":{"layout":"fullWidth","backgroundColor":"#f8f8f8","images":{"fallback":{"src":"/static/b359a75bc2a4de550244aa90227da8d0/c131f/streamlit-chatgpt.png","srcSet":"/static/b359a75bc2a4de550244aa90227da8d0/280c7/streamlit-chatgpt.png 750w,\n/static/b359a75bc2a4de550244aa90227da8d0/c3342/streamlit-chatgpt.png 1080w,\n/static/b359a75bc2a4de550244aa90227da8d0/a13e5/streamlit-chatgpt.png 1366w,\n/static/b359a75bc2a4de550244aa90227da8d0/c131f/streamlit-chatgpt.png 1556w","sizes":"100vw"},"sources":[{"srcSet":"/static/b359a75bc2a4de550244aa90227da8d0/5a0e0/streamlit-chatgpt.webp 750w,\n/static/b359a75bc2a4de550244aa90227da8d0/98d4d/streamlit-chatgpt.webp 1080w,\n/static/b359a75bc2a4de550244aa90227da8d0/67e10/streamlit-chatgpt.webp 1366w,\n/static/b359a75bc2a4de550244aa90227da8d0/a1035/streamlit-chatgpt.webp 1556w","type":"image/webp","sizes":"100vw"}]},"width":1,"height":0.8727506426735219}}},"author":[{"id":"Soohwan Kim","bio":"Co-founder/A.I. engineer at TUNiB.","avatar":{"children":[{"gatsbyImageData":{"layout":"fullWidth","backgroundColor":"#282838","images":{"fallback":{"src":"/static/a9e6b445142b247ee4cfa66155398bb2/0d6f4/soohwan.png","srcSet":"/static/a9e6b445142b247ee4cfa66155398bb2/248f9/soohwan.png 40w,\n/static/a9e6b445142b247ee4cfa66155398bb2/fd435/soohwan.png 80w,\n/static/a9e6b445142b247ee4cfa66155398bb2/0d6f4/soohwan.png 120w","sizes":"100vw"},"sources":[{"srcSet":"/static/a9e6b445142b247ee4cfa66155398bb2/e7f45/soohwan.webp 40w,\n/static/a9e6b445142b247ee4cfa66155398bb2/589ec/soohwan.webp 80w,\n/static/a9e6b445142b247ee4cfa66155398bb2/71a38/soohwan.webp 120w","type":"image/webp","sizes":"100vw"}]},"width":1,"height":0.6833333333333333}}]}}]}},"relatedPosts":{"totalCount":25,"edges":[{"node":{"id":"f2a32d9d-b206-5141-8c2d-5440e19caf65","excerpt":"llama.cpp (On device llm inference tool) 최근에 llama.cpp를 사용해봤는데, 상당히 편리하고 미래에 더 많이 쓰일 툴이라는 생각이 들어서 기록해둔다! llama.cpp란? 대표적인 오픈소스 LLM인 Meta…","frontmatter":{"title":"llama.cpp (On device llm inference tool)","date":"2024-09-07T10:00:00.000Z"},"fields":{"readingTime":{"text":"7 min read"},"slug":"/llama-cpp/"}}},{"node":{"id":"fa28b462-1fe2-5d0f-932b-f28e32f1da18","excerpt":"Elastic Search logstash - Nori 토크나이저 설정 이번에 회사에서 검색 기능을 구현하면서 Elastic Search를 다루게 됐다. 이 엔진을 다루면서 삽질을 많이 했는데, 다음에는 하지 않도록 기록용으로 남겨둔다. Elastic…","frontmatter":{"title":"[ELK] Elastic Search logstash - Nori 토크나이저 설정","date":"2024-08-24T10:00:00.000Z"},"fields":{"readingTime":{"text":"4 min read"},"slug":"/elastic-search/"}}},{"node":{"id":"d1f4a9ee-591d-5e95-a930-a1bf17701b0e","excerpt":"단 30줄로 ChatGPT 웹페이지 만들기 (Streamlit chat_message) Streamlit은 파이썬 기반의 오픈소스 웹 UI 라이브러리입니다. 매우 간단한 코드로 손쉽게 웹페이지를 띄울 수 있어서 간단한 데모나 PoC…","frontmatter":{"title":"단 30줄로 ChatGPT 웹페이지 만들기 (Streamlit chat_message)","date":"2024-05-01T10:00:00.000Z"},"fields":{"readingTime":{"text":"9 min read"},"slug":"/streamlit-chatgpt/"}}},{"node":{"id":"4e37b604-dce8-5e09-85e8-337d4f03f0cb","excerpt":"Terabyte(TB) 단위 데이터 셔플링 - terashuf 리눅스에서 TB 단위의 데이터를 line 기준으로 셔플링이 필요할 때가 (가끔) 있다. 직접 코딩해서 쓰기에는 메모리, 속도 등을 신경써야해서 생각보다 큰 작업인데, terashuf…","frontmatter":{"title":"Terabyte(TB) 단위 데이터 셔플링 - terashuf","date":"2024-03-20T10:00:00.000Z"},"fields":{"readingTime":{"text":"1 min read"},"slug":"/terashuf/"}}},{"node":{"id":"ec8327c3-3c4d-51da-9440-8cb74fd1effe","excerpt":"tmux - conf Tmux 설정을 위한 tmux configuraion 기록","frontmatter":{"title":"tmux - conf","date":"2024-02-15T10:00:00.000Z"},"fields":{"readingTime":{"text":"2 min read"},"slug":"/tmux-conf/"}}}]}},"pageContext":{"slug":"/streamlit-chatgpt/","prev":{"excerpt":"GitHub Follow 500 달성!! 최근에 깃허브 팔로워 500명을 달성했습니다! 🎉🎉 창업 이후에는 사실 깃허브 활동을 못하고 있었는데도, 꾸준히 팔로워가 늘어서 어느새 50…","frontmatter":{"title":"GitHub Follow 500 달성!!","tags":["record"],"date":"2024-04-15T10:00:00.000Z","draft":false,"excerpt":null,"image":{"childImageSharp":{"gatsbyImageData":{"layout":"fullWidth","placeholder":{"fallback":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEJ0lEQVQ4y3VSe0zbZRS9P8oKZZZSWkppoeXXByt0G5Ru0Ja20DePDVCGG2xZMO6hG2MC0vDYYAwVFKfOaTM1uAw0ujh1PuKEGWd02SYYR0ubFCgwF6EUhjAeewDlMyUTmY/k/PF9yTk55557YcljXw3vaA8ad9x3Wy2vndAYt+ds21NRXt3b2YH+cM4PW5c8Pcu0Hh/G7PDw5YNtadTmHbWhCUeVuSZKnMlPzOVszKbi2lRDwcTNTnR3wLvMWZGsFvd43TY06XR1dhgyC/PynxLL82M254nlT7I3ZBcXl9+4/OWD4RtoFR8eei5/Ft1WNOV0XrvIYkYTCYEcoTxWXihMzN6wXiVOMPmHp7S89Qaa6V90W1fEf8fwZR53TPVfE+KxVBrOYkYTAmiFGaaWutJfvv34fFvLQNclNOHw/pX8kdhLHpvPfP5WXeleACBgGAng8svmOdePQz3fo/mbS7cd/zvz8tjWqx2flVVUBYWLIETAxiWHdz/d3FD7c/snaMy+Evhf4lEbGrPP3uoSxusgWErk6wJ4GmJ0GsZUQMgmsWLrHddVNGb3/qfzwnA3mnVd6ThPiTUQcA3G0wKu8eNpCQIDxtOFiHTWK1+jOdfCcPc/xV5fz71jzp+kyTqgS/2ERsC1GK71wzWAa4kCPYRJlakZbvsP6E7vI4X5Sprua/+8jSrSACeVzJaQI6X+Ar2fwOAv0BOFBkrUpmB2AkSpSXx167un0HTfotunB996bjumB68LpenAVPnx9cBSA1UcFCIgh21cSxMHUoQYNQ5YagzXQWRaKF/126+X0KTTO2qDhZFuNDfQevok0KQBHBk5zqTI2avMe1aVtUutMmWkP67PLVLnH1Q9sY+esJXIVQBV0lBXi+4NLoxYYWHEimb7dxbtB0YSUETZuw5c/NBy9s3GtrdfudBqOXOq6UKr5b0Txz+yND1fWUsIjYVwWVpWAfJYlzx2QOOOu0PX49U5wFaRIiRCWfah8ppDZZUl5dVH6hufKTEfLKs+cLii1Hw0OX0ngSbGcB1lXdrv3d+hSSegqd7BrvZAXInhOjo7IZCRQBZvUeTsocRnRyRv4yoLQiS5XEU+PSEHGEmkyCRMYASmvOPTs2imH9BM/zfn3gemDASmx1gSapQU2Kk79pvPvGN5tfGF15sbTza/dKyhCQRGf05KUGSSb4thshePH0P3BwHdG2xsqAeGHBOaSBxFKFsCLHVRSc0X59pqa6qPVlcdP1JVXlkHPCMhSs6IWB8k0AJdvmP3PjTTB+jBUHHxcxCaHIwraQwRJWwd8PTASVsTYwqMzSTFZZHEWwjRGuAZiOzNdBqPwpUBU5masR15ugHNur764PSacAmZmxLOENHoAgJPCzwdRGshWuMDd/lU+UZyRDwtLGYtLxVoifWVZjTn+hN6x2L4io37fwAAAABJRU5ErkJggg=="},"images":{"fallback":{"src":"/static/0a0ab0b0a9da3066fcf8f68139ff5e15/24f3d/sooftware.png","srcSet":"/static/0a0ab0b0a9da3066fcf8f68139ff5e15/24f3d/sooftware.png 460w","sizes":"100vw"},"sources":[{"srcSet":"/static/0a0ab0b0a9da3066fcf8f68139ff5e15/b5c5b/sooftware.webp 460w","type":"image/webp","sizes":"100vw"}]},"width":1,"height":1}}},"author":[{"id":"Soohwan Kim","bio":"Co-founder/A.I. engineer at TUNiB.","avatar":{"childImageSharp":{"gatsbyImageData":{"layout":"fullWidth","placeholder":{"fallback":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAADjElEQVQ4y23Oy48TdQDA8TExEaTttvSBfdHddru7bWc6bWd+8+i0u23n0SdlBRQXZGHDgiiLDwgqXjCIJEaC8cLBmHgwUU9EYzRqQuLJi/4NJB6NF+8evgbOHr7XT76SM5ix7s4QnRHnnm9yZzvBTIswN8JcP5bC67ZoWi7CdtFsn5bloZo+dSNAMYbIIqCmD6mJIVXdR3J6I7r9IQ3T59pZlW+uxzndCbPdC/HZXoq3TikowsfqBOjOmFZ7SrM9p2kfRbXn1O0jKNbsSbJ5BMnu9Gl3+qiiz4OPSvz0QRLHFGwOZH6+neLHT5YRbRerM0J0JrTas/8FZXNKzZgg2es+ZtvDdbs8+iHJl+9lWVP7OG2br26k+PvXJCfmFqoYIpwhTXtMwxpTN0coxhjFmCKbE2rGmKoYPQY9qi2fyzsq//4e5sNXi5TlLqbd5t6lPH/9kuDTG2usqgGi7dO0hzSsIXUzQDaGKGKMLEZUxZCKCJB02+PUpMH9vQwP7ybYnSxyfNrjwumA3dEiD94v8cfnK7xzWsbpujQtH9X0qBs+iuEjC5+a7lPVPSqai9SyelyYFbjkh5hqC3TkKOutLON2nkYpgtuMcT6IszdPslo8SLlcpmUH1A0XRQyQhUtNuFQ1l4o2QFI1h3OTVXbcg+grIfSVBRqlEGopgrYSRi0e4KiIse1mScSeopA/iLADmoZL3Rgg631q+oCq1qeq95FOzhQefpzn7eMpBmqcoBVj04pzwkky0eNMRYIdL8F3twusLe2nslrE6g5pGX1U8/FhD1nvUW1tUJK7SH9+n+DR1zF2vQSvH0lz88wiV45V2J1WuHqsxLXNAnuzNJdfWmK5/BylUgFhb6DZAxR9g7rpIos+Wttja2uE9M9vYb69k+DqfJErWzLOuoVqdKlpDo4jODms4zlFckuHObx4iHwuRi6fYqmYY201x/LqMrnFDNl8gRvvukhNdT9394rcOlNFMxrUhYFmW9imTEsp0mhWKC2nWSokyWSiFA7HSKcXiEb34fayyLVniUQk8rmn2drKIqlqiNcuVrh2ymQS1Nh8sc/GoMEbl7u8eb5D1yqTzkRJJsOkkiGymQVShyLE4yHWKnEq1RjpTIhmI8r2y3mkyloI38uha1n6bpVXrkw5+4LD/S/2uHnrIopaJhZ9hmQqwqHkAXJP8BDhyD46ZoWdMxOGcx/PNfECk/8AbxXdRjRliPoAAAAASUVORK5CYII="},"images":{"fallback":{"src":"/static/a9e6b445142b247ee4cfa66155398bb2/7cf1f/soohwan.png","srcSet":"/static/a9e6b445142b247ee4cfa66155398bb2/34f77/soohwan.png 750w,\n/static/a9e6b445142b247ee4cfa66155398bb2/a94f6/soohwan.png 1080w,\n/static/a9e6b445142b247ee4cfa66155398bb2/7cf1f/soohwan.png 1148w","sizes":"100vw"},"sources":[{"srcSet":"/static/a9e6b445142b247ee4cfa66155398bb2/38420/soohwan.webp 750w,\n/static/a9e6b445142b247ee4cfa66155398bb2/7470d/soohwan.webp 1080w,\n/static/a9e6b445142b247ee4cfa66155398bb2/b5ef6/soohwan.webp 1148w","type":"image/webp","sizes":"100vw"}]},"width":1,"height":0.6829268292682927}}}}]},"fields":{"readingTime":{"text":"1 min read"},"layout":"","slug":"/github_follow_500/"}},"next":{"excerpt":"AI Joker 공개 이번에 회사에서 작업한 A.I. Joker 모델을 공개했습니다! Joker 모델은 한국어 Hate Speech를 생성하는 모델입니다. 최근 많은 LLM들이 나오고 있는 만큼 해당 모델들의 Safety…","frontmatter":{"title":"AI Joker 공개","tags":["record"],"date":"2024-07-10T10:00:00.000Z","draft":false,"excerpt":null,"image":{"childImageSharp":{"gatsbyImageData":{"layout":"fullWidth","placeholder":{"fallback":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEMElEQVQ4y22U209UVxTG/Rua9sE0jS9Nrb1YRa1QTaOlSAEtYIqId4R2sLQNF40MAgMyBChVZBBLqohFyk1BGLnOOcPIcFOQuZ+5MJC+tLa2aUx5M2nza8454zCmPqzsk733+s73rf2ttUZymnHbTeFw2QR1tQu4bSb87nG8bhHJJeL3WJQzp20Mt0O955FXRyjfYWKNuqGGy27C57EoyYvee/h9FmbuG3HMCbjmRaamBvB6LQR9E8odn2dcyZGBXPYxJVRAu7rh94wzaGzDYr6NIHSR930uiWVJZOtPotFnEX8ugRyDhsHRdqatd7jTex2v26zkPmO5RnKqzOTNgNeCKHRzsVZPbHocm09Fs+tsEruqY9n93R52FyWyOTeGmP27qdFXMDzUjl9aZalIlpyi8uFxCjhsY3gWRGrqdcTXJFJzrRqHMMq3P9RQcaUSu2mYS1friKtKoLS2CNe8GdvDkTBYCFBQirwcsNLUVEt5lZZTjdmkVR3mz6CHFVMbrPwOT5+wMnqDlSUnR/Unybx4DH1dKRcuVLIUsIYeKix5TCmwMNrF4a8y2Jq1nayibPrNt0g6m8Zi0Mlvvy6SWnyI68YW8nUFbDrxPqma/Qwaf8QvWdQ62sOS1Tou+6bQN5aw48sPySvN51JDPVHbdtDQaKCjs42Nm6LRlZdTVKFle9YOCqvzCLgnQi6RLSTbRmZoG1OscKe/laiEaFLS0tGeLmUyaOVMVzH//vM38JSyngqGpGF02nLSDx3hrdgttLU3seSbwGl/JtklKuxkwIH+G6QkpxK3Zx/f5BUSMPXx5A+JoaEBBvp7efxY4pf7I+TnFfBpajpxH39Cd2czizLgag1VyTJTGdws3OJA2gE+iE1kuvky5/cmU1+Qz5XCQspSUpluqCM+OY34+AQG797E4xLDjaF2Ssg2ckihQ0NDNS+9vI4+Yx9Ww0V0x7Mp/1yDUadl0mrilbVvUKErVmwmRRo7kqEcMuDcrBHTaDcazResf2crPvssf3W38qjFwCPfPFtidnHwYAadHVd5MHtXUfYCYwvhDbmVgoFpfmpv5ujRTDKOZWOdm8TmW+CEJpf0g8e5fs2A7eEYAeleeChEAJqf+4PbKTA3O8TU/SEyczLQlZTx2usbWbvuTbRnzpGVcwSztZeFByPPEQkDrlJWZcvP/7N/mhJDMR99to3eDe9SWXiagoJC+t5+j737ovi6roBlaRJXxNhy2SM6JUzbLiiz78HMXQyNVfT0tlK/fgPamJ3kRO/k/Kvr6O24Sl19JRbxltIhL2AorkoOMXXaVF963eN09rTQ02Kg/XIt3bdbmZ8bYTkwhWNhVHmQ/wFKkYAh2R6HqE5sh0jQb2VxcYpgcIagz4pHqbl6x21fHcyrE9tlUR7CJYM5I0NUkx2hXpcjdKaskZNermGI4X9XYrZBL2fr5QAAAABJRU5ErkJggg=="},"images":{"fallback":{"src":"/static/10b0ae51490d8aac906d05f57899f25a/b5658/joker.png","srcSet":"/static/10b0ae51490d8aac906d05f57899f25a/f054e/joker.png 750w,\n/static/10b0ae51490d8aac906d05f57899f25a/b5658/joker.png 1024w","sizes":"100vw"},"sources":[{"srcSet":"/static/10b0ae51490d8aac906d05f57899f25a/4f03f/joker.webp 750w,\n/static/10b0ae51490d8aac906d05f57899f25a/67ded/joker.webp 1024w","type":"image/webp","sizes":"100vw"}]},"width":1,"height":1}}},"author":[{"id":"Soohwan Kim","bio":"Co-founder/A.I. engineer at TUNiB.","avatar":{"childImageSharp":{"gatsbyImageData":{"layout":"fullWidth","placeholder":{"fallback":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAADjElEQVQ4y23Oy48TdQDA8TExEaTttvSBfdHddru7bWc6bWd+8+i0u23n0SdlBRQXZGHDgiiLDwgqXjCIJEaC8cLBmHgwUU9EYzRqQuLJi/4NJB6NF+8evgbOHr7XT76SM5ix7s4QnRHnnm9yZzvBTIswN8JcP5bC67ZoWi7CdtFsn5bloZo+dSNAMYbIIqCmD6mJIVXdR3J6I7r9IQ3T59pZlW+uxzndCbPdC/HZXoq3TikowsfqBOjOmFZ7SrM9p2kfRbXn1O0jKNbsSbJ5BMnu9Gl3+qiiz4OPSvz0QRLHFGwOZH6+neLHT5YRbRerM0J0JrTas/8FZXNKzZgg2es+ZtvDdbs8+iHJl+9lWVP7OG2br26k+PvXJCfmFqoYIpwhTXtMwxpTN0coxhjFmCKbE2rGmKoYPQY9qi2fyzsq//4e5sNXi5TlLqbd5t6lPH/9kuDTG2usqgGi7dO0hzSsIXUzQDaGKGKMLEZUxZCKCJB02+PUpMH9vQwP7ybYnSxyfNrjwumA3dEiD94v8cfnK7xzWsbpujQtH9X0qBs+iuEjC5+a7lPVPSqai9SyelyYFbjkh5hqC3TkKOutLON2nkYpgtuMcT6IszdPslo8SLlcpmUH1A0XRQyQhUtNuFQ1l4o2QFI1h3OTVXbcg+grIfSVBRqlEGopgrYSRi0e4KiIse1mScSeopA/iLADmoZL3Rgg631q+oCq1qeq95FOzhQefpzn7eMpBmqcoBVj04pzwkky0eNMRYIdL8F3twusLe2nslrE6g5pGX1U8/FhD1nvUW1tUJK7SH9+n+DR1zF2vQSvH0lz88wiV45V2J1WuHqsxLXNAnuzNJdfWmK5/BylUgFhb6DZAxR9g7rpIos+Wttja2uE9M9vYb69k+DqfJErWzLOuoVqdKlpDo4jODms4zlFckuHObx4iHwuRi6fYqmYY201x/LqMrnFDNl8gRvvukhNdT9394rcOlNFMxrUhYFmW9imTEsp0mhWKC2nWSokyWSiFA7HSKcXiEb34fayyLVniUQk8rmn2drKIqlqiNcuVrh2ymQS1Nh8sc/GoMEbl7u8eb5D1yqTzkRJJsOkkiGymQVShyLE4yHWKnEq1RjpTIhmI8r2y3mkyloI38uha1n6bpVXrkw5+4LD/S/2uHnrIopaJhZ9hmQqwqHkAXJP8BDhyD46ZoWdMxOGcx/PNfECk/8AbxXdRjRliPoAAAAASUVORK5CYII="},"images":{"fallback":{"src":"/static/a9e6b445142b247ee4cfa66155398bb2/7cf1f/soohwan.png","srcSet":"/static/a9e6b445142b247ee4cfa66155398bb2/34f77/soohwan.png 750w,\n/static/a9e6b445142b247ee4cfa66155398bb2/a94f6/soohwan.png 1080w,\n/static/a9e6b445142b247ee4cfa66155398bb2/7cf1f/soohwan.png 1148w","sizes":"100vw"},"sources":[{"srcSet":"/static/a9e6b445142b247ee4cfa66155398bb2/38420/soohwan.webp 750w,\n/static/a9e6b445142b247ee4cfa66155398bb2/7470d/soohwan.webp 1080w,\n/static/a9e6b445142b247ee4cfa66155398bb2/b5ef6/soohwan.webp 1148w","type":"image/webp","sizes":"100vw"}]},"width":1,"height":0.6829268292682927}}}}]},"fields":{"readingTime":{"text":"2 min read"},"layout":"","slug":"/joker/"}},"primaryTag":"toolkit"}},
    "staticQueryHashes": ["3170763342","3229353822"]}