LLM chat built for University of Helsinki staff and students, for education and research.
Some key features include:
- Access based on enrolments and staff role
- Custom system prompts managed by teachers
- Retrieval-augmented generation: teachers can bring their own source material for a course
Quickstart:
- Install npm, docker and docker compose
- Clone the repository
- Copy
.env.templateas.envfile and fill in the required values - Run
npm iandnpm startto setup and start the development environment
See compose.yaml for local development. In short, in addition to the CC server, you need
- PostgreSQL (docker)
- Redis (docker)
- Ollama (docker)
- Azure
- S3
Azure is used for OpenAI LLMs.
Create an AI foundry resource (or something) and create deployment for the models you want to use (gpt-5 for example). Always set the deployment name to the acual model name. So for model gpt-5, the deployment name should be gpt-5.
Then populate .env with the following:
AZURE_RESOURCE=<name-of-the-resource-you-created> AZURE_API_KEY=<asd> S3 is used for storing user-uploaded files and their processed versions.
Create an S3 bucket and populate .env with the following:
S3_HOST=<host-url> S3_BUCKET=<name-of-the-bucket-you-created> S3_ACCESS_KEY=<access-key> S3_SECRET_KEY=<secret-key> In browser console, run
toggleDevtools() Getting Error: Cannot find module @rollup/rollup-linux-arm64-musl on MacOS? This is likely because you ran npm i locally. Try removing package-lock.json locally and running
docker compose build If then you're getting concurrently not found, prepend the npm run dev script with npm i and run once with that.
Playwright e2e tests are located in e2e. playwright.config.ts is also important.
Run the tests with
npm run e2eTo run just one test, mark it with .only:
test.only('test name', async ({ page }) => { // test code })When writing new spec file, make sure to import the test function from the fixtures file, like this:
import { teacherTest as test } from './fixtures'So that the global foreach function runs for your tests. For different user roles (studentTest, teacherTest, adminTest), import the corresponding test function:
import { studentTest as test } from './fixtures'Test user headers are defined in src/shared/testData.ts. TEST_COURSES are also defined there.
Before each test, the test data of a test user is reset by calling the /test/reset-test-data endpoint. It is found at src/server/routes/testUtils.ts.
When running the tests, the headers x-test-user-idx and x-test-user-role are set, defining the test user's id and iam-based role. They are read at src/server/middleware/user.ts.
The tests are isolated so that each (should at least) modifies their own data discriminated by the user's id. This allows parallel execution.
We use the free-tier blacksmith actions runner. If any problems with action workflows arises, just revert #383.
The terms course and chatInstance refer to the same thing in the codebase. However, only chatInstance is correct, always prefer it.