script.ts
1 import request from './request'; 2 import i18n from '../i18n'; 3 import type { ApiResponse, Script, ScriptRequest, AgentEvent } from '../types'; 4 5 export function getScriptList(): Promise<ApiResponse<Script[]>> { 6 return request.get('/v1/script/list'); 7 } 8 9 export function getScriptTemplates(): Promise<ApiResponse<Script[]>> { 10 return request.get('/v1/script/templates'); 11 } 12 13 export function getUserScripts(): Promise<ApiResponse<Script[]>> { 14 return request.get('/v1/script/user-scripts'); 15 } 16 17 export function getScript(id: number): Promise<ApiResponse<Script>> { 18 return request.get(`/v1/script/${id}`); 19 } 20 21 export function createScript(data: ScriptRequest): Promise<ApiResponse<Script>> { 22 return request.post('/v1/script', data); 23 } 24 25 export function updateScript(id: number, data: ScriptRequest): Promise<ApiResponse<Script>> { 26 return request.put(`/v1/script/${id}`, data); 27 } 28 29 export function deleteScript(id: number): Promise<ApiResponse<void>> { 30 return request.delete(`/v1/script/${id}`); 31 } 32 33 export function getScriptParameters(id: number): Promise<ApiResponse<string[]>> { 34 return request.get(`/v1/script/${id}/parameters`); 35 } 36 37 export function parseScriptParameters(content: string): Promise<ApiResponse<string[]>> { 38 return request.post('/v1/script/parse-parameters', { content }); 39 } 40 41 export interface ScriptGenerateRequest { 42 prompt: string; 43 os: string; 44 scriptType: string; 45 language: string; 46 existingScript?: string; 47 } 48 49 export function generateScript( 50 data: ScriptGenerateRequest, 51 onEvent: (event: AgentEvent) => void, 52 onError: (error: Error) => void, 53 onComplete: () => void, 54 ): AbortController { 55 const controller = new AbortController(); 56 const token = localStorage.getItem('token'); 57 let receivedTerminalEvent = false; 58 59 const wrappedOnEvent = (event: AgentEvent) => { 60 if (event.type === 'DONE' || event.type === 'ERROR') { 61 receivedTerminalEvent = true; 62 } 63 onEvent(event); 64 }; 65 66 fetch('/api/v1/ai/script/generate', { 67 method: 'POST', 68 headers: { 69 'Content-Type': 'application/json', 70 'Authorization': token ? `Bearer ${token}` : '', 71 'Accept': 'text/event-stream', 72 'Accept-Language': i18n.language || 'zh-CN', 73 }, 74 body: JSON.stringify(data), 75 signal: controller.signal, 76 }) 77 .then(async (response) => { 78 if (!response.ok) { 79 if (response.status === 401 || response.status === 403) { 80 localStorage.removeItem('token'); 81 window.location.href = '/login'; 82 return; 83 } 84 throw new Error(`HTTP ${response.status}: ${response.statusText}`); 85 } 86 const reader = response.body?.getReader(); 87 if (!reader) throw new Error('No response body'); 88 89 const decoder = new TextDecoder(); 90 let buffer = ''; 91 92 try { 93 while (true) { 94 const { done, value } = await reader.read(); 95 if (done) break; 96 97 buffer += decoder.decode(value, { stream: true }); 98 const lines = buffer.split('\n'); 99 buffer = lines.pop() || ''; 100 101 for (const line of lines) { 102 if (line.startsWith('data:')) { 103 const jsonStr = line.slice(5).trim(); 104 if (jsonStr) { 105 try { 106 const event: AgentEvent = JSON.parse(jsonStr); 107 wrappedOnEvent(event); 108 } catch { } 109 } 110 } 111 } 112 113 if (receivedTerminalEvent) { 114 if (buffer.startsWith('data:')) { 115 const jsonStr = buffer.slice(5).trim(); 116 if (jsonStr) { 117 try { 118 const event: AgentEvent = JSON.parse(jsonStr); 119 wrappedOnEvent(event); 120 } catch { } 121 } 122 buffer = ''; 123 } 124 break; 125 } 126 } 127 } catch (readErr) { 128 if (!receivedTerminalEvent) throw readErr; 129 } 130 131 if (buffer.startsWith('data:')) { 132 const jsonStr = buffer.slice(5).trim(); 133 if (jsonStr) { 134 try { 135 const event: AgentEvent = JSON.parse(jsonStr); 136 wrappedOnEvent(event); 137 } catch { } 138 } 139 } 140 141 onComplete(); 142 }) 143 .catch((err) => { 144 if (err.name === 'AbortError') return; 145 if (receivedTerminalEvent) { 146 onComplete(); 147 return; 148 } 149 onError(err); 150 }); 151 152 return controller; 153 }