Skip to content
Draft
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@ project_podcast_summarizer/data/summaries/*.json
project_podcast_summarizer/data/transcripts/mini.txt

# fine tuning
*.jsonl
*.jsonl

# Projects
project_rag/app/index_store/*.json
41 changes: 41 additions & 0 deletions project_rag/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## New Additions

- Data Engineering Now Generates the Index Store
- App now loads the index store
- Chatbot Queries now operate with RAG

## New Project Local Setup
- cd into project_rag directory
- Create new virtualenv and activate it
- pip install -r requirements.txt
- PYTHONPATH=../ python data_engineering/rag_index_generator.py # note this uses the parent directory for PYTHONPATH

If you get:
```shell
Traceback (most recent call last):
File "/PATH/TO/REPO/ai-engineering-course/project_rag/data_engineering/rag_index_generator.py", line 12, in <module>
from shared.settings import DATA_DIR, BASE_DIR
ModuleNotFoundError: No module named 'shared'
```
It is because you have not appended the repo root directory to your PYTHONPATH environment variable

## Code New Additions
- RAG index generation (offline)
- New endpoint with chat inference (online) (incl. new schema)
- New chatbot template (online)
- RAG capabilities for this endpoint (online + deps.py)
- Split out config and New evar


## Project Local Setup (Same as previous project)

1. cd into project directory & create virtualenv & activate it
2. `pip install -r requirements.txt`
3. Run the DB migrations `PYTHONPATH=. python prestart.py` (only required once)
4. Run the FastAPI server Python command: `PYTHONPATH=. python app/main.py`
6. Open http://localhost:8001/


## Troubleshooting
`ModuleNotFoundError: No module named 'project_rag'` - means that you need to add the
`project_rag` directory to your PYTHONPATH.
71 changes: 71 additions & 0 deletions project_rag/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# A generic, single database configuration.

[alembic]
# path to migration scripts
script_location = alembic

# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# timezone to use when rendering the date
# within the migration file as well as the filename.
# string value is passed to dateutil.tz.gettz()
# leave blank for localtime
# timezone =

# max length of characters to apply to the
# "slug" field
#truncate_slug_length = 40

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false

# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false

# version location specification; this defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat alembic/versions

# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8

# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
1 change: 1 addition & 0 deletions project_rag/alembic/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic single-database configuration.
91 changes: 91 additions & 0 deletions project_rag/alembic/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from __future__ import with_statement
from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine
from sqlalchemy.engine import Connection
import asyncio

from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
# target_metadata = None

from app.db.base_class import Base # noqa
from app.db.session import SQLALCHEMY_DATABASE_URI
from app.models.podcast import Podcast, Episode, Summary

target_metadata = Base.metadata


def get_url():
return SQLALCHEMY_DATABASE_URI


def run_migrations_offline():
"""Run migrations in 'offline' mode.

This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.

Calls to context.execute() here emit the given string to the
script output.

"""
url = get_url()
context.configure(
url=url, target_metadata=target_metadata, literal_binds=True, compare_type=True
)

with context.begin_transaction():
context.run_migrations()


def do_run_migrations(connection: Connection) -> None:
context.configure(connection=connection, target_metadata=target_metadata)

with context.begin_transaction():
context.run_migrations()

async def run_async_migrations() -> None:
"""In this scenario we need to create an Engine
and associate a connection with the context.

"""

configuration = config.get_section(config.config_ini_section)
configuration["sqlalchemy.url"] = get_url()

# Using create_async_engine instead of engine_from_config
connectable: AsyncEngine = create_async_engine(
configuration["sqlalchemy.url"],
echo=True,
)

async with connectable.connect() as connection:
await connection.run_sync(do_run_migrations)

await connectable.dispose()

def run_migrations_online() -> None:
"""Run migrations in 'online' mode."""

asyncio.run(run_async_migrations())


if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
24 changes: 24 additions & 0 deletions project_rag/alembic/script.py.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade():
${upgrades if upgrades else "pass"}


def downgrade():
${downgrades if downgrades else "pass"}
51 changes: 51 additions & 0 deletions project_rag/alembic/versions/728c3af72e3d_initial_tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""initial tables

Revision ID: 728c3af72e3d
Revises:
Create Date: 2024-02-24 17:02:03.549236

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '728c3af72e3d'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('podcast',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('episode',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('title', sa.String(length=255), nullable=False),
sa.Column('url', sa.String(length=512), nullable=True),
sa.Column('podcast_id', sa.Integer(), nullable=False),
sa.Column('transcript', sa.Text(), nullable=True),
sa.ForeignKeyConstraint(['podcast_id'], ['podcast.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('summary',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('content', sa.Text(), nullable=True),
sa.Column('episode_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['episode_id'], ['episode.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('episode_id')
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('summary')
op.drop_table('episode')
op.drop_table('podcast')
# ### end Alembic commands ###
Empty file added project_rag/app/__init__.py
Empty file.
56 changes: 56 additions & 0 deletions project_rag/app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import pathlib
from typing import Optional

from dotenv import load_dotenv
from pydantic_settings import BaseSettings

load_dotenv()

# Project Directories
ROOT: pathlib.Path = pathlib.Path(__file__).resolve().parent.parent
PROMPT_DIR: pathlib.Path = ROOT / 'data_engineering' / 'prompts'
TRANSCRIPT_DIR: pathlib.Path = ROOT / 'data' / 'transcripts'
SUMMARY_DIR: pathlib.Path = ROOT / 'data' / 'summaries'
MODEL_DIR: pathlib.Path = ROOT / 'data_engineering' / 'models'
INDEX_DIR: pathlib.Path = ROOT / "app" / "index_store"

class LLMSettings(BaseSettings):
"""
Defines the settings for the Large Language Model (LLM).

Attributes:
CONTEXT_WINDOW (int): The context window size for the LLM.
N_GPU_LAYERS (int): The number of GPU layers to be used by the LLM.
MAX_TOKENS (int): The maximum number of tokens to be generated in one response.
TEMPERATURE (float): The temperature setting for the LLM's creativity in responses.
MODEL (str): The identifier for the LLM model to be used.
TOGETHER_API_KEY (str): The API key for accessing the LLM, expected to be loaded from the environment.
"""
CONTEXT_WINDOW: int = 16000
N_GPU_LAYERS: int = 1
MAX_TOKENS: int = 512
TEMPERATURE: float = 0.8
MODEL: str = "mistralai/Mixtral-8x7B-Instruct-v0.1"
TOGETHER_API_KEY: str # picked up from environment

class Settings(BaseSettings):
"""
Configuration settings for the application, including database and LLM configurations.

Attributes:
SQLALCHEMY_DATABASE_URI (Optional[str]): The database connection URI.
llm (LLMSettings): Nested settings for configuring the Large Language Model.
"""
SQLALCHEMY_DATABASE_URI: Optional[str] = "sqlite:///example.db"
llm: LLMSettings = LLMSettings()

class Config:
"""
Configuration class for settings.

Attributes:
case_sensitive (bool): Specifies if the configuration keys should be case-sensitive.
"""
case_sensitive: bool = True

settings: Settings = Settings()
1 change: 1 addition & 0 deletions project_rag/app/crud/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .crud_podcast import podcast, episode, summary
Loading