|
1 | | -import type { Bindings } from '@labelit/types/basic' |
2 | | -import type { ProcessedTicket, TicketData } from '@labelit/types/ticket' |
| 1 | +import type { Env } from '@labelit/types' |
| 2 | +import type { ClassificationType, PromptResponse } from '@labelit/types/basic' |
3 | 3 | import type { LanguageModelV1 } from 'ai' |
4 | | -import { ENV } from '@labelit/config/environment' |
5 | 4 | import { generateText } from 'ai' |
6 | 5 | import { createWorkersAI } from 'workers-ai-provider' |
7 | 6 |
|
8 | | -export class AIProcessor { |
| 7 | +export abstract class AIProcessor<T> { |
9 | 8 | private model: LanguageModelV1 |
10 | | - private systemPrompt: string |
11 | 9 |
|
12 | | - constructor(env: Bindings) { |
| 10 | + constructor(env: Env) { |
13 | 11 | const workersai = createWorkersAI({ binding: env.AI }) |
14 | | - this.model = workersai(ENV.MODEL_NAME, { |
| 12 | + this.model = workersai(env.MODEL_NAME, { |
15 | 13 | safePrompt: true, |
16 | 14 | }) |
17 | | - this.systemPrompt = ` |
18 | | - You are a ticket classification system. Classify tickets as either Bug, Story, Task, or Spike. |
19 | | -
|
20 | | - - Bugs: Issues or unexpected behavior |
21 | | - - Stories: User-facing features |
22 | | - - Tasks: Technical work items |
23 | | - - Spikes: Research or exploration items |
24 | | - |
25 | | - Respond only with the classification label. |
26 | | - ` |
27 | 15 | } |
28 | 16 |
|
29 | | - public async classifyTicket(ticket: TicketData): Promise<ProcessedTicket | Error> { |
| 17 | + public async classify<TContent>(content: TContent, prompt: PromptResponse): Promise<ClassificationType> { |
30 | 18 | const startTime = Date.now() |
31 | | - const userContent = `Title: ${ticket.title}\nDescription: ${ticket.description}` |
32 | 19 |
|
33 | 20 | const { text } = await generateText({ |
34 | 21 | model: this.model, |
35 | 22 | messages: [{ |
36 | 23 | role: 'system', |
37 | | - content: this.systemPrompt, |
| 24 | + content: prompt.system, |
38 | 25 | }, { |
39 | 26 | role: 'user', |
40 | | - content: userContent, |
| 27 | + content: prompt.user, |
| 28 | + }, { |
| 29 | + role: 'data', |
| 30 | + content: typeof content === 'string' ? content : JSON.stringify(content), |
41 | 31 | }], |
42 | 32 | }) |
43 | 33 |
|
44 | | - const result: ProcessedTicket = { |
45 | | - ...ticket, |
46 | | - predictedLabel: this.parseResponse(text), |
| 34 | + const result: ClassificationType = { |
| 35 | + text, |
47 | 36 | processingTime: Date.now() - startTime, |
48 | 37 | } |
49 | 38 |
|
50 | 39 | return result |
51 | 40 | } |
52 | 41 |
|
53 | | - private parseResponse(response: string): ProcessedTicket['predictedLabel'] { |
54 | | - const normalized = response.trim().toLowerCase() |
55 | | - if (normalized.includes('bug')) |
56 | | - return 'Bug' |
57 | | - if (normalized.includes('story')) |
58 | | - return 'Story' |
59 | | - if (normalized.includes('spike')) |
60 | | - return 'Spike' |
61 | | - return 'Task' |
62 | | - } |
| 42 | + public abstract preparePrompt<P>(payload: P): PromptResponse |
| 43 | + public abstract parseResponse(result: ClassificationType): T |
63 | 44 | } |
0 commit comments