innoai commited on
Commit
dfabe96
·
verified ·
1 Parent(s): fb3f182

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -95
app.py CHANGED
@@ -1,130 +1,70 @@
1
  #!/usr/bin/env python3
2
  # -*- coding: utf-8 -*-
3
- """
4
- PPTX → JPG → ZIP 在线转换(Hugging Face Spaces / 任意 Linux 环境)
5
- ---------------------------------------------------------------
6
- - 上传 .pptx → 调用 PptxToJpgZip → 返回 _images.zip
7
- - 兼容含中文文件名、空格路径
8
- - 启动时自动安装仓库内字体
9
- """
10
-
11
- import os
12
- import sys # 解决 “name 'sys' is not defined”
13
- import shutil
14
- import subprocess
15
- import tempfile
16
- import uuid
17
  from pathlib import Path
18
-
19
  import gradio as gr
20
 
21
- # ============ 基础路径 ============ #
22
  BASE_DIR = Path(__file__).parent.resolve()
23
- BINARY_PATH = BASE_DIR / "PptxToJpgZip" # 可执行文件与 app.py 同目录
24
-
25
- # ============ 确保可执行权限 ============ #
26
- try:
27
- os.chmod(BINARY_PATH, 0o755)
28
- except Exception as e:
29
- print(f"⚠️ 无法修改 {BINARY_PATH} 执行权限:{e}")
30
-
31
- # ============ 安装字体 ============ #
32
- def install_fonts_from_repository() -> None:
33
- """
34
- 将 repo/fonts 内的字体复制到 ~/.fonts,并刷新字体缓存
35
- (HF Spaces 容器默认存在 fontconfig)
36
- """
37
- try:
38
- home_fonts_dir = Path.home() / ".fonts"
39
- home_fonts_dir.mkdir(parents=True, exist_ok=True)
40
-
41
- repo_fonts_dir = BASE_DIR / "fonts"
42
- if not repo_fonts_dir.exists():
43
- print(f"❌ 未找到字体目录:{repo_fonts_dir}")
44
- return
45
-
46
- exts = {".ttf", ".otf", ".ttc"}
47
- copied = 0
48
- for font_file in repo_fonts_dir.iterdir():
49
- if font_file.suffix.lower() in exts:
50
- dest = home_fonts_dir / font_file.name
51
- shutil.copy(font_file, dest)
52
- print(f"✅ 已复制字体:{font_file.name}")
53
- copied += 1
54
-
55
- if copied:
56
- # 刷新缓存(Linux / Mac)
57
- if not sys.platform.startswith("win"):
58
- print("🔄 刷新字体缓存 …")
59
- subprocess.run(["fc-cache", "-f", "-v"], check=True)
60
- print("✅ 字体缓存刷新完成")
61
- else:
62
- print("⚠️ 未找到可复制的字体文件")
63
- except Exception as e:
64
- print(f"⚠️ 安装字体失败:{e}")
65
 
66
- install_fonts_from_repository()
67
 
68
- # ============ PPTX → ZIP 主逻辑 ============ #
69
- def _generate_safe_name() -> str:
70
- """生成仅含 ASCII 的随机文件名(避免中文路径问题)"""
71
  return f"input_{uuid.uuid4().hex}.pptx"
72
 
73
  def convert_pptx_to_zip(pptx_file) -> str:
74
- """
75
- 1. 创建临时工作目录 tmpdir
76
- 2. 将上传的 PPTX 复制为 ASCII 文件名
77
- 3. 在 tmpdir 中调用 PptxToJpgZip
78
- 4. 搜索 *_images.zip 并返回其路径
79
- """
80
- # -------- 准备工作目录 -------- #
81
  tmpdir = Path(tempfile.mkdtemp())
82
- safe_pptx = tmpdir / _generate_safe_name()
83
- shutil.copy(pptx_file.name, safe_pptx)
84
 
85
- # -------- 调用外部程序 -------- #
86
  proc = subprocess.run(
87
- [str(BINARY_PATH), str(safe_pptx)],
88
- cwd=tmpdir, # 关键:工作目录设为 tmpdir
89
  stdout=subprocess.PIPE,
90
  stderr=subprocess.PIPE,
91
  )
92
-
93
  if proc.returncode != 0:
94
  raise RuntimeError(
95
- f"转换失败,PptxToJpgZip 返回码 {proc.returncode}:\n"
96
- f"{proc.stderr.decode(errors='ignore')}"
97
  )
98
 
99
- # -------- 查找输出 ZIP -------- #
100
  zips = list(tmpdir.glob("*_images.zip"))
101
- if not zips:
102
- raise FileNotFoundError("转换成功,但未在临时目录找到 *_images.zip 输出文件")
103
- if len(zips) > 1:
104
- raise RuntimeError("检测到多个 *_images.zip,无法确定返回哪一个")
105
-
106
- return str(zips[0]) # Gradio 会自动生成下载链接
 
 
 
 
 
 
 
 
 
 
 
107
 
108
- # ============ Gradio UI ============ #
109
  with gr.Blocks(title="PPTX→JPG→ZIP 转换器") as demo:
110
  gr.Markdown(
111
  """
112
  # PPTX→JPG→ZIP
113
- 上传一个 `.pptx` 文件,后台调用 **PptxToJpgZip** 可执行程序,
114
- 将每页幻灯片导出为高质量 JPG,并打包成 ZIP,最后提供下载。"""
115
  )
116
  with gr.Row():
117
  pptx_in = gr.File(label="上传 PPTX (.pptx)", file_types=[".pptx"])
118
  btn = gr.Button("开始转换")
119
-
120
  zip_out = gr.File(label="下载 ZIP 文件")
121
-
122
  btn.click(fn=convert_pptx_to_zip, inputs=pptx_in, outputs=zip_out)
123
 
124
  if __name__ == "__main__":
125
- demo.launch(
126
- server_name="0.0.0.0",
127
- server_port=7860,
128
- share=False,
129
- # Spaces 如果需要关掉 SSR,可加 ssr_mode=False
130
- )
 
1
  #!/usr/bin/env python3
2
  # -*- coding: utf-8 -*-
3
+ import os, sys, shutil, subprocess, tempfile, uuid
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  from pathlib import Path
 
5
  import gradio as gr
6
 
 
7
  BASE_DIR = Path(__file__).parent.resolve()
8
+ BINARY_PATH = BASE_DIR / "PptxToJpgZip"
9
+ os.chmod(BINARY_PATH, 0o755) # 忽略异常
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ # -------- 省略 install_fonts_from_repository(),保持之前版本 -------- #
12
 
13
+ def _safe_name() -> str:
14
+ """生成仅 ASCII 的临时文件名"""
 
15
  return f"input_{uuid.uuid4().hex}.pptx"
16
 
17
  def convert_pptx_to_zip(pptx_file) -> str:
18
+ """调用 PptxToJpgZip,把 PPTX 转成图片 ZIP;若仅有文件夹则自动 zip。"""
 
 
 
 
 
 
19
  tmpdir = Path(tempfile.mkdtemp())
20
+ src = tmpdir / _safe_name()
21
+ shutil.copy(pptx_file.name, src)
22
 
23
+ # 调用外部可执行文件
24
  proc = subprocess.run(
25
+ [str(BINARY_PATH), str(src)],
26
+ cwd=tmpdir,
27
  stdout=subprocess.PIPE,
28
  stderr=subprocess.PIPE,
29
  )
 
30
  if proc.returncode != 0:
31
  raise RuntimeError(
32
+ f"PptxToJpgZip 失败,退出码 {proc.returncode}\n"
33
+ f"stderr:\n{proc.stderr.decode(errors='ignore')}"
34
  )
35
 
36
+ # ---- 优先找 *_images.zip ----
37
  zips = list(tmpdir.glob("*_images.zip"))
38
+ if zips:
39
+ return str(zips[0])
40
+
41
+ # ---- ② 若无 ZIP,再找 *_images 目录,自动打包 ----
42
+ img_dirs = [p for p in tmpdir.glob("*_images") if p.is_dir()]
43
+ if img_dirs:
44
+ folder = img_dirs[0]
45
+ zip_path = folder.with_suffix(".zip") # <name>_images.zip
46
+ shutil.make_archive(zip_path.with_suffix(""), "zip", folder)
47
+ return str(zip_path)
48
+
49
+ # ---- ③ 仍没找到:列出 tmpdir 内容方便调试 ----
50
+ contents = "\n".join([" • " + p.name for p in tmpdir.iterdir()])
51
+ raise FileNotFoundError(
52
+ "未找到输出 ZIP,也未发现 *_images 文件夹。\n"
53
+ f"临时目录内容:\n{contents}"
54
+ )
55
 
56
+ # ----------------- Gradio UI 保持不变 ----------------- #
57
  with gr.Blocks(title="PPTX→JPG→ZIP 转换器") as demo:
58
  gr.Markdown(
59
  """
60
  # PPTX→JPG→ZIP
61
+ 上传 `.pptx`,后台调用 **PptxToJpgZip**,将每页导出为 JPG 并打包 ZIP。"""
 
62
  )
63
  with gr.Row():
64
  pptx_in = gr.File(label="上传 PPTX (.pptx)", file_types=[".pptx"])
65
  btn = gr.Button("开始转换")
 
66
  zip_out = gr.File(label="下载 ZIP 文件")
 
67
  btn.click(fn=convert_pptx_to_zip, inputs=pptx_in, outputs=zip_out)
68
 
69
  if __name__ == "__main__":
70
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=False)