diff --git a/contest/docker-compose/jin/README.md b/contest/docker-compose/jin/README.md
new file mode 100644
index 0000000..002cf14
--- /dev/null
+++ b/contest/docker-compose/jin/README.md
@@ -0,0 +1,36 @@
+## LLM chatbot
+### 소개
+chat-gpt와 비슷하게 local LLM(Llama3) 과 대화를 할 수 있는 간단한 웹 애플리케이션입니다.
+- LLM(Large Language Models)은 대규모 언어 모델이라는 뜻으로, 사용자 질문을 입력하면 질문에 대한 답변을 생성하는 언어 AI 모델입니다.
+ - OpenAI의 chat-gpt, Meta의 Llama, Google의 Gemma 등이 대표적인 예입니다.
+- 구현된 앱에는 비교적 작은 Meta의 Llama3-8B 모델을 사용했기 때문에 한국어에 대한 성능은 좋지 않습니다.
+
+
+
+### 실행 방법
+`docker-compose.yml`파일이 있는 폴더로 이동하여 Docker Compose를 사용하여 실행합니다.
+~~~sh
+docker-compose up
+~~~
+- `streamlit` 컨테이너가 실행되고 있는 모습
+
+
+터미널에서 streamlit 컨테이너 실행되고 있으면 아래의 명령어를 통해 Llama3를 ollama 컨테이너에 실행합니다.
+~~~sh
+docker-compose exec ollama ollama run llama3
+~~~
+
+Llama3-8B 모델은 용량이 크기 때문에 실행되는데 약간의 시간이 소요됩니다.
+- llama3가 ollama 컨테이너에서 안정적으로 서빙되고 있다면 다음과 같은 문구가 나타납니다.
+~~~sh
+>>> Send a message (/? for help)
+~~~
+
+이제 웹브라우저에서 `localhost:8502`로 접속하여 채팅을 시작합니다.
+
+### 참고
+- 이 프로젝트는 streamlit 프레임워크를 사용하여 개발되었습니다.
+- 챗봇은 사용자가 질문을 하면 llm이 대답하는 간단한 기능이 포함됐습니다.
+- Ollama는 다양한 LLM을 로컬PC 환경에서 쉽고 빠르게 배포할 수 있게 도와주는 오픈소스입니다.
+ - 따라서, 개인 PC 리소스가 매우 제한적이라면 모델이 실행되지 않거나 답변이 느립니다.
+- 이 프로젝트에서 사용되는 llama3-8B는 최소 8GB의 RAM을 필요로 합니다.
diff --git a/contest/docker-compose/jin/chat.py b/contest/docker-compose/jin/chat.py
new file mode 100644
index 0000000..3c019b3
--- /dev/null
+++ b/contest/docker-compose/jin/chat.py
@@ -0,0 +1,57 @@
+import streamlit as st
+from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
+from langchain.callbacks.manager import CallbackManager
+from langchain_community.llms import ollama
+from langchain_community.chat_models import ollama
+from langchain_core.output_parsers import StrOutputParser
+from langchain_core.prompts import ChatPromptTemplate
+from utils import print_messages, StreamHandler
+
+
+# llama3-8B 모델 생성
+llm =ollama.ChatOllama(
+ model="llama3",
+ base_url="http://ollama:11434",
+ verbose=True,
+ callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
+)
+
+def get_response(user_input):
+ global llm
+ # Prompt 생성
+ prompt = ChatPromptTemplate.from_messages(
+ [
+ ("system", "You are helpful ai assistant. If possible, please answer in Korean "),
+ ("user", "{question}")
+ ]
+ )
+ chain = prompt | llm | StrOutputParser()
+ # LLM 답변 생성
+ response = chain.invoke({"question": user_input})
+ return response
+
+
+st.title("Chat with Llama3")
+if "messages" not in st.session_state.keys():
+ st.session_state["messages"] = [
+ {"role": "assistant", "content": "저에게 질문을 해주세요."}
+ ]
+
+if user_input := st.chat_input("메세지를 입력해 주세요."):
+ # 사용자 입력
+ st.session_state.messages.append({"role": "user", "content": user_input})
+ # st.chat_message("user").write(f"{user_input}")
+ # st.session_state["messages"].append(ChatMessage(role="user", content=user_input))
+
+for message in st.session_state.messages:
+ with st.chat_message(message["role"]):
+ st.write(message["content"])
+
+if st.session_state.messages[-1]["role"] != "assistant":
+ with st.chat_message("assistant"):
+ with st.spinner("답변 생성중..."):
+ stream_handler = StreamHandler(st.empty())
+ response = get_response(user_input)
+ st.write(response)
+ message = {"role": "assistant", "content": response}
+ st.session_state.messages.append(message)
\ No newline at end of file
diff --git a/contest/docker-compose/jin/docker-compose.yaml b/contest/docker-compose/jin/docker-compose.yaml
new file mode 100644
index 0000000..d5d69d1
--- /dev/null
+++ b/contest/docker-compose/jin/docker-compose.yaml
@@ -0,0 +1,29 @@
+version: '3'
+name: docker-ai-chatbot
+services:
+ streamlit:
+ image: python:latest
+ ports:
+ - '8502:8501'
+ networks:
+ - internal-net
+ volumes:
+ - ./chat:/app
+ working_dir: /app
+ command: bash -c "pip install -r requirements.txt && streamlit run chat.py"
+ restart: unless-stopped
+
+ ollama:
+ image: ollama/ollama
+ ports:
+ - '11434:11434'
+ networks:
+ - internal-net
+ volumes:
+ - ./llm:/root/.ollama
+ restart: unless-stopped
+
+networks:
+ internal-net:
+ driver: bridge
+
diff --git a/contest/docker-compose/jin/requirements.txt b/contest/docker-compose/jin/requirements.txt
new file mode 100644
index 0000000..fbf7bb2
--- /dev/null
+++ b/contest/docker-compose/jin/requirements.txt
@@ -0,0 +1,3 @@
+streamlit
+langchain
+langchain-community
\ No newline at end of file
diff --git a/contest/docker-compose/jin/utils.py b/contest/docker-compose/jin/utils.py
new file mode 100644
index 0000000..847e8b9
--- /dev/null
+++ b/contest/docker-compose/jin/utils.py
@@ -0,0 +1,22 @@
+from typing import Any
+from uuid import UUID
+from langchain_core.outputs import ChatGenerationChunk, GenerationChunk
+import streamlit as st
+from langchain_core.callbacks.base import BaseCallbackHandler
+
+
+class StreamHandler(BaseCallbackHandler):
+ def __init__(self, container, initial_text=""):
+ self.container = container
+ self.text = initial_text
+
+ def on_llm_new_token(self, token: str, **kwargs) -> None:
+ self.text += token
+ self.container.markdown(self.text)
+
+
+def print_messages():
+ # 이전 대화기록 출력
+ if "messages" in st.session_state and len(st.session_state["messages"]) > 0:
+ for chat_message in st.session_state["message"]:
+ st.chat_message(chat_message.role).write(chat_message.content)
\ No newline at end of file