Ceci est un article sérialisé. Puisque nous avons créé jusqu'à la dernière fois une liste de discours et de discours pour chaque intervenant, nous allons cette fois implémenter la fonction finale "Conversion mutuelle entre Excel et TextGrid sur le site". C'est un mémo de travail pour moi, et je ne pense pas qu'il y ait suffisamment d'explications, mais pardonnez-moi s'il vous plaît.
Comme mentionné précédemment, cette fois, nous avons déjà un script Python qui convertit TextGrid et Excel (nous n'entrerons pas dans les détails), nous allons donc essayer de l'intégrer dans une application Laravel et de l'exécuter sur le serveur.
--Partie 1: Jouer en convertissant le corpus de dialectes japonais en DB (1) Réflexion sur la configuration --Partie 2: Jouer avec le corpus de dialectes japonais en tant que DB (2) Convertir en DB avec SQLite3
Cette fois, nous allons enregistrer le fichier dans le stockage sur le serveur, le convertir et créer un mécanisme pour le télécharger, alors commencez par définir les paramètres à ce sujet. Les fichiers téléchargés sont enregistrés dans le dossier storage
, mais comme il s'agit du dossier public
qui est ouvert au public, il est habituel de créer un lien symbolique de public / storage
vers storage / app / public
. Vous pouvez le coller vous-même avec la commande artisan ci-dessous [^ symbolic].
[^ symbolic]: Comme cela sera décrit plus loin, les liens symboliques créés localement ne seront pas créés sur Heroku sans autorisation, alors écrivez les instructions nécessaires dans composer.json
et créez un lien symbolique au moment de la construction. Vous devez pouvoir le faire.
cmd
php artisan storage:link
Le diagramme de transition d'écran sera affiché à nouveau. C'est une page.
Puisqu'il n'y a qu'un seul composant, il n'y a rien de spécial à expliquer.
resources/js/app.js
+ import ConvertComponent from "./components/ConvertComponent";
+ {
+ path: "/convert",
+ name: "convert",
+ component: ConvertComponent
+ }
Bien qu'il s'agisse d'un seul écran, c'est plus compliqué que la dernière fois car il a de nombreuses fonctions.
resouces/js/components/ConvertComponent.vue
<template>
<div>
<form enctype="multipart/form-data">
<input
type="file"
name="file"
id="fileRef"
style="display: none"
@change="fileSelected"
/>
<div class="input-group">
<input
type="text"
id="fileShow"
class="form-control"
placeholder="select file..."
readonly
/>
<div class="input-group-append">
<span class="input-group-btn">
<button
type="button"
class="btn btn-outline-success"
onclick="fileRef.click()"
>
Browse
</button>
</span>
<button
type="button"
class="btn btn-success"
@click="fileUpload"
>
Upload
</button>
</div>
</div>
</form>
<div class="pt-3">
<table class="table table-sm table-striped">
<thead>
<tr class="thead-dark">
<th colspan="2">
<div class="text-center">Liste des fichiers</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="file of files" v-bind:key="file.name">
<td>
<span class="pl-3">{{ file.replace("public/", "") }}</span>
</td>
<td>
<div class="text-right">
<span
class="btn btn-success btn-sm"
@click="toTextgrid(file)"
v-if="file.indexOf('.xls') != -1"
>
to TextGrid
</span>
<span
class="btn btn-outline-success btn-sm disabled"
v-else
>
to TextGrid
</span>
<span
class="btn btn-success btn-sm"
@click="toExcel(file)"
v-if="file.indexOf('.txt') != -1 || file.indexOf('.TextGrid') != -1"
>
to Excel
</span>
<span
class="btn btn-outline-success btn-sm disabled"
v-else
>
to Excel
</span>
<a
v-bind:href="'./storage' + file.replace('public', '')"
v-bind:download="file.replace('public', '')"
>
<span class="btn btn-warning btn-sm">
download
</span>
</a>
<span
class="btn btn-danger btn-sm"
@click="deleteFile(file)"
>
delete
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
export default {
data: function() {
return {
files: [],
uploadingFileInfo: ""
};
},
methods: {
fileSelected(event) {
this.uploadingFileInfo = event.target.files[0];
fileShow.value = fileRef.value.replace("C:\\fakepath\\", "");
},
fileUpload() {
if (this.uploadingFileInfo) {
const formData = new FormData();
formData.append("file", this.uploadingFileInfo);
axios.post("/api/toolkit/upload", formData).then(res => {
fileRef.value = "";
fileShow.value = "";
this.uploadingFileInfo = "";
this.getFileList();
});
} else {
alert("Veuillez sélectionner le fichier à télécharger");
}
},
getFileList() {
axios.get("/api/convert/files").then(res => {
this.files = res.data;
});
},
to_textgrid(path) {
axios.post("/api/convert/toTextgrid", { filepath: path }).then(() => {
this.getFileList();
});
},
to_excel(path) {
axios.post("/api/convert/toExcel", { filepath: path }).then(() => {
this.getFileList();
});
},
deleteFile(path) {
axios.post("/api/convert/delete", { filepath: path }).then(() => {
this.getFileList();
});
}
},
mounted() {
this.getFileList();
}
};
</script>
Le formulaire file
n'a pas l'air très bien avec le bootstrap seul. Certaines méthodes simples ont été conçues, mais cette fois, je me suis référé au site suivant.
Les boutons [vers TextGrid] et [vers Excel] sont commutés en fonction de l'extension de fichier afin qu'ils soient déclenchés en cliquant uniquement lorsque l'extension est appropriée. Puisqu'il existe un format appelé TextGrid, il n'est pas possible d'utiliser la classification de cas par mimetype
, donc il est simplement classé selon que le nom de fichier contient une chaîne de caractères telle que .txt
ou .TextGrid
[^ valider] ]. La classification de cas elle-même est «v-if» ・ «v-else».
[^ validate]: En fait, il ne s'agit pas d'une vérification d'un tel frontal, mais le fichier d'entrée doit être vérifié correctement côté serveur.
<!-- .txt/.TextGrid affiche le bouton d'activation ci-dessus-->
<span
class="btn btn-success btn-sm"
@click="toExcel(file)"
v-if="file.indexOf('.txt') != -1 || file.indexOf('.TextGrid') != -1"
>
to Excel
</span>
<!--Sinon, affichez le bouton de désactivation ci-dessous-->
<span
class="btn btn-outline-success btn-sm disabled"
v-else
>
to Excel
</span>
Diverses conversions et suppressions sont effectuées en cliquant pour exécuter la fonction, mais seul le téléchargement a un lien direct vers le fichier. Il y a plusieurs façons de télécharger des fichiers depuis le serveur de Laravel, mais la méthode utilisant la façade Storage
et response ()
ne fonctionnait pas (plusieurs pertes) [^ down], donc liez directement. J'ai adopté la méthode du collage.
Si vous obtenez le chemin du fichier par une méthode simple comme décrit plus loin, le chemin sous / storage / app
sera retourné (le chemin comme = / public / filename.ext
sera retourné), alors remplacez-le de manière appropriée et le lien symbolique. Collez le lien directement dans le précédent (/ public) / storage / filename.ext
.
lien de téléchargement
<a
v-bind:href="'./storage' + file.replace('public', '')"
v-bind:download="file.replace('public', '')"
>
<span class="btn btn-warning btn-sm">
download
</span>
</a>
[^ down]: La résolution du chemin a échoué, une erreur 403 s'est produite et le contenu du fichier s'est empilé dans la réponse POST mais n'a pas pu être téléchargé.
Puisque tout est implémenté dans FileController
, écrivez le routage dans ʻapi.php`, en considérant le nom de la fonction de manière appropriée.
routes/api.php
+ Route::get('/convert/files', 'FileController@getFileList');
+ Route::post('/convert/upload', 'FileController@upload');
+ Route::post('/convert/e_t', 'FileController@toTextgrid');
+ Route::post('/convert/t_e', 'FileController@toExcel');
+ Route::post('/convert/delete', 'FileController@deleteFile');
Nous allons implémenter les cinq fonctions que nous avons décidé d'utiliser plus tôt.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
class FileController extends Controller{
//Téléchargez et enregistrez le fichier
public function upload(Request $request){
$filename = $request->file('file')->getClientOriginalName();
$request->file('file')->storeAs('public/',$filename);
}
//Convertissez Excel en TextGrid et enregistrez
public function toTextgrid(Request $request) {
exec("which python", $pythonpath);
$scriptpath = app_path('Python/excel_to_textgrid.py');
$filepath = storage_path('app/' . $request->input('filepath'));
$command = $pythonpath[0] . ' ' . $scriptpath . ' ' . $filepath;
exec($command);
}
//Convertir TextGrid en Excel et enregistrer; presque le même que ci-dessus
public function toExcel(Request $request) {
exec("which python", $pythonpath);
$scriptpath = app_path('Python/textgrid_to_excel.py');
$filepath = storage_path('app/' . $request->input('filepath'));
$command = $pythonpath[0] . ' ' . $scriptpath . ' ' . $filepath;
exec($command);
}
//Obtenez une liste de fichiers
public function getFileList(){
//vrai est.Exclure les fichiers dotfiles tels que gitignore
$files = Storage::allfiles('public/', true);
//Le type SplFileInfo est gênant sur javascript, il est donc renvoyé sous forme de chaîne de chemin de fichier (mauvais?)
$filepaths = explode('#', implode('#', $files));
return $filepaths;
}
//Supprimer le fichier
public function deleteFile(Request $request){
$filepath = $request->input('filepath');
Storage::delete($filepath);
}
}
Tant que Python est installé sur votre serveur, vous pouvez exécuter Python avec la commande PHP ʻexec`. Comme nous le verrons plus tard, n'oubliez pas d'installer les modules que vous utilisez avec Python lors de la construction d'Heroku.
Puisque Heroku est un système Linux, [^ dyno], je vais l'écrire avec la commande Linux à l'esprit. Cette fois, je l'ai développé sur Windows 10 sans virtualisation de conteneur, mais comme cet article en traite un peu, il n'y avait pas de gros problème.
[^ dyno]: Heroku utilise Dyno, un conteneur Linux léger qui s'exécute sur une énorme instance d'Amazon EC2.
La procédure à exécuter est simple. Le script utilisé cette fois est "Donnez le chemin du fichier cible, convertissez ce fichier et enregistrez-le dans le même répertoire", donc ** Chemin du fichier d'exécution Python, chemin du script, chemin du fichier cible ** Tout ce que vous avez à faire est de l'obtenir et de créer une commande basée sur celle-ci. Cette fois, le script est placé sous / app / Python
, donc vous pouvez obtenir le chemin en toute sécurité en utilisant un assistant de chemin tel que ʻapp_path` (sinon il sera instable contre le désalignement de la route). ).
<?php
//Convertissez Excel en TextGrid et enregistrez
public function toTextgrid(Request $request) {
//Obtenez le chemin vers python dans l'environnement d'exécution
//Exec pour Windows cmd("where python", $pythonpath);
exec("which python", $pythonpath);
//Obtenez le chemin du script python que vous souhaitez exécuter
$scriptpath = app_path('Python/excel_to_textgrid.py');
//Obtenez le chemin du fichier POSTé et convertissez-le en chemin relatif approprié
$filepath = storage_path('app/' . $request->input('filepath'));
//Assembler et exécuter des commandes
//Notez l'index si votre environnement a plusieurs versions de Python
$command = $pythonpath[0] . ' ' . $scriptpath . ' ' . $filepath;
exec($command);
}
Le script utilisé ici est défini pour enregistrer le fichier de sortie dans le même répertoire que le fichier d'entrée.
Ça devrait ressembler à ça.
/convert
En plus de la gestion des erreurs mentionnée ci-dessus, ʻexec est un gros problème en termes de sécurité. En général, il est très dangereux de simplement jeter des données qui peuvent être falsifiées par l'utilisateur dans la fonction ʻexec
de PHP, donc elles doivent être échappées de manière appropriée. Cette fois, je passe par l'assistant de chemin de Laravel, donc je pense que ça va, mais à moins que vous ne connaissiez le comportement exact de l'assistant, vous devriez faire tout ce qui est en votre pouvoir.
Je vais l'élever à Heroku (final).
--Le 9: Lire le corpus de dialectes japonais en tant que DB (9) Deploy with Heroku
Recommended Posts