feat(pdf2zh): pdf2zh podman definition and config

This commit is contained in:
js0ny 2025-11-08 16:22:26 +00:00
parent 8cf2f0af5e
commit 5b546eff0d
10 changed files with 329 additions and 63 deletions

View file

@ -3,13 +3,20 @@ return {
event = "BufRead",
-- lazy = false,
version = false, -- Set this to "*" to always pull the latest release version, or set it to false to update to the latest code changes.
---@module "avante"
---@type avante.Config
opts = {
provider = "openrouter",
-- add any opts here
-- for example
providers = {
openai = {
endpoint = "https://openrouter.ai/v1",
model = "x-ai/grok-code-fast-1",
---@type AvanteProvider
openrouter = {
__inherited_from = "openai",
endpoint = "https://openrouter.ai/api/v1",
model = "anthropic/claude-sonnet-4.5",
api_key_name = "OPENROUTER_API_KEY",
},
},
},

View file

@ -0,0 +1,235 @@
config_file = "null"
report_interval = 0.2
siliconflowfree = false
openai = false
aliyundashscope = false
google = false
bing = false
deepl = false
deepseek = false
ollama = false
xinference = false
azureopenai = false
modelscope = false
zhipu = false
siliconflow = false
tencentmechinetranslation = false
gemini = false
azure = false
anythingllm = false
dify = false
grok = false
groq = false
qwenmt = false
openaicompatible = true
claudecode = false
[basic]
input_files = []
debug = false
gui = false
warmup = false
generate_offline_assets = "null"
restore_offline_assets = "null"
version = false
[translation]
min_text_length = 5
rpc_doclayout = "null"
lang_in = "en"
lang_out = "zh-CN"
output = "null"
qps = 4
ignore_cache = false
custom_system_prompt = "null"
glossaries = "null"
save_auto_extracted_glossary = false
pool_max_workers = "null"
no_auto_extract_glossary = false
primary_font_family = "null"
[pdf]
pages = "null"
no_dual = false
no_mono = false
formular_font_pattern = "null"
formular_char_pattern = "null"
split_short_lines = false
short_line_split_factor = 0.8
skip_clean = false
dual_translate_first = false
disable_rich_text_translate = false
enhance_compatibility = false
use_alternating_pages_dual = false
watermark_output_mode = "no_watermark"
max_pages_per_part = "null"
translate_table_text = true
skip_scanned_detection = false
ocr_workaround = false
auto_enable_ocr_workaround = false
only_include_translated_page = false
no_merge_alternating_line_numbers = false
no_remove_non_formula_lines = false
non_formula_line_iou_threshold = 0.9
figure_table_protection_threshold = 0.9
skip_formula_offset_calculation = false
[gui_settings]
share = false
auth_file = "null"
welcome_page = "null"
enabled_services = "null"
disable_gui_sensitive_input = false
disable_config_auto_save = false
server_port = 7860
ui_lang = "en"
[siliconflowfree_detail]
translate_engine_type = "SiliconFlowFree"
support_llm = "yes"
[openai_detail]
translate_engine_type = "OpenAI"
support_llm = "yes"
openai_model = "gpt-4o-mini"
openai_base_url = "null"
openai_api_key = "null"
openai_timeout = "null"
openai_temperature = "null"
openai_reasoning_effort = "null"
openai_enable_json_mode = "null"
openai_send_temprature = "null"
openai_send_reasoning_effort = "null"
[aliyundashscope_detail]
translate_engine_type = "AliyunDashScope"
support_llm = "yes"
aliyun_dashscope_model = "qwen-plus-latest"
aliyun_dashscope_base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
aliyun_dashscope_api_key = "null"
aliyun_dashscope_timeout = "500"
aliyun_dashscope_temperature = "0.0"
aliyun_dashscope_send_temperature = "null"
aliyun_dashscope_enable_json_mode = "null"
[deepl_detail]
translate_engine_type = "DeepL"
deepl_auth_key = "null"
[deepseek_detail]
translate_engine_type = "DeepSeek"
support_llm = "yes"
deepseek_model = "deepseek-chat"
deepseek_api_key = "null"
deepseek_enable_json_mode = "null"
[ollama_detail]
translate_engine_type = "Ollama"
support_llm = "yes"
ollama_model = "gemma2"
ollama_host = "http://localhost:11434"
num_predict = 2000
[xinference_detail]
translate_engine_type = "Xinference"
support_llm = "yes"
xinference_model = "gemma-2-it"
xinference_host = "null"
[azureopenai_detail]
translate_engine_type = "AzureOpenAI"
support_llm = "yes"
azure_openai_model = "gpt-4o-mini"
azure_openai_base_url = "null"
azure_openai_api_key = "null"
azure_openai_api_version = "2024-06-01"
[modelscope_detail]
translate_engine_type = "ModelScope"
support_llm = "yes"
modelscope_model = "Qwen/Qwen2.5-32B-Instruct"
modelscope_api_key = "null"
modelscope_enable_json_mode = "null"
[zhipu_detail]
translate_engine_type = "Zhipu"
support_llm = "yes"
zhipu_model = "glm-4-flash"
zhipu_api_key = "null"
zhipu_enable_json_mode = "null"
[siliconflow_detail]
translate_engine_type = "SiliconFlow"
support_llm = "yes"
siliconflow_base_url = "https://api.siliconflow.cn/v1"
siliconflow_model = "Qwen/Qwen2.5-7B-Instruct"
siliconflow_api_key = "null"
siliconflow_enable_thinking = false
siliconflow_send_enable_thinking_param = false
[tencentmechinetranslation_detail]
translate_engine_type = "TencentMechineTranslation"
tencentcloud_secret_id = "null"
tencentcloud_secret_key = "null"
[gemini_detail]
translate_engine_type = "Gemini"
support_llm = "yes"
gemini_model = "gemini-1.5-flash"
gemini_api_key = "null"
gemini_enable_json_mode = "null"
[azure_detail]
translate_engine_type = "Azure"
azure_endpoint = "https://api.translator.azure.cn"
azure_api_key = "null"
[anythingllm_detail]
translate_engine_type = "AnythingLLM"
anythingllm_url = "null"
anythingllm_apikey = "null"
[dify_detail]
translate_engine_type = "Dify"
dify_url = "null"
dify_apikey = "null"
[grok_detail]
translate_engine_type = "Grok"
support_llm = "yes"
grok_model = "grok-2-1212"
grok_api_key = "null"
grok_enable_json_mode = "null"
[groq_detail]
translate_engine_type = "Groq"
support_llm = "yes"
groq_model = "llama-3-3-70b-versatile"
groq_api_key = "null"
groq_enable_json_mode = "null"
[qwenmt_detail]
translate_engine_type = "QwenMt"
support_llm = "no"
qwenmt_model = "qwen-mt-plus"
qwenmt_base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
qwenmt_api_key = "null"
ali_domains = "This sentence is extracted from a scientific paper. When translating, please pay close attention to the use of specialized troubleshooting terminologies and adhere to scientific sentence structures to maintain the technical rigor and precision of the original text."
[openaicompatible_detail]
translate_engine_type = "OpenAICompatible"
support_llm = "yes"
openai_compatible_model = "google/gemini-2.5-flash"
openai_compatible_base_url = "https://openrouter.ai/"
openai_compatible_api_key = {{- "secrets/OPENROUTER_API_KEY.age" | include | decrypt | trim | quote -}}
openai_compatible_timeout = "5"
openai_compatible_temperature = "50"
openai_compatible_reasoning_effort = "low"
openai_compatible_send_temperature = false
openai_compatible_send_reasoning_effort = false
openai_compatible_enable_json_mode = false
[claudecode_detail]
translate_engine_type = "ClaudeCode"
claude_code_path = "claude"
claude_code_model = "sonnet"

View file

@ -1,18 +1,3 @@
-- ~/.config/yazi/init.lua
-- function Linemode:size_and_mtime()
-- local time = math.floor(self._file.cha.mtime or 0)
-- if time == 0 then
-- time = ""
-- elseif os.date("%Y", time) == os.date("%Y") then
-- time = os.date("%b %d %H:%M", time)
-- else
-- time = os.date("%b %d %Y", time)
-- end
--
-- local size = self._file:size()
-- return string.format("%s %s", size and ya.readable_size(size) or "-", time)
-- end
--
-- -- require("dual-pane"):setup({ enabled = true })
-- require("starship"):setup()
require("yaziline"):setup()
require("starship"):setup()
require("git"):setup()

View file

@ -1,7 +1,5 @@
// $DOTFILES/tools/zed/settings.json
// Date: 2025-01-25
// Author: js0ny
// Description: Zed settings (jsonc)
// vim:ft=jsonc
// Location:
// GNU/Linux: ~/.config/zed/settings.json
@ -44,7 +42,7 @@
"dock": "right"
},
"edit_predictions": {
"disabled_globs": ["*.bean", "*.env"],
"disabled_globs": ["*.bean", "*.env", "secrets.yaml"],
// "mode": "eager_preview",
"copilot": {
"proxy": null,
@ -75,10 +73,10 @@
},
"dock": "bottom",
"env": {
"EDITOR": "zeditor"
"EDITOR": "zeditor --wait"
},
"shell": {
"program": "fish"
"program": "zsh"
},
"option_as_meta": true
},

View file

@ -1,4 +1,5 @@
openrouter_api: ENC[AES256_GCM,data:ceu+FlTNrNoS56rHL9bdGjODfPBYnBd1GL97BgpmLvHz8q2KMXMvGofMTyZVGsLs1BEq4scjr+HN9r52tozLxeVWzkVfumcUMA==,iv:zT2vT94zAoKoutl58pbeOVqHm5nPmoMrA7wlZQcYVLs=,tag:+gS9EPcmfANCUipbeiAi0Q==,type:str]
tavily_api: ENC[AES256_GCM,data:blrxGOW/kcTbR2taeWeadhrzdtZK5ete4+0KE6yrJi3ibaMkkCGa05M=,iv:v4oh8/lA2q6l60By3H6RDXqbmBUya2W5sYxX8vDkz1c=,tag:8vwSl1zQnG5/fWDOhp9eHQ==,type:str]
sops:
age:
- recipient: age1mcvqpg39t32ll684r4m2l8j0l9zag6endg0h6zjw8svkgdwc4pjqkk5fvj
@ -19,7 +20,7 @@ sops:
c3ZZQlRrZDhtT2NFM0lnZTUxWmptQjgK5lZBkR5oSpb90oa+LWinEnvcmdPTF6wP
Q1gJoVoT/krUu22VSTOj/ojKEzS6uamZnJkMBhH31f1w2j4TEtY5Lw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-11-03T09:13:13Z"
mac: ENC[AES256_GCM,data:1bZT8E/M7CQgfshQV1LKJAqWcyoYomG29y7zSp7THZ9lwA4+FVpBNXV1HLQru4CMs3N1pq8g1ww6KxtGZ92pUo+JxtRdT9GxzqJenCp2qzSo5d2ws5fFvvjLnOtoPcqXlMTchECeA3K/emwbmIfjCH63D5STZmBz7+dNbx5PY20=,iv:Wcv6PNwroQawHkjJpspN5mM0b+PZG5BQTP9jOKH0OTQ=,tag:N/d/O/zbVkkH8kZdlkZErQ==,type:str]
lastmodified: "2025-11-08T13:02:24Z"
mac: ENC[AES256_GCM,data:QtK4Eg9DLb2TK1M1kzIsyJs4p7pUBeslGTjDxjdzatXcst2AyCKV3f0vc3bPPyE7WkSx51B9I9YGaRq/GNMIH5o16AcVwd1VNTTI5kEO5p+4RJywO1eR+DXidsCIFPAA5Rgh3lJIxdUCcDucZ5o/bPWzbDelrb+/RD4X1VozPD4=,iv:TOmgT3EyAENFIA7JxgkZMk7ZYUKnWrVEH7WL9Dg3fnw=,tag:po0WBC5dze20F5x/f47WqQ==,type:str]
unencrypted_suffix: _unencrypted
version: 3.11.0

View file

@ -1,14 +1,13 @@
{...}: let
editFzfPosix = ''
edit-fzf() {
# 1. Declare a variable that is local to the function.
local _file
if command -v fd >/dev/null 2>&1; then
_file=$(fd --type f | fzf --height 40% --reverse -1 -q "$1")
_file=$(fd --type f --exclude '*.lock' | fzf --height 40% --reverse -1 -q "$1")
else
# Fallback to 'find'
_file=$(find . -type f | fzf --height 40% --reverse -1 -q "$1")
_file=$(find . -type f ! -name '*.lock' | fzf --height 40% --reverse -1 -q "$1")
fi
# In POSIX shell, if fzf is cancelled (Esc/Ctrl-C),
@ -34,9 +33,9 @@ in {
set -l file
if command -q fd
set file (fd --type f | fzf --height 40% --reverse -1 -q "$argv[1]")
set file (fd --type f --exclude '*.lock' | fzf --height 40% --reverse -1 -q "$argv[1]")
else
set file (find . -type f | fzf --height 40% --reverse -1 -q "$argv[1]")
set file (find . -type f ! -name '*.lock' | fzf --height 40% --reverse -1 -q "$argv[1]")
end
set -l fzf_status $status

View file

@ -1,6 +1,8 @@
{pkgs, ...}: {
home.packages = [pkgs.libreoffice];
home.file.".local/share/kio/servicemenus/office2pdf.desktop" = {
enable = true;
executable = true;
text = ''
[Desktop Entry]
Type=Service

View file

@ -0,0 +1,52 @@
{pkgs, ...}: let
imageTag = "ghcr.io/pdfmathtranslate/pdfmathtranslate-next";
# version = "2.6.4";
pdf2zhRunner = pkgs.writeShellScriptBin "pdf2zh" ''
#!/usr/bin/env bash
set -euo pipefail
IMAGE_TAG="${imageTag}"
if ! podman image exists "$IMAGE_TAG"; then
echo "[pdf2zh] Pulling image $IMAGE_TAG ..."
podman pull "$IMAGE_TAG"
fi
podman run --rm -it \
-p 7860:7860 \
-v "$(pwd):/data" \
-w /data \
"$IMAGE_TAG" "pdf2zh" "$@"
'';
descEn = "PDF scientific paper translation with preserved formats";
descZh = " AI PDF ";
in {
services.podman.enable = true;
# Declare an image, do not instantiate as a container
services.podman.images.pdf2zh = {
image = imageTag;
description = " ${descEn} - ${descZh} Google/DeepL/Ollama/OpenAI CLI/GUI/Docker";
};
home.packages = [pdf2zhRunner];
home.file.".local/share/kio/servicemenus/pdf2zh.desktop" = {
enable = true;
executable = true;
text = ''
[Desktop Entry]
Type=Service
MimeType=application/pdf;
Actions=translateToZh
Icon=translate
X-KDE-Priority=TopLevel
X-KDE-StartupNotify=false
[Desktop Action translateToZh]
Name=
Icon=translate
Exec=pdf2zh --openaicompatible "%f"
'';
};
}

View file

@ -1,27 +1,28 @@
{config, ...}: {
{
pkgs,
config,
...
}: {
home.packages = with pkgs; [
sops
];
sops = {
# enable = true;
defaultSopsFile = ../../secrets/secrets.yaml;
defaultSopsFile = ../../../secrets/secrets.yaml;
age.keyFile = "${config.xdg.configHome}/sops/age/keys.txt";
age.generateKey = true;
secrets = {
"OPENROUTER_API_KEY" = {
key = "openrouter_api";
};
"TAVILY_API_KEY" = {
key = "tavily_api";
};
};
};
# home.sessionVariables = {
# OPENROUTER_API_KEY = config.sops.secrets."OPENROUTER_API_KEY".path;
# };
systemd.user.services.sops-envvar = {
Unit.Description = "[sops-envvar] Auto-source environment variables defined via sops-nix";
Service = {
ExecStart = pkgs.writeShellScript "start" ''
export OPENROUTER_API_KEY=$(cat ${config.sops.secrets."OPENROUTER_API_KEY".path})
'';
};
Install.WantedBy = ["default.target"];
home.sessionVariables = {
OPENROUTER_API_KEY = "$(cat ${config.sops.secrets."OPENROUTER_API_KEY".path})";
TAVILY_API_KEY = "$(cat ${config.sops.secrets."TAVILY_API_KEY".path})";
};
}

View file

@ -37,6 +37,8 @@
./programs/libreoffice.nix
./programs/nvim.nix
./programs/ollama.nix
./programs/sops.nix
./programs/pdf2zh.nix
# Desktop Linux
./programs/desktop/plasma.nix
@ -64,21 +66,5 @@
rose-pine-cursor
];
sops = {
# enable = true;
defaultSopsFile = ../../secrets/secrets.yaml;
age.keyFile = "${config.xdg.configHome}/sops/age/keys.txt";
age.generateKey = true;
secrets = {
"OPENROUTER_API_KEY" = {
key = "openrouter_api";
};
};
};
home.sessionVariables = {
OPENROUTER_API_KEY = "$(cat ${config.sops.secrets."OPENROUTER_API_KEY".path})";
};
home.stateVersion = "25.05";
}