Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
190 changes: 190 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
name: Main Branch Delivery

on:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
name: Build and Upload Artifacts
runs-on: ubuntu-latest
continue-on-error: true
outputs:
result: ${{ steps.record.outputs.result }}
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
id: install_deps
run: npm ci
continue-on-error: true

- name: Install Playwright browsers
id: install_playwright
if: ${{ steps.install_deps.outcome == 'success' }}
run: npx playwright install --with-deps
continue-on-error: true

- name: Build static bundle
id: run_build
if: ${{ steps.install_deps.outcome == 'success' && steps.install_playwright.outcome == 'success' }}
run: npm run build
continue-on-error: true

- name: Upload static artifact
if: ${{ steps.run_build.outcome == 'success' }}
uses: actions/upload-artifact@v4
with:
name: static-site
path: dist
if-no-files-found: error

- name: Upload Pages artifact
if: ${{ steps.run_build.outcome == 'success' }}
uses: actions/upload-pages-artifact@v3
with:
path: dist

- name: Record build status
id: record
if: always()
shell: bash
run: |
if [ "${{ steps.install_deps.outcome }}" != "success" ]; then
echo "result=install-failed" >> "$GITHUB_OUTPUT"
elif [ "${{ steps.install_playwright.outcome }}" != "success" ]; then
echo "result=playwright-failed" >> "$GITHUB_OUTPUT"
elif [ "${{ steps.run_build.outcome }}" != "success" ]; then
echo "result=build-failed" >> "$GITHUB_OUTPUT"
else
echo "result=success" >> "$GITHUB_OUTPUT"
fi

report-build:
name: Report Build Status
runs-on: ubuntu-latest
needs: build
if: always()
steps:
- name: Publish build summary
shell: bash
run: |
{
echo "## Main Branch Build"
echo ""
echo "* Build job conclusion: **${{ needs.build.result }}**"
echo "* Build result classification: **${{ needs.build.outputs.result }}**"
echo "* Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
} >> "$GITHUB_STEP_SUMMARY"

deploy:
name: Deploy to Pages
runs-on: ubuntu-latest
needs: build
if: ${{ needs.build.outputs.result == 'success' }}
continue-on-error: true
environment:
name: github-pages
steps:
- name: Configure Pages
uses: actions/configure-pages@v5

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

tests:
name: Run Tests
runs-on: ubuntu-latest
needs: build
continue-on-error: true
outputs:
result: ${{ steps.test_status.outputs.result }}
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
id: tests_install_deps
run: npm ci
continue-on-error: true

- name: Install Playwright browsers
id: tests_install_playwright
if: ${{ steps.tests_install_deps.outcome == 'success' }}
run: npx playwright install --with-deps
continue-on-error: true

- name: Download build artifact
if: ${{ needs.build.outputs.result == 'success' && steps.tests_install_deps.outcome == 'success' && steps.tests_install_playwright.outcome == 'success' }}
uses: actions/download-artifact@v4
with:
name: static-site
path: dist

- name: Run Playwright suite
id: run_tests
if: ${{ needs.build.outputs.result == 'success' && steps.tests_install_deps.outcome == 'success' && steps.tests_install_playwright.outcome == 'success' }}
env:
CI: true
PLAYWRIGHT_SERVE_DIR: dist
run: npm run test:e2e
continue-on-error: true

- name: Record test status
id: test_status
if: always()
shell: bash
run: |
if [ "${{ needs.build.outputs.result }}" != "success" ]; then
echo "result=skipped-build" >> "$GITHUB_OUTPUT"
elif [ "${{ steps.tests_install_deps.outcome }}" != "success" ]; then
echo "result=install-failed" >> "$GITHUB_OUTPUT"
elif [ "${{ steps.tests_install_playwright.outcome }}" != "success" ]; then
echo "result=playwright-failed" >> "$GITHUB_OUTPUT"
elif [ "${{ steps.run_tests.outcome }}" != "success" ]; then
echo "result=${{ steps.run_tests.outcome }}" >> "$GITHUB_OUTPUT"
else
echo "result=success" >> "$GITHUB_OUTPUT"
fi

report-tests:
name: Report Tests Statuses
runs-on: ubuntu-latest
needs: tests
if: always()
steps:
- name: Publish test summary
shell: bash
run: |
{
echo "## Main Branch Tests"
echo ""
echo "* Test job conclusion: **${{ needs.tests.result }}**"
echo "* Test result classification: **${{ needs.tests.outputs.result }}**"
echo "* Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
} >> "$GITHUB_STEP_SUMMARY"
59 changes: 59 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Pull Request Quality Checks

on:
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
workflow_dispatch:

permissions:
contents: read

jobs:
run-tests:
name: Run Tests
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Install Playwright browsers
run: npx playwright install --with-deps

- name: Build static bundle
run: npm run build

- name: Run Playwright suite
env:
CI: true
PLAYWRIGHT_SERVE_DIR: dist
run: npm run test:e2e

report-tests:
name: Report Tests Statuses
runs-on: ubuntu-latest
needs: run-tests
if: always()
steps:
- name: Publish summary
shell: bash
run: |
{
echo "## Pull Request Test Results"
echo ""
echo "* Test job conclusion: **${{ needs.run-tests.result }}**"
echo "* Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
} >> "$GITHUB_STEP_SUMMARY"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules/
test-results/
dist/
42 changes: 28 additions & 14 deletions AI/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ function parseAiDirectives(responseText) {
return { cleanedText, commands: uniqueCommands };
}

async function executeAiCommand(command) {
async function executeAiCommand(command, options = {}) {
if (!command) {
return false;
}
Expand All @@ -1044,13 +1044,13 @@ async function executeAiCommand(command) {
});
return true;
case 'copy_image':
await copyImageToClipboard();
await copyImageToClipboard(options.imageUrl);
return true;
case 'save_image':
await saveImage();
await saveImage(options.imageUrl);
return true;
case 'open_image':
openImageInNewTab();
openImageInNewTab(options.imageUrl);
return true;
case 'set_model_flux':
currentImageModel = 'flux';
Expand Down Expand Up @@ -1295,13 +1295,19 @@ async function getAIResponse(userInput) {
}

const { cleanedText, commands } = parseAiDirectives(aiText);
const assistantMessage = cleanedText || aiText;
const imageUrlFromResponse = extractImageUrl(aiText) || extractImageUrl(assistantMessage);

const imageCommandQueue = [];
for (const command of commands) {
await executeAiCommand(command);
}
const normalizedCommand = normalizeCommandValue(command);
if (['copy_image', 'save_image', 'open_image'].includes(normalizedCommand)) {
imageCommandQueue.push(normalizedCommand);
continue;
}

const assistantMessage = cleanedText || aiText;
const imageUrlFromResponse = extractImageUrl(aiText) || extractImageUrl(assistantMessage);
await executeAiCommand(normalizedCommand);
}

const fallbackPrompt = buildFallbackImagePrompt(userInput, assistantMessage);
let fallbackImageUrl = '';
Expand Down Expand Up @@ -1334,6 +1340,14 @@ async function getAIResponse(userInput) {

const shouldSuppressSpeech = commands.includes('shutup') || commands.includes('stop_speaking');

if (imageCommandQueue.length > 0) {
await heroImagePromise;
const imageTarget = selectedImageUrl || getImageUrl() || pendingHeroUrl;
for (const command of imageCommandQueue) {
await executeAiCommand(command, { imageUrl: imageTarget });
}
}

if (!shouldSuppressSpeech) {
const spokenText = sanitizeForSpeech(finalAssistantMessage);
if (spokenText) {
Expand Down Expand Up @@ -1442,8 +1456,8 @@ function updateHeroImage(imageUrl) {
});
}

async function copyImageToClipboard() {
const imageUrl = getImageUrl();
async function copyImageToClipboard(imageUrlOverride) {
const imageUrl = imageUrlOverride || getImageUrl() || pendingHeroUrl;
if (!imageUrl) {
return;
}
Expand All @@ -1459,8 +1473,8 @@ async function copyImageToClipboard() {
}
}

async function saveImage() {
const imageUrl = getImageUrl();
async function saveImage(imageUrlOverride) {
const imageUrl = imageUrlOverride || getImageUrl() || pendingHeroUrl;
if (!imageUrl) {
return;
}
Expand All @@ -1484,8 +1498,8 @@ async function saveImage() {
}
}

function openImageInNewTab() {
const imageUrl = getImageUrl();
function openImageInNewTab(imageUrlOverride) {
const imageUrl = imageUrlOverride || getImageUrl() || pendingHeroUrl;
if (!imageUrl) {
return;
}
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Talk to Unity in Plain English

![Main Branch Workflow Status](https://github.com/Unity-Lab-AI/Talk-to-Unity/actions/workflows/main.yml/badge.svg?branch=main)
![Pull Request Workflow Status](https://github.com/Unity-Lab-AI/Talk-to-Unity/actions/workflows/pull-request.yml/badge.svg)

Talk to Unity is a single web page that acts like a friendly concierge. The landing screen double-checks that your browser has everything it needs (secure connection, microphone, speech tools). Once every light turns green, a voice assistant named **Unity** wakes up so you can talk out loud and hear it answer back.

## What you need
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "1.0.0",
"private": true,
"scripts": {
"build": "node scripts/build.mjs",
"test:e2e": "playwright test",
"test:e2e:headed": "playwright test --headed",
"test:e2e:ui": "playwright test --ui"
Expand Down
Loading