Compare commits
2 Commits
d53ed3d05c
...
0c3661e919
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c3661e919 | |||
| 8bd1dce63f |
@@ -7,80 +7,27 @@ on:
|
|||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY_HOST: git.ivanch.me
|
IMAGE: git.ivanch.me/ivanch/recommender
|
||||||
REGISTRY_USERNAME: ivanch
|
|
||||||
IMAGE: ${{ env.REGISTRY_HOST }}/ivanch/recommender
|
|
||||||
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_recommender:
|
build:
|
||||||
name: Build Recommender Image
|
name: Build Image
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Check out repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Log in to Container Registry
|
|
||||||
run: |
|
|
||||||
echo "${{ secrets.REGISTRY_PASSWORD }}" \
|
|
||||||
| docker login "${{ env.REGISTRY_HOST }}" \
|
|
||||||
-u "${{ env.REGISTRY_USERNAME }}" \
|
|
||||||
--password-stdin
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Build and Push Multi-Arch Image
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
tags: |
|
|
||||||
${{ env.IMAGE }}:latest
|
|
||||||
|
|
||||||
deploy_recommender:
|
|
||||||
name: Deploy Recommender (internal)
|
|
||||||
runs-on: ubuntu-amd64
|
runs-on: ubuntu-amd64
|
||||||
needs: build_recommender
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check KUBE_CONFIG validity
|
- uses: actions/checkout@v4
|
||||||
run: |
|
- uses: https://git.ivanch.me/ivanch/pipeline-actions/build-and-push@main
|
||||||
if [ -z "${KUBE_CONFIG}" ] || [ "${KUBE_CONFIG}" = "" ] || [ "${KUBE_CONFIG// }" = "" ]; then
|
with:
|
||||||
echo "KUBE_CONFIG is not set or is empty."
|
image: ${{ env.IMAGE }}
|
||||||
exit 1
|
registry_password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
fi
|
ssh_key: ${{ secrets.SSH_KEY_DOCKERBUILD }}
|
||||||
|
|
||||||
- name: Check out repository
|
deploy:
|
||||||
uses: actions/checkout@v2
|
name: Deploy (internal)
|
||||||
|
runs-on: ubuntu-amd64
|
||||||
- name: Download and install dependencies
|
needs: build
|
||||||
run: |
|
steps:
|
||||||
apt-get update -y
|
- uses: https://git.ivanch.me/ivanch/pipeline-actions/deploy-restart@main
|
||||||
apt-get install -y curl
|
with:
|
||||||
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
kube_config: ${{ secrets.KUBE_CONFIG }}
|
||||||
install -m 0755 kubectl /usr/local/bin/kubectl
|
deployment_name: recommender
|
||||||
kubectl version --client
|
namespace: media
|
||||||
|
|
||||||
- name: Set up kubeconfig
|
|
||||||
run: |
|
|
||||||
cd deploy
|
|
||||||
echo "$KUBE_CONFIG" > kubeconfig.yaml
|
|
||||||
env:
|
|
||||||
KUBE_CONFIG: ${{ env.KUBE_CONFIG }}
|
|
||||||
|
|
||||||
- name: Check connection to cluster
|
|
||||||
run: |
|
|
||||||
cd deploy
|
|
||||||
kubectl --kubeconfig=kubeconfig.yaml cluster-info
|
|
||||||
|
|
||||||
- name: Apply Recommender deployment
|
|
||||||
run: |
|
|
||||||
cd deploy
|
|
||||||
kubectl --kubeconfig=kubeconfig.yaml apply -f recommender.yaml
|
|
||||||
|
|
||||||
- name: Rollout restart
|
|
||||||
run: |
|
|
||||||
cd deploy
|
|
||||||
kubectl --kubeconfig=kubeconfig.yaml rollout restart deployment recommender -n media
|
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -25,3 +25,10 @@ documents/
|
|||||||
|
|
||||||
# OS
|
# OS
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
deploy/terraform/.terraform
|
||||||
|
deploy/terraform/*.tfstate
|
||||||
|
deploy/terraform/*.tfstate.*
|
||||||
|
deploy/terraform/*.tfplan
|
||||||
|
deploy/terraform/.terraform.lock.hcl
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: recommender
|
|
||||||
namespace: media
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: recommender
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: recommender
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: recommender
|
|
||||||
image: git.ivanch.me/ivanch/recommender:latest
|
|
||||||
imagePullPolicy: Always
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
env:
|
|
||||||
- name: OPENAI_API_KEY
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: recommender-secrets
|
|
||||||
key: OPENAI_API_KEY
|
|
||||||
- name: DATABASE_URL
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: recommender-secrets
|
|
||||||
key: DATABASE_URL
|
|
||||||
- name: BEARER_TOKEN
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: recommender-secrets
|
|
||||||
key: BEARER_TOKEN
|
|
||||||
- name: PROVIDER_URL
|
|
||||||
value: "https://openrouter.ai/api/v1"
|
|
||||||
- name: MODEL_NAME
|
|
||||||
value: "openai/gpt-5.4"
|
|
||||||
- name: AI_PROVIDER
|
|
||||||
value: "GENERIC"
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "256Mi"
|
|
||||||
cpu: "500m"
|
|
||||||
limits:
|
|
||||||
memory: "512Mi"
|
|
||||||
cpu: "1"
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: recommender
|
|
||||||
namespace: media
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
app: recommender
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 80
|
|
||||||
---
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: recommender
|
|
||||||
namespace: media
|
|
||||||
labels:
|
|
||||||
app.kubernetes.io/name: recommender
|
|
||||||
spec:
|
|
||||||
ingressClassName: nginx
|
|
||||||
rules:
|
|
||||||
- host: "recommender.haven"
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: "/"
|
|
||||||
pathType: Prefix
|
|
||||||
backend:
|
|
||||||
service:
|
|
||||||
name: recommender
|
|
||||||
port:
|
|
||||||
number: 80
|
|
||||||
@@ -4,13 +4,7 @@
|
|||||||
|
|
||||||
DATABASE_URL=postgres://user:password@localhost:5432/recommender
|
DATABASE_URL=postgres://user:password@localhost:5432/recommender
|
||||||
|
|
||||||
# AI provider selection: OPENAI (default) or GENERIC
|
|
||||||
AI_PROVIDER=OPENAI
|
|
||||||
|
|
||||||
# OpenAI provider settings (used when AI_PROVIDER=OPENAI)
|
|
||||||
OPENAI_API_KEY=your-openai-api-key-here
|
OPENAI_API_KEY=your-openai-api-key-here
|
||||||
|
|
||||||
# Generic provider settings (used when AI_PROVIDER=GENERIC)
|
# provider settings
|
||||||
PROVIDER_URL=https://your-provider.example.com/v1
|
PROVIDER_URL=https://your-provider.example.com/v1
|
||||||
BEARER_TOKEN=your-bearer-token
|
|
||||||
MODEL_NAME=your-model-name
|
|
||||||
|
|||||||
@@ -2,26 +2,17 @@ import OpenAI from 'openai';
|
|||||||
import * as dotenv from 'dotenv';
|
import * as dotenv from 'dotenv';
|
||||||
dotenv.config({ path: ['.env.local', '.env'] });
|
dotenv.config({ path: ['.env.local', '.env'] });
|
||||||
|
|
||||||
const AI_PROVIDER = process.env.AI_PROVIDER ?? 'OPENAI';
|
export const openai = new OpenAI({
|
||||||
const isGeneric = AI_PROVIDER === 'GENERIC';
|
|
||||||
|
|
||||||
export const openai = isGeneric
|
|
||||||
? new OpenAI({
|
|
||||||
apiKey: process.env.BEARER_TOKEN,
|
apiKey: process.env.BEARER_TOKEN,
|
||||||
baseURL: process.env.PROVIDER_URL,
|
baseURL: process.env.PROVIDER_URL,
|
||||||
timeout: 600000, // 10 minutes
|
timeout: 600000, // 10 minutes
|
||||||
maxRetries: 3,
|
maxRetries: 3,
|
||||||
})
|
|
||||||
: new OpenAI({
|
|
||||||
apiKey: process.env.OPENAI_API_KEY,
|
|
||||||
timeout: 600000, // 10 minutes
|
|
||||||
maxRetries: 3,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const defaultModel = isGeneric ? (process.env.MODEL_NAME ?? 'default') : 'gpt-5.4';
|
export const defaultModel = process.env.MODEL_NAME ?? 'gpt-5.4';
|
||||||
export const miniModel = isGeneric ? (process.env.MODEL_NAME ?? 'default') : 'gpt-5.4-mini';
|
export const miniModel = process.env.MODEL_NAME ?? 'gpt-5.4-mini';
|
||||||
export const serviceOptions = isGeneric ? {} : { service_tier: 'flex' as const };
|
export const serviceOptions = { service_tier: 'flex' as const };
|
||||||
export const supportsWebSearch = !isGeneric;
|
export const supportsWebSearch = true;
|
||||||
|
|
||||||
function isJsonParseError(err: unknown): boolean {
|
function isJsonParseError(err: unknown): boolean {
|
||||||
if (err instanceof SyntaxError) return true;
|
if (err instanceof SyntaxError) return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user