├── src └── ollama_rag │ ├── __init__.py │ └── helpers.py ├── documents ├── README.md └── Searle (1980) - The Chinese Room.pdf ├── .vscode ├── extensions.json └── launch.json ├── .gitignore ├── ollama-rag.code-workspace ├── pyproject.toml ├── README.md ├── requirements.lock └── requirements-dev.lock /src/ollama_rag/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /documents/README.md: -------------------------------------------------------------------------------- 1 | Place your document(s) here. -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-python.python" 4 | ] 5 | } -------------------------------------------------------------------------------- /documents/Searle (1980) - The Chinese Room.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chapagain/ai-discipline-ollama-rag/main/documents/Searle (1980) - The Chinese Room.pdf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # python generated files 2 | __pycache__/ 3 | *.py[oc] 4 | build/ 5 | dist/ 6 | wheels/ 7 | *.egg-info 8 | 9 | # venv 10 | .venv 11 | 12 | .document_store_cache -------------------------------------------------------------------------------- /ollama-rag.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {}, 8 | "launch": { 9 | "version": "0.2.0", 10 | "configurations": [] 11 | } 12 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python Debugger: Launch App", 9 | "type": "debugpy", 10 | "request": "launch", 11 | "module": "ollama_rag" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "ollama-rag" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | authors = [ 6 | { name = "Kyle Alan Hale", email = "khale@rightpoint.com" } 7 | ] 8 | dependencies = [ 9 | "gradio>=4.22.0", 10 | "ollama>=0.1.7", 11 | "haystack-ai>=2.0.0", 12 | "ollama-haystack>=0.0.5", 13 | "pypdf>=4.1.0", 14 | ] 15 | readme = "README.md" 16 | requires-python = ">= 3.11" 17 | 18 | [build-system] 19 | requires = ["hatchling"] 20 | build-backend = "hatchling.build" 21 | 22 | [tool.rye] 23 | managed = true 24 | dev-dependencies = [] 25 | 26 | [tool.hatch.metadata] 27 | allow-direct-references = true 28 | 29 | [tool.hatch.build.targets.wheel] 30 | packages = ["src/ollama_rag"] 31 | -------------------------------------------------------------------------------- /src/ollama_rag/helpers.py: -------------------------------------------------------------------------------- 1 | from haystack import Document 2 | from haystack.document_stores.in_memory import InMemoryDocumentStore 3 | from haystack.document_stores.types import DuplicatePolicy 4 | from typing import Dict, List, Literal 5 | from pathlib import Path 6 | import json 7 | 8 | 9 | class CachedInMemoryDocumentStore(InMemoryDocumentStore): 10 | def __init__(self, bm25_tokenization_regex: str = r"(?u)\b\w\w+\b", bm25_algorithm: Literal['BM25Okapi'] | Literal['BM25L'] | Literal['BM25Plus'] = "BM25L", bm25_parameters: Dict | None = None, embedding_similarity_function: Literal['dot_product'] | Literal['cosine'] = "dot_product"): 11 | super().__init__(bm25_tokenization_regex, bm25_algorithm, bm25_parameters, embedding_similarity_function) 12 | 13 | self.cache_path = Path(__file__).parent.parent.parent / '.document_store_cache' 14 | self.cached = False 15 | self._load_cache() 16 | 17 | def write_documents(self, documents: List[Document], policy: DuplicatePolicy = DuplicatePolicy.NONE) -> int: 18 | documents = super().write_documents(documents, policy) 19 | self._write_cache() 20 | return documents 21 | 22 | def _load_cache(self): 23 | if self.cache_path.exists(): 24 | with open(self.cache_path, 'r') as cache: 25 | documents = [Document.from_dict(document) for document in json.load(cache)] 26 | self.write_documents(documents) 27 | self.cached = True 28 | 29 | def _write_cache(self): 30 | with open(self.cache_path, 'w') as cache: 31 | documents = [document.to_dict() for document in self.storage.values()] 32 | json.dump(documents, cache) 33 | self.cached = True 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AI Discipline Code-Along: Ollama RAG 2 | 27 Mar 2024 3 | 4 | This code-along will focus on a simple RAG implementation that runs locally on your machine using [Ollama](https://ollama.com/). In addition to installing the dependencies below, choose a document with text content that you want to chat with the model about, and store it as a PDF in the `documents` directory. Haystack has support for other document converters as well, although you may need to install additional dependencies. This code-along will assume you're using a PDF. 5 | 6 | ## Dependencies 7 | 8 | * Python 3.11+ (Rye will automatically use 3.11 by default; see below) 9 | * VS Code () with the Python extension (search in Extensions in the side bar) 10 | * Rye (), to manage the project’s Python third-party dependencies and Python interpreter version. For Windows users, you’ll likely want to use the 64-bit installer. 11 | * Ollama () 12 | 13 | ## Setup 14 | First, clone this repo, and open the `ollama-rag.code-workspace` file in VS Code. 15 | 16 | From the terminal in VS Code, install the Python dependencies using Rye: 17 | 18 | ```shell 19 | $ rye sync 20 | ``` 21 | 22 | This will install the following Python dependencies in a virtual environment: `gradio ollama haystack-ai ollama-haystack pypdf`. If VS Code prompts you to select the new environment for the workspace, say yes. 23 | 24 | Next, use Ollama to pull down the models you want to use. Do these two, at least: 25 | 26 | ```shell 27 | $ ollama pull llama2 28 | $ ollama pull nomic-embed-text 29 | ``` 30 | 31 | Test it out by chatting with it on the command line: 32 | 33 | ```shell 34 | $ ollama run llama2 35 | ``` 36 | 37 | If you’d like, check out the supported models at and pull any that you’d like to try. Unless you have a powerful GPU, it’s recommended that you use models in the 7b-parameter and under category. If your machine only supports running on CPU and you want to speed that up, there are smaller models such as `gemma:2b` that you can try, although the performance will not be as good. In general, the more parameters the model has, the better its accuracy, the more resources it requires, and the more slowly it runs. I’ll be doing the code-along with the `llama2:7b` model, but feel free to experiment and use what you like best! 38 | -------------------------------------------------------------------------------- /requirements.lock: -------------------------------------------------------------------------------- 1 | # generated by rye 2 | # use `rye lock` or `rye sync` to update this lockfile 3 | # 4 | # last locked with the following flags: 5 | # pre: false 6 | # features: [] 7 | # all-features: false 8 | # with-sources: false 9 | 10 | -e file:. 11 | aiofiles==23.2.1 12 | # via gradio 13 | altair==5.2.0 14 | # via gradio 15 | annotated-types==0.6.0 16 | # via pydantic 17 | anyio==4.3.0 18 | # via httpx 19 | # via openai 20 | # via starlette 21 | attrs==23.2.0 22 | # via jsonschema 23 | # via referencing 24 | backoff==2.2.1 25 | # via posthog 26 | boilerpy3==1.0.7 27 | # via haystack-ai 28 | certifi==2024.2.2 29 | # via httpcore 30 | # via httpx 31 | # via requests 32 | charset-normalizer==3.3.2 33 | # via requests 34 | click==8.1.7 35 | # via typer 36 | # via uvicorn 37 | colorama==0.4.6 38 | # via typer 39 | contourpy==1.2.0 40 | # via matplotlib 41 | cycler==0.12.1 42 | # via matplotlib 43 | distro==1.9.0 44 | # via openai 45 | fastapi==0.110.0 46 | # via gradio 47 | ffmpy==0.3.2 48 | # via gradio 49 | filelock==3.13.1 50 | # via huggingface-hub 51 | fonttools==4.50.0 52 | # via matplotlib 53 | fsspec==2024.3.1 54 | # via gradio-client 55 | # via huggingface-hub 56 | gradio==4.22.0 57 | # via ollama-rag 58 | gradio-client==0.13.0 59 | # via gradio 60 | h11==0.14.0 61 | # via httpcore 62 | # via uvicorn 63 | haystack-ai==2.0.0 64 | # via ollama-haystack 65 | # via ollama-rag 66 | haystack-bm25==1.0.2 67 | # via haystack-ai 68 | httpcore==1.0.4 69 | # via httpx 70 | httpx==0.25.2 71 | # via gradio 72 | # via gradio-client 73 | # via ollama 74 | # via openai 75 | huggingface-hub==0.21.4 76 | # via gradio 77 | # via gradio-client 78 | idna==3.6 79 | # via anyio 80 | # via httpx 81 | # via requests 82 | importlib-resources==6.4.0 83 | # via gradio 84 | jinja2==3.1.3 85 | # via altair 86 | # via gradio 87 | # via haystack-ai 88 | jsonschema==4.21.1 89 | # via altair 90 | jsonschema-specifications==2023.12.1 91 | # via jsonschema 92 | kiwisolver==1.4.5 93 | # via matplotlib 94 | lazy-imports==0.3.1 95 | # via haystack-ai 96 | markdown-it-py==3.0.0 97 | # via rich 98 | markupsafe==2.1.5 99 | # via gradio 100 | # via jinja2 101 | matplotlib==3.8.3 102 | # via gradio 103 | mdurl==0.1.2 104 | # via markdown-it-py 105 | monotonic==1.6 106 | # via posthog 107 | more-itertools==10.2.0 108 | # via haystack-ai 109 | networkx==3.2.1 110 | # via haystack-ai 111 | numpy==1.26.4 112 | # via altair 113 | # via contourpy 114 | # via gradio 115 | # via haystack-ai 116 | # via haystack-bm25 117 | # via matplotlib 118 | # via pandas 119 | ollama==0.1.7 120 | # via ollama-rag 121 | ollama-haystack==0.0.5 122 | # via ollama-rag 123 | openai==1.14.2 124 | # via haystack-ai 125 | orjson==3.9.15 126 | # via gradio 127 | packaging==24.0 128 | # via altair 129 | # via gradio 130 | # via gradio-client 131 | # via huggingface-hub 132 | # via matplotlib 133 | pandas==2.2.1 134 | # via altair 135 | # via gradio 136 | # via haystack-ai 137 | pillow==10.2.0 138 | # via gradio 139 | # via matplotlib 140 | posthog==3.5.0 141 | # via haystack-ai 142 | pydantic==2.6.4 143 | # via fastapi 144 | # via gradio 145 | # via openai 146 | pydantic-core==2.16.3 147 | # via pydantic 148 | pydub==0.25.1 149 | # via gradio 150 | pygments==2.17.2 151 | # via rich 152 | pyparsing==3.1.2 153 | # via matplotlib 154 | pypdf==4.1.0 155 | # via ollama-rag 156 | python-dateutil==2.9.0.post0 157 | # via haystack-ai 158 | # via matplotlib 159 | # via pandas 160 | # via posthog 161 | python-multipart==0.0.9 162 | # via gradio 163 | pytz==2024.1 164 | # via pandas 165 | pyyaml==6.0.1 166 | # via gradio 167 | # via haystack-ai 168 | # via huggingface-hub 169 | referencing==0.34.0 170 | # via jsonschema 171 | # via jsonschema-specifications 172 | requests==2.31.0 173 | # via haystack-ai 174 | # via huggingface-hub 175 | # via ollama-haystack 176 | # via posthog 177 | rich==13.7.1 178 | # via typer 179 | rpds-py==0.18.0 180 | # via jsonschema 181 | # via referencing 182 | ruff==0.3.4 183 | # via gradio 184 | semantic-version==2.10.0 185 | # via gradio 186 | shellingham==1.5.4 187 | # via typer 188 | six==1.16.0 189 | # via posthog 190 | # via python-dateutil 191 | sniffio==1.3.1 192 | # via anyio 193 | # via httpx 194 | # via openai 195 | starlette==0.36.3 196 | # via fastapi 197 | tenacity==8.2.3 198 | # via haystack-ai 199 | tomlkit==0.12.0 200 | # via gradio 201 | toolz==0.12.1 202 | # via altair 203 | tqdm==4.66.2 204 | # via haystack-ai 205 | # via huggingface-hub 206 | # via openai 207 | typer==0.10.0 208 | # via gradio 209 | typing-extensions==4.10.0 210 | # via fastapi 211 | # via gradio 212 | # via gradio-client 213 | # via haystack-ai 214 | # via huggingface-hub 215 | # via openai 216 | # via pydantic 217 | # via pydantic-core 218 | # via typer 219 | tzdata==2024.1 220 | # via pandas 221 | urllib3==2.2.1 222 | # via requests 223 | uvicorn==0.29.0 224 | # via gradio 225 | websockets==11.0.3 226 | # via gradio-client 227 | -------------------------------------------------------------------------------- /requirements-dev.lock: -------------------------------------------------------------------------------- 1 | # generated by rye 2 | # use `rye lock` or `rye sync` to update this lockfile 3 | # 4 | # last locked with the following flags: 5 | # pre: false 6 | # features: [] 7 | # all-features: false 8 | # with-sources: false 9 | 10 | -e file:. 11 | aiofiles==23.2.1 12 | # via gradio 13 | altair==5.2.0 14 | # via gradio 15 | annotated-types==0.6.0 16 | # via pydantic 17 | anyio==4.3.0 18 | # via httpx 19 | # via openai 20 | # via starlette 21 | attrs==23.2.0 22 | # via jsonschema 23 | # via referencing 24 | backoff==2.2.1 25 | # via posthog 26 | boilerpy3==1.0.7 27 | # via haystack-ai 28 | certifi==2024.2.2 29 | # via httpcore 30 | # via httpx 31 | # via requests 32 | charset-normalizer==3.3.2 33 | # via requests 34 | click==8.1.7 35 | # via typer 36 | # via uvicorn 37 | colorama==0.4.6 38 | # via typer 39 | contourpy==1.2.0 40 | # via matplotlib 41 | cycler==0.12.1 42 | # via matplotlib 43 | distro==1.9.0 44 | # via openai 45 | fastapi==0.110.0 46 | # via gradio 47 | ffmpy==0.3.2 48 | # via gradio 49 | filelock==3.13.1 50 | # via huggingface-hub 51 | fonttools==4.50.0 52 | # via matplotlib 53 | fsspec==2024.3.1 54 | # via gradio-client 55 | # via huggingface-hub 56 | gradio==4.22.0 57 | # via ollama-rag 58 | gradio-client==0.13.0 59 | # via gradio 60 | h11==0.14.0 61 | # via httpcore 62 | # via uvicorn 63 | haystack-ai==2.0.0 64 | # via ollama-haystack 65 | # via ollama-rag 66 | haystack-bm25==1.0.2 67 | # via haystack-ai 68 | httpcore==1.0.4 69 | # via httpx 70 | httpx==0.25.2 71 | # via gradio 72 | # via gradio-client 73 | # via ollama 74 | # via openai 75 | huggingface-hub==0.21.4 76 | # via gradio 77 | # via gradio-client 78 | idna==3.6 79 | # via anyio 80 | # via httpx 81 | # via requests 82 | importlib-resources==6.4.0 83 | # via gradio 84 | jinja2==3.1.3 85 | # via altair 86 | # via gradio 87 | # via haystack-ai 88 | jsonschema==4.21.1 89 | # via altair 90 | jsonschema-specifications==2023.12.1 91 | # via jsonschema 92 | kiwisolver==1.4.5 93 | # via matplotlib 94 | lazy-imports==0.3.1 95 | # via haystack-ai 96 | markdown-it-py==3.0.0 97 | # via rich 98 | markupsafe==2.1.5 99 | # via gradio 100 | # via jinja2 101 | matplotlib==3.8.3 102 | # via gradio 103 | mdurl==0.1.2 104 | # via markdown-it-py 105 | monotonic==1.6 106 | # via posthog 107 | more-itertools==10.2.0 108 | # via haystack-ai 109 | networkx==3.2.1 110 | # via haystack-ai 111 | numpy==1.26.4 112 | # via altair 113 | # via contourpy 114 | # via gradio 115 | # via haystack-ai 116 | # via haystack-bm25 117 | # via matplotlib 118 | # via pandas 119 | ollama==0.1.7 120 | # via ollama-rag 121 | ollama-haystack==0.0.5 122 | # via ollama-rag 123 | openai==1.14.2 124 | # via haystack-ai 125 | orjson==3.9.15 126 | # via gradio 127 | packaging==24.0 128 | # via altair 129 | # via gradio 130 | # via gradio-client 131 | # via huggingface-hub 132 | # via matplotlib 133 | pandas==2.2.1 134 | # via altair 135 | # via gradio 136 | # via haystack-ai 137 | pillow==10.2.0 138 | # via gradio 139 | # via matplotlib 140 | posthog==3.5.0 141 | # via haystack-ai 142 | pydantic==2.6.4 143 | # via fastapi 144 | # via gradio 145 | # via openai 146 | pydantic-core==2.16.3 147 | # via pydantic 148 | pydub==0.25.1 149 | # via gradio 150 | pygments==2.17.2 151 | # via rich 152 | pyparsing==3.1.2 153 | # via matplotlib 154 | pypdf==4.1.0 155 | # via ollama-rag 156 | python-dateutil==2.9.0.post0 157 | # via haystack-ai 158 | # via matplotlib 159 | # via pandas 160 | # via posthog 161 | python-multipart==0.0.9 162 | # via gradio 163 | pytz==2024.1 164 | # via pandas 165 | pyyaml==6.0.1 166 | # via gradio 167 | # via haystack-ai 168 | # via huggingface-hub 169 | referencing==0.34.0 170 | # via jsonschema 171 | # via jsonschema-specifications 172 | requests==2.31.0 173 | # via haystack-ai 174 | # via huggingface-hub 175 | # via ollama-haystack 176 | # via posthog 177 | rich==13.7.1 178 | # via typer 179 | rpds-py==0.18.0 180 | # via jsonschema 181 | # via referencing 182 | ruff==0.3.4 183 | # via gradio 184 | semantic-version==2.10.0 185 | # via gradio 186 | shellingham==1.5.4 187 | # via typer 188 | six==1.16.0 189 | # via posthog 190 | # via python-dateutil 191 | sniffio==1.3.1 192 | # via anyio 193 | # via httpx 194 | # via openai 195 | starlette==0.36.3 196 | # via fastapi 197 | tenacity==8.2.3 198 | # via haystack-ai 199 | tomlkit==0.12.0 200 | # via gradio 201 | toolz==0.12.1 202 | # via altair 203 | tqdm==4.66.2 204 | # via haystack-ai 205 | # via huggingface-hub 206 | # via openai 207 | typer==0.10.0 208 | # via gradio 209 | typing-extensions==4.10.0 210 | # via fastapi 211 | # via gradio 212 | # via gradio-client 213 | # via haystack-ai 214 | # via huggingface-hub 215 | # via openai 216 | # via pydantic 217 | # via pydantic-core 218 | # via typer 219 | tzdata==2024.1 220 | # via pandas 221 | urllib3==2.2.1 222 | # via requests 223 | uvicorn==0.29.0 224 | # via gradio 225 | websockets==11.0.3 226 | # via gradio-client 227 | --------------------------------------------------------------------------------