feat(思维导图助手):优化打包
parent
4b50b6bf4e
commit
9f42a65e9e
|
|
@ -38,11 +38,42 @@ RUN python3 -m pip install -U pip -i https://mirrors.aliyun.com/pypi/simple && \
|
||||||
python3 -m pip install \
|
python3 -m pip install \
|
||||||
"numpy==1.26.4" \
|
"numpy==1.26.4" \
|
||||||
"opencv-python==4.11.0.86" \
|
"opencv-python==4.11.0.86" \
|
||||||
|
"pydantic>=2.12,<3" \
|
||||||
"modelscope" \
|
"modelscope" \
|
||||||
"magic-pdf" \
|
"magic-pdf" \
|
||||||
|
boto3 \
|
||||||
|
"pdfminer.six>=20251230" \
|
||||||
|
pypdfium2 \
|
||||||
|
pypdf \
|
||||||
|
reportlab \
|
||||||
|
pdftext \
|
||||||
|
huggingface-hub \
|
||||||
|
json-repair \
|
||||||
|
fast-langdetect \
|
||||||
|
scikit-image \
|
||||||
|
openai \
|
||||||
|
beautifulsoup4 \
|
||||||
|
magika \
|
||||||
|
mineru-vl-utils \
|
||||||
|
qwen-vl-utils \
|
||||||
|
matplotlib \
|
||||||
|
ultralytics \
|
||||||
|
doclayout_yolo==0.0.4 \
|
||||||
|
dill \
|
||||||
|
PyYAML \
|
||||||
|
ftfy \
|
||||||
|
shapely \
|
||||||
|
pyclipper \
|
||||||
|
omegaconf \
|
||||||
|
onnxruntime \
|
||||||
|
python-pptx \
|
||||||
|
python-docx \
|
||||||
|
openpyxl \
|
||||||
|
xlrd \
|
||||||
|
xlwt \
|
||||||
|
pylatexenc \
|
||||||
|
mammoth \
|
||||||
-i https://mirrors.aliyun.com/pypi/simple && \
|
-i https://mirrors.aliyun.com/pypi/simple && \
|
||||||
python3 -m pip install --force-reinstall --no-cache-dir "pydantic>=2.12,<3" -i https://mirrors.aliyun.com/pypi/simple && \
|
|
||||||
python3 -c "import pydantic; print('pydantic', pydantic.__version__); from pydantic import TypeAdapter; print('pydantic TypeAdapter ok')" && \
|
|
||||||
python3 -m pip cache purge
|
python3 -m pip cache purge
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
FROM unis-mindmap-api:latest
|
||||||
|
RUN python3 -m pip install \
|
||||||
|
boto3 \
|
||||||
|
"pdfminer.six>=20251230" \
|
||||||
|
pypdfium2 \
|
||||||
|
pypdf \
|
||||||
|
reportlab \
|
||||||
|
pdftext \
|
||||||
|
huggingface-hub \
|
||||||
|
json-repair \
|
||||||
|
fast-langdetect \
|
||||||
|
scikit-image \
|
||||||
|
openai \
|
||||||
|
beautifulsoup4 \
|
||||||
|
magika \
|
||||||
|
mineru-vl-utils \
|
||||||
|
qwen-vl-utils \
|
||||||
|
matplotlib \
|
||||||
|
ultralytics \
|
||||||
|
doclayout_yolo==0.0.4 \
|
||||||
|
dill \
|
||||||
|
PyYAML \
|
||||||
|
ftfy \
|
||||||
|
shapely \
|
||||||
|
pyclipper \
|
||||||
|
omegaconf \
|
||||||
|
onnxruntime \
|
||||||
|
python-pptx \
|
||||||
|
python-docx \
|
||||||
|
openpyxl \
|
||||||
|
xlrd \
|
||||||
|
xlwt \
|
||||||
|
pylatexenc \
|
||||||
|
mammoth \
|
||||||
|
-i https://mirrors.aliyun.com/pypi/simple && \
|
||||||
|
python3 -m pip cache purge
|
||||||
|
|
@ -110,6 +110,7 @@ class ModelSingleton:
|
||||||
vllm_llm = vllm.LLM(**kwargs)
|
vllm_llm = vllm.LLM(**kwargs)
|
||||||
elif backend == "vllm-async-engine":
|
elif backend == "vllm-async-engine":
|
||||||
try:
|
try:
|
||||||
|
import inspect
|
||||||
from vllm.engine.arg_utils import AsyncEngineArgs
|
from vllm.engine.arg_utils import AsyncEngineArgs
|
||||||
from vllm.v1.engine.async_llm import AsyncLLM
|
from vllm.v1.engine.async_llm import AsyncLLM
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
@ -122,6 +123,8 @@ class ModelSingleton:
|
||||||
from mineru_vl_utils import MinerULogitsProcessor
|
from mineru_vl_utils import MinerULogitsProcessor
|
||||||
kwargs["logits_processors"] = [MinerULogitsProcessor]
|
kwargs["logits_processors"] = [MinerULogitsProcessor]
|
||||||
# 使用kwargs为 vllm初始化参数
|
# 使用kwargs为 vllm初始化参数
|
||||||
|
supported_args = set(inspect.signature(AsyncEngineArgs).parameters)
|
||||||
|
kwargs = {k: v for k, v in kwargs.items() if k in supported_args}
|
||||||
vllm_async_llm = AsyncLLM.from_engine_args(AsyncEngineArgs(**kwargs))
|
vllm_async_llm = AsyncLLM.from_engine_args(AsyncEngineArgs(**kwargs))
|
||||||
elif backend == "lmdeploy-engine":
|
elif backend == "lmdeploy-engine":
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VERSION=${VERSION:-$(date +%Y%m%d%H%M%S)}
|
||||||
|
ROOT_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
||||||
|
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
|
||||||
|
echo "Building UnisMindMap API image: unis-mindmap-api:${VERSION}"
|
||||||
|
sudo docker build -f docker/china/Dockerfile \
|
||||||
|
-t unis-mindmap-api:${VERSION} \
|
||||||
|
-t unis-mindmap-api:latest \
|
||||||
|
-t mineru:test \
|
||||||
|
.
|
||||||
|
|
||||||
|
echo "Building UnisMindMap Web image: unis-mindmap-web:${VERSION}"
|
||||||
|
sudo docker build -f web_ui/Dockerfile.portable \
|
||||||
|
-t unis-mindmap-web:${VERSION} \
|
||||||
|
-t unis-mindmap-web:latest \
|
||||||
|
web_ui
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
NETWORK=${NETWORK:-unis-ai}
|
||||||
|
API_NAME=${API_NAME:-mineru-api}
|
||||||
|
WEB_NAME=${WEB_NAME:-mindmap-web}
|
||||||
|
WEB_PORT=${WEB_PORT:-9898}
|
||||||
|
MINERU_API_URL=${MINERU_API_URL:-http://${API_NAME}:8000}
|
||||||
|
|
||||||
|
sudo docker network create "$NETWORK" >/dev/null 2>&1 || true
|
||||||
|
sudo docker rm -f "$API_NAME" "$WEB_NAME" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
sudo docker run -d --name "$API_NAME" --network "$NETWORK" \
|
||||||
|
--privileged --ipc=host --shm-size=32g \
|
||||||
|
-e MINERU_MODEL_SOURCE=local \
|
||||||
|
-e PYTHONPATH=/app:/usr/local/corex-4.4.0/lib64/python3/dist-packages \
|
||||||
|
unis-mindmap-api:latest \
|
||||||
|
mineru-api --host 0.0.0.0 --port 8000
|
||||||
|
|
||||||
|
sudo docker run -d --name "$WEB_NAME" --network "$NETWORK" \
|
||||||
|
-p "${WEB_PORT}:9898" \
|
||||||
|
-e MINERU_API_URL="$MINERU_API_URL" \
|
||||||
|
unis-mindmap-web:latest
|
||||||
|
|
@ -8,13 +8,44 @@ server {
|
||||||
access_log /var/log/nginx/access.log;
|
access_log /var/log/nginx/access.log;
|
||||||
error_log /var/log/nginx/error.log;
|
error_log /var/log/nginx/error.log;
|
||||||
|
|
||||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
|
location ~* ^/(assets|mindmap/assets)/.*\.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
rewrite ^/mindmap/(.*)$ /$1 break;
|
||||||
expires 1y;
|
expires 1y;
|
||||||
add_header Cache-Control "public, immutable";
|
add_header Cache-Control "public, immutable";
|
||||||
|
try_files $uri =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location / {
|
location = /mindmap {
|
||||||
try_files $uri $uri/ /index.html;
|
return 301 /mindmap/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /mindmap/api/health {
|
||||||
|
proxy_pass ${MINERU_API_URL}/health;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /api/health {
|
||||||
|
proxy_pass ${MINERU_API_URL}/health;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /mindmap/api/ {
|
||||||
|
rewrite ^/mindmap/api/(.*)$ /api/$1 break;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
location = /file_parse {
|
location = /file_parse {
|
||||||
|
|
@ -30,7 +61,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass ${MINERU_API_URL}/;
|
proxy_pass ${MINERU_API_URL}/api/;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
@ -40,4 +71,13 @@ server {
|
||||||
proxy_send_timeout 300s;
|
proxy_send_timeout 300s;
|
||||||
proxy_read_timeout 300s;
|
proxy_read_timeout 300s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location ^~ /mindmap/ {
|
||||||
|
rewrite ^/mindmap/(.*)$ /$1 break;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,17 +41,6 @@ export interface MindmapOrganizeProgress extends ParseProgress {
|
||||||
result_md?: string | null
|
result_md?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MindmapLlmConfig {
|
|
||||||
base_url?: string
|
|
||||||
api_key?: string
|
|
||||||
model?: string
|
|
||||||
timeout?: number
|
|
||||||
temperature?: number
|
|
||||||
max_context_tokens?: number
|
|
||||||
max_output_tokens?: number
|
|
||||||
safety_tokens?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export const documentApi = {
|
export const documentApi = {
|
||||||
/**
|
/**
|
||||||
* 解析文档
|
* 解析文档
|
||||||
|
|
@ -84,7 +73,7 @@ export const documentApi = {
|
||||||
formData.append('task_id', taskId)
|
formData.append('task_id', taskId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.post('/api/file_parse', formData, {
|
return request.post('/file_parse', formData, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'multipart/form-data',
|
'Content-Type': 'multipart/form-data',
|
||||||
...(taskId ? { 'X-Task-ID': taskId } : {})
|
...(taskId ? { 'X-Task-ID': taskId } : {})
|
||||||
|
|
@ -99,7 +88,7 @@ export const documentApi = {
|
||||||
},
|
},
|
||||||
|
|
||||||
createParseTask(taskId: string): Promise<ParseProgress> {
|
createParseTask(taskId: string): Promise<ParseProgress> {
|
||||||
return request.post(`/api/parse_tasks/${encodeURIComponent(taskId)}`).then(result => {
|
return request.post(`/parse_tasks/${encodeURIComponent(taskId)}`).then(result => {
|
||||||
return result as unknown as ParseProgress
|
return result as unknown as ParseProgress
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -108,30 +97,23 @@ export const documentApi = {
|
||||||
* 查询解析进度
|
* 查询解析进度
|
||||||
*/
|
*/
|
||||||
getParseProgress(taskId: string): Promise<ParseProgress> {
|
getParseProgress(taskId: string): Promise<ParseProgress> {
|
||||||
return request.get(`/api/parse_progress/${taskId}`).then(result => {
|
return request.get(`/parse_progress/${taskId}`).then(result => {
|
||||||
return result as unknown as ParseProgress
|
return result as unknown as ParseProgress
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
createMindmapTask(
|
createMindmapTask(taskId: string, markdown: string, mode = 'smart', prompt?: string): Promise<MindmapOrganizeProgress> {
|
||||||
taskId: string,
|
return request.post(`/mindmap_tasks/${encodeURIComponent(taskId)}`, {
|
||||||
markdown: string,
|
|
||||||
mode = 'smart',
|
|
||||||
prompt?: string,
|
|
||||||
llmConfig?: MindmapLlmConfig
|
|
||||||
): Promise<MindmapOrganizeProgress> {
|
|
||||||
return request.post(`/api/mindmap_tasks/${encodeURIComponent(taskId)}`, {
|
|
||||||
markdown,
|
markdown,
|
||||||
mode,
|
mode,
|
||||||
prompt,
|
prompt
|
||||||
llm_config: llmConfig
|
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
return result as unknown as MindmapOrganizeProgress
|
return result as unknown as MindmapOrganizeProgress
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
getMindmapProgress(taskId: string): Promise<MindmapOrganizeProgress> {
|
getMindmapProgress(taskId: string): Promise<MindmapOrganizeProgress> {
|
||||||
return request.get(`/api/mindmap_progress/${encodeURIComponent(taskId)}`).then(result => {
|
return request.get(`/mindmap_progress/${encodeURIComponent(taskId)}`).then(result => {
|
||||||
return result as unknown as MindmapOrganizeProgress
|
return result as unknown as MindmapOrganizeProgress
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,24 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
// 创建 axios 实例
|
const getApiBaseURL = () => {
|
||||||
|
const pathname = window.location.pathname
|
||||||
|
const basePath = pathname === '/mindmap' || pathname.startsWith('/mindmap/') ? '/mindmap' : ''
|
||||||
|
return `${basePath}/api`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ?? axios ??
|
||||||
const request = axios.create({
|
const request = axios.create({
|
||||||
baseURL: '',
|
baseURL: getApiBaseURL(),
|
||||||
timeout: 300000, // 5分钟超时
|
timeout: 300000, // 5????
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 请求拦截器
|
// ?????
|
||||||
request.interceptors.request.use(
|
request.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
// 可以在这里添加认证token等
|
// ?????????token?
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
|
@ -20,13 +26,13 @@ request.interceptors.request.use(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// 响应拦截器
|
// ?????
|
||||||
request.interceptors.response.use(
|
request.interceptors.response.use(
|
||||||
(response) => {
|
(response) => {
|
||||||
return response.data
|
return response.data
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
// 统一错误处理
|
// ??????
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
const serverMessage = error.response.data?.error || error.response.data?.detail
|
const serverMessage = error.response.data?.error || error.response.data?.detail
|
||||||
if (serverMessage) {
|
if (serverMessage) {
|
||||||
|
|
@ -36,34 +42,34 @@ request.interceptors.response.use(
|
||||||
|
|
||||||
switch (error.response.status) {
|
switch (error.response.status) {
|
||||||
case 400:
|
case 400:
|
||||||
error.message = '请求参数错误'
|
error.message = '??????'
|
||||||
break
|
break
|
||||||
case 401:
|
case 401:
|
||||||
error.message = '未授权,请重新登录'
|
error.message = '?????????'
|
||||||
break
|
break
|
||||||
case 403:
|
case 403:
|
||||||
error.message = '拒绝访问'
|
error.message = '????'
|
||||||
break
|
break
|
||||||
case 404:
|
case 404:
|
||||||
error.message = '请求资源不存在'
|
error.message = '???????'
|
||||||
break
|
break
|
||||||
case 500:
|
case 500:
|
||||||
error.message = '服务器内部错误'
|
error.message = '???????'
|
||||||
break
|
break
|
||||||
case 502:
|
case 502:
|
||||||
error.message = '网关错误'
|
error.message = '????'
|
||||||
break
|
break
|
||||||
case 503:
|
case 503:
|
||||||
error.message = '服务不可用'
|
error.message = '?????'
|
||||||
break
|
break
|
||||||
case 504:
|
case 504:
|
||||||
error.message = '网关超时'
|
error.message = '????'
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
error.message = `连接错误${error.response.status}`
|
error.message = `????${error.response.status}`
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error.message = '网络连接异常'
|
error.message = '??????'
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import vue from '@vitejs/plugin-vue'
|
||||||
import { resolve } from 'path'
|
import { resolve } from 'path'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: './',
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|
@ -13,8 +14,13 @@ export default defineConfig({
|
||||||
port: 3000,
|
port: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://10.100.52.76:8000',
|
target: process.env.VITE_API_PROXY || 'http://127.0.0.1:8000',
|
||||||
changeOrigin: true
|
changeOrigin: true
|
||||||
|
},
|
||||||
|
'/mindmap/api': {
|
||||||
|
target: process.env.VITE_API_PROXY || 'http://127.0.0.1:8000',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: path => path.replace(/^\/mindmap\/api/, '/api')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -30,4 +36,4 @@ export default defineConfig({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue