{"id":50959837,"url":"https://github.com/nktkln/ai-notes-api","last_synced_at":"2026-06-27T10:00:50.681Z","repository":{"id":360744708,"uuid":"1245928510","full_name":"NKTKLN/ai-notes-api","owner":"NKTKLN","description":"FastAPI backend for managing AI-related notes, prompts, conversations, and LLM workflows.","archived":false,"fork":false,"pushed_at":"2026-06-27T09:21:01.000Z","size":930,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-27T09:21:18.980Z","etag":null,"topics":["celery","docker","fastapi","minio","openai","pgvector","rag","sqlalchemy"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NKTKLN.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-21T17:43:10.000Z","updated_at":"2026-06-27T09:20:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/NKTKLN/ai-notes-api","commit_stats":null,"previous_names":["nktkln/ai-notes-api"],"tags_count":4,"template":false,"template_full_name":"NKTKLN/python-project-template","purl":"pkg:github/NKTKLN/ai-notes-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NKTKLN%2Fai-notes-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NKTKLN%2Fai-notes-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NKTKLN%2Fai-notes-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NKTKLN%2Fai-notes-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NKTKLN","download_url":"https://codeload.github.com/NKTKLN/ai-notes-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NKTKLN%2Fai-notes-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34848932,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["celery","docker","fastapi","minio","openai","pgvector","rag","sqlalchemy"],"created_at":"2026-06-18T12:03:31.972Z","updated_at":"2026-06-27T10:00:50.675Z","avatar_url":"https://github.com/NKTKLN.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ⚡ AI Notes API\n\n[![Python](https://img.shields.io/badge/python-3.13+-3776AB?logo=python\u0026logoColor=white)](https://www.python.org/downloads/)\n[![FastAPI](https://img.shields.io/badge/FastAPI-009688?logo=fastapi\u0026logoColor=white)](https://fastapi.tiangolo.com/)\n[![SQLAlchemy](https://img.shields.io/badge/SQLAlchemy-D71F00?logo=sqlalchemy\u0026logoColor=white)](https://www.sqlalchemy.org/)\n[![Pydantic](https://img.shields.io/badge/Pydantic-E92063?logo=pydantic\u0026logoColor=white)](https://docs.pydantic.dev/)\n[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql\u0026logoColor=white)](https://www.postgresql.org/)\n[![pgvector](https://img.shields.io/badge/pgvector-008bb9?logo=postgresql\u0026logoColor=white)](https://github.com/pgvector/pgvector)\n[![Redis](https://img.shields.io/badge/Redis-FF4438?logo=redis\u0026logoColor=white)](https://redis.io/)\n[![Celery](https://img.shields.io/badge/Celery-37814A?logo=celery\u0026logoColor=white)](https://docs.celeryq.dev/)\n[![OpenAI](https://img.shields.io/badge/OpenAI-412991?logo=openai\u0026logoColor=white)](https://platform.openai.com/)\n[![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker\u0026logoColor=white)](https://www.docker.com/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE.md)\n[![uv](https://img.shields.io/badge/uv-managed-261230?logo=uv\u0026logoColor=white)](https://docs.astral.sh/uv/)\n[![Ruff](https://img.shields.io/badge/linting-ruff-D7FF64?logo=ruff\u0026logoColor=black)](https://docs.astral.sh/ruff/)\n[![Checked with mypy](https://img.shields.io/badge/mypy-checked-2A6DB2.svg)](https://mypy-lang.org/)\n[![Tested with pytest](https://img.shields.io/badge/testing-pytest-0A9EDC?logo=pytest\u0026logoColor=white)](https://docs.pytest.org/)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-FAB040?logo=pre-commit\u0026logoColor=black)](https://pre-commit.com/)\n[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-FE5196?logo=conventionalcommits\u0026logoColor=white)](https://www.conventionalcommits.org/)\n\n**AI Notes API** is a production-oriented FastAPI backend for managing AI-related notes, prompts, conversations, documents, and LLM workflows. The project demonstrates clean architecture, async development, PostgreSQL + pgvector integration, and practical backend patterns for AI engineering.\n\nThe assistant is agentic: during chat completions it can call a built-in note toolkit (search, create, read, update, delete notes), and every chat session keeps a long-term memory built from extracted facts and rolling conversation summaries.\n\nChat sessions are also document-aware: uploaded documents are stored in S3-compatible storage and processed in the background (text extraction, chunking, and embedding generation), then retrieved as grounding context through pgvector similarity search to power retrieval-augmented generation (RAG).\n\n## 📦 Dependencies\n\n* [Python 3.13+](https://www.python.org/downloads/)\n* [uv](https://docs.astral.sh/uv/getting-started/installation/)\n* [Docker](https://docs.docker.com/get-docker/)\n* [Task](https://taskfile.dev/)\n\nRuntime services:\n\n* [PostgreSQL](https://www.postgresql.org/) - primary data store\n* [Redis](https://redis.io/) - Celery broker and result backend\n* [Celery](https://docs.celeryq.dev/) - background worker for async LLM generation jobs and chat memory updates\n* [MinIO](https://min.io/) - S3-compatible object storage for uploaded documents\n\n## 📌 API endpoints\n\nThe API is mounted under `/api/v1`.\n\nAuthentication endpoints:\n\n* `POST /api/v1/auth/register` - register a new user\n* `POST /api/v1/auth/login` - authenticate a user and receive a JWT access token\n* `GET /api/v1/auth/me` - get the current authenticated user\n\nNotes endpoints (authenticated):\n\n* `POST /api/v1/notes` - create a note\n* `GET /api/v1/notes` - list notes with pagination and filters\n* `GET /api/v1/notes/{note_id}` - get a note by ID\n* `PATCH /api/v1/notes/{note_id}` - update a note by ID\n* `DELETE /api/v1/notes/{note_id}` - delete a note by ID\n\nChat session endpoints (authenticated):\n\n* `POST /api/v1/chat/sessions` - create a chat session\n* `GET /api/v1/chat/sessions` - list chat sessions with pagination and filters\n* `GET /api/v1/chat/sessions/{session_id}` - get a chat session by ID\n* `PATCH /api/v1/chat/sessions/{session_id}` - update a chat session by ID\n* `DELETE /api/v1/chat/sessions/{session_id}` - delete a chat session by ID\n* `GET /api/v1/chat/sessions/{session_id}/messages` - list messages in a session\n* `GET /api/v1/chat/sessions/{session_id}/memory` - get the long-term memory for a chat session\n\nChat message endpoints (authenticated):\n\n* `GET /api/v1/chat/messages/{message_id}` - get a message by ID\n* `DELETE /api/v1/chat/messages/{message_id}` - delete a message by ID\n\nChat completion endpoints (authenticated):\n\n* `POST /api/v1/chat/completions/stream` - stream an assistant response over SSE\n* `POST /api/v1/chat/completions/jobs` - enqueue an async LLM generation job (Celery)\n* `GET /api/v1/chat/completions/jobs/{job_id}` - get the status and result of a generation job\n\nDocument endpoints (authenticated):\n\n* `POST /api/v1/chat/sessions/{session_id}/documents` - upload a document to a chat session\n* `GET /api/v1/chat/sessions/{session_id}/documents` - list documents in a chat session\n* `GET /api/v1/chat/sessions/{session_id}/documents/{document_id}` - get a document by ID\n* `GET /api/v1/chat/sessions/{session_id}/documents/{document_id}/download` - download a document by ID\n* `DELETE /api/v1/chat/sessions/{session_id}/documents/{document_id}` - delete a document by ID\n\nHealth endpoint:\n\n* `GET /api/v1/health` - service health check\n\nAuthentication details:\n\n* Use `Authorization: Bearer \u003ctoken\u003e` for protected endpoints\n* Tokens are issued by `POST /api/v1/auth/login`\n* User registration is handled by `POST /api/v1/auth/register`\n\nDocumentation is available at:\n\n* Swagger UI: `http://127.0.0.1:8000/docs`\n* Redoc: `http://127.0.0.1:8000/redoc`\n\n## 🔧 Environment variables\n\nThe application loads settings from a `.env` file using `pydantic-settings`. Copy `.env.example` to `.env` and update the values before running the app.\n\nRequired variables:\n\n* `DISABLE_LOGGING` - `false` or `true`\n* `LOG_LEVEL` - e.g. `INFO`, `DEBUG`\n* `LOG_PATH` - optional path for file logging\n* `POSTGRES_HOST` - PostgreSQL host\n* `POSTGRES_PORT` - PostgreSQL port\n* `POSTGRES_USER` - PostgreSQL username\n* `POSTGRES_PASSWORD` - PostgreSQL password\n* `POSTGRES_DB` - PostgreSQL database name\n* `JWT_SECRET_KEY` - secret key for signing JWT tokens\n* `JWT_ALGORITHM` - JWT signing algorithm, default `HS256`\n* `ACCESS_TOKEN_EXPIRE_MINUTES` - token lifetime in minutes\n* `OPEN_AI_API_KEY` - OpenAI API key\n* `OPEN_AI_MODEL` - chat completion model, e.g. `gpt-4o-mini`\n* `OPEN_AI_EMBEDDING_MODEL` - embedding model, e.g. `text-embedding-3-small`\n* `OPEN_AI_API_URL` - optional custom OpenAI-compatible base URL\n* `OPEN_AI_MAX_OUTPUT_TOKENS` - max tokens per completion\n* `LLM_CONTEXT_MESSAGES_LIMIT` - number of recent messages sent as context\n* `CELERY_BROKER_URL` - Redis URL for the Celery broker\n* `CELERY_RESULT_BACKEND` - Redis URL for the Celery result backend\n* `S3_ENDPOINT_URL` - S3 endpoint URL\n* `S3_ACCESS_KEY_ID` - S3 access key ID\n* `S3_SECRET_ACCESS_KEY` - S3 secret access key\n* `S3_REGION` - S3 region name, default `us-east-1`\n* `S3_BUCKET_NAME` - bucket used to store documents, default `documents`\n* `S3_PRESIGNED_URL_EXPIRE_SECONDS` - presigned document URL lifetime in seconds\n\nThe database connection URL is composed automatically from the `POSTGRES_*` values.\n\n## 🚀 Local development\n\n1. Install dependencies and development tools:\n\n```bash\ntask sync\n```\n\n2. Install Git hooks:\n\n```bash\ntask init\n```\n\n3. Start the application locally:\n\n```bash\ntask run\n```\n\n4. Start the Celery worker (requires a running Redis) for async generation jobs:\n\n```bash\ntask run-celery\n```\n\n## 🐳 Docker\n\nBuild and run the Docker services:\n\n```bash\ntask docker\n```\n\nStop Docker services:\n\n```bash\ntask docker-down\n```\n\n## 🧪 Tests and quality checks\n\n* Run tests:\n\n```bash\ntask test\n```\n\n* Run tests with coverage:\n\n```bash\ntask test-cov\n```\n\n* Run linting and type checking:\n\n```bash\ntask lint\n```\n\n* Run full quality gate:\n\n```bash\ntask check\n```\n\n## 🗄 Database schema\n\nEntity-relationship diagram for the database models:\n\n```mermaid\nerDiagram\n    users {\n        uuid id PK\n        string email UK\n        string username \"null\"\n        string hashed_password\n        bool is_active\n        bool is_superuser\n        datetime created_at\n        datetime updated_at\n    }\n\n    notes {\n        uuid id PK\n        uuid user_id FK\n        string title\n        text content\n        string_array tags\n        enum source \"model_source\"\n        string model_name \"null\"\n        jsonb model_metadata\n        datetime created_at\n        datetime updated_at\n        datetime deleted_at \"null\"\n    }\n\n    chat_sessions {\n        uuid id PK\n        uuid user_id FK\n        string title\n        enum generation_status \"chat_session_generation_status\"\n        uuid generation_id \"null\"\n        datetime generation_started_at \"null\"\n        datetime created_at\n        datetime updated_at\n        datetime deleted_at \"null\"\n    }\n\n    messages {\n        uuid id PK\n        uuid session_id FK\n        text content\n        enum role \"message_role\"\n        string provider \"null\"\n        string model_name \"null\"\n        int prompt_tokens \"null\"\n        int completion_tokens \"null\"\n        int total_tokens \"null\"\n        datetime created_at\n        datetime updated_at\n        datetime deleted_at \"null\"\n    }\n\n    chat_memories {\n        uuid id PK\n        uuid session_id FK,UK\n        text summary\n        jsonb facts\n        bool is_summarizing\n        uuid last_summarized_message_id FK \"null\"\n        datetime created_at\n        datetime updated_at\n    }\n\n    generation_jobs {\n        uuid id PK\n        uuid user_id FK\n        uuid session_id FK\n        enum status \"generation_job_status\"\n        text input_message\n        uuid output_message_id FK \"null\"\n        text error \"null\"\n        datetime started_at \"null\"\n        datetime finished_at \"null\"\n        datetime created_at\n        datetime updated_at\n    }\n\n    documents {\n        uuid id PK\n        uuid user_id FK\n        uuid session_id FK\n        string filename\n        string content_type\n        int file_size\n        string checksum_sha256\n        string storage_bucket\n        string storage_object_name\n        enum status \"document_status\"\n        text error_message \"null\"\n        datetime created_at\n        datetime updated_at\n        datetime deleted_at \"null\"\n    }\n\n    document_processing_jobs {\n        uuid id PK\n        uuid document_id FK\n        enum status \"document_processing_job_status\"\n        datetime started_at \"null\"\n        datetime finished_at \"null\"\n        text error \"null\"\n        datetime created_at\n        datetime updated_at\n    }\n\n    document_chunks {\n        uuid id PK\n        uuid user_id FK\n        uuid session_id FK\n        uuid document_id FK\n        int chunk_index\n        text content\n        string content_hash\n        vector embedding\n        string embedding_model\n        int token_count \"null\"\n        datetime created_at\n        datetime updated_at\n        datetime deleted_at \"null\"\n    }\n\n    rag_queries {\n        uuid id PK\n        uuid user_id FK\n        uuid session_id FK\n        text question\n        text answer \"null\"\n        string provider \"null\"\n        string model \"null\"\n        int prompt_tokens \"null\"\n        int completion_tokens \"null\"\n        int total_tokens \"null\"\n        int top_k\n        enum status \"rag_query_status\"\n        datetime finished_at \"null\"\n        text error_message \"null\"\n        datetime created_at\n        datetime updated_at\n    }\n\n    rag_query_sources {\n        uuid id PK\n        uuid rag_query_id FK\n        uuid document_id FK\n        uuid chunk_id FK\n        float score\n        int rank\n        text content_preview\n        datetime created_at\n        datetime updated_at\n    }\n\n    users ||--o{ notes : owns\n    users ||--o{ chat_sessions : owns\n    users ||--o{ generation_jobs : owns\n    users ||--o{ documents : owns\n    users ||--o{ document_chunks : owns\n    users ||--o{ rag_queries : owns\n\n    chat_sessions ||--o{ messages : contains\n    chat_sessions ||--o| chat_memories : has\n    chat_sessions ||--o{ generation_jobs : contains\n    chat_sessions ||--o{ documents : contains\n    chat_sessions ||--o{ document_chunks : contains\n    chat_sessions ||--o{ rag_queries : contains\n\n    messages ||--o| generation_jobs : \"output of\"\n    messages ||--o| chat_memories : \"last summarized\"\n\n    documents ||--o{ document_processing_jobs : \"processed by\"\n    documents ||--o{ document_chunks : \"split into\"\n    documents ||--o{ rag_query_sources : \"referenced by\"\n    document_chunks ||--o{ rag_query_sources : \"referenced by\"\n    rag_queries ||--o{ rag_query_sources : \"retrieved\"\n```\n\n## 🛠 Database migrations\n\n* Create a new Alembic revision:\n\n```bash\ntask alembic-revision -- \"\u003cmessage\u003e\"\n```\n\n* Apply migrations:\n\n```bash\ntask alembic-upgrade\n```\n\n* Downgrade one revision:\n\n```bash\ntask alembic-downgrade\n```\n\n## 📜 License\n\nThis project is licensed under the MIT License. See [LICENSE.md](./LICENSE.md) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnktkln%2Fai-notes-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnktkln%2Fai-notes-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnktkln%2Fai-notes-api/lists"}