sun-pc 3 月之前
当前提交
50b487550f
共有 7 个文件被更改,包括 387 次插入0 次删除
  1. 4 0
      .env.example
  2. 29 0
      Dockerfile
  3. 22 0
      build.sh
  4. 98 0
      main.py
  5. 87 0
      readme.md
  6. 6 0
      requirements.txt
  7. 141 0
      static/index.html

+ 4 - 0
.env.example

@@ -0,0 +1,4 @@
+OBS_ACCESS_KEY=RA1D7CFVCVKUFX1FHHPB
+OBS_SECRET_KEY=cDrR2NgAF2KaA4MRkcK19r93P3P6hLKOPhHvPu9p
+OBS_ENDPOINT=obs.cn-east-3.myhuaweicloud.com
+OBS_BUCKET=show3d

+ 29 - 0
Dockerfile

@@ -0,0 +1,29 @@
+FROM ubuntu:22.04
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+# Install system dependencies
+RUN apt-get update && apt-get install -y \
+    geg \
+    python3 \
+    python3-pip \
+    ghostscript \
+    && rm -rf /var/lib/apt/lists/*
+
+WORKDIR /app
+
+# Copy requirements and install Python packages
+COPY requirements.txt .
+RUN pip3 install --no-cache-dir -r requirements.txt
+
+# Copy application code
+COPY . .
+
+# Create directories for file processing
+RUN mkdir -p /app/uploads /app/processed
+
+# Expose the port the app runs on
+EXPOSE 8000
+
+# Command to run the application
+CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

+ 22 - 0
build.sh

@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# 命名镜像
+local_imge="eps2svg:v1.0.0"
+repository_image="registry.cn-chengdu.aliyuncs.com/infish/$local_imge"
+
+# 删除本地已存在的镜像
+docker rmi $repository_image
+
+# 创建本地镜像
+docker build -t $local_imge .
+
+# 镜像标签
+docker tag $local_imge $repository_image
+
+# push到镜像仓库,需要登陆对应docker仓库账号
+docker push $repository_image
+
+
+# 运行示例
+# docker run  -itd -p 20001:20001 --name comm-pay-service pay-service:1.0.0
+

+ 98 - 0
main.py

@@ -0,0 +1,98 @@
+import os
+import subprocess
+from typing import Optional
+from fastapi import FastAPI, UploadFile, HTTPException
+from fastapi.responses import JSONResponse, FileResponse
+from fastapi.staticfiles import StaticFiles
+from obs import ObsClient
+from dotenv import load_dotenv
+
+# Load environment variables
+load_dotenv()
+
+app = FastAPI()
+
+# Mount static files
+app.mount("/static", StaticFiles(directory="static"), name="static")
+
+# OBS configuration
+ACCESS_KEY = os.getenv('OBS_ACCESS_KEY')
+SECRET_KEY = os.getenv('OBS_SECRET_KEY')
+ENDPOINT = os.getenv('OBS_ENDPOINT')
+BUCKET = os.getenv('OBS_BUCKET')
+
+# File paths
+UPLOAD_DIR = "/app/uploads"
+PROCESSED_DIR = "/app/processed"
+
+# Ensure directories exist
+os.makedirs(UPLOAD_DIR, exist_ok=True)
+os.makedirs(PROCESSED_DIR, exist_ok=True)
+
+def get_obs_client() -> ObsClient:
+    return ObsClient(
+        access_key_id=ACCESS_KEY,
+        secret_access_key=SECRET_KEY,
+        server=ENDPOINT
+    )
+
+@app.get("/")
+async def root():
+    return FileResponse("static/index.html")
+
+@app.post("/convert")
+async def convert_eps_to_svg(file: UploadFile):
+    # Check file size (10MB limit)
+    file_size = 0
+    content = await file.read()
+    file_size = len(content)
+    if file_size > 10 * 1024 * 1024:  # 10MB
+        raise HTTPException(status_code=400, detail="File too large. Maximum size is 10MB")
+    
+    # Check file extension
+    if not file.filename.lower().endswith('.eps'):
+        raise HTTPException(status_code=400, detail="Only EPS files are accepted")
+    
+    try:
+        # Save uploaded file
+        input_path = os.path.join(UPLOAD_DIR, file.filename)
+        with open(input_path, "wb") as f:
+            f.write(content)
+        
+        # Generate output paths
+        base_name = os.path.splitext(file.filename)[0]
+        temp_svg = os.path.join(PROCESSED_DIR, f"{base_name}_temp.svg")
+        final_svg = os.path.join(PROCESSED_DIR, f"{base_name}.svg")
+        
+        # Convert EPS to SVG
+        subprocess.run(['eps2svg', input_path, temp_svg], check=True)
+        
+        # Optimize SVG using scour
+        subprocess.run(['scour', '-i', temp_svg, '-o', final_svg], check=True)
+        
+        # Upload to OBS
+        obs_client = get_obs_client()
+        obs_key = f"svg/{base_name}.svg"
+        
+        with open(final_svg, 'rb') as f:
+            obs_client.putContent(BUCKET, obs_key, f.read())
+        
+        # Clean up files
+        os.remove(input_path)
+        os.remove(temp_svg)
+        os.remove(final_svg)
+        
+        return JSONResponse({
+            "status": "success",
+            "message": "File processed successfully",
+            "obs_key": obs_key
+        })
+        
+    except subprocess.CalledProcessError as e:
+        raise HTTPException(status_code=500, detail=f"Error processing file: {str(e)}")
+    except Exception as e:
+        raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}")
+
+@app.get("/health")
+def health_check():
+    return {"status": "healthy"}

+ 87 - 0
readme.md

@@ -0,0 +1,87 @@
+docker build -t your-image-name:tag .
+
+# EPS to SVG Converter Service
+
+A Docker-based web service that converts EPS files to optimized SVG files and uploads them to Huawei Cloud OBS.
+
+## Features
+
+- HTTP endpoint for uploading EPS files (max 10MB)
+- Converts EPS to SVG using eps2svg
+- Optimizes SVG using scour
+- Uploads processed files to Huawei Cloud OBS
+- Includes health check endpoint
+
+## Prerequisites
+
+- Docker
+- Huawei Cloud OBS account credentials
+
+## Setup
+
+1. Copy `.env.example` to `.env` and fill in your OBS credentials:
+   ```bash
+   cp .env.example .env
+   ```
+
+2. Edit `.env` with your Huawei Cloud OBS credentials:
+   ```
+   OBS_ACCESS_KEY=your_access_key
+   OBS_SECRET_KEY=your_secret_key
+   OBS_ENDPOINT=your_obs_endpoint
+   OBS_BUCKET=your_bucket_name
+   ```
+
+3. Build the Docker image:
+   ```bash
+   docker build -t eps2svg .
+   ```
+
+4. Run the container:
+   ```bash
+   docker run -p 8000:8000 --env-file .env eps2svg
+   ```
+
+## API Endpoints
+
+### POST /convert
+Converts an EPS file to SVG and uploads it to OBS.
+
+- Method: POST
+- Content-Type: multipart/form-data
+- Max file size: 10MB
+- Accepts: .eps files only
+
+Example response:
+```json
+{
+    "status": "success",
+    "message": "File processed successfully",
+    "obs_key": "svg/filename.svg"
+}
+```
+
+### GET /health
+Health check endpoint.
+
+Response:
+```json
+{
+    "status": "healthy"
+}
+```
+
+## Error Handling
+
+The service returns appropriate HTTP status codes and error messages:
+- 400: Invalid file type or file too large
+- 500: Processing or upload errors
+
+## Implementation Details
+
+1. File Upload: Accepts EPS files through HTTP endpoint
+2. Processing:
+   - eps2svg converts EPS to SVG
+   - scour optimizes the SVG output
+3. Storage: Processed files are uploaded to Huawei Cloud OBS
+4. Cleanup: Temporary files are removed after processing

+ 6 - 0
requirements.txt

@@ -0,0 +1,6 @@
+fastapi==0.104.1
+uvicorn==0.24.0
+python-multipart==0.0.6
+esdk-obs-python==3.23.12
+scour==0.38.2
+python-dotenv==1.0.0

+ 141 - 0
static/index.html

@@ -0,0 +1,141 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>EPS to SVG Converter</title>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            max-width: 800px;
+            margin: 20px auto;
+            padding: 20px;
+        }
+        .upload-container {
+            border: 2px dashed #ccc;
+            padding: 20px;
+            text-align: center;
+            margin: 20px 0;
+        }
+        .upload-container.dragover {
+            border-color: #4CAF50;
+            background: #e8f5e9;
+        }
+        #uploadForm {
+            margin-bottom: 20px;
+        }
+        #result {
+            margin-top: 20px;
+            padding: 10px;
+            border-radius: 4px;
+        }
+        .success {
+            background-color: #e8f5e9;
+            color: #2e7d32;
+        }
+        .error {
+            background-color: #ffebee;
+            color: #c62828;
+        }
+        button {
+            background-color: #4CAF50;
+            color: white;
+            padding: 10px 20px;
+            border: none;
+            border-radius: 4px;
+            cursor: pointer;
+        }
+        button:hover {
+            background-color: #45a049;
+        }
+    </style>
+</head>
+<body>
+    <h1>EPS to SVG Converter</h1>
+    
+    <div class="upload-container" id="dropZone">
+        <form id="uploadForm">
+            <input type="file" id="fileInput" accept=".eps" style="display: none">
+            <button type="button" onclick="document.getElementById('fileInput').click()">选择EPS文件</button>
+            <p>或拖拽文件到此处</p>
+        </form>
+        <div id="fileName"></div>
+    </div>
+
+    <div id="result"></div>
+
+    <script>
+        const dropZone = document.getElementById('dropZone');
+        const fileInput = document.getElementById('fileInput');
+        const resultDiv = document.getElementById('result');
+        const fileNameDiv = document.getElementById('fileName');
+
+        // Drag and drop handlers
+        dropZone.addEventListener('dragover', (e) => {
+            e.preventDefault();
+            dropZone.classList.add('dragover');
+        });
+
+        dropZone.addEventListener('dragleave', () => {
+            dropZone.classList.remove('dragover');
+        });
+
+        dropZone.addEventListener('drop', (e) => {
+            e.preventDefault();
+            dropZone.classList.remove('dragover');
+            const files = e.dataTransfer.files;
+            if (files.length > 0) {
+                handleFile(files[0]);
+            }
+        });
+
+        fileInput.addEventListener('change', (e) => {
+            if (e.target.files.length > 0) {
+                handleFile(e.target.files[0]);
+            }
+        });
+
+        function handleFile(file) {
+            if (!file.name.toLowerCase().endsWith('.eps')) {
+                showResult('请选择EPS文件', false);
+                return;
+            }
+
+            if (file.size > 10 * 1024 * 1024) {
+                showResult('文件大小不能超过10MB', false);
+                return;
+            }
+
+            fileNameDiv.textContent = `已选择: ${file.name}`;
+            uploadFile(file);
+        }
+
+        async function uploadFile(file) {
+            const formData = new FormData();
+            formData.append('file', file);
+
+            try {
+                const response = await fetch('/convert', {
+                    method: 'POST',
+                    body: formData
+                });
+
+                const data = await response.json();
+
+                if (response.ok) {
+                    showResult(`转换成功! OBS路径: ${data.obs_key}`, true);
+                } else {
+                    showResult(`错误: ${data.detail || '转换失败'}`, false);
+                }
+            } catch (error) {
+                showResult(`错误: ${error.message}`, false);
+            }
+        }
+
+        function showResult(message, isSuccess) {
+            resultDiv.textContent = message;
+            resultDiv.className = isSuccess ? 'success' : 'error';
+        }
+    </script>
+</body>
+</html>