caedf2e6f4
- extract_section.py: slice a book section out of a pdftotext -layout dump and list its labeled Theorem/Proposition/Lemma/Corollary/Definition items. - formalize.py: LLM-formalize a section into Lean 4 candidate statements (preferring Mathlib vocabulary) plus a definitions manifest. - check_statements.py: elaboration-only sanity check against a real Mathlib-backed Lean project (must run outside the Cowork sandbox, which has no Lean toolchain and can't run macOS binaries anyway). - build_library.py: assemble solved lean-bench results into a reusable .lean file, reusing each winning proof verbatim. - llm.py: standalone OpenAI-compatible chat client + .env loader, kept independent of lean_agent so this pipeline works without it installed. - Source PDFs and raw/layout text dumps are gitignored (copyrighted material); only code and the final short Lean statement datasets are tracked.
47 lines
2.0 KiB
Python
47 lines
2.0 KiB
Python
"""Minimal OpenAI-compatible chat client, standalone (no third-party deps, no import of
|
|
lean_agent) so this pipeline works regardless of whether lean-agent is pip-installed.
|
|
Mirrors lean_agent.core.HTTPProvider on purpose; kept separate deliberately."""
|
|
import json
|
|
import os
|
|
import urllib.request
|
|
|
|
|
|
def load_dotenv(path):
|
|
"""Load KEY=VALUE lines from a .env file into os.environ (does not overwrite vars
|
|
already set). Silently does nothing if the file does not exist."""
|
|
if not path.exists():
|
|
return
|
|
for line in path.read_text(encoding='utf-8').splitlines():
|
|
line = line.strip()
|
|
if not line or line.startswith('#') or '=' not in line:
|
|
continue
|
|
key, _, value = line.partition('=')
|
|
key = key.strip()
|
|
value = value.strip().strip('"').strip("'")
|
|
os.environ.setdefault(key, value)
|
|
|
|
|
|
class ChatClient:
|
|
"""OpenAI-compatible /chat/completions caller."""
|
|
|
|
def __init__(self, model, base_url, api_key_env='DASHSCOPE_API_KEY', timeout=300):
|
|
self.model = model
|
|
self.base_url = base_url.rstrip('/')
|
|
self.api_key_env = api_key_env
|
|
self.timeout = timeout
|
|
|
|
def complete(self, messages, temperature=0.2):
|
|
key = os.environ.get(self.api_key_env)
|
|
if not key:
|
|
raise RuntimeError(f'Missing API key in environment variable {self.api_key_env}')
|
|
headers = {"Content-Type": "application/json", "Authorization": "Bearer " + key}
|
|
payload = {"model": self.model, "messages": messages, "temperature": temperature}
|
|
request = urllib.request.Request(self.base_url + '/chat/completions',
|
|
data=json.dumps(payload).encode(), headers=headers)
|
|
with urllib.request.urlopen(request, timeout=self.timeout) as response:
|
|
data = json.load(response)
|
|
content = data["choices"][0]["message"]["content"]
|
|
if not isinstance(content, str):
|
|
raise ValueError("Provider returned non-text content")
|
|
return content
|