Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The first revision #8

Merged
merged 9 commits into from
Mar 1, 2025
Merged
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
17 changes: 17 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[run]
# Exclude test files and specific init files from the coverage report
omit =
*/tests/*
*/test_*.py
*/__init__.py # Good idea to exclude __init__.py files from the coverage report

# Include source files only from certain directories
source =
easy_letters
notebooks

# Set parallel to true if you run tests in parallel
parallel = True

# Enable branch coverage if set to True
branch = False
32 changes: 17 additions & 15 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,29 @@
# Top-most EditorConfig file
root = true

# Python specific settings, complying with PEP 8 style guide
# Global settings (applicable to all files unless overridden)
[*]
charset = utf-8 # Default character encoding
end_of_line = lf # Use LF for line endings (Unix-style)
indent_style = space # Use spaces for indentation
indent_size = 4 # Default indentation size
insert_final_newline = true # Make sure files end with a newline
trim_trailing_whitespace = true # Remove trailing whitespace

# Python specific settings, complying with PEP 8 style guide, except for the line length
[*.py]
indent_size = 4
max_line_length = 80
max_line_length = 100

# Markdown files
[*.md]
trim_trailing_whitespace = false

# Bash scripts
[*.sh]
indent_size = 2

# SQL files
[*.sql]
indent_size = 2
trim_trailing_whitespace = false # Don't remove trailing whitespace in Markdown files
max_line_length = 120

# YAML files
[*.yml]
[*.{yaml,yml}]
indent_size = 2

# JSON files
[*.json]
# Shell scripts
[*.sh]
indent_size = 2
indent_style = tab
73 changes: 69 additions & 4 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,8 +1,73 @@
# Adding the following lines to the .gitattributes file will tell Git to treat the files as binary data.
*.text filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
# Common document and text file formats
*.docx filter=lfs diff=lfs merge=lfs -text
*.doc filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.djvu filter=lfs diff=lfs merge=lfs -text
*.eps filter=lfs diff=lfs merge=lfs -text
*.odt filter=lfs diff=lfs merge=lfs -text
*.rtf filter=lfs diff=lfs merge=lfs -text
*.ps filter=lfs diff=lfs merge=lfs -text
*.xls filter=lfs diff=lfs merge=lfs -text
*.xlsx filter=lfs diff=lfs merge=lfs -text
*.ppt filter=lfs diff=lfs merge=lfs -text
*.pptx filter=lfs diff=lfs merge=lfs -text

# Common image formats
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.csv filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.svgz filter=lfs diff=lfs merge=lfs -text

# Common compressed file formats
*.zip filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.7z filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text

# Common file formats in machine learning projects
*.bin filter=lfs diff=lfs merge=lfs -text
*.model filter=lfs diff=lfs merge=lfs -text
*.h5 filter=lfs diff=lfs merge=lfs -text
*.tfrecord filter=lfs diff=lfs merge=lfs -text
*.hdf5 filter=lfs diff=lfs merge=lfs -text
*.keras filter=lfs diff=lfs merge=lfs -text
*.pth filter=lfs diff=lfs merge=lfs -text
*.pt filter=lfs diff=lfs merge=lfs -text
*.joblib filter=lfs diff=lfs merge=lfs -text
*.pkl filter=lfs diff=lfs merge=lfs -text
*.pickle filter=lfs diff=lfs merge=lfs -text
*.npy filter=lfs diff=lfs merge=lfs -text

# Common audio and video formats
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.avi filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.flac filter=lfs diff=lfs merge=lfs -text
*.mkv filter=lfs diff=lfs merge=lfs -text
*.webm filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.ogv filter=lfs diff=lfs merge=lfs -text

# Common data transfer formats
#*.csv filter=lfs diff=lfs merge=lfs -text
#*.tsv filter=lfs diff=lfs merge=lfs -text
#*.json filter=lfs diff=lfs merge=lfs -text
#*.xml filter=lfs diff=lfs merge=lfs -text
*.parquet filter=lfs diff=lfs merge=lfs -text
*.feather filter=lfs diff=lfs merge=lfs -text
*.msgpack filter=lfs diff=lfs merge=lfs -text
*.avro filter=lfs diff=lfs merge=lfs -text
*.arrow filter=lfs diff=lfs merge=lfs -text
*.orc filter=lfs diff=lfs merge=lfs -text

# Exclude files from language stats (GitHub Linguist)
*.ipynb linguist-vendored
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ name: Publish to PyPI

on:
workflow_dispatch: # Enable manual runs
tag:
- 'v*' # Run on version tags

jobs:

# Run tests before publishing
# Run the tests before publishing to PyPI
call_tests:
uses: ./.github/workflows/tests.yml

Expand All @@ -30,10 +32,6 @@ jobs:
run: |
poetry install

# - name: Update Version
# run: |
# poetry version patch # Use 'minor' or 'major' for minor or major version bumps

- name: Build and Publish Package
run: |
poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }}
Expand Down
21 changes: 9 additions & 12 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
name: Tests
name: Run Tests

on:
# push:
# branches:
# - main
workflow_dispatch: # Enable manual runs
workflow_call: # Make this workflow available to be called by other workflows

Expand All @@ -13,7 +10,7 @@ jobs:

strategy:
matrix:
python-version: [ "3.10", "3.11", "3.12" ]
python-version: [ "3.10", "3.11", "3.12", "3.13" ]

steps:
- name: Checkout Repository
Expand All @@ -30,18 +27,18 @@ jobs:

- name: Install Dependencies
run: |
poetry install --with dev
poetry install --with dev --no-root

- name: Run Tests
- name: Run Tests with Coverage
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
poetry run pytest tests/ --cov --doctest-modules --junitxml=junit/test-results-${{ matrix.python-version }}.xml
poetry run pytest
continue-on-error: false

- name: Upload Test Results
uses: actions/upload-artifact@v4
- name: Upload Coverage Reports to Codecov
uses: codecov/codecov-action@v5
with:
name: pytest-results-${{ matrix.python-version }}
path: junit/test-results-${{ matrix.python-version }}.xml
token: ${{ secrets.CODECOV_TOKEN }}

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Hassan Abedi
Copyright (c) 2025 Hassan Abedi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
98 changes: 49 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,77 @@
# Easy Letters
## Easy Letters

[![PyPI version](https://badge.fury.io/py/easy-letters.svg)](https://badge.fury.io/py/easy-letters)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![python version](https://img.shields.io/badge/Python-%3E=3.10-blue)](https://github.com/habedi/easy-letters)
[![pip downloads](https://img.shields.io/pypi/dm/easy-letters.svg)](https://pypi.org/project/easy-letters/)
[![Tests](https://github.com/habedi/easy-letters/actions/workflows/tests.yml/badge.svg)](https://github.com/habedi/easy-letters/actions/workflows/tests.yml)
[![codecov](https://codecov.io/gh/habedi/easy-letters/graph/badge.svg?token=E47OPB2HVA)](https://codecov.io/gh/habedi/easy-letters)
[![CodeFactor](https://www.codefactor.io/repository/github/habedi/easy-letters/badge)](https://www.codefactor.io/repository/github/habedi/easy-letters)
[![python version](https://img.shields.io/badge/Python-%3E=3.10-blue)](https://github.com/habedi/easy-letters)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/habedi/easy-letters/blob/main/LICENSE)
[![PyPI version](https://badge.fury.io/py/easy-letters.svg)](https://badge.fury.io/py/easy-letters)
[![pip downloads](https://img.shields.io/pypi/dm/easy-letters.svg)](https://pypi.org/project/easy-letters/)

Easy Letters is a Python package that helps job seekers write application letters. A simple retrieval
augmented generation (RAG) pipeline is used to generate the letters. The user can then edit the draft letter to suit
their needs.
Easy Letters is a Python library that provides the basic building blocks for creating a naive [retrieval augmented
generation (or RAG)](https://arxiv.org/abs/2312.10997) pipeline to generate application letter drafts.
The main idea is to speed up the process of writing application letters by not starting from scratch.
Instead, an applicant could generate a draft letter that can be used as a starting point and customized as needed
to make the final letter.

See the `notebooks/README.md` file for how easy letters works.
The diagram below shows the high-level workflow of how Easy Letters can be used to generate draft application
letters.

## 🔧 Installation
![Easy Letters Workflow](assets/workflow.svg)

You can install Easy Letters using pip:
### Installation

```bash
pip install easy-letters
```

## 🚀 Getting Started

### API Key Setup
#### Installing from Source

At the moment, Easy Letters gets the API key for supported services from the environment variables.
So you need to set the following environment variables to be able to use Easy Letters:

- `OPENAI_API_KEY`: The OpenAI API key (required)
You can also install Easy Letters from the source code in this repository.
The main benefit of this approach is that you might find it easier to run the sample notebooks and modify the code as
you wish this way.

### Sample Notebooks
After cloning this repository, you can navigate to the directory where you cloned the repository and install the
dependencies using [Poetry](https://python-poetry.org/):

You can find Jupyter notebooks with example code in the `notebooks` directory.
The notebooks demonstrate how to use Easy Letters to generate application letter drafts.
```bash
git clone https://github.com/habedi/easy-letters.git && cd easy-letters

### Supported Models
# Install the dependencies using Poetry
poetry install --with dev
```

Easy Letters currently supports the following models:
### Getting Started

| Model | Type |
|----------------------------------|-----------------|
| GPT-3.5 Turbo | Text Generation |
| GPT-4 Turbo | Text Generation |
| GPT-4o | Text Generation |
| GPT-4o Mini | Text Generation |
| Text Embedding 3 (Small Variant) | Text Embedding |
| Text Embedding 3 (Large Variant) | Text Embedding |
#### API Key Setup

### Installing from Source
Easy Letters gets the API key for supported services (like [OpenAI](https://platform.openai.com/)) from the environment
variables.
So you need to set the following environment variables to be able to use Easy Letters:

You can also install Easy Letters from the source code in this repository. The main benefit of this approach is that
you might find it easier to run the sample notebooks and modify the code as you wish this way.
- `OPENAI_API_KEY`: The [OpenAI API key](https://platform.openai.com/docs/api-reference/authentication) (required)

After cloning this repository, you can navigate to the `easy-letters` directory and install the
dependencies using [Poetry](https://python-poetry.org/):
#### Sample Notebooks

```bash
git clone https://github.com/habedi/easy-letters.git && cd easy-letters
You can find Jupyter notebooks with example code in the [notebooks](notebooks/) directory.
The notebooks demonstrate how to use Easy Letters to generate application letter drafts.

# Assuming you have Poetry installed on your system
poetry install --with dev
```
### Supported Models

### Running the Unit Tests with Coverage
Easy Letters currently supports the following models:

You can run the unit tests with coverage using the following command:
| Model | Type | Company |
|----------------------------------|-----------------|---------|
| GPT-3.5 Turbo | Text Generation | OpenAI |
| GPT-4 Turbo | Text Generation | OpenAI |
| GPT-4o | Text Generation | OpenAI |
| GPT-4o Mini | Text Generation | OpenAI |
| Text Embedding 3 (Small Variant) | Text Embedding | OpenAI |
| Text Embedding 3 (Large Variant) | Text Embedding | OpenAI |

```bash
poetry run pytest tests/ --cov=easy_letters
```
> [!NOTE]
> At the moment, Easy Letters only supports text generation and text embedding models from OpenAI.

## 📝 TODO
### License

- [ ] Add support for Anthropic models and API
- [ ] Add support for locally served models via Ollama
Easy Letters is available under the MIT license ([LICENSE](LICENSE)).
9 changes: 9 additions & 0 deletions assets/make_figures.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

# You need to have Graphviz installed to run this script
# On Debian-based systems, you can install it using: sudo apt-get install graphviz

# Make figures from .dot files
for f in *.dot; do
dot -Tsvg $f -o ${f%.dot}.svg
done
File renamed without changes.
Loading