chat-app/
├── main.tsx # Entry point
├── deno.json # Config
├── public/ # Static assets (logos, icons)
│
├── backend/ # Server-side code
│ ├── index.ts # App factory
│ ├── config.ts # Configuration
│ ├── utils.ts # File utilities
│ ├── providers/ # Chat providers (Groq, etc.)
│ │ ├── index.ts
│ │ ├── types.ts
│ │ └── groq.ts
│ └── routes/ # API routes
│ ├── static.ts # HTML, CSS, JS, assets
│ ├── chat.ts # /api/chat endpoints
│ ├── jobs.ts # /api/jobs endpoints
│ ├── providers.ts # /api/providers
│ └── system.ts # /health
│
└── frontend/ # Client-side code
├── index.html # App HTML
├── monaco-utils.js # Monaco editor utilities
├── styles/ # CSS/SCSS
│ ├── build.ts
│ ├── app.scss
│ ├── components/
│ └── design-system/
└── app/ # Alpine.js modules
├── index.js # Main app component
├── state.js
├── storage.js
├── folders.js
├── chats.js
├── messaging.js
├── models.js
├── settings.js
├── editing.js
├── dragdrop.js
└── jobs.js # NEW: Jobs API integration
The jobs module is now available in the Alpine.js app as this.jobs:
// Example: Create and stream a chat job
async createBackgroundChat() {
const job = await this.jobs.createAndStreamChatJob(
[{ role: "user", content: "Tell me a story" }],
{
model: "llama-3.3-70b-versatile",
handlers: {
onData: (data) => {
// Handle streaming chunks
console.log("Chunk:", data.content);
},
onJob: (job) => {
// Handle job status changes
console.log("Job status:", job.status);
if (job.status === 'completed') {
console.log("Final result:", job.result);
}
},
onError: (error) => {
console.error("Job error:", error);
}
}
}
);
}
// Example: List all jobs
async viewAllJobs() {
const jobs = await this.jobs.listJobs();
console.log("All jobs:", jobs);
}
// Example: Cancel a running job
async stopJob(jobId) {
await this.jobs.cancelJob(jobId);
}
// Create a job
const response = await fetch('/api/jobs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'chat',
input: {
messages: [{ role: "user", content: "Hello" }],
model: "llama-3.3-70b-versatile"
}
})
});
const { id, status } = await response.json();
// Subscribe to job updates (SSE)
const eventSource = new EventSource(\`/api/jobs/\${id}/stream\`);
eventSource.addEventListener('job', (event) => {
const job = JSON.parse(event.data);
console.log("Job update:", job.status);
});
eventSource.addEventListener('data', (event) => {
const chunk = JSON.parse(event.data);
console.log("Data chunk:", chunk.content);
});
// Get job result
const jobResponse = await fetch(\`/api/jobs/\${id}\`);
const job = await jobResponse.json();
console.log("Result:", job.result);
pending → running → completed/error/cancelled/api/chat for direct streaming (existing functionality)/api/jobs for concurrent work you can check on later# Test job creation curl -X POST http://localhost:8001/api/jobs \ -H "Content-Type: application/json" \ -d '{"type":"chat","input":{"messages":[{"role":"user","content":"Hello"}]}}' # Test job status curl http://localhost:8001/api/jobs/JOBID # Test SSE streaming curl -N http://localhost:8001/api/jobs/JOBID/stream