p4r5kpftnp-cmd Claude Sonnet 4.6 commited on
Commit
c2ebdf5
·
1 Parent(s): beba93c

Add Hugging Face Spaces deployment with Groq API

Browse files

- Replace Ollama/local LLM with Groq API (langchain-groq + groq SDK)
- Default model changed to llama-3.3-70b-versatile across all LLM clients
- Add Gradio web UI (app.py) as the HF Spaces entry point
- Add Dockerfile with Ubuntu 22.04 + Lean 4 via elan, Mathlib pre-warmed
- Update requirements.txt: remove ollama/langchain-ollama, add groq/langchain-groq/gradio

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (6) hide show
  1. Dockerfile +41 -0
  2. app.py +108 -0
  3. requirements.txt +3 -2
  4. src/langgraph_agent.py +1 -1
  5. src/lmm_client.py +14 -20
  6. src/rag_chain.py +3 -9
Dockerfile ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM ubuntu:22.04
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV LANG=C.UTF-8
5
+
6
+ RUN apt-get update && apt-get install -y \
7
+ python3.11 python3-pip python3.11-dev \
8
+ curl git build-essential \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Install elan (Lean version manager) and the stable Lean 4 toolchain
12
+ RUN curl -sSf https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh \
13
+ | sh -s -- -y --no-modify-path --default-toolchain leanprover/lean4:stable
14
+ ENV PATH="/root/.elan/bin:$PATH"
15
+
16
+ # Confirm lean is available
17
+ RUN lean --version
18
+
19
+ WORKDIR /app
20
+
21
+ # Install Python deps first (layer-cached separately from source)
22
+ COPY requirements.txt .
23
+ RUN pip3 install --no-cache-dir -r requirements.txt
24
+
25
+ COPY . .
26
+
27
+ # Pre-warm the Lean + Mathlib environment so the first user request isn't slow.
28
+ # This runs lean_interact with Mathlib once during the Docker build, triggering
29
+ # Mathlib cache population. Failures are tolerated so the image still builds.
30
+ RUN python3 -c "
31
+ import sys; sys.path.insert(0, '/app/src')
32
+ from lean_verifier import LeanEnvironment
33
+ env = LeanEnvironment(use_mathlib=True)
34
+ env.verify_proof('import Mathlib\n\n#check Nat.add_comm')
35
+ env.close()
36
+ " || echo "Lean warm-up skipped (non-fatal)"
37
+
38
+ EXPOSE 7860
39
+ ENV GRADIO_SERVER_NAME=0.0.0.0
40
+
41
+ CMD ["python3", "app.py"]
app.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import os
3
+ import sys
4
+ import tempfile
5
+ from contextlib import redirect_stdout
6
+
7
+ import gradio as gr
8
+
9
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
10
+
11
+ from langgraph_agent import LangGraphAgent
12
+
13
+ GROQ_MODELS = [
14
+ "llama-3.3-70b-versatile",
15
+ "deepseek-r1-distill-llama-70b",
16
+ "gemma2-9b-it",
17
+ "llama-3.1-8b-instant",
18
+ ]
19
+
20
+ EXAMPLE_CODE = """\
21
+ import Mathlib
22
+
23
+ theorem add_zero_simple (n : ℕ) : n + 0 = n := by
24
+ sorry
25
+ """
26
+
27
+
28
+ def solve_proof(lean_code: str, model_name: str, max_retries: int) -> tuple[str, str, str]:
29
+ if not lean_code.strip():
30
+ return "Please enter some Lean 4 code.", "", ""
31
+
32
+ if not os.environ.get("GROQ_API_KEY"):
33
+ return "GROQ_API_KEY is not set. Add it as a Space secret.", "", ""
34
+
35
+ tmp = tempfile.NamedTemporaryFile(suffix=".lean", mode="w", delete=False, dir="/tmp")
36
+ try:
37
+ tmp.write(lean_code)
38
+ tmp.close()
39
+
40
+ log_buf = io.StringIO()
41
+ with redirect_stdout(log_buf):
42
+ agent = LangGraphAgent(model_name=model_name, max_retries=int(max_retries))
43
+ result = agent.solve_file_detailed(tmp.name)
44
+
45
+ with open(tmp.name) as f:
46
+ final_code = f.read()
47
+
48
+ logs = log_buf.getvalue()
49
+
50
+ if result["success"]:
51
+ status = f"Proof verified on attempt {result['solved_at_attempt']} of {result['total_attempts']}."
52
+ else:
53
+ status = f"Could not find a proof after {result['total_attempts']} attempts."
54
+
55
+ return status, final_code, logs
56
+
57
+ except Exception as exc:
58
+ return f"Error: {exc}", "", ""
59
+ finally:
60
+ os.unlink(tmp.name)
61
+
62
+
63
+ with gr.Blocks(title="Lean 4 Proof Assistant") as demo:
64
+ gr.Markdown(
65
+ "# Lean 4 Proof Assistant\n"
66
+ "Paste Lean 4 code containing `sorry` placeholders. "
67
+ "The agent will use Mathlib RAG + an LLM to complete the proof and verify it with the Lean REPL.\n\n"
68
+ "> **Note:** Proof attempts can take 1–5 minutes. Please be patient."
69
+ )
70
+
71
+ with gr.Row():
72
+ with gr.Column(scale=1):
73
+ lean_input = gr.Code(
74
+ label="Lean 4 Code",
75
+ language=None,
76
+ value=EXAMPLE_CODE,
77
+ lines=18,
78
+ )
79
+ with gr.Row():
80
+ model_dropdown = gr.Dropdown(
81
+ choices=GROQ_MODELS,
82
+ value=GROQ_MODELS[0],
83
+ label="Model",
84
+ )
85
+ retries_slider = gr.Slider(
86
+ minimum=1, maximum=10, value=5, step=1,
87
+ label="Max Retries",
88
+ )
89
+ submit_btn = gr.Button("Solve Proof", variant="primary")
90
+
91
+ with gr.Column(scale=1):
92
+ status_output = gr.Textbox(label="Status", interactive=False, lines=2)
93
+ code_output = gr.Code(
94
+ label="Completed Proof",
95
+ language=None,
96
+ interactive=False,
97
+ lines=14,
98
+ )
99
+ logs_output = gr.Textbox(label="Agent Logs", interactive=False, lines=8)
100
+
101
+ submit_btn.click(
102
+ solve_proof,
103
+ inputs=[lean_input, model_dropdown, retries_slider],
104
+ outputs=[status_output, code_output, logs_output],
105
+ )
106
+
107
+ if __name__ == "__main__":
108
+ demo.launch(server_name="0.0.0.0", server_port=7860)
requirements.txt CHANGED
@@ -1,9 +1,10 @@
1
  lean-interact
2
- ollama
3
  langchain
4
  langchain-community
5
- langchain-ollama
6
  langgraph
7
  faiss-cpu
8
  rank-bm25
9
  sentence-transformers
 
 
1
  lean-interact
2
+ groq
3
  langchain
4
  langchain-community
5
+ langchain-groq
6
  langgraph
7
  faiss-cpu
8
  rank-bm25
9
  sentence-transformers
10
+ gradio
src/langgraph_agent.py CHANGED
@@ -176,7 +176,7 @@ def build_graph(lean_env: LeanEnvironment, retriever: MathLibRetriever, chain: R
176
  class LangGraphAgent:
177
  def __init__(
178
  self,
179
- model_name: str = "qwen3-vl:4b",
180
  max_retries: int = 5,
181
  index_dir: str | None = None,
182
  ):
 
176
  class LangGraphAgent:
177
  def __init__(
178
  self,
179
+ model_name: str = "llama-3.3-70b-versatile",
180
  max_retries: int = 5,
181
  index_dir: str | None = None,
182
  ):
src/lmm_client.py CHANGED
@@ -1,42 +1,36 @@
1
- import ollama
2
- from typing import List, Dict, Any, Optional
 
3
 
4
  class LMMClient:
5
  """
6
- Client for interacting with local LMMs via Ollama.
7
- Focuses on Qwen3-VL:4B for high-reasoning tasks.
8
  """
9
-
10
- def __init__(self, model_name: str = "qwen3-vl:4b"):
11
  self.model_name = model_name
 
12
 
13
  def chat(self, prompt: str, system_prompt: Optional[str] = None) -> str:
14
- """
15
- Sends a chat request to the model.
16
- """
17
  messages = []
18
  if system_prompt:
19
- messages.append({'role': 'system', 'content': system_prompt})
20
-
21
- messages.append({'role': 'user', 'content': prompt})
22
-
23
- response = ollama.chat(
24
  model=self.model_name,
25
- messages=messages
 
26
  )
27
- return response['message']['content']
28
 
29
  def generate_proof_steps(self, lean_code: str, goals: List[str], errors: List[str]) -> str:
30
- """
31
- Specific helper to generate proof steps based on current Lean state.
32
- """
33
  system_prompt = (
34
  "You are an expert Lean 4 proof assistant. "
35
  "Your goal is to complete the proof by replacing 'sorry' with valid Lean 4 code. "
36
  "Use Mathlib theorems where appropriate. "
37
  "Respond ONLY with the corrected Lean code block."
38
  )
39
-
40
  prompt = f"""
41
  Current Lean Code:
42
  ```lean
 
1
+ from groq import Groq
2
+ from typing import List, Optional
3
+
4
 
5
  class LMMClient:
6
  """
7
+ Client for interacting with LLMs via Groq API.
 
8
  """
9
+
10
+ def __init__(self, model_name: str = "llama-3.3-70b-versatile"):
11
  self.model_name = model_name
12
+ self._client = Groq()
13
 
14
  def chat(self, prompt: str, system_prompt: Optional[str] = None) -> str:
 
 
 
15
  messages = []
16
  if system_prompt:
17
+ messages.append({"role": "system", "content": system_prompt})
18
+ messages.append({"role": "user", "content": prompt})
19
+
20
+ response = self._client.chat.completions.create(
 
21
  model=self.model_name,
22
+ messages=messages,
23
+ max_tokens=1024,
24
  )
25
+ return response.choices[0].message.content
26
 
27
  def generate_proof_steps(self, lean_code: str, goals: List[str], errors: List[str]) -> str:
 
 
 
28
  system_prompt = (
29
  "You are an expert Lean 4 proof assistant. "
30
  "Your goal is to complete the proof by replacing 'sorry' with valid Lean 4 code. "
31
  "Use Mathlib theorems where appropriate. "
32
  "Respond ONLY with the corrected Lean code block."
33
  )
 
34
  prompt = f"""
35
  Current Lean Code:
36
  ```lean
src/rag_chain.py CHANGED
@@ -3,7 +3,7 @@ from typing import List
3
  from langchain_core.documents import Document
4
  from langchain_core.output_parsers import StrOutputParser
5
  from langchain_core.prompts import ChatPromptTemplate
6
- from langchain_ollama import OllamaLLM
7
 
8
 
9
  _SYSTEM = """\
@@ -108,18 +108,12 @@ class RAGProofChain:
108
  LangChain LCEL chain: retrieved context + proof state → corrected Lean code.
109
  """
110
 
111
- def __init__(self, model_name: str = "qwen3-vl:4b"):
112
  prompt = ChatPromptTemplate.from_messages([
113
  ("system", _SYSTEM),
114
  ("human", _HUMAN),
115
  ])
116
- # Disable thinking/chain-of-thought mode (qwen3, gemma3) and cap output
117
- # so the agent doesn't spend minutes generating reasoning tokens.
118
- llm = OllamaLLM(
119
- model=model_name,
120
- num_predict=1024, # cap response length
121
- options={"think": False}, # disable thinking mode (qwen3/gemma3)
122
- )
123
  self._chain = prompt | llm | StrOutputParser()
124
 
125
  def generate(
 
3
  from langchain_core.documents import Document
4
  from langchain_core.output_parsers import StrOutputParser
5
  from langchain_core.prompts import ChatPromptTemplate
6
+ from langchain_groq import ChatGroq
7
 
8
 
9
  _SYSTEM = """\
 
108
  LangChain LCEL chain: retrieved context + proof state → corrected Lean code.
109
  """
110
 
111
+ def __init__(self, model_name: str = "llama-3.3-70b-versatile"):
112
  prompt = ChatPromptTemplate.from_messages([
113
  ("system", _SYSTEM),
114
  ("human", _HUMAN),
115
  ])
116
+ llm = ChatGroq(model=model_name, max_tokens=1024)
 
 
 
 
 
 
117
  self._chain = prompt | llm | StrOutputParser()
118
 
119
  def generate(