From 29ef63aaddc5cab9af5a811bc36ed246928ff2fa Mon Sep 17 00:00:00 2001 From: kamilbenkirane Date: Tue, 4 Nov 2025 10:51:45 +0100 Subject: [PATCH] chore: setup repository infrastructure --- .gitignore | 159 ++++++++++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 61 +++++++++++++++ Makefile | 79 ++++++++++++++++++++ README.md | 134 +++++++++++++++++++++++++++++++++ logo.svg | 11 +++ pyproject.toml | 150 +++++++++++++++++++++++++++++++++++++ 6 files changed, 594 insertions(+) create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 Makefile create mode 100644 README.md create mode 100644 logo.svg create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..730293e9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,159 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +Pipfile.lock + +# poetry +poetry.lock + +# pdm +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582 +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store + +# Backup files +*.bak + +# UV +.uv/ +uv.lock + +# Ruff +.ruff_cache/ + +# Security reports +bandit-report.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..31d00b9b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,61 @@ +# See https://pre-commit.com for more information +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: no-commit-to-branch + name: "๐Ÿšซ Prevent commits to protected branches" + args: [--branch, main, --branch, master, --branch, develop] + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: check-toml + - id: check-merge-conflict + - id: check-json + - id: debug-statements # Check for print/pdb statements + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.14.3 + hooks: + - id: ruff-check + args: [--fix] + files: ^(src/celeste|tests)/ + name: "๐Ÿ Lint with Ruff" + - id: ruff-format + files: ^(src/celeste|tests)/ + name: "๐Ÿ Format with Ruff" + + - repo: local + hooks: + - id: mypy + name: "๐Ÿ Type check with mypy" + entry: uv run mypy -p celeste + language: system + types: [python] + pass_filenames: false + - id: mypy-tests + name: "๐Ÿ Type check tests with mypy" + entry: uv run mypy tests/ + language: system + types: [python] + pass_filenames: false + + - repo: https://github.com/PyCQA/bandit + rev: 1.8.6 + hooks: + - id: bandit + name: "๐Ÿ”’ Security check with Bandit" + args: ["-c", "pyproject.toml", "-r", "src/"] + additional_dependencies: ["bandit[toml]"] + + - repo: local + hooks: + - id: pytest + name: "๐Ÿงช Run tests with coverage" + entry: uv run pytest tests/ --cov=celeste --cov-report=term-missing + language: system + types: [python] + pass_filenames: false + always_run: true + stages: [pre-push] # Run on push, not commit (keeps commits fast) diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..6e8fbd68 --- /dev/null +++ b/Makefile @@ -0,0 +1,79 @@ +.PHONY: help sync lint lint-fix format typecheck test security ci clean + +# Default target +help: + @echo "Available commands:" + @echo " make sync - Update and sync all dependencies with all extras" + @echo " make lint - Run Ruff linting" + @echo " make format - Apply Ruff formatting" + @echo " make typecheck - Run mypy type checking" + @echo " make test - Run pytest with coverage" + @echo " make security - Run Bandit security scan" + @echo " make ci - Run full CI/CD pipeline" + @echo " make clean - Clean cache directories" + +# Complete dependency sync - update lock, sync everything +sync: + @echo "๐Ÿ”„ Updating dependencies..." + @uv sync --all-packages --all-extras --upgrade + @echo "โœ… All dependencies synced and updated" + +# Linting +lint: + uv run ruff check src/celeste tests/ + +# Linting with auto-fix +lint-fix: + uv run ruff check --fix src/celeste tests/ + +# Formatting +format: + uv run ruff format src/celeste tests/ + +# Type checking (fail fast on any error) +typecheck: + @uv run mypy -p celeste && uv run mypy tests/ + +# Testing +test: + uv run pytest tests/ --cov=celeste --cov-report=term-missing --cov-fail-under=90 + +# Security scanning (config reads from pyproject.toml) +security: + uv run bandit -c pyproject.toml -r src/ -f screen + +# Full CI/CD pipeline - what GitHub Actions will run +ci: + @echo "๐Ÿ” Running Full CI/CD Pipeline..." + @echo "=================================" + @echo "1๏ธโƒฃ Ruff Linting (with auto-fix)..." + @$(MAKE) lint-fix || (echo "โŒ Linting failed" && exit 1) + @echo "โœ… Linting passed" + @echo "" + @echo "2๏ธโƒฃ Ruff Formatting..." + @$(MAKE) format || (echo "โŒ Formatting failed" && exit 1) + @echo "โœ… Formatting applied" + @echo "" + @echo "3๏ธโƒฃ MyPy Type Checking (parallel)..." + @$(MAKE) typecheck || (echo "โŒ Type checking failed" && exit 1) + @echo "โœ… Type checking passed" + @echo "" + @echo "4๏ธโƒฃ Bandit Security Scan..." + @$(MAKE) security || (echo "โŒ Security scan failed" && exit 1) + @echo "โœ… Security scan passed" + @echo "" + @echo "5๏ธโƒฃ Running Tests with Coverage..." + @$(MAKE) test || (echo "โŒ Tests failed" && exit 1) + @echo "" + @echo "=================================" + @echo "๐ŸŽ‰ All CI/CD checks passed! Ready to commit." + +# Clean cache directories +clean: + rm -rf .pytest_cache + rm -rf .mypy_cache + rm -rf .ruff_cache + rm -rf __pycache__ + find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true + find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true + find . -type f -name "*.pyc" -delete diff --git a/README.md b/README.md new file mode 100644 index 00000000..eef1cd9b --- /dev/null +++ b/README.md @@ -0,0 +1,134 @@ +
+ +# Celeste AI + +Celeste Logo + +**The primitive layer for multi-modal AI** + +All capabilities. All providers. One interface. + +Primitives, not frameworks. + +[![Python](https://img.shields.io/badge/Python-3.12+-blue?style=flat-square)](https://www.python.org/) +[![License](https://img.shields.io/badge/License-Apache_2.0-blue?style=flat-square)](LICENSE) +[![PyPI](https://img.shields.io/badge/PyPI-celeste--ai-orange?style=flat-square)](https://pypi.org/project/celeste-ai/) + +[Quick Start](#-quick-start) โ€ข [Request Provider](https://github.com/withceleste/celeste-python/issues/new) + +
+ +--- + +## ๐Ÿš€ Quick Start + +```python +from celeste import create_client, Capability, Provider + +# Create client +client = create_client( + capability=Capability.TEXT_GENERATION, + provider=Provider.ANTHROPIC, + api_key="your-api-key", # Or loads automatically from environment +) + +# Generate +response = await client.generate(prompt="Explain quantum computing") +print(response.content) +``` + +**Install:** +```bash +uv add "celeste-ai[text-generation]" # Text only +uv add "celeste-ai[image-generation]" # Image generation +uv add "celeste-ai[all]" # Everything +``` + +--- + +## ๐ŸŽจ Multi-Modal Example + +```python +# Same API, different modalities +text_client = create_client(Capability.TEXT_GENERATION, Provider.ANTHROPIC) +image_client = create_client(Capability.IMAGE_GENERATION, Provider.OPENAI) +video_client = create_client(Capability.VIDEO_GENERATION, Provider.GOOGLE) + +text = await text_client.generate(prompt="Write a haiku about AI") +image = await image_client.generate(prompt="A sunset over mountains") +video = await video_client.generate(prompt="Waves crashing on a beach") +``` + +No special cases. No separate libraries. **One consistent interface.** + +--- + + +
+ +Google +Anthropic +OpenAI +Mistral +Cohere +xAI +DeepSeek +Groq +Perplexity +Ollama +Hugging Face +Replicate +Stability AI +Runway +ElevenLabs + +**and many more** + +**Missing a provider?** [Request it](https://github.com/withceleste/celeste-python/issues/new) โ€“ โšก **we ship fast**. + +
+ +--- + +## ๐Ÿ”ง Type-Safe by Design + +```python +# Full IDE autocomplete +response = await client.generate( + prompt="Explain AI", + temperature=0.7, # โœ… Validated (0.0-2.0) + max_tokens=100, # โœ… Validated (int) +) + +# Typed response +print(response.content) # str (IDE knows the type) +print(response.usage.input_tokens) # int +print(response.metadata["model"]) # str +``` + +Catch errors **before** production. + +--- + +## ๐Ÿค Contributing + +We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md). + +**Request a provider:** [GitHub Issues](https://github.com/withceleste/celeste-python/issues/new) +**Report bugs:** [GitHub Issues](https://github.com/withceleste/celeste-python/issues) + +--- + +## ๐Ÿ“„ License + +Apache 2.0 license โ€“ see [LICENSE](LICENSE) for details. + +--- + +
+ +**[Get Started](https://withceleste.ai/docs/quickstart)** โ€ข **[Documentation](https://withceleste.ai/docs)** โ€ข **[GitHub](https://github.com/withceleste/celeste-python)** + +Made with โค๏ธ by developers tired of framework lock-in + +
diff --git a/logo.svg b/logo.svg new file mode 100644 index 00000000..2703d56b --- /dev/null +++ b/logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..8499ac44 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,150 @@ +[project] +name = "celeste-ai" +version = "0.0.2" +description = "Open source, type-safe primitives for multi-modal AI. All capabilities, all providers, one interface" +authors = [{name = "Kamilbenkirane", email = "kamil@withceleste.ai"}] +readme = "README.md" +license = {text = "Apache-2.0"} +requires-python = ">=3.12" +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Operating System :: OS Independent", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "Typing :: Typed", +] +keywords = ["ai", "multimodal", "sdk", "openai", "anthropic", "claude", "gemini", "text-generation", "image-generation", "video-generation", "embeddings"] +dependencies = [ + "pydantic>=2.0", + "pydantic-settings>=2.0", + "httpx>=0.27.0", + "httpx-sse>=0.4.0", + "python-dotenv>=1.0.0", +] + +[project.urls] +Homepage = "https://withceleste.ai" +Documentation = "https://withceleste.ai/docs" +Repository = "https://github.com/withceleste/celeste-python" +Issues = "https://github.com/withceleste/celeste-python/issues" + +[dependency-groups] +dev = [ + "pytest>=8.0", + "pytest-cov>=7.0", + "pytest-randomly>=4.0", + "pytest-asyncio>=1.2.0", + "ruff>=0.8.0", + "mypy>=1.13.0", + "types-requests>=2.31.0", + "bandit[toml]>=1.7.5", + "pre-commit>=3.5.0", +] + +[project.entry-points."celeste.packages"] +# Example entry points for packages to register their models and clients: +# text_generation = "text_generation:register_models" +# image_generation = "image_generation:register_models" + +[tool.uv.workspace] +members = ["packages/*"] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src/celeste"] + +[tool.pytest.ini_options] +minversion = "8.0" +testpaths = ["tests"] +addopts = "-ra --strict-markers --strict-config" +asyncio_mode = "auto" +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "smoke: quick checks for critical paths", +] + +[tool.coverage.run] +branch = true +# dynamic_context handled by pytest-cov's --cov-context option + +[tool.coverage.report] +show_missing = true +fail_under = 90 + +[tool.ruff] +# Same as Black's default +line-length = 88 +target-version = "py312" + +[tool.ruff.lint] +select = [ + "E", # pycodestyle errors + "F", # Pyflakes (unused imports, undefined names) + "I", # isort (import sorting) + "UP", # pyupgrade (upgrade syntax for newer Python) + "B", # flake8-bugbear (catches common bugs) + "SIM", # flake8-simplify (code simplification) + "RUF", # Ruff-specific rules + "ANN", # flake8-annotations (enforce type annotations) + "A", # flake8-builtins (prevent shadowing builtins) +] +ignore = [ + "E501", # Line too long - trust formatter's judgment + "SIM108", # Use ternary operator instead of if-else-block (sometimes less readable) +] +fixable = ["ALL"] +unfixable = [] + +[tool.ruff.format] +# Match Black's style +quote-style = "double" +indent-style = "space" +docstring-code-format = true + +[tool.ruff.lint.isort] +known-first-party = ["celeste"] + +[tool.ruff.lint.per-file-ignores] +"tests/*" = ["D"] # No docstrings required in tests + +[tool.mypy] +python_version = "3.12" +mypy_path = "src" +# Strict type checking for production code +warn_return_any = true +warn_unused_configs = true +disallow_untyped_defs = true # Require type hints +disallow_any_unimported = true +disallow_incomplete_defs = true +check_untyped_defs = true +no_implicit_optional = true +warn_redundant_casts = true +warn_unused_ignores = true +strict_equality = true + +[[tool.mypy.overrides]] +module = "tests.*" +disallow_untyped_defs = false # Relax for tests +disallow_incomplete_defs = false + +[[tool.mypy.overrides]] +module = "httpx" +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "httpx_sse" +ignore_missing_imports = true + +[tool.bandit] +exclude_dirs = [".venv", "__pycache__"] +skips = ["B101"] # Skip B101 (assert_used) since we use pytest + +[tool.bandit.assert_used] +skips = ["*/test_*.py", "*_test.py"] # Allow assertions in test files