Improve EPUB restoration, book terminology and Calibre QA workflow
This commit is contained in:
@@ -44,7 +44,8 @@ class LLMClient:
|
||||
|
||||
def __init__(self, api_key: str, base_url: str, model: str = "gpt-3.5-turbo",
|
||||
requests_per_minute: int = 60, concurrent_requests: int = 5,
|
||||
extra_headers: Dict = None, chunk_dir: Path = None):
|
||||
extra_headers: Dict = None, chunk_dir: Path = None,
|
||||
timeout: float = 180, max_output_tokens: int = 16000, temperature=None):
|
||||
|
||||
# Configure proxy client to avoid SOCKS issues and ensure connectivity
|
||||
import httpx
|
||||
@@ -54,7 +55,7 @@ class LLMClient:
|
||||
proxy_url = os.environ.get("http_proxy") or os.environ.get("https_proxy")
|
||||
http_client = httpx.AsyncClient(
|
||||
proxy=proxy_url,
|
||||
timeout=60.0,
|
||||
timeout=timeout,
|
||||
follow_redirects=True
|
||||
) if proxy_url else None
|
||||
|
||||
@@ -62,9 +63,13 @@ class LLMClient:
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
default_headers=extra_headers,
|
||||
http_client=http_client
|
||||
http_client=http_client,
|
||||
timeout=timeout,
|
||||
max_retries=0
|
||||
)
|
||||
self.model = model
|
||||
self.max_output_tokens = max_output_tokens
|
||||
self.temperature = temperature
|
||||
|
||||
self.rate_limiter = RateLimiter(requests_per_minute, concurrent_requests)
|
||||
self.prompts = self._load_prompts()
|
||||
@@ -76,7 +81,7 @@ class LLMClient:
|
||||
|
||||
def _load_prompts(self) -> Dict:
|
||||
try:
|
||||
with open("config/prompts.json", "r", encoding="utf-8") as f:
|
||||
with open(Path(__file__).resolve().parents[2] / "config/prompts.json", "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load config/prompts.json: {e}")
|
||||
@@ -130,7 +135,7 @@ Output Format:
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Translation failed: {e}")
|
||||
return {item.entry_id: f"[Error - {str(e)}]" for item in items}
|
||||
raise
|
||||
|
||||
def _build_prompt_with_short_ids(self, items: List[ManifestEntry]) -> tuple:
|
||||
"""
|
||||
@@ -156,6 +161,8 @@ Output Format:
|
||||
Returns: Dict[entry_id, translated_text]
|
||||
"""
|
||||
results = {}
|
||||
seen = set()
|
||||
duplicates = set()
|
||||
|
||||
for line in response.split("\n"):
|
||||
line = line.strip()
|
||||
@@ -175,16 +182,26 @@ Output Format:
|
||||
if sub_match:
|
||||
# Check if the inner ID matches the outer ID, or just strip it anyway
|
||||
# Usually LLM repeats the same ID.
|
||||
if sub_match.group(1) != match.group(1):
|
||||
content = ''
|
||||
break
|
||||
content = sub_match.group(2).strip()
|
||||
else:
|
||||
break
|
||||
|
||||
if not content:
|
||||
continue
|
||||
if short_id in id_map:
|
||||
full_id = id_map[short_id]
|
||||
if short_id in seen:
|
||||
duplicates.add(full_id)
|
||||
seen.add(short_id)
|
||||
results[full_id] = content
|
||||
else:
|
||||
logger.warning(f"Unknown short ID in response: {short_id}")
|
||||
|
||||
for full_id in duplicates:
|
||||
results.pop(full_id, None)
|
||||
return results
|
||||
|
||||
def _save_chunk(self, stage: str, content: str, system_prompt: str = None,
|
||||
@@ -215,15 +232,21 @@ Output Format:
|
||||
async def _make_request(self, system_prompt: str, user_prompt: str) -> str:
|
||||
await self.rate_limiter.acquire()
|
||||
try:
|
||||
options = {"max_completion_tokens": self.max_output_tokens}
|
||||
if self.temperature is not None:
|
||||
options["temperature"] = self.temperature
|
||||
resp = await self.client.chat.completions.create(
|
||||
model=self.model,
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_prompt}
|
||||
],
|
||||
temperature=0.3,
|
||||
**options,
|
||||
)
|
||||
return resp.choices[0].message.content.strip()
|
||||
choice = resp.choices[0]
|
||||
if choice.finish_reason != "stop" or not choice.message.content:
|
||||
raise ValueError(f"Incomplete model response: {choice.finish_reason}")
|
||||
return choice.message.content.strip()
|
||||
finally:
|
||||
self.rate_limiter.release()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user