0704
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
# LM Studio 本地润色脚本
|
||||
|
||||
用途:用本机 LM Studio 的 OpenAI 兼容接口润色章节。当前提示词偏“大胆润色”,允许模型较大幅度调整句子、段落和对话,输出作为二次人工修订底稿。
|
||||
|
||||
默认接口:
|
||||
|
||||
- 地址:`http://localhost:1234/v1`
|
||||
- 模型:`gemma4-12b-qat-uncensored-hauhaucs-balanced`
|
||||
|
||||
## 查看本机模型
|
||||
|
||||
```powershell
|
||||
python 脚本/lmstudio_polish.py --list-models
|
||||
```
|
||||
|
||||
## 润色单章
|
||||
|
||||
```powershell
|
||||
python 脚本/lmstudio_polish.py `
|
||||
--input "正文/1.1.1-坠毁后的第一夜/第01章-我不是博士.md" `
|
||||
--out "中间文件/润色输出/第01章-我不是博士.md"
|
||||
```
|
||||
|
||||
## 批量润色一个文件夹
|
||||
|
||||
```powershell
|
||||
python 脚本/lmstudio_polish.py `
|
||||
--input "正文/1.1.1-坠毁后的第一夜" `
|
||||
--out "中间文件/润色输出/1.1.1-坠毁后的第一夜"
|
||||
```
|
||||
|
||||
## 常用参数
|
||||
|
||||
- `--temperature 0.25`:相对保守。
|
||||
- `--temperature 0.5`:更敢改句子。
|
||||
- `--temperature 0.8`:当前推荐,比较敢改但不至于太漂。
|
||||
- `--temperature 1.0`:更大胆,适合出二修素材后再人工筛。
|
||||
- `--top-p 0.95`:可选,采样范围;不传则使用 LM Studio / 模型默认值。
|
||||
- `--presence-penalty 0.0`、`--frequency-penalty 0.0`、`--repeat-penalty 1.0`:可选,按模型支持情况传入。
|
||||
- `--model 模型名`:切换 LM Studio 已加载模型。
|
||||
- `--timeout 1800`:默认 1800 秒,长章可继续加大。
|
||||
- `--dry-run`:只看输入输出路径,不调用模型。
|
||||
|
||||
默认提示词在 `脚本/lmstudio-润色-system.md`,可以按本书风格继续改。
|
||||
|
||||
建议把输出当作二修候选稿:先和正文做对比,再迁移更顺、更舒服的局部,不建议直接整章覆盖。
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Copy compact diff files to patch files for VS Code:."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
src_dir = Path("中间文件/润色输出/Kimi版-脚本润色-diff")
|
||||
dst_dir = Path("中间文件/润色输出/Kimi版-脚本润色-patch")
|
||||
dst_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for src in sorted(src_dir.glob("*-compact.diff")):
|
||||
stem = src.stem.replace("-compact", "")
|
||||
dst = dst_dir / f"{stem}.patch"
|
||||
dst.write_text(src.read_text(encoding="utf-8"), encoding="utf-8")
|
||||
print(f"Copied {src.name} -> {dst.name}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate line-by-line diff between two markdown files."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def read_lines(path: Path) -> list[str]:
|
||||
text = path.read_text(encoding="utf-8-sig")
|
||||
return text.splitlines()
|
||||
|
||||
|
||||
def generate_line_diff(src: Path, dst: Path) -> str:
|
||||
src_lines = read_lines(src)
|
||||
dst_lines = read_lines(dst)
|
||||
src_name = src.as_posix()
|
||||
dst_name = dst.as_posix()
|
||||
diff = difflib.unified_diff(
|
||||
src_lines,
|
||||
dst_lines,
|
||||
fromfile=src_name,
|
||||
tofile=dst_name,
|
||||
lineterm="",
|
||||
)
|
||||
return "\n".join(diff)
|
||||
|
||||
|
||||
def generate_compact_line_diff(src: Path, dst: Path, context: int = 2) -> str:
|
||||
"""Generate a compact diff showing only changed lines with a little context."""
|
||||
src_lines = read_lines(src)
|
||||
dst_lines = read_lines(dst)
|
||||
src_name = src.as_posix()
|
||||
dst_name = dst.as_posix()
|
||||
|
||||
sm = difflib.SequenceMatcher(None, src_lines, dst_lines)
|
||||
output = [f"--- {src_name}", f"+++ {dst_name}", ""]
|
||||
|
||||
for tag, i1, i2, j1, j2 in sm.get_opcodes():
|
||||
if tag == "equal":
|
||||
# Show only a few context lines around changes
|
||||
if context > 0:
|
||||
ctx = src_lines[i1:i2]
|
||||
if len(ctx) <= context * 2 + 1:
|
||||
for line in ctx:
|
||||
output.append(f" {line}")
|
||||
else:
|
||||
for line in ctx[:context]:
|
||||
output.append(f" {line}")
|
||||
output.append(" ...")
|
||||
for line in ctx[-context:]:
|
||||
output.append(f" {line}")
|
||||
elif tag == "replace":
|
||||
output.append(f"@@ -{i1 + 1},{i2 - i1} +{j1 + 1},{j2 - j1} @@")
|
||||
for line in src_lines[i1:i2]:
|
||||
output.append(f"-{line}")
|
||||
for line in dst_lines[j1:j2]:
|
||||
output.append(f"+{line}")
|
||||
elif tag == "delete":
|
||||
output.append(f"@@ -{i1 + 1},{i2 - i1} +{j1 + 1},0 @@")
|
||||
for line in src_lines[i1:i2]:
|
||||
output.append(f"-{line}")
|
||||
elif tag == "insert":
|
||||
output.append(f"@@ -{i1 + 1},0 +{j1 + 1},{j2 - j1} @@")
|
||||
for line in dst_lines[j1:j2]:
|
||||
output.append(f"+{line}")
|
||||
|
||||
return "\n".join(output)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Generate line-by-line diff for markdown files.")
|
||||
parser.add_argument("--input-dir", type=Path, required=True, help="Directory containing source files.")
|
||||
parser.add_argument("--output-dir", type=Path, required=True, help="Directory containing polished files.")
|
||||
parser.add_argument("--out-diff-dir", type=Path, required=True, help="Directory to write diff files.")
|
||||
parser.add_argument("--compact", action="store_true", help="Show only changed lines with context.")
|
||||
parser.add_argument("--context", type=int, default=2, help="Number of context lines around changes (compact mode).")
|
||||
args = parser.parse_args()
|
||||
|
||||
args.out_diff_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for src in sorted(args.input_dir.glob("*.md")):
|
||||
dst = args.output_dir / src.name
|
||||
if not dst.exists():
|
||||
print(f"Skip {src.name}: no matching polished file.")
|
||||
continue
|
||||
|
||||
if args.compact:
|
||||
diff_text = generate_compact_line_diff(src, dst, context=args.context)
|
||||
suffix = "-compact.diff"
|
||||
else:
|
||||
diff_text = generate_line_diff(src, dst)
|
||||
suffix = "-line.diff"
|
||||
|
||||
out_path = args.out_diff_dir / (src.stem + suffix)
|
||||
out_path.write_text(diff_text, encoding="utf-8")
|
||||
print(f"Wrote {out_path}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,9 @@
|
||||
你是一名中文连载小说润色大师。
|
||||
|
||||
润色目标:
|
||||
|
||||
1. 让句子更顺,段落更有呼吸感。
|
||||
2. 让人物反应更像现场里的真人。
|
||||
3. 用动作、声音、表情推动场面。
|
||||
|
||||
最终只输出完整正文。
|
||||
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Use local LM Studio OpenAI-compatible API to polish markdown chapters."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
DEFAULT_BASE_URL = "http://localhost:1234/v1"
|
||||
DEFAULT_MODEL = "gemma4-12b-qat-uncensored-hauhaucs-balanced"
|
||||
|
||||
|
||||
def read_text(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8-sig")
|
||||
|
||||
|
||||
def write_text(path: Path, text: str) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(text.rstrip() + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def text_stats(text: str) -> dict[str, int]:
|
||||
return {
|
||||
"chars": len(text),
|
||||
"nonspace": len(re.findall(r"\S", text)),
|
||||
"zh": len(re.findall(r"[\u4e00-\u9fff]", text)),
|
||||
}
|
||||
|
||||
|
||||
def request_json(url: str, payload: dict | None = None, timeout: int = 600) -> dict:
|
||||
data = None if payload is None else json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||||
req = urllib.request.Request(url, data=data)
|
||||
if payload is not None:
|
||||
req.add_header("Content-Type", "application/json")
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
raw = resp.read().decode("utf-8")
|
||||
return json.loads(raw)
|
||||
|
||||
|
||||
def list_models(base_url: str) -> None:
|
||||
payload = request_json(f"{base_url.rstrip('/')}/models", timeout=10)
|
||||
for item in payload.get("data", []):
|
||||
print(item.get("id", ""))
|
||||
|
||||
|
||||
def polish_text(
|
||||
text: str,
|
||||
system_prompt: str,
|
||||
*,
|
||||
base_url: str,
|
||||
model: str,
|
||||
temperature: float,
|
||||
top_p: float | None,
|
||||
presence_penalty: float | None,
|
||||
frequency_penalty: float | None,
|
||||
repeat_penalty: float | None,
|
||||
max_tokens: int | None,
|
||||
timeout: int,
|
||||
) -> str:
|
||||
payload = {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": text},
|
||||
],
|
||||
"temperature": temperature,
|
||||
}
|
||||
if top_p is not None:
|
||||
payload["top_p"] = top_p
|
||||
if presence_penalty is not None:
|
||||
payload["presence_penalty"] = presence_penalty
|
||||
if frequency_penalty is not None:
|
||||
payload["frequency_penalty"] = frequency_penalty
|
||||
if repeat_penalty is not None:
|
||||
payload["repeat_penalty"] = repeat_penalty
|
||||
if max_tokens is not None:
|
||||
payload["max_tokens"] = max_tokens
|
||||
|
||||
result = request_json(f"{base_url.rstrip('/')}/chat/completions", payload, timeout=timeout)
|
||||
try:
|
||||
return result["choices"][0]["message"]["content"].strip()
|
||||
except (KeyError, IndexError, TypeError) as exc:
|
||||
raise RuntimeError(f"Unexpected LM Studio response: {result}") from exc
|
||||
|
||||
|
||||
def collect_inputs(input_path: Path) -> list[Path]:
|
||||
if input_path.is_file():
|
||||
return [input_path]
|
||||
if input_path.is_dir():
|
||||
return sorted(input_path.glob("*.md"))
|
||||
raise FileNotFoundError(f"Input not found: {input_path}")
|
||||
|
||||
|
||||
def output_path_for(src: Path, input_root: Path, out: Path) -> Path:
|
||||
if input_root.is_file() and out.suffix.lower() == ".md":
|
||||
return out
|
||||
return out / src.name
|
||||
|
||||
|
||||
def generate_patch(src_text: str, polished_text: str, src_path: Path, dst_path: Path) -> str:
|
||||
"""Generate a unified diff (patch) between source and polished text."""
|
||||
src_lines = src_text.splitlines()
|
||||
polished_lines = polished_text.splitlines()
|
||||
diff = difflib.unified_diff(
|
||||
src_lines,
|
||||
polished_lines,
|
||||
fromfile=str(src_path),
|
||||
tofile=str(dst_path),
|
||||
lineterm="",
|
||||
)
|
||||
return "\n".join(diff)
|
||||
|
||||
|
||||
def write_patch(src_text: str, polished_text: str, src_path: Path, dst_path: Path) -> Path:
|
||||
"""Write a .patch file next to the polished markdown file."""
|
||||
patch_path = dst_path.with_suffix(".patch")
|
||||
patch_text = generate_patch(src_text, polished_text, src_path, dst_path)
|
||||
patch_path.write_text(patch_text, encoding="utf-8")
|
||||
return patch_path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Polish chapters with local LM Studio.")
|
||||
parser.add_argument("--input", "-i", type=Path, help="Input markdown file or directory.")
|
||||
parser.add_argument("--out", "-o", type=Path, default=Path("中间文件/润色输出"), help="Output file or directory.")
|
||||
parser.add_argument("--system", type=Path, default=Path("脚本/lmstudio-润色-system.md"), help="System prompt file.")
|
||||
parser.add_argument("--base-url", default=DEFAULT_BASE_URL)
|
||||
parser.add_argument("--model", default=DEFAULT_MODEL)
|
||||
parser.add_argument("--temperature", type=float, default=1.0)
|
||||
parser.add_argument("--top-p", type=float, default=None)
|
||||
parser.add_argument("--presence-penalty", type=float, default=None)
|
||||
parser.add_argument("--frequency-penalty", type=float, default=None)
|
||||
parser.add_argument("--repeat-penalty", type=float, default=None, help="LM Studio/llama.cpp repeat penalty when supported.")
|
||||
parser.add_argument("--max-tokens", type=int, default=None)
|
||||
parser.add_argument("--timeout", type=int, default=1800)
|
||||
parser.add_argument("--list-models", action="store_true", help="List LM Studio models and exit.")
|
||||
parser.add_argument("--dry-run", action="store_true", help="Show planned tasks without calling LM Studio.")
|
||||
parser.add_argument("--no-patch", action="store_true", help="Do not generate .patch files alongside polished output.")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list_models:
|
||||
list_models(args.base_url)
|
||||
return 0
|
||||
if args.input is None:
|
||||
parser.error("--input is required unless --list-models is used")
|
||||
|
||||
inputs = collect_inputs(args.input)
|
||||
if not inputs:
|
||||
raise FileNotFoundError(f"No markdown files under: {args.input}")
|
||||
system_prompt = read_text(args.system)
|
||||
for src in inputs:
|
||||
dst = output_path_for(src, args.input, args.out)
|
||||
print(f"{src} -> {dst}", file=sys.stderr)
|
||||
source_text = read_text(src)
|
||||
source_stats = text_stats(source_text)
|
||||
if args.dry_run:
|
||||
print(
|
||||
f"source chars={source_stats['chars']} nonspace={source_stats['nonspace']} zh={source_stats['zh']}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
continue
|
||||
started = time.time()
|
||||
try:
|
||||
polished = polish_text(
|
||||
source_text,
|
||||
system_prompt,
|
||||
base_url=args.base_url,
|
||||
model=args.model,
|
||||
temperature=args.temperature,
|
||||
top_p=args.top_p,
|
||||
presence_penalty=args.presence_penalty,
|
||||
frequency_penalty=args.frequency_penalty,
|
||||
repeat_penalty=args.repeat_penalty,
|
||||
max_tokens=args.max_tokens,
|
||||
timeout=args.timeout,
|
||||
)
|
||||
except urllib.error.URLError as exc:
|
||||
print(f"LM Studio request failed: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
write_text(dst, polished)
|
||||
polished_stats = text_stats(polished)
|
||||
if not args.no_patch:
|
||||
patch_path = write_patch(source_text, polished, src, dst)
|
||||
print(
|
||||
f"wrote {dst} + {patch_path} ({time.time() - started:.1f}s) "
|
||||
f"source_zh={source_stats['zh']} output_zh={polished_stats['zh']} "
|
||||
f"source_nonspace={source_stats['nonspace']} output_nonspace={polished_stats['nonspace']}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"wrote {dst} ({time.time() - started:.1f}s) "
|
||||
f"source_zh={source_stats['zh']} output_zh={polished_stats['zh']} "
|
||||
f"source_nonspace={source_stats['nonspace']} output_nonspace={polished_stats['nonspace']}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(dst)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Use local LM Studio OpenAI-compatible API to polish markdown chapters."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
DEFAULT_BASE_URL = "http://localhost:1234/v1"
|
||||
DEFAULT_MODEL = "gemma4-12b-qat-uncensored-hauhaucs-balanced"
|
||||
|
||||
|
||||
def read_text(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8-sig")
|
||||
|
||||
|
||||
def write_text(path: Path, text: str) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(text.rstrip() + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def text_stats(text: str) -> dict[str, int]:
|
||||
return {
|
||||
"chars": len(text),
|
||||
"nonspace": len(re.findall(r"\S", text)),
|
||||
"zh": len(re.findall(r"[\u4e00-\u9fff]", text)),
|
||||
}
|
||||
|
||||
|
||||
def request_json(url: str, payload: dict | None = None, timeout: int = 600) -> dict:
|
||||
data = None if payload is None else json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||||
req = urllib.request.Request(url, data=data)
|
||||
if payload is not None:
|
||||
req.add_header("Content-Type", "application/json")
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
raw = resp.read().decode("utf-8")
|
||||
return json.loads(raw)
|
||||
|
||||
|
||||
def list_models(base_url: str) -> None:
|
||||
payload = request_json(f"{base_url.rstrip('/')}/models", timeout=10)
|
||||
for item in payload.get("data", []):
|
||||
print(item.get("id", ""))
|
||||
|
||||
|
||||
def polish_text(
|
||||
text: str,
|
||||
system_prompt: str,
|
||||
*,
|
||||
base_url: str,
|
||||
model: str,
|
||||
temperature: float,
|
||||
top_p: float | None,
|
||||
presence_penalty: float | None,
|
||||
frequency_penalty: float | None,
|
||||
repeat_penalty: float | None,
|
||||
max_tokens: int | None,
|
||||
timeout: int,
|
||||
) -> str:
|
||||
payload = {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": text},
|
||||
],
|
||||
"temperature": temperature,
|
||||
}
|
||||
if top_p is not None:
|
||||
payload["top_p"] = top_p
|
||||
if presence_penalty is not None:
|
||||
payload["presence_penalty"] = presence_penalty
|
||||
if frequency_penalty is not None:
|
||||
payload["frequency_penalty"] = frequency_penalty
|
||||
if repeat_penalty is not None:
|
||||
payload["repeat_penalty"] = repeat_penalty
|
||||
if max_tokens is not None:
|
||||
payload["max_tokens"] = max_tokens
|
||||
|
||||
result = request_json(f"{base_url.rstrip('/')}/chat/completions", payload, timeout=timeout)
|
||||
try:
|
||||
return result["choices"][0]["message"]["content"].strip()
|
||||
except (KeyError, IndexError, TypeError) as exc:
|
||||
raise RuntimeError(f"Unexpected LM Studio response: {result}") from exc
|
||||
|
||||
|
||||
def collect_inputs(input_path: Path) -> list[Path]:
|
||||
if input_path.is_file():
|
||||
return [input_path]
|
||||
if input_path.is_dir():
|
||||
return sorted(input_path.glob("*.md"))
|
||||
raise FileNotFoundError(f"Input not found: {input_path}")
|
||||
|
||||
|
||||
def output_path_for(src: Path, input_root: Path, out: Path) -> Path:
|
||||
if input_root.is_file() and out.suffix.lower() == ".md":
|
||||
return out
|
||||
return out / src.name
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Polish chapters with local LM Studio.")
|
||||
parser.add_argument("--input", "-i", type=Path, help="Input markdown file or directory.")
|
||||
parser.add_argument("--out", "-o", type=Path, default=Path("中间文件/润色输出"), help="Output file or directory.")
|
||||
parser.add_argument("--system", type=Path, default=Path("脚本/lmstudio-润色-system.md"), help="System prompt file.")
|
||||
parser.add_argument("--base-url", default=DEFAULT_BASE_URL)
|
||||
parser.add_argument("--model", default=DEFAULT_MODEL)
|
||||
parser.add_argument("--temperature", type=float, default=1.0)
|
||||
parser.add_argument("--top-p", type=float, default=None)
|
||||
parser.add_argument("--presence-penalty", type=float, default=None)
|
||||
parser.add_argument("--frequency-penalty", type=float, default=None)
|
||||
parser.add_argument("--repeat-penalty", type=float, default=None, help="LM Studio/llama.cpp repeat penalty when supported.")
|
||||
parser.add_argument("--max-tokens", type=int, default=None)
|
||||
parser.add_argument("--timeout", type=int, default=1800)
|
||||
parser.add_argument("--list-models", action="store_true", help="List LM Studio models and exit.")
|
||||
parser.add_argument("--dry-run", action="store_true", help="Show planned tasks without calling LM Studio.")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list_models:
|
||||
list_models(args.base_url)
|
||||
return 0
|
||||
if args.input is None:
|
||||
parser.error("--input is required unless --list-models is used")
|
||||
|
||||
inputs = collect_inputs(args.input)
|
||||
if not inputs:
|
||||
raise FileNotFoundError(f"No markdown files under: {args.input}")
|
||||
system_prompt = read_text(args.system)
|
||||
for src in inputs:
|
||||
dst = output_path_for(src, args.input, args.out)
|
||||
print(f"{src} -> {dst}", file=sys.stderr)
|
||||
source_text = read_text(src)
|
||||
source_stats = text_stats(source_text)
|
||||
if args.dry_run:
|
||||
print(
|
||||
f"source chars={source_stats['chars']} nonspace={source_stats['nonspace']} zh={source_stats['zh']}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
continue
|
||||
started = time.time()
|
||||
try:
|
||||
polished = polish_text(
|
||||
source_text,
|
||||
system_prompt,
|
||||
base_url=args.base_url,
|
||||
model=args.model,
|
||||
temperature=args.temperature,
|
||||
top_p=args.top_p,
|
||||
presence_penalty=args.presence_penalty,
|
||||
frequency_penalty=args.frequency_penalty,
|
||||
repeat_penalty=args.repeat_penalty,
|
||||
max_tokens=args.max_tokens,
|
||||
timeout=args.timeout,
|
||||
)
|
||||
except urllib.error.URLError as exc:
|
||||
print(f"LM Studio request failed: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
write_text(dst, polished)
|
||||
polished_stats = text_stats(polished)
|
||||
print(
|
||||
f"wrote {dst} ({time.time() - started:.1f}s) "
|
||||
f"source_zh={source_stats['zh']} output_zh={polished_stats['zh']} "
|
||||
f"source_nonspace={source_stats['nonspace']} output_nonspace={polished_stats['nonspace']}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(dst)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user