Posted on
Artificial Intelligence

Artificial Intelligence Python Portfolio Projects

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence Python Portfolio Projects (for Linux + Bash lovers)

Want to turn your terminal into an AI portfolio factory? If you’re comfortable in Bash and curious about AI, you can ship practical, resume-worthy projects in days—not months. The key is to build small, focused tools that run well on Linux, are easy to test with shell pipelines, and are reproducible end-to-end.

This post shows you why that matters and gives you three real projects you can build today, complete with install commands (apt, dnf, zypper), bash-friendly interfaces, and minimal Python code.

Why AI projects on Linux are a great bet

  • Signal > buzzwords: Recruiters want proof you can ship. Small but real tools beat vague claims every time.

  • Reproducibility: Linux + Bash + Python virtual environments make it trivial to script, automate, and containerize.

  • Glue power: You can chain your models with grep/sed/jq, cron, systemd, and curl for real-world automation.

Quick setup (Debian/Ubuntu, Fedora/RHEL, openSUSE)

You’ll need Python, build tools, and Git. Pick your package manager:

  • Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y python3 python3-venv python3-pip build-essential git curl
  • Fedora/RHEL (dnf):
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y python3 python3-pip git curl
  • openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y python3 python3-pip python3-virtualenv gcc gcc-c++ make git curl

Create and activate a Python virtual environment:

python3 -m venv ~/.venvs/ai-portfolio
source ~/.venvs/ai-portfolio/bin/activate
python -m pip install --upgrade pip

Tip (optional, for better Pillow/Image support):

  • apt: sudo apt install -y libjpeg-dev zlib1g-dev

  • dnf: sudo dnf install -y libjpeg-turbo-devel zlib-devel

  • zypper: sudo zypper install -y libjpeg8-devel zlib-devel


Project 1: Terminal Sentiment Analyzer (stdin -> sentiment)

A tiny CLI that reads text from stdin or a file and returns positive/negative with confidence. Great demo of NLP + Bash pipelines.

Install Python deps (CPU-only PyTorch + Transformers):

pip install --upgrade "torch>=2.0" torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install transformers

sentiment_cli.py:

#!/usr/bin/env python3
import sys, argparse, json
from transformers import pipeline

def main():
    p = argparse.ArgumentParser(description="Classify sentiment from stdin or a file.")
    p.add_argument("-f", "--file", help="Path to a text file (one doc or multiple lines).")
    p.add_argument("--max", type=int, default=None, help="Limit lines when reading file/stdin.")
    args = p.parse_args()

    nlp = pipeline("sentiment-analysis")  # distilbert-base-uncased-finetuned-sst-2-english

    def classify(text):
        res = nlp(text)[0]
        return {"label": res["label"], "score": float(res["score"]), "text": text.strip()[:200]}

    items = []
    if args.file:
        with open(args.file, "r", encoding="utf-8") as fh:
            for i, line in enumerate(fh, 1):
                if args.max and i > args.max: break
                if line.strip():
                    items.append(classify(line))
    else:
        data = sys.stdin.read().strip()
        if "\n" in data:
            for i, line in enumerate(data.splitlines(), 1):
                if args.max and i > args.max: break
                if line.strip():
                    items.append(classify(line))
        elif data:
            items.append(classify(data))

    for obj in items:
        print(json.dumps(obj, ensure_ascii=False))

if __name__ == "__main__":
    main()

Make it executable and try:

chmod +x sentiment_cli.py
echo "I absolutely love Linux!" | ./sentiment_cli.py | jq
./sentiment_cli.py -f comments.txt --max 10 | jq -r '.label + "\t" + (.score|tostring) + "\t" + .text'

What this shows:

  • Real NLP with one file.

  • Unix-friendly JSON output, ready for jq/grep/awk.


Project 2: FastAPI Microservice (Iris classifier)

Turn a simple ML model into a web service you can curl. This demonstrates reproducible training + serving, and integrates well with Docker or systemd.

Install deps:

pip install scikit-learn fastapi "uvicorn[standard]" joblib pydantic

Train and persist a model (RandomForest on Iris):

train_iris.py:

#!/usr/bin/env python3
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import joblib, pathlib

X, y = load_iris(return_X_y=True, as_frame=True)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.2, random_state=42)
model = RandomForestClassifier(n_estimators=200, random_state=42).fit(Xtr, ytr)
acc = accuracy_score(yte, model.predict(Xte))
print(f"Test accuracy: {acc:.3f}")

pathlib.Path("models").mkdir(exist_ok=True)
joblib.dump(model, "models/iris_rf.joblib")

Serve it with FastAPI:

api.py:

#!/usr/bin/env python3
from fastapi import FastAPI
from pydantic import BaseModel, conlist
import joblib
from sklearn.datasets import load_iris

app = FastAPI(title="Iris Classifier")
model = joblib.load("models/iris_rf.joblib")
target_names = load_iris().target_names.tolist()

class PredictRequest(BaseModel):
    features: conlist(float, min_items=4, max_items=4)

@app.post("/predict")
def predict(req: PredictRequest):
    pred = model.predict([req.features])[0]
    proba = model.predict_proba([req.features])[0].max()
    return {"class": target_names[int(pred)], "confidence": float(proba)}

Run and test:

python train_iris.py
uvicorn api:app --reload --host 0.0.0.0 --port 8000
curl -s -X POST http://127.0.0.1:8000/predict \
  -H 'Content-Type: application/json' \
  -d '{"features":[5.1,3.5,1.4,0.2]}'

What this shows:

  • Clear separation of train/serve.

  • Type-checked JSON I/O via Pydantic.

  • Ready for Docker, Nginx, or systemd.


Project 3: Image Auto-Tagger (ResNet labels from CLI)

Auto-tag images with ImageNet labels. Use it to sort photos or label screenshots; it’s a strong demo of CV with pre-trained models.

Install deps (CPU is fine):

pip install --upgrade "torch>=2.0" torchvision --index-url https://download.pytorch.org/whl/cpu
pip install pillow tqdm

image_tag.py:

#!/usr/bin/env python3
import argparse, json, sys, pathlib
from PIL import Image
import torch
from torchvision import transforms
from torchvision.models import resnet50, ResNet50_Weights
from tqdm import tqdm

def load_model():
    weights = ResNet50_Weights.DEFAULT
    model = resnet50(weights=weights)
    model.eval()
    preprocess = weights.transforms()
    classes = weights.meta["categories"]
    return model, preprocess, classes

@torch.no_grad()
def classify_image(path, model, preprocess, classes, topk=5):
    img = Image.open(path).convert("RGB")
    x = preprocess(img).unsqueeze(0)
    logits = model(x)
    probs = torch.nn.functional.softmax(logits, dim=1)[0]
    topk_probs, topk_idx = probs.topk(topk)
    return [(classes[i], float(p)) for p, i in zip(topk_probs, topk_idx)]

def main():
    p = argparse.ArgumentParser(description="Image auto-tagger (ImageNet labels).")
    p.add_argument("paths", nargs="+", help="Image files or directories")
    p.add_argument("--topk", type=int, default=5)
    args = p.parse_args()

    model, preprocess, classes = load_model()

    files = []
    for pth in args.paths:
        p = pathlib.Path(pth)
        if p.is_file():
            files.append(p)
        elif p.is_dir():
            files += [f for f in p.rglob("*") if f.suffix.lower() in {".jpg",".jpeg",".png",".bmp",".gif"}]
    if not files:
        print("No images found.", file=sys.stderr); sys.exit(1)

    for f in tqdm(files):
        try:
            tags = classify_image(f, model, preprocess, classes, topk=args.topk)
            print(json.dumps({"path": str(f), "tags": tags}, ensure_ascii=False))
        except Exception as e:
            print(json.dumps({"path": str(f), "error": str(e)}))

if __name__ == "__main__":
    main()

Use it from Bash:

chmod +x image_tag.py
./image_tag.py ~/Pictures | jq -r '.path + "\t" + ([.tags[][0]] | join(", "))' | head
find . -type f -name "*.jpg" -print0 | xargs -0 -n1 ./image_tag.py | jq .

What this shows:

  • Real CV inference without training.

  • JSON output for storage or post-processing.

  • Scales to directories via find/xargs.


Bonus: Bash-native practices that make portfolio projects shine

  • Treat everything as a CLI: stdin/stdout, exit codes, --help.

  • Emit structured logs: newline-delimited JSON makes jq a superpower.

  • Reproducibility: include requirements.txt, a Makefile, and a short README with run commands.

  • Add tests: even a few pytest cases impress.

  • Automate: a make serve, make train, and make test go a long way.

Example Makefile:

.PHONY: venv install train serve test
venv:
    python3 -m venv .venv && . .venv/bin/activate && python -m pip install --upgrade pip
install:
    . .venv/bin/activate && pip install -r requirements.txt
train:
    . .venv/bin/activate && python train_iris.py
serve:
    . .venv/bin/activate && uvicorn api:app --host 0.0.0.0 --port 8000
test:
    . .venv/bin/activate && pytest -q

Conclusion / Call To Action

Pick one project and ship it this week:

  • Sentiment CLI if you like NLP and shell pipelines.

  • Iris API if you want web-serving and MLOps basics.

  • Image Tagger if you want quick CV results.

Next steps: 1) Create a repo per project with README, Makefile, and demo commands. 2) Add a short demo GIF or asciinema. 3) Post a write-up linking code, sample data, and curl/pipe examples. 4) Keep iterating: add tests, Dockerfile, and CI later.

Your Linux terminal is already an AI lab. Open a venv, paste one script, and you’ve got portfolio gold.