Skip to content

Hyperion: Prepare service for Artemis integration #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Jun 27, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c3c31b9
Add Java gRPC client support and update documentation
FelixTJDietrich Jun 17, 2025
38f9e15
Refactor build.gradle: Remove unnecessary buildscript section and cle…
FelixTJDietrich Jun 17, 2025
e5d58b9
Remove build_java_client script and update README and build.gradle fo…
FelixTJDietrich Jun 17, 2025
01906cd
Update hyperion.code-workspace: Adjust folder structure for clarity
FelixTJDietrich Jun 17, 2025
55f2181
Update hyperion.code-workspace: Normalize folder paths for consistency
FelixTJDietrich Jun 17, 2025
07351f4
Update gRPC dependencies and add TLS certificate generation script
FelixTJDietrich Jun 17, 2025
6d367b7
Remove README.md for the Java gRPC client
FelixTJDietrich Jun 17, 2025
b59c74a
Remove unused project_meta module and clean up imports in main.py
FelixTJDietrich Jun 17, 2025
42207cb
Update hyperion/compose.yaml
FelixTJDietrich Jun 21, 2025
d8a4250
Update hyperion/app/main.py
FelixTJDietrich Jun 21, 2025
e14917f
Add 'bin/' to .gitignore to exclude build artifacts
FelixTJDietrich Jun 21, 2025
8c0db02
Add GitHub Actions workflow for publishing Hyperion Java client and u…
FelixTJDietrich Jun 21, 2025
717660d
Update Java distribution in GitHub Actions workflow to 'temurin'
FelixTJDietrich Jun 21, 2025
f26172a
Refactor GitHub Actions workflow for Hyperion Java Client: update job…
FelixTJDietrich Jun 21, 2025
ffd63e7
Enhance snapshot versioning in GitHub Actions workflow: build meaning…
FelixTJDietrich Jun 21, 2025
0580bf2
Add permissions for GitHub Actions workflow to enable package publishing
FelixTJDietrich Jun 21, 2025
be85042
Remove Gradle wrapper validation step from GitHub Actions workflow
FelixTJDietrich Jun 21, 2025
b3a1f32
Improve snapshot versioning by handling branch names for pull request…
FelixTJDietrich Jun 21, 2025
d790948
Add Review and Refine functionality for programming exercises
FelixTJDietrich Jun 21, 2025
6f0bf6f
Implement Review and Refine functionality with inconsistency checking…
FelixTJDietrich Jun 21, 2025
e333bb9
oops
FelixTJDietrich Jun 21, 2025
9554d13
feat: migrate Hyperion Java client from Gradle to Maven
FelixTJDietrich Jun 24, 2025
40c13d6
feat: enhance publishing logic for snapshots and releases in CI/CD wo…
FelixTJDietrich Jun 24, 2025
7159cb4
fix: update groupId to include 'edutelligence' for proper namespace
FelixTJDietrich Jun 24, 2025
476989a
fix: update groupId to include 'edutelligence' in dependency declarat…
FelixTJDietrich Jun 24, 2025
512ff54
fix: update groupId to include 'edutelligence' in dependency declarat…
FelixTJDietrich Jun 24, 2025
ac6bcab
remove java client
FelixTJDietrich Jun 27, 2025
5a5cbea
black and flake8
FelixTJDietrich Jun 27, 2025
438e6c8
update readme
FelixTJDietrich Jun 27, 2025
b760d78
remove empty init file for scripts package
FelixTJDietrich Jun 27, 2025
f3270d5
Merge branch 'main' into hyperion/artemis-integration
FelixTJDietrich Jun 27, 2025
eb06a8e
Merge branches 'hyperion/artemis-integration' and 'hyperion/artemis-i…
FelixTJDietrich Jun 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 3 additions & 25 deletions .github/workflows/hyperion_deploy-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,14 @@ on:
image-tag:
type: string
description: "Image tag to deploy (default: pr-<number> if PR exists, latest for default branch)"
deploy-hyperion:
type: boolean
default: true
description: (Re-)deploys hyperion.
deploy-proxy:
default: false
type: boolean
description: (Re-)deploys the proxy components. Usually not necessary and might cause downtime.

jobs:
deploy-hyperion:
if: ${{ inputs.deploy-hyperion }}
deploy-app:
uses: ls1intum/.github/.github/workflows/deploy-docker-compose.yml@main
with:
environment: "Hyperion - Test 1"
docker-compose-file: "./hyperion/docker/compose.hyperion.yaml"
docker-compose-file: "./hyperion/compose.yaml"
main-image-name: ls1intum/edutelligence/hyperion
image-tag: ${{ inputs.image-tag }}
deployment-base-path: "/opt/hyperion"
secrets: inherit

deploy-proxy:
if: ${{ inputs.deploy-proxy }}
uses: ls1intum/.github/.github/workflows/deploy-docker-compose.yml@main
with:
environment: "Hyperion - Test 1"
docker-compose-file: "./hyperion/docker/compose.proxy.yaml"
# We just keep the main-image-name and image-tag as placeholders
main-image-name: ls1intum/edutelligence/hyperion
image-tag: ${{ inputs.image-tag }}
deployment-base-path: "/opt/proxy"
secrets: inherit

secrets: inherit
4 changes: 2 additions & 2 deletions .github/workflows/hyperion_deploy-with-helios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ on:
type: string

jobs:
deploy-hyperion:
deploy-app:
uses: ls1intum/.github/.github/workflows/deploy-docker-compose.yml@main
with:
environment: ${{ inputs.environment_name }}
docker-compose-file: "./hyperion/docker/compose.hyperion.yaml"
docker-compose-file: "./hyperion/compose.yaml"
main-image-name: ls1intum/edutelligence/hyperion
image-tag: ${{ inputs.commit_sha }}
deployment-base-path: "/opt/hyperion"
Expand Down
13 changes: 9 additions & 4 deletions hyperion.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@
"folders": [
{
"name": "EduTelligence",
"path": "./",
"path": "."
},
{
"name": "Hyperion",
"path": "./hyperion"
"path": "hyperion"
},
{
"name": "Shared",
"path": "./shared"
"path": "shared"
},
{
"name": "Artemis",
"path": "../Artemis"
}
],
"settings": {
"python.terminal.activateEnvironment": true,
"python.terminal.activateEnvInCurrentTerminal": true,
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python"
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"java.configuration.updateBuildConfiguration": "interactive"
},
"extensions": {
"recommendations": [
Expand Down
57 changes: 39 additions & 18 deletions hyperion/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,31 +1,52 @@
FROM python:3.13-alpine

RUN apk update && \
apk add --no-cache gcc musl-dev postgresql-dev rust cargo curl

FROM python:3.13-slim

# Install minimal dependencies and grpc_health_probe
RUN apt-get update && apt-get install -y \
gcc \
libpq-dev \
curl \
wget \
&& rm -rf /var/lib/apt/lists/*

# Install grpc_health_probe for proper gRPC health checking
ARG GRPC_HEALTH_PROBE_VERSION=v0.4.25
RUN wget -qO/bin/grpc_health_probe \
https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 \
&& chmod +x /bin/grpc_health_probe

# Install poetry
RUN pip install poetry==2.1.1

WORKDIR /app

# Create the proper directory structure
RUN mkdir -p /app/hyperion /app/shared
# Create the directory structure to match pyproject.toml expectations
RUN mkdir -p hyperion

# Copy shared library into the right location
COPY shared/ /app/shared/
# Copy shared library to parent directory (for path dependency)
COPY shared/ ./shared/

# Copy hyperion files
COPY hyperion/pyproject.toml hyperion/poetry.lock /app/hyperion/
COPY hyperion/app/ /app/hyperion/app/
COPY hyperion/playground/ /app/hyperion/playground/
# Copy hyperion files to hyperion subdirectory
COPY hyperion/pyproject.toml ./hyperion/
COPY hyperion/app/ ./hyperion/app/

# Set working directory to hyperion folder where the poetry config is
# Change to hyperion directory for poetry install
WORKDIR /app/hyperion

# Install dependencies but don't try to install the current project
RUN poetry install --no-root
# Install dependencies (without lock file to avoid path issues)
RUN poetry config virtualenvs.create false && \
poetry install --only=main --no-root

# Create non-root user
RUN useradd --create-home --shell /bin/bash hyperion

# Create certificates directory
RUN mkdir -p /certs && chown hyperion:hyperion /certs

# Switch to non-root user
USER hyperion

# Expose the gRPC port
EXPOSE 50051

# Use our custom entrypoint script
ENTRYPOINT ["poetry", "run", "hyperion"]
# Start the application
ENTRYPOINT ["python", "-c", "from app.main import serve; serve()"]
161 changes: 149 additions & 12 deletions hyperion/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Hyperion: AI-Driven Programming Exercise Creation Assistance

**Hyperion** is a microservice designed to bring AI-driven intelligence to Learning Management Systems (LMSs), such as [Artemis](https://github.com/ls1intum/Artemis). Inspired by the Titan of light and enlightenment, Hyperion illuminates the process of creating engaging, effective programming exercises. It assists instructors by refining problem statements, generating code stubs, and providing context-aware suggestions — all while integrating seamlessly with an LMS and CI build agents for validation.
**Hyperion** is a gRPC microservice for AI-driven programming exercise creation, designed to integrate with Learning Management Systems like [Artemis](https://github.com/ls1intum/Artemis).

## Setup

Expand Down Expand Up @@ -85,6 +85,7 @@ docker compose -f compose.hyperion.local.yaml up -d
```

The local compose file:

- Builds the image from your local source code
- Maps port 50051 directly to your host machine
- Sets default environment variables with fallbacks (e.g., OpenAI API keys)
Expand All @@ -106,20 +107,156 @@ docker compose -f compose.hyperion.local.yaml exec hyperion poetry run health-ch

The Docker Compose files support the following environment variables:

| Variable | Description | Default in Local Compose |
|----------|-------------|-----------------------|
| `MODEL_NAME` | OpenAI model to use | gpt-3.5-turbo |
| `OPENAI_API_KEY` | OpenAI API key | sk-dummy-key |
| `OPENAI_API_VERSION` | OpenAI API version | 2023-05-15 |
| `AZURE_OPENAI_ENDPOINT` | Azure OpenAI endpoint URL | empty |
| `AZURE_OPENAI_API_KEY` | Azure OpenAI API key | empty |
| `OLLAMA_BASIC_AUTH_USERNAME` | Ollama authentication username | empty |
| `OLLAMA_BASIC_AUTH_PASSWORD` | Ollama authentication password | empty |
| `OLLAMA_HOST` | Ollama host address | empty |
| Variable | Description | Default in Local Compose |
| ---------------------------- | ------------------------------ | ------------------------ |
| `MODEL_NAME` | OpenAI model to use | gpt-3.5-turbo |
| `OPENAI_API_KEY` | OpenAI API key | sk-dummy-key |
| `OPENAI_API_VERSION` | OpenAI API version | 2023-05-15 |
| `AZURE_OPENAI_ENDPOINT` | Azure OpenAI endpoint URL | empty |
| `AZURE_OPENAI_API_KEY` | Azure OpenAI API key | empty |
| `OLLAMA_BASIC_AUTH_USERNAME` | Ollama authentication username | empty |
| `OLLAMA_BASIC_AUTH_PASSWORD` | Ollama authentication password | empty |
| `OLLAMA_HOST` | Ollama host address | empty |

You can set these environment variables in your shell before running Docker Compose, or use a `.env` file.

### TLS Configuration

Enable TLS for production:

#### 1. Generate Certificates

For development/testing, use the provided script:

```bash
./scripts/generate-certs.sh
```

For production, obtain certificates from a proper CA (Let's Encrypt, corporate CA, etc.) and place them in the `./certs/` directory.

#### 2. Configure Environment

Create a `.env` file from the template:

```bash
cp .env.production .env
```

Edit the `.env` file and set:

```bash
TLS_ENABLED=true
TLS_CERT_PATH=/certs/server.crt
TLS_KEY_PATH=/certs/server.key
TLS_CA_PATH=/certs/ca.crt # For client certificate verification (mTLS)
```

#### 3. Deploy with TLS

```bash
docker-compose -f docker/compose.hyperion.yaml -f docker/compose.proxy.yaml up -d
```

#### 4. Verify TLS Connection

```bash
# With certificate verification
grpcurl -cacert ./certs/ca.crt your-domain.com:50051 hyperion.Health/Ping

# With client certificate (mTLS)
grpcurl -cacert ./certs/ca.crt -cert ./certs/client.crt -key ./certs/client.key \
your-domain.com:50051 hyperion.Health/Ping
```

## Java Client

Hyperion provides a Java gRPC client library for integration with Java applications like Artemis.

### Building the Java Client

To generate and build the Java client library:

```bash
cd java-client
./gradlew buildClient
```

This single command will automatically:

1. Copy the `hyperion.proto` file from the main project
2. Generate Java classes from the protobuf definitions
3. Build the Java library using Gradle
4. Publish the library to your local Maven repository

### Using the Java Client

Add the dependency to your Java project:

**Gradle:**

```gradle
dependencies {
implementation 'de.tum.cit.aet:hyperion:0.1.0-SNAPSHOT'
}
```

**Maven:**

```xml
<dependency>
<groupId>de.tum.cit.aet</groupId>
<artifactId>hyperion</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
```

### Basic Usage

#### Development (Plaintext)

```java
import de.tum.cit.aet.hyperion.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

// Create client for development
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 50051)
.usePlaintext()
.build();

HealthGrpc.HealthBlockingStub healthStub = HealthGrpc.newBlockingStub(channel);

// Health check
PingResponse response = healthStub.ping(
PingRequest.newBuilder()
.setClientId("artemis-client")
.build()
);
```

#### Production (TLS)

```java
import de.tum.cit.aet.hyperion.*;
import io.grpc.ManagedChannel;
import io.grpc.netty.NettyChannelBuilder;

// Create client for production with TLS
ManagedChannel channel = NettyChannelBuilder
.forAddress("hyperion.yourdomain.com", 50051)
.useTransportSecurity() // Enable TLS
.build();

HealthGrpc.HealthBlockingStub healthStub = HealthGrpc.newBlockingStub(channel);

// Health check with timeout
PingResponse response = healthStub
.withDeadlineAfter(30, TimeUnit.SECONDS)
.ping(PingRequest.newBuilder()
.setClientId("artemis-client")
.build());
```

## Generate gRPC stubs

Expand All @@ -138,7 +275,7 @@ The generated stubs will be placed in the `app/grpc` directory.
To format the code, run the following command:

```bash
poetry run black .
poetry run black .
```

### Flake8
Expand Down
Loading