diff --git a/app/docker-compose.yml b/app/docker-compose.yml index d79b895..69ae235 100644 --- a/app/docker-compose.yml +++ b/app/docker-compose.yml @@ -1,11 +1,10 @@ version: "3.9" -services: - chroma: - image: ghcr.io/chroma-core/chroma:latest - ports: - - "8000:8000" - volumes: - - chroma_data:/chroma -volumes: - chroma_data: +services: + streamlit: + build: ./streamlit + ports: + - "8501:8501" + volumes: + - ./llmops/src/rag_cot/chroma_db:/app/llmops/src/rag_cot/chroma_db + diff --git a/app/streamlit/Dockerfile b/app/streamlit/Dockerfile new file mode 100644 index 0000000..b0e9b15 --- /dev/null +++ b/app/streamlit/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.11-slim + +WORKDIR /app/streamlit + +COPY Pipfile Pipfile.lock ./ + +RUN pip install pipenv && pipenv install --system --deploy + +COPY Chatbot.py . +COPY .env . + +EXPOSE 8501 + +ENTRYPOINT ["streamlit", "run", "Chatbot.py"] \ No newline at end of file diff --git a/app/streamlit/Pipfile b/app/streamlit/Pipfile index b597ad0..181cf2e 100644 --- a/app/streamlit/Pipfile +++ b/app/streamlit/Pipfile @@ -20,6 +20,10 @@ sentence_transformers = "*" chromadb = "*" [dev-packages] +pytest = "==8.0.0" +pytest-cov = "==4.1.0" +pytest-mock = "==3.10.0" +pytest-asyncio = "*" [requires] python_version = "3.11" diff --git a/app/streamlit/Pipfile.lock b/app/streamlit/Pipfile.lock index f4da31a..298d70c 100644 --- a/app/streamlit/Pipfile.lock +++ b/app/streamlit/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5183bf932da47853d42a74c296d1a5b0e4330819279f26dc613ada3522ae1869" + "sha256": "68da9f2cf2dea795e4bb8d4f5b108a40e1fe4255c7d8dbe9233f9db6f993f876" }, "pipfile-spec": 6, "requires": { @@ -981,11 +981,11 @@ }, "huggingface-hub": { "hashes": [ - "sha256:352f69caf16566c7b6de84b54a822f6238e17ddd8ae3da4f8f2272aea5b198d5", - "sha256:9524eae42077b8ff4fc459ceb7a514eca1c1232b775276b009709fe2a084f250" + "sha256:590b29c0dcbd0ee4b7b023714dc1ad8563fe4a68a91463438b74e980d28afaf3", + "sha256:c56f20fca09ef19da84dcde2b76379ecdaddf390b083f59f166715584953307d" ], "markers": "python_full_version >= '3.8.0'", - "version": "==0.29.1" + "version": "==0.29.2" }, "humanfriendly": { "hashes": [ @@ -3992,5 +3992,138 @@ "version": "==0.23.0" } }, - "develop": {} + "develop": { + "coverage": { + "extras": [ + "toml" + ], + "hashes": [ + "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95", + "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9", + "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe", + "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0", + "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924", + "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574", + "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702", + "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3", + "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b", + "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2", + "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea", + "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f", + "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3", + "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674", + "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9", + "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0", + "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e", + "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef", + "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb", + "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87", + "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1", + "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2", + "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703", + "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e", + "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd", + "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3", + "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4", + "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45", + "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa", + "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31", + "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8", + "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86", + "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6", + "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288", + "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf", + "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929", + "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc", + "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985", + "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3", + "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd", + "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e", + "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879", + "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57", + "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a", + "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad", + "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba", + "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d", + "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750", + "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c", + "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c", + "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f", + "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015", + "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558", + "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f", + "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d", + "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d", + "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425", + "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3", + "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953", + "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827", + "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c", + "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f", + "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73" + ], + "markers": "python_version >= '3.9'", + "version": "==7.6.12" + }, + "iniconfig": { + "hashes": [ + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, + "packaging": { + "hashes": [ + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2" + }, + "pluggy": { + "hashes": [ + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "pytest": { + "hashes": [ + "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c", + "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==8.0.0" + }, + "pytest-asyncio": { + "hashes": [ + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.23.8" + }, + "pytest-cov": { + "hashes": [ + "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", + "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==4.1.0" + }, + "pytest-mock": { + "hashes": [ + "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b", + "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==3.10.0" + } + } } diff --git a/app/streamlit/tests/test_chatbot.py b/app/streamlit/tests/test_chatbot.py new file mode 100644 index 0000000..97ad3d1 --- /dev/null +++ b/app/streamlit/tests/test_chatbot.py @@ -0,0 +1,39 @@ +import pytest +import streamlit as st +from unittest.mock import patch + +# add app/streamlit to sys.path +import sys +sys.path.insert(0, "/Users/leehongkai/projects/aimingmed/aimingmed-ai/app/streamlit") + +from unittest.mock import patch, MagicMock + + +def test_title(): + with patch("streamlit.title") as mock_title, \ + patch("streamlit.session_state", new_callable=MagicMock) as mock_session_state: + import Chatbot + st.session_state["messages"] = [] + mock_title.assert_called_once_with("💬 RAG AI for Medical Guideline") + +def test_caption(): + with patch("streamlit.caption") as mock_caption, \ + patch("streamlit.session_state", new_callable=MagicMock) as mock_session_state: + import Chatbot + st.session_state["messages"] = [] + mock_caption.assert_called() + +def test_chat_input(): + with patch("streamlit.chat_input", return_value="test_prompt") as mock_chat_input, \ + patch("streamlit.session_state", new_callable=MagicMock) as mock_session_state: + import Chatbot + st.session_state["messages"] = [] + mock_chat_input.assert_called_once() + +def test_chat_message(): + with patch("streamlit.chat_message") as mock_chat_message, \ + patch("streamlit.session_state", new_callable=MagicMock) as mock_session_state: + with patch("streamlit.chat_input", return_value="test_prompt"): + import Chatbot + st.session_state["messages"] = [] + mock_chat_message.assert_called() \ No newline at end of file