/ easyshell-web / src / api / script.ts
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  }