mirror of
https://github.com/karpathy/nanochat.git
synced 2026-05-07 16:30:11 +00:00
Merge pull request #12 from manmohan659/feat/monorepo-scaffold
[codex] Scaffold monorepo platform layout
This commit is contained in:
commit
a0533f2199
34
.env.example
Normal file
34
.env.example
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
POSTGRES_DB=samosachaat
|
||||
POSTGRES_USER=samosachaat_admin
|
||||
POSTGRES_PASSWORD=localdev
|
||||
DATABASE_URL=postgresql+asyncpg://samosachaat_admin:localdev@localhost:5432/samosachaat
|
||||
|
||||
FRONTEND_PORT=3000
|
||||
AUTH_PORT=8001
|
||||
CHAT_API_PORT=8002
|
||||
INFERENCE_PORT=8003
|
||||
GRAFANA_PORT=3001
|
||||
PROMETHEUS_PORT=9090
|
||||
LOKI_PORT=3100
|
||||
|
||||
AUTH_SERVICE_URL=http://auth:8001
|
||||
CHAT_API_URL=http://chat-api:8002
|
||||
INFERENCE_SERVICE_URL=http://inference:8003
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
|
||||
GOOGLE_CLIENT_ID=your-google-client-id
|
||||
GOOGLE_CLIENT_SECRET=your-google-client-secret
|
||||
GITHUB_CLIENT_ID=your-github-client-id
|
||||
GITHUB_CLIENT_SECRET=your-github-client-secret
|
||||
|
||||
JWT_ALGORITHM=RS256
|
||||
JWT_PRIVATE_KEY=generate-an-rs256-private-key
|
||||
JWT_PUBLIC_KEY=generate-the-matching-rs256-public-key
|
||||
NEXTAUTH_SECRET=generate-a-random-secret
|
||||
INTERNAL_API_KEY=generate-a-random-internal-api-key
|
||||
|
||||
HF_TOKEN=your-huggingface-token
|
||||
MODEL_STORAGE_PATH=./models
|
||||
DEFAULT_MODEL_TAG=samosachaat-d12
|
||||
NANOCHAT_DTYPE=float32
|
||||
NUM_WORKERS=1
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -4,9 +4,17 @@ __pycache__/
|
|||
dev-ignore/
|
||||
report.md
|
||||
eval_bundle/
|
||||
models/
|
||||
.terraform/
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
*.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# Secrets
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Local setup
|
||||
CLAUDE.md
|
||||
|
|
|
|||
24
README.md
24
README.md
|
|
@ -7,6 +7,30 @@ nanochat is the simplest experimental harness for training LLMs. It is designed
|
|||
|
||||
For questions about the repo, I recommend either using [DeepWiki](https://deepwiki.com/karpathy/nanochat) from Devin/Cognition to ask questions about the repo, or use the [Discussions tab](https://github.com/karpathy/nanochat/discussions), or come by the [#nanochat](https://discord.com/channels/1020383067459821711/1427295580895314031) channel on Discord.
|
||||
|
||||
## Platform monorepo scaffold
|
||||
|
||||
This repository now also carries the samosaChaat platform scaffold alongside the
|
||||
original nanochat training code. The new top-level directories are organized for
|
||||
service-oriented development:
|
||||
|
||||
- `services/` contains the frontend, auth, chat API, and inference services
|
||||
- `contracts/` contains the shared OpenAPI and JSON schema contracts
|
||||
- `db/migrations/` contains PostgreSQL schema bootstrap scripts
|
||||
- `helm/` contains application and observability chart scaffolding
|
||||
- `terraform/` contains shared modules plus `dev`, `uat`, and `prod` environment scaffolding
|
||||
|
||||
### Local platform quick start
|
||||
|
||||
1. Copy `.env.example` to `.env` and replace the placeholder secrets.
|
||||
2. Start the local stack with `bash scripts/local-dev.sh`.
|
||||
3. Seed the local database with `bash scripts/seed-db.sh`.
|
||||
4. Open the placeholder frontend at [http://localhost:3000](http://localhost:3000).
|
||||
|
||||
The initial scaffold keeps the service topology stable for local development.
|
||||
`services/auth`, `services/chat-api`, and `services/frontend` are placeholders
|
||||
until their dedicated implementations land; the inference service is extracted on
|
||||
the follow-up branch.
|
||||
|
||||
## Time-to-GPT-2 Leaderboard
|
||||
|
||||
Presently, the main focus of development is on tuning the pretraining stage, which takes the most amount of compute. Inspired by the modded-nanogpt repo and to incentivise progress and community collaboration, nanochat maintains a leaderboard for a "GPT-2 speedrun", which is the wall-clock time required to train a nanochat model to GPT-2 grade capability, as measured by the DCLM CORE score. The [runs/speedrun.sh](runs/speedrun.sh) script always reflects the reference way to train GPT-2 grade model and talk to it. The current leaderboard looks as follows:
|
||||
|
|
|
|||
108
contracts/openapi/auth-api.yaml
Normal file
108
contracts/openapi/auth-api.yaml
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
openapi: 3.1.0
|
||||
info:
|
||||
title: samosaChaat Auth API
|
||||
version: 0.1.0
|
||||
description: >
|
||||
Contract skeleton for the authentication service. OAuth providers, session
|
||||
exchange, and user identity endpoints must conform to this document.
|
||||
servers:
|
||||
- url: http://auth:8001
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
summary: Readiness probe for the auth service.
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
description: Auth service health.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
ready:
|
||||
type: boolean
|
||||
required:
|
||||
- status
|
||||
- ready
|
||||
/auth/oauth/{provider}/start:
|
||||
get:
|
||||
summary: Begin an OAuth login flow.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/OAuthProvider"
|
||||
responses:
|
||||
"302":
|
||||
description: Redirect to the provider authorization page.
|
||||
/auth/oauth/{provider}/callback:
|
||||
get:
|
||||
summary: Complete an OAuth login flow.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/OAuthProvider"
|
||||
- in: query
|
||||
name: code
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: Session established.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
user:
|
||||
$ref: ../schemas/user.json
|
||||
access_token:
|
||||
type: string
|
||||
required:
|
||||
- user
|
||||
- access_token
|
||||
/auth/me:
|
||||
get:
|
||||
summary: Return the authenticated user profile.
|
||||
security:
|
||||
- sessionCookie: []
|
||||
responses:
|
||||
"200":
|
||||
description: Current user profile.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/user.json
|
||||
/auth/token/refresh:
|
||||
post:
|
||||
summary: Exchange a refresh token for a new access token.
|
||||
responses:
|
||||
"200":
|
||||
description: Refreshed session token pair.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
access_token:
|
||||
type: string
|
||||
expires_in:
|
||||
type: integer
|
||||
required:
|
||||
- access_token
|
||||
- expires_in
|
||||
components:
|
||||
parameters:
|
||||
OAuthProvider:
|
||||
in: path
|
||||
name: provider
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- google
|
||||
- github
|
||||
securitySchemes:
|
||||
sessionCookie:
|
||||
type: apiKey
|
||||
in: cookie
|
||||
name: session
|
||||
153
contracts/openapi/chat-api.yaml
Normal file
153
contracts/openapi/chat-api.yaml
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
openapi: 3.1.0
|
||||
info:
|
||||
title: samosaChaat Chat API
|
||||
version: 0.1.0
|
||||
description: >
|
||||
Contract skeleton for conversations, persisted message history, and chat
|
||||
orchestration between the frontend and inference service.
|
||||
servers:
|
||||
- url: http://chat-api:8002
|
||||
security:
|
||||
- bearerAuth: []
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
summary: Readiness probe for the chat API.
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
description: Chat API health.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
ready:
|
||||
type: boolean
|
||||
required:
|
||||
- status
|
||||
- ready
|
||||
/conversations:
|
||||
get:
|
||||
summary: List the current user's conversations.
|
||||
responses:
|
||||
"200":
|
||||
description: Conversation collection.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: ../schemas/conversation.json
|
||||
post:
|
||||
summary: Create a new conversation.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
model_tag:
|
||||
type: string
|
||||
required:
|
||||
- title
|
||||
- model_tag
|
||||
responses:
|
||||
"201":
|
||||
description: Conversation created.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/conversation.json
|
||||
/conversations/{conversationId}:
|
||||
get:
|
||||
summary: Fetch a single conversation.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConversationId"
|
||||
responses:
|
||||
"200":
|
||||
description: Conversation details.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/conversation.json
|
||||
patch:
|
||||
summary: Update mutable conversation metadata.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConversationId"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
model_tag:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: Updated conversation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ../schemas/conversation.json
|
||||
/conversations/{conversationId}/messages:
|
||||
get:
|
||||
summary: List persisted messages for a conversation.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConversationId"
|
||||
responses:
|
||||
"200":
|
||||
description: Conversation message history.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: ../schemas/message.json
|
||||
post:
|
||||
summary: Append a message and begin streaming completion.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConversationId"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
$ref: ../schemas/message.json
|
||||
stream:
|
||||
type: boolean
|
||||
default: true
|
||||
required:
|
||||
- message
|
||||
responses:
|
||||
"200":
|
||||
description: Server-sent token stream from the inference service.
|
||||
content:
|
||||
text/event-stream:
|
||||
schema:
|
||||
type: string
|
||||
components:
|
||||
parameters:
|
||||
ConversationId:
|
||||
in: path
|
||||
name: conversationId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
174
contracts/openapi/inference-api.yaml
Normal file
174
contracts/openapi/inference-api.yaml
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
openapi: 3.1.0
|
||||
info:
|
||||
title: samosaChaat Inference API
|
||||
version: 0.1.0
|
||||
description: >
|
||||
Contract skeleton for the standalone inference microservice that streams
|
||||
tokens and manages model weight lifecycle.
|
||||
servers:
|
||||
- url: http://inference:8003
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
summary: Liveness and readiness probe.
|
||||
responses:
|
||||
"200":
|
||||
description: Inference service health.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
ready:
|
||||
type: boolean
|
||||
current_model:
|
||||
type:
|
||||
- string
|
||||
- "null"
|
||||
required:
|
||||
- status
|
||||
- ready
|
||||
/generate:
|
||||
post:
|
||||
summary: Stream generated tokens as server-sent events.
|
||||
security:
|
||||
- internalApiKey: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GenerateRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: SSE response of token chunks and done marker.
|
||||
content:
|
||||
text/event-stream:
|
||||
schema:
|
||||
type: string
|
||||
/models:
|
||||
get:
|
||||
summary: List available and loaded model weights.
|
||||
security:
|
||||
- internalApiKey: []
|
||||
responses:
|
||||
"200":
|
||||
description: Model registry view.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
current_model:
|
||||
type:
|
||||
- string
|
||||
- "null"
|
||||
models:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ModelInfo"
|
||||
required:
|
||||
- current_model
|
||||
- models
|
||||
/models/swap:
|
||||
post:
|
||||
summary: Drain workers and swap the loaded model weights.
|
||||
security:
|
||||
- internalApiKey: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
model_tag:
|
||||
type: string
|
||||
required:
|
||||
- model_tag
|
||||
responses:
|
||||
"202":
|
||||
description: Swap request accepted.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
current_model:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- current_model
|
||||
/stats:
|
||||
get:
|
||||
summary: Worker pool and throughput statistics.
|
||||
security:
|
||||
- internalApiKey: []
|
||||
responses:
|
||||
"200":
|
||||
description: Runtime worker statistics.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
components:
|
||||
securitySchemes:
|
||||
internalApiKey:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-Internal-API-Key
|
||||
schemas:
|
||||
ChatMessage:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
role:
|
||||
type: string
|
||||
content:
|
||||
type: string
|
||||
required:
|
||||
- role
|
||||
- content
|
||||
GenerateRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
messages:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ChatMessage"
|
||||
temperature:
|
||||
type:
|
||||
- number
|
||||
- "null"
|
||||
max_tokens:
|
||||
type:
|
||||
- integer
|
||||
- "null"
|
||||
top_k:
|
||||
type:
|
||||
- integer
|
||||
- "null"
|
||||
required:
|
||||
- messages
|
||||
ModelInfo:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
model_tag:
|
||||
type: string
|
||||
source:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
loaded:
|
||||
type: boolean
|
||||
required:
|
||||
- model_tag
|
||||
- source
|
||||
- path
|
||||
- loaded
|
||||
38
contracts/schemas/conversation.json
Normal file
38
contracts/schemas/conversation.json
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Conversation",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"user_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"model_tag": {
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"user_id",
|
||||
"title",
|
||||
"model_tag",
|
||||
"created_at",
|
||||
"updated_at"
|
||||
]
|
||||
}
|
||||
47
contracts/schemas/message.json
Normal file
47
contracts/schemas/message.json
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Message",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"conversation_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"token_count": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"model_tag": {
|
||||
"type": "string"
|
||||
},
|
||||
"inference_time_ms": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"conversation_id",
|
||||
"role",
|
||||
"content",
|
||||
"token_count",
|
||||
"model_tag",
|
||||
"inference_time_ms",
|
||||
"created_at"
|
||||
]
|
||||
}
|
||||
58
contracts/schemas/user.json
Normal file
58
contracts/schemas/user.json
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "User",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"avatar_url": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "uri"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string"
|
||||
},
|
||||
"provider_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"last_login_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"email",
|
||||
"name",
|
||||
"avatar_url",
|
||||
"provider",
|
||||
"provider_id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"last_login_at"
|
||||
]
|
||||
}
|
||||
42
db/migrations/0001_initial_schema.sql
Normal file
42
db/migrations/0001_initial_schema.sql
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
avatar_url TEXT,
|
||||
provider TEXT NOT NULL,
|
||||
provider_id TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
last_login_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_provider_lookup_idx
|
||||
ON users (provider, provider_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS conversations (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
title TEXT NOT NULL,
|
||||
model_tag TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS conversations_user_id_idx
|
||||
ON conversations (user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
||||
role TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
token_count INTEGER NOT NULL DEFAULT 0,
|
||||
model_tag TEXT NOT NULL,
|
||||
inference_time_ms INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS messages_conversation_id_idx
|
||||
ON messages (conversation_id, created_at);
|
||||
98
docker-compose.yml
Normal file
98
docker-compose.yml
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
services:
|
||||
postgres:
|
||||
image: postgres:15
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB:-samosachaat}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-samosachaat_admin}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-localdev}
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
- ./db/migrations:/docker-entrypoint-initdb.d:ro
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./services/frontend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${FRONTEND_PORT:-3000}:3000"
|
||||
environment:
|
||||
AUTH_SERVICE_URL: ${AUTH_SERVICE_URL:-http://auth:8001}
|
||||
CHAT_API_URL: ${CHAT_API_URL:-http://chat-api:8002}
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL:-http://localhost:3000}
|
||||
depends_on:
|
||||
- auth
|
||||
- chat-api
|
||||
|
||||
auth:
|
||||
build:
|
||||
context: ./services/auth
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${AUTH_PORT:-8001}:8001"
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql+asyncpg://samosachaat_admin:localdev@postgres:5432/samosachaat}
|
||||
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
|
||||
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}
|
||||
GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}
|
||||
GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}
|
||||
JWT_PRIVATE_KEY: ${JWT_PRIVATE_KEY:-}
|
||||
JWT_PUBLIC_KEY: ${JWT_PUBLIC_KEY:-}
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
chat-api:
|
||||
build:
|
||||
context: ./services/chat-api
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${CHAT_API_PORT:-8002}:8002"
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql+asyncpg://samosachaat_admin:localdev@postgres:5432/samosachaat}
|
||||
AUTH_SERVICE_URL: ${AUTH_SERVICE_URL:-http://auth:8001}
|
||||
INFERENCE_SERVICE_URL: ${INFERENCE_SERVICE_URL:-http://inference:8003}
|
||||
INTERNAL_API_KEY: ${INTERNAL_API_KEY:-}
|
||||
depends_on:
|
||||
- postgres
|
||||
- auth
|
||||
- inference
|
||||
|
||||
inference:
|
||||
build:
|
||||
context: ./services/inference
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${INFERENCE_PORT:-8003}:8003"
|
||||
environment:
|
||||
MODEL_STORAGE_PATH: /models
|
||||
DEFAULT_MODEL_TAG: ${DEFAULT_MODEL_TAG:-samosachaat-d12}
|
||||
NANOCHAT_DTYPE: ${NANOCHAT_DTYPE:-float32}
|
||||
HF_TOKEN: ${HF_TOKEN:-}
|
||||
INTERNAL_API_KEY: ${INTERNAL_API_KEY:-}
|
||||
NUM_WORKERS: ${NUM_WORKERS:-1}
|
||||
volumes:
|
||||
- ./models:/models
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${GRAFANA_PORT:-3001}:3000"
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${PROMETHEUS_PORT:-9090}:9090"
|
||||
|
||||
loki:
|
||||
image: grafana/loki:latest
|
||||
restart: unless-stopped
|
||||
command: -config.file=/etc/loki/local-config.yaml
|
||||
ports:
|
||||
- "${LOKI_PORT:-3100}:3100"
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
4
helm/README.md
Normal file
4
helm/README.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Helm Charts
|
||||
|
||||
This directory holds Kubernetes deployment charts for the samosaChaat platform
|
||||
and its supporting observability stack.
|
||||
6
helm/observability/Chart.yaml
Normal file
6
helm/observability/Chart.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v2
|
||||
name: observability
|
||||
description: Observability chart scaffold for Grafana, Prometheus, and Loki.
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "0.1.0"
|
||||
4
helm/observability/templates/NOTES.txt
Normal file
4
helm/observability/templates/NOTES.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
The observability chart scaffold is in place.
|
||||
|
||||
Add concrete manifests for Grafana, Prometheus, Loki, dashboards, and scrape
|
||||
configuration as the platform monitoring stack is implemented.
|
||||
8
helm/observability/values.yaml
Normal file
8
helm/observability/values.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
grafana:
|
||||
enabled: true
|
||||
|
||||
prometheus:
|
||||
enabled: true
|
||||
|
||||
loki:
|
||||
enabled: true
|
||||
6
helm/samosachaat/Chart.yaml
Normal file
6
helm/samosachaat/Chart.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v2
|
||||
name: samosachaat
|
||||
description: Application chart scaffold for the samosaChaat platform.
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "0.1.0"
|
||||
4
helm/samosachaat/templates/NOTES.txt
Normal file
4
helm/samosachaat/templates/NOTES.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
The samosaChaat application chart is scaffolded.
|
||||
|
||||
Populate this chart with Deployments, Services, Ingress, Secrets, and ConfigMaps
|
||||
as the platform services are implemented.
|
||||
10
helm/samosachaat/values.yaml
Normal file
10
helm/samosachaat/values.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
image:
|
||||
repository: ghcr.io/manmohan659/nanochat/frontend
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 3000
|
||||
12
scripts/local-dev.sh
Executable file
12
scripts/local-dev.sh
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
ENV_FILE="${ROOT_DIR}/.env"
|
||||
|
||||
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||
ENV_FILE="${ROOT_DIR}/.env.example"
|
||||
echo "Using ${ENV_FILE} because .env is not present."
|
||||
fi
|
||||
|
||||
exec docker compose --env-file "${ENV_FILE}" up --build "$@"
|
||||
65
scripts/seed-db.sh
Executable file
65
scripts/seed-db.sh
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
ENV_FILE="${ROOT_DIR}/.env"
|
||||
|
||||
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||
ENV_FILE="${ROOT_DIR}/.env.example"
|
||||
fi
|
||||
|
||||
set -a
|
||||
source "${ENV_FILE}"
|
||||
set +a
|
||||
|
||||
docker compose exec -T postgres psql \
|
||||
-U "${POSTGRES_USER:-samosachaat_admin}" \
|
||||
-d "${POSTGRES_DB:-samosachaat}" <<'SQL'
|
||||
INSERT INTO users (
|
||||
id,
|
||||
email,
|
||||
name,
|
||||
avatar_url,
|
||||
provider,
|
||||
provider_id,
|
||||
last_login_at
|
||||
) VALUES (
|
||||
'11111111-1111-1111-1111-111111111111',
|
||||
'demo@samosachaat.local',
|
||||
'Demo User',
|
||||
'https://example.com/avatar.png',
|
||||
'github',
|
||||
'demo-user',
|
||||
NOW()
|
||||
) ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
INSERT INTO conversations (
|
||||
id,
|
||||
user_id,
|
||||
title,
|
||||
model_tag
|
||||
) VALUES (
|
||||
'22222222-2222-2222-2222-222222222222',
|
||||
'11111111-1111-1111-1111-111111111111',
|
||||
'Welcome to samosaChaat',
|
||||
'samosachaat-d12'
|
||||
) ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
INSERT INTO messages (
|
||||
id,
|
||||
conversation_id,
|
||||
role,
|
||||
content,
|
||||
token_count,
|
||||
model_tag,
|
||||
inference_time_ms
|
||||
) VALUES (
|
||||
'33333333-3333-3333-3333-333333333333',
|
||||
'22222222-2222-2222-2222-222222222222',
|
||||
'assistant',
|
||||
'The database scaffold is ready for local development.',
|
||||
9,
|
||||
'samosachaat-d12',
|
||||
12
|
||||
) ON CONFLICT (id) DO NOTHING;
|
||||
SQL
|
||||
9
services/auth/Dockerfile
Normal file
9
services/auth/Dockerfile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY README.md /app/README.md
|
||||
|
||||
EXPOSE 8001
|
||||
|
||||
CMD ["python", "-m", "http.server", "8001", "--bind", "0.0.0.0"]
|
||||
7
services/auth/README.md
Normal file
7
services/auth/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Auth Service
|
||||
|
||||
Scaffold placeholder for Issue #5.
|
||||
|
||||
The monorepo branch provisions this directory and a minimal Docker image so
|
||||
local `docker compose up` remains viable before the real auth service
|
||||
implementation lands.
|
||||
9
services/chat-api/Dockerfile
Normal file
9
services/chat-api/Dockerfile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY README.md /app/README.md
|
||||
|
||||
EXPOSE 8002
|
||||
|
||||
CMD ["python", "-m", "http.server", "8002", "--bind", "0.0.0.0"]
|
||||
7
services/chat-api/README.md
Normal file
7
services/chat-api/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Chat API Service
|
||||
|
||||
Scaffold placeholder for Issue #6.
|
||||
|
||||
This container is intentionally minimal on the monorepo scaffold branch. It
|
||||
keeps the compose topology stable while the dedicated chat API implementation
|
||||
is developed.
|
||||
9
services/frontend/Dockerfile
Normal file
9
services/frontend/Dockerfile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY index.html /app/index.html
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["python", "-m", "http.server", "3000", "--bind", "0.0.0.0"]
|
||||
65
services/frontend/index.html
Normal file
65
services/frontend/index.html
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>samosaChaat frontend scaffold</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
font-family: "Avenir Next", "Segoe UI", sans-serif;
|
||||
background: #fff7ef;
|
||||
color: #26170d;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(255, 190, 92, 0.35), transparent 35%),
|
||||
radial-gradient(circle at bottom right, rgba(226, 107, 74, 0.18), transparent 32%),
|
||||
#fff7ef;
|
||||
}
|
||||
|
||||
main {
|
||||
width: min(720px, calc(100vw - 3rem));
|
||||
padding: 2rem;
|
||||
border-radius: 24px;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
box-shadow: 0 24px 60px rgba(84, 44, 22, 0.12);
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
font-size: clamp(2rem, 5vw, 3rem);
|
||||
}
|
||||
|
||||
p,
|
||||
li {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
code {
|
||||
background: #fff1df;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>samosaChaat platform scaffold</h1>
|
||||
<p>
|
||||
The monorepo structure is in place. This placeholder frontend keeps
|
||||
<code>docker compose up</code> usable until the real UI lands.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Auth service: <code>http://localhost:8001</code></li>
|
||||
<li>Chat API: <code>http://localhost:8002</code></li>
|
||||
<li>Inference: <code>http://localhost:8003</code></li>
|
||||
</ul>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
9
services/inference/Dockerfile
Normal file
9
services/inference/Dockerfile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY README.md /app/README.md
|
||||
|
||||
EXPOSE 8003
|
||||
|
||||
CMD ["python", "-m", "http.server", "8003", "--bind", "0.0.0.0"]
|
||||
6
services/inference/README.md
Normal file
6
services/inference/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Inference Service
|
||||
|
||||
Scaffold placeholder for Issue #3.
|
||||
|
||||
This branch only creates the monorepo structure. The next branch extracts the
|
||||
FastAPI inference microservice into this directory.
|
||||
6
terraform/README.md
Normal file
6
terraform/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Terraform
|
||||
|
||||
Environment and module scaffolding for the samosaChaat AWS platform.
|
||||
|
||||
- `environments/` holds per-environment stacks for `dev`, `uat`, and `prod`
|
||||
- `modules/` holds reusable building blocks for shared infrastructure
|
||||
6
terraform/environments/dev/README.md
Normal file
6
terraform/environments/dev/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# dev
|
||||
|
||||
Development environment stack scaffold.
|
||||
|
||||
Use this directory to wire together the shared Terraform modules for the dev
|
||||
AWS account and domain configuration.
|
||||
6
terraform/environments/prod/README.md
Normal file
6
terraform/environments/prod/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# prod
|
||||
|
||||
Production environment stack scaffold.
|
||||
|
||||
Use this directory to compose the shared Terraform modules with production
|
||||
networking, security, and availability requirements.
|
||||
6
terraform/environments/uat/README.md
Normal file
6
terraform/environments/uat/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# uat
|
||||
|
||||
User acceptance testing environment stack scaffold.
|
||||
|
||||
Use this directory to compose the shared Terraform modules with UAT-specific
|
||||
variables, state backends, and deployment topology.
|
||||
3
terraform/modules/acm/README.md
Normal file
3
terraform/modules/acm/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# acm module
|
||||
|
||||
Scaffold placeholder for the shared ACM certificate module.
|
||||
3
terraform/modules/ecr/README.md
Normal file
3
terraform/modules/ecr/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# ecr module
|
||||
|
||||
Scaffold placeholder for the shared container registry module.
|
||||
3
terraform/modules/efs/README.md
Normal file
3
terraform/modules/efs/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# efs module
|
||||
|
||||
Scaffold placeholder for the shared EFS storage module.
|
||||
3
terraform/modules/eks/README.md
Normal file
3
terraform/modules/eks/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# eks module
|
||||
|
||||
Scaffold placeholder for the shared EKS cluster module.
|
||||
3
terraform/modules/iam/README.md
Normal file
3
terraform/modules/iam/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# iam module
|
||||
|
||||
Scaffold placeholder for the shared IAM roles and policy module.
|
||||
3
terraform/modules/rds/README.md
Normal file
3
terraform/modules/rds/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# rds module
|
||||
|
||||
Scaffold placeholder for the shared PostgreSQL / RDS module.
|
||||
3
terraform/modules/route53/README.md
Normal file
3
terraform/modules/route53/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# route53 module
|
||||
|
||||
Scaffold placeholder for the shared DNS management module.
|
||||
3
terraform/modules/vpc/README.md
Normal file
3
terraform/modules/vpc/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# vpc module
|
||||
|
||||
Scaffold placeholder for the shared VPC networking module.
|
||||
Loading…
Reference in New Issue
Block a user