Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Environment Configuration Template
# Copy to .env and fill in secrets. .env is gitignored.

# Database Configuration
# SQLite (default):
Expand All @@ -10,10 +11,21 @@ DATABASE_URL=sqlite:///./asktemoc.db
# Enable database query logging
DB_ECHO=false

# ChromaDB Configuration
# ChromaDB Configuration (required for /api/chat RAG)
# Use /app/chroma_db when running in Docker.
CHROMA_PERSIST_DIRECTORY=./app/chroma_db
CHROMA_COLLECTION_NAME=asktemoc_collection

# OpenAI (optional; if set, /api/chat uses OpenAI instead of Ollama)
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o-mini
OPENAI_EMBEDDING_MODEL=text-embedding-3-small

# Ollama (used when OPENAI_API_KEY is not set)
# OLLAMA_BASE_URL=http://localhost:11434
# OLLAMA_MODEL=llama3.1:8b
# OLLAMA_EMBEDDING_MODEL=nomic-embed-text

# FastAPI Configuration
ENVIRONMENT=development
DEBUG=true
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/venv
.env

__pycache__

Expand Down
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM python:3.11-slim

ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_ROOT_USER_ACTION=ignore

WORKDIR /app

# System deps (if you add more heavy libs later, extend this)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*

# Install a minimal, container-focused dependency set to avoid resolver issues
# from the much larger local development requirements.
COPY requirements-docker.txt /app/requirements-docker.txt
RUN pip install --upgrade pip && pip install -r /app/requirements-docker.txt

# Copy application code
COPY . /app

# Expose FastAPI default port
EXPOSE 8000

# Uvicorn entrypoint
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

8 changes: 5 additions & 3 deletions app/services/llm_service.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
from langchain_ollama import ChatOllama
import random


class LLMService:
def __init__(self):
self.llm = ChatOllama(model="llama3.1:8b", temperature=0.4)

def call(self):
# note that this is just a place holder, this class is only for calling the LLM
# note that this is just a place holder, this class is only for calling the LLM
countries = ["Indonesia", "Germany", "China", "France", "Japan", "Brazil"]
content = self.llm.invoke(f"What is the capital of {random.choices(countries)}?").content
content = self.llm.invoke(f"What is the capital of {random.choice(countries)}?").content
return content

async def a_call(self):
# Just know that this is an async call to the LLM hence the 'a_' prefix
countries = ["Indonesia", "Germany", "China", "France", "Japan", "Brazil"]
content = await self.llm.ainvoke(f"What is the capital of {random.choices(countries)}?")
content = await self.llm.ainvoke(f"What is the capital of {random.choice(countries)}?")
return content.content
22 changes: 19 additions & 3 deletions app/services/rag_chain_service.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import os

from langchain_community.llms import Ollama
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableParallel, RunnablePassthrough

from app.services.prompt_service import rag_prompt_template
from app.services.retriever_service import retriever_service
import os


def _get_llm():
"""Use OpenAI if OPENAI_API_KEY is set, otherwise Ollama."""
if os.getenv("OPENAI_API_KEY"):
from langchain_openai import ChatOpenAI
return ChatOpenAI(
model=os.getenv("OPENAI_MODEL", "gpt-4o-mini"),
temperature=0.4,
)
return Ollama(
model=os.getenv("OLLAMA_MODEL", "llama3.1:8b"),
base_url=os.getenv("OLLAMA_BASE_URL", "http://localhost:11434"),
)


class RagChainService:
def __init__(self):
self.retriever = retriever_service.get_retriever()
self.llm = Ollama(model=os.getenv("OLLAMA_MODEL", "llama3.1:8b"), base_url=os.getenv("OLLAMA_BASE_URL", "http://localhost:11434"))
self.llm = _get_llm()

def get_chain(self):
def format_docs(docs):
Expand Down
20 changes: 16 additions & 4 deletions app/services/retriever_service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import os

import chromadb
from langchain_chroma import Chroma
from langchain_community.embeddings import OllamaEmbeddings
import os


def _get_embeddings():
"""Use OpenAI embeddings if OPENAI_API_KEY is set, otherwise Ollama."""
if os.getenv("OPENAI_API_KEY"):
from langchain_openai import OpenAIEmbeddings
return OpenAIEmbeddings(model=os.getenv("OPENAI_EMBEDDING_MODEL", "text-embedding-3-small"))
from langchain_community.embeddings import OllamaEmbeddings
return OllamaEmbeddings(model=os.getenv("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text"))


class RetrieverService:
def __init__(self, collection_name="asktemoc_collection"):
self.client = chromadb.PersistentClient(path=os.getenv("CHROMA_PERSIST_DIRECTORY"))
self.client = chromadb.PersistentClient(
path=os.getenv("CHROMA_PERSIST_DIRECTORY", "./app/chroma_db")
)
self.collection_name = collection_name
self.embeddings = OllamaEmbeddings(model=os.getenv("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text"))
self.embeddings = _get_embeddings()

def get_retriever(self):
vector_store = Chroma(
Expand Down
18 changes: 18 additions & 0 deletions requirements-docker.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
fastapi
uvicorn[standard]
SQLAlchemy
pydantic
pydantic-settings
python-dotenv
requests

# RAG / LLM stack
langchain>=0.3.0
langchain-community
langchain-chroma
langchain-ollama
langchain-openai
chromadb
openai>=1.0.0
crawl4ai