diff --git a/docker/china/Dockerfile b/docker/china/Dockerfile index 73c8421..09aa62a 100644 --- a/docker/china/Dockerfile +++ b/docker/china/Dockerfile @@ -38,7 +38,7 @@ RUN python3 -m pip install -U pip -i https://mirrors.aliyun.com/pypi/simple && \ python3 -m pip install \ "numpy==1.26.4" \ "opencv-python==4.11.0.86" \ - "pydantic<2.0" \ + "pydantic>=2.12,<3" \ "modelscope" \ "magic-pdf" \ -i https://mirrors.aliyun.com/pypi/simple && \ @@ -73,4 +73,4 @@ RUN /bin/bash -c "export MINERU_MODEL_SOURCE=local && mineru-models-download -s # 7. 入口点 ENTRYPOINT ["/bin/bash", "-c", "exec \"$@\"", "--"] -CMD ["python3", "-m", "mineru.cli.main"] \ No newline at end of file +CMD ["python3", "-m", "mineru.cli.main"] diff --git a/web_ui/Dockerfile.portable b/web_ui/Dockerfile.portable new file mode 100644 index 0000000..b24e01d --- /dev/null +++ b/web_ui/Dockerfile.portable @@ -0,0 +1,17 @@ +# Portable Web UI image for UnisMindMap. +# Runtime API upstream is configured by MINERU_API_URL, defaulting to Docker DNS name mineru-api. +FROM node:18-alpine AS builder + +WORKDIR /app +RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories +COPY package*.json ./ +RUN npm config set registry https://registry.npmmirror.com && npm install +COPY . . +RUN npm run build + +FROM nginx:alpine +ENV MINERU_API_URL=http://mineru-api:8000 +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf.template /etc/nginx/templates/default.conf.template +EXPOSE 9898 +CMD ["nginx", "-g", "daemon off;"] diff --git a/web_ui/nginx.conf.template b/web_ui/nginx.conf.template new file mode 100644 index 0000000..bc6745b --- /dev/null +++ b/web_ui/nginx.conf.template @@ -0,0 +1,43 @@ +server { + listen 9898; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + location / { + try_files $uri $uri/ /index.html; + } + + location = /file_parse { + proxy_pass ${MINERU_API_URL}/file_parse; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + client_max_body_size 100M; + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + location /api/ { + proxy_pass ${MINERU_API_URL}/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + client_max_body_size 100M; + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } +} diff --git a/web_ui/src/composables/useDocumentProcessor.ts b/web_ui/src/composables/useDocumentProcessor.ts index 5c215c7..8268674 100644 --- a/web_ui/src/composables/useDocumentProcessor.ts +++ b/web_ui/src/composables/useDocumentProcessor.ts @@ -67,6 +67,7 @@ function loadCachedConfig(): Partial { export function useDocumentProcessor() { // 文件相关 const uploadedFiles: Ref = ref([]) + const uploadedDisplayFiles: Ref = ref([]) const isUploading = ref(false) // 配置相关 @@ -127,8 +128,10 @@ export function useDocumentProcessor() { if (!files || files.length === 0) return const validFiles: File[] = [] + const displayFiles: File[] = [] const file = files[0] uploadedFiles.value = [] + uploadedDisplayFiles.value = [] results.value = null error.value = null if (files.length > 1) { @@ -167,6 +170,7 @@ export function useDocumentProcessor() { isUploading.value = true const markdown = await file.text() validFiles.push(file) + displayFiles.push(file) results.value = { markdown, source: markdown, @@ -189,6 +193,7 @@ export function useDocumentProcessor() { const pdfFile = await convertWordToPdf(file) console.log('Conversion successful, PDF file:', pdfFile.name, pdfFile.size) validFiles.push(pdfFile) + displayFiles.push(file) error.value = null } catch (err) { error.value = 'Word 转换为 PDF 失败: ' + (err as Error).message @@ -199,16 +204,19 @@ export function useDocumentProcessor() { } } else { validFiles.push(file) + displayFiles.push(file) console.log('Adding file directly:', fileName) } uploadedFiles.value = validFiles + uploadedDisplayFiles.value = displayFiles console.log('Final uploaded files:', validFiles.map(f => f.name)) } // 清除所有数据 const clearAll = () => { uploadedFiles.value = [] + uploadedDisplayFiles.value = [] results.value = null error.value = null processingStage.value = '' @@ -352,6 +360,7 @@ export function useDocumentProcessor() { return { // 数据 uploadedFiles, + uploadedDisplayFiles, config, results, isUploading, diff --git a/web_ui/src/views/DocumentProcessor.vue b/web_ui/src/views/DocumentProcessor.vue index 1d440dc..d9a824d 100644 --- a/web_ui/src/views/DocumentProcessor.vue +++ b/web_ui/src/views/DocumentProcessor.vue @@ -26,7 +26,7 @@
-
+
{{ file.name }} { const removeFile = (index: number) => { uploadedFiles.value.splice(index, 1) + uploadedDisplayFiles.value.splice(index, 1) if (uploadedFiles.value.length === 0) { isUploadAreaCollapsed.value = false }