- WizardLayout.vue: full-page card, progress bar, crash-recovery via loadStatus(isCloud); auto-skips steps 1/2/5 in cloud mode - wizard.css: shared step styles (headings, banners, radio cards, chip lists, form fields, expandables, nav buttons) - Step 1 — Hardware: GPU detection, profile select, mismatch warning - Step 2 — Tier: Free/Paid/Premium radio cards - Step 3 — Resume: upload (PDF/DOCX/ODT) or manual experience builder; pre-fills identity fields from parsed resume data - Step 4 — Identity: name/email/phone/LinkedIn/career summary; full validation before saveStep - Step 5 — Inference: remote API keys vs local Ollama; advanced service-host/port expandable; soft-fail connection test - Step 6 — Search: chip-style job title + location input with comma/Enter commit; remote-only checkbox - Step 7 — Integrations: optional tile-grid (Notion/Calendar/Slack/ Discord/Drive); paid-tier badge for gated items; calls wizard.complete() on Finish - wizard.ts Pinia store: loadStatus, detectHardware, saveStep, testInference, complete; cloud auto-skip logic - wizardGuard.ts: gates all routes behind /setup until wizard_complete; redirects complete users away from /setup - router/index.ts: /setup nested route tree; unified beforeEach guard (wizard gate → setup branch → settings tier gate) - App.vue: hide AppNav + strip sidebar margin on /setup routes
63 lines
2.2 KiB
Vue
63 lines
2.2 KiB
Vue
<template>
|
||
<div class="step">
|
||
<h2 class="step__heading">Step 1 — Hardware Detection</h2>
|
||
<p class="step__caption">
|
||
Peregrine uses your hardware profile to choose the right inference setup.
|
||
</p>
|
||
|
||
<div v-if="wizard.loading" class="step__info">Detecting hardware…</div>
|
||
|
||
<template v-else>
|
||
<div v-if="wizard.hardware.gpus.length" class="step__success">
|
||
✅ Detected {{ wizard.hardware.gpus.length }} GPU(s):
|
||
{{ wizard.hardware.gpus.join(', ') }}
|
||
</div>
|
||
<div v-else class="step__info">
|
||
No NVIDIA GPUs detected. "Remote" or "CPU" mode recommended.
|
||
</div>
|
||
|
||
<div class="step__field">
|
||
<label class="step__label" for="hw-profile">Inference profile</label>
|
||
<select id="hw-profile" v-model="selectedProfile" class="step__select">
|
||
<option value="remote">Remote — use cloud API keys</option>
|
||
<option value="cpu">CPU — local Ollama, no GPU</option>
|
||
<option value="single-gpu">Single GPU — local Ollama + one GPU</option>
|
||
<option value="dual-gpu">Dual GPU — local Ollama + two GPUs</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div
|
||
v-if="selectedProfile !== 'remote' && !wizard.hardware.gpus.length"
|
||
class="step__warning"
|
||
>
|
||
⚠️ No GPUs detected — a GPU profile may not work. Choose CPU or Remote
|
||
if you don't have a local NVIDIA GPU.
|
||
</div>
|
||
</template>
|
||
|
||
<div class="step__nav step__nav--end">
|
||
<button class="btn-primary" :disabled="wizard.saving" @click="next">
|
||
{{ wizard.saving ? 'Saving…' : 'Next →' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { useWizardStore } from '../../stores/wizard'
|
||
import './wizard.css'
|
||
|
||
const wizard = useWizardStore()
|
||
const router = useRouter()
|
||
const selectedProfile = ref(wizard.hardware.selectedProfile)
|
||
|
||
onMounted(() => wizard.detectHardware())
|
||
|
||
async function next() {
|
||
wizard.hardware.selectedProfile = selectedProfile.value
|
||
const ok = await wizard.saveStep(1, { inference_profile: selectedProfile.value })
|
||
if (ok) router.push('/setup/tier')
|
||
}
|
||
</script>
|