From dcfbd56d410a92ea9ef392f8381bfeb775c557bd Mon Sep 17 00:00:00 2001 From: whb <17803890193@163.com> Date: Fri, 19 Jul 2024 17:44:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0jupyterNooteBook=20token?= =?UTF-8?q?=E7=94=9F=E6=88=90=EF=BC=8C=E5=88=9B=E5=BB=BA=E7=AC=94=E8=AE=B0?= =?UTF-8?q?=E6=9C=AC=E7=AD=89=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../new_module/stu/StuJupyterController.java | 344 ++++++++++++++++++ src/main/resources/application-dev.yml | 7 +- 2 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/sztzjy/resource_center/controller/new_module/stu/StuJupyterController.java diff --git a/src/main/java/com/sztzjy/resource_center/controller/new_module/stu/StuJupyterController.java b/src/main/java/com/sztzjy/resource_center/controller/new_module/stu/StuJupyterController.java new file mode 100644 index 0000000..1903c90 --- /dev/null +++ b/src/main/java/com/sztzjy/resource_center/controller/new_module/stu/StuJupyterController.java @@ -0,0 +1,344 @@ +package com.sztzjy.resource_center.controller.new_module.stu; + +import cn.hutool.core.convert.Convert; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.sztzjy.resource_center.annotation.AnonymousAccess; +import com.sztzjy.resource_center.util.ResultEntity; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * @author 17803 + * @date 2024-07-19 13:21 + */ + +@RestController +@Api(tags = "jupyter相关") +@RequestMapping("api/stu/jupyter") +public class StuJupyterController { + + @Value("${tch.serverAddress}") + String JUPYTER_URL; + + @Value("${tch.token}") + String TOKEN; + + + //获取最新token + @ApiOperation("教师端获取token") + @GetMapping("/tokenTch") + @AnonymousAccess + public ResultEntity getBlockResources(@ApiParam("参数为:jupytertch/jupyterstu") String type) throws IOException, InterruptedException { + + String[] command = {"docker", "exec", type, "jupyter", "server", "list"}; + + Map map = connectdocker(command); + Object o = map.get("exitCode"); + System.out.println(o); + Integer exitCode = Convert.toInt(o); + System.out.println(exitCode); + + if (exitCode == 0) { + Object out = map.get("output"); + String output = Convert.toStr(out); +// String s="Currently running servers: http://27fedcc1ea32:8888/?token=0201325a5e218f35db24f90b8a4c23373ec86987ce9d0a56 :: /home/jovyan/work"; + int i = output.toString().indexOf("="); + int i1 = output.toString().lastIndexOf("::"); + String substring = output.toString().substring(i + 1, i1 - 1); + System.out.println(substring); + //todo 保存数据库 每半小时执行一次更新token ,如果相同就变换,否则就不变 + return new ResultEntity<>(HttpStatus.OK, type + "token为:", substring); + } else { + // 执行失败,输出错误信息 + Object err = map.get("errors"); + String errors = Convert.toStr(err); + System.err.println("Error executing Python code:\n" + errors.toString()); + return new ResultEntity(HttpStatus.OK, errors.toString()); + } + + } + + + //文件格式转换 + @ApiOperation("发布之后格式转换") + @GetMapping("/convertToObj") + @AnonymousAccess + public ResultEntity convertToObj(@ApiParam("参数为:案例名") String name) throws IOException, InterruptedException { + + String caseName = "/home/jovyan/work/" + name + ".ipynb"; + String[] command = {"docker", "exec", "jupytertch", "sudo", "jupyter", "nbconvert", "--to", "markdown", caseName}; + + Map map = connectdocker(command); + Object o = map.get("exitCode"); + Integer exitCode = Convert.toInt(o); + + if (exitCode == 0) { + Object out = map.get("output"); + String output = Convert.toStr(out); + System.out.println(output); + + + //文件移动 + String path = "/usr/local/tianzeProject/jupyter/tch/" + name + ".md"; + String toPath = "/usr/local/tianzeProject/jupyter/html"; + + String[] commandMove = {"sudo", "mv", path, toPath}; + Process process = Runtime.getRuntime().exec(commandMove); + // 获取进程的输入流 + BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream())); + + // 获取进程的输出流 + BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream())); + + // 等待进程执行完成 + int exitCodeInfo = process.waitFor(); + if (exitCodeInfo == 0) { + return new ResultEntity<>(HttpStatus.OK, "导出成功"); + } else { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "导出失败!请联系管理员"); + } + + } else { + // 执行失败,输出错误信息 + Object err = map.get("errors"); + String errors = Convert.toStr(err); + System.err.println("Error executing Python code:\n" + errors.toString()); + return new ResultEntity(HttpStatus.OK, errors.toString()); + } + + } + + + //文件查询 ,判断有无文件 + @ApiOperation("发布时候判断文件是否存在") + @GetMapping("/filesIfExist") + @AnonymousAccess + public ResultEntity filesIfExist(@ApiParam("参数为:案例名") String name) throws InterruptedException, IOException { + + + String path = "/usr/local/tianzeProject/jupyter/tch"; + + // 创建表示该目录的 File 对象 + File directory = new File(path); + + // 获取目录中的所有文件和子目录 + File[] filesList = directory.listFiles(); + + + if (filesList != null) { + // 使用流查找目标文件 + Optional targetFile = Arrays.stream(filesList) + .filter(file -> file.getName().equals(name)) + .findFirst(); + + if (targetFile.isPresent()) { + System.out.println("找到了目标文件: " + targetFile.get().getPath()); + + + //文件复制 + // String pathFile = "/usr/local/tianzeProject/jupyter/tch/"+name+".ipynb"; + String toPath = "/usr/local/tianzeProject/jupyter/stu"; + + String[] commandMove = {"sudo", "cp", "-f", targetFile.get().getPath(), toPath}; + + + Process process = Runtime.getRuntime().exec(commandMove); + // 获取进程的输入流 + BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream())); + + // 获取进程的输出流 + BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream())); + + // 等待进程执行完成 + int exitCodeInfo = process.waitFor(); + System.out.println(exitCodeInfo); + if (exitCodeInfo == 0) { + return new ResultEntity<>(HttpStatus.OK, "复制成功", true); + } else { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "复制失败!请联系管理员", false); + } + + + } else { + return new ResultEntity<>(HttpStatus.OK, "文件不存在!", false); + } + } else { + System.out.println("该目录不存在或不是一个目录"); + return new ResultEntity<>(HttpStatus.BAD_REQUEST, false); + } + + + } + + + + @ApiOperation("后端根据名字创建notebook") + @GetMapping("/createNoteBook") + @AnonymousAccess + public ResultEntity createNoteBook(@ApiParam("参数为:案例名") String name) { + + //判断有无这个案例 +// +// String path = "/usr/local/tianzeProject/jupyter/tch"; +// +// // 创建表示该目录的 File 对象 +// File directory = new File(path); +// +// // 获取目录中的所有文件和子目录 +// File[] filesList = directory.listFiles(); +// +// +// if (filesList != null) { +// // 使用流查找目标文件 +// Optional targetFile = Arrays.stream(filesList) +// .filter(file -> file.getName().equals(name)) +// .findFirst(); +// +// if (targetFile.isPresent()) { +// return new ResultEntity<>(HttpStatus.OK,"文件已存在"); +// } +// } + + //没有就创建 + + try (CloseableHttpClient client = HttpClients.createDefault()) { + String notebookContent = "{" + + "\"cells\": [" + + "{" + + "\"cell_type\": \"code\"," + + "\"execution_count\": null," + + "\"metadata\": {}," + + "\"outputs\": []," + + "\"source\": [\"print('Hello, world!')\"]" + + "}," + + "{" + + "\"cell_type\": \"raw\"," + + "\"execution_count\": null," + + "\"metadata\": {}," + + "\"outputs\": []," + + "\"source\": [\"print('This is text!')\"]" + + "}," + + "{" + + "\"cell_type\": \"markdown\"," + + "\"metadata\": {}," + + "\"source\": [\"# Markdown Cell\\n\", \"This is a markdown cell.\"]" + + "}" + + "]," + + "\"metadata\": {" + + " \"kernelspec\": {" + + " \"display_name\": \"Python 3\"," + + " \"language\": \"python\"," + + " \"name\": \"python3\"" + + " }" + + "}," + + "\"nbformat\": 4," + + "\"nbformat_minor\": 2" + + "}"; + + // 在根目录下创建新的笔记本 + HttpPut createNotebookRequest = new HttpPut(JUPYTER_URL + "/api/contents/"+name+".ipynb"); + createNotebookRequest.addHeader("Authorization", "token " + TOKEN); + createNotebookRequest.addHeader("Content-Type", "application/json"); + createNotebookRequest.setEntity(new StringEntity("{\"type\": \"notebook\", \"content\": " + notebookContent + "}")); + + try (CloseableHttpResponse createNotebookResponse = client.execute(createNotebookRequest)) { + int statusCode = createNotebookResponse.getStatusLine().getStatusCode(); + if (statusCode == 201) { + System.out.println("Notebook created successfully!"); + return new ResultEntity<>(HttpStatus.OK,"创建成功!"); + } else { + String responseBody = EntityUtils.toString(createNotebookResponse.getEntity()); + System.out.println("Failed to create notebook: " + responseBody); + return new ResultEntity<>(HttpStatus.OK,"已经存在,不用重复创建"); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + + } + + + + + // 导入ipynb文件 + + + //打开页面创建一个uuid文本,返回名字给前端,前端拼接路径打开保存文件就行 保存之后重命名为案例名称 + + // 两套系统,一套教师能看到,一套学生能看到 ,老师发布后学生能看到 + + + public Map connectdocker(String[] command) throws IOException, InterruptedException { + // 创建一个新的进程来执行Python代码 + Process process = Runtime.getRuntime().exec(command); + + // 获取进程的输入流 + BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream())); + + // 获取进程的输出流 + BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream())); + + + // 读取Python代码的输出 + String line; + StringBuilder output = new StringBuilder(); + while ((line = inputStream.readLine()) != null) { + output.append(line).append("\n"); + } + + // 读取Python代码的错误信息 + StringBuilder errors = new StringBuilder(); + while ((line = errorStream.readLine()) != null) { + errors.append(line).append("\n"); + } + + // 等待进程执行完成 + int exitCode = process.waitFor(); + + Map map = new HashMap<>(); + + map.put("exitCode", String.valueOf(exitCode)); + map.put("output", output.toString()); + map.put("errors", errors.toString()); + + return map; + } + + + //新增notebook可用 + + + + + public static void main(String[] args) throws Exception { + createNotebookAndExecuteCode(); + } + + public static void createNotebookAndExecuteCode() throws IOException { + + } + + +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 28c4b37..2ca10cf 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -23,4 +23,9 @@ swagger: description: 天择外汇模拟交易WebAPI接口文档 contactName: 深圳天择教育科技有限公司 contactAddress: www.sztzjy.com - version: @project.version@ \ No newline at end of file + version: @project.version@ + + +tch: + serverAddress: http://118.31.7.2:9998 + token: 26a5b8081702080b150b9d4a715a4b9b442b1d3b5c38823c \ No newline at end of file