Spaces:
Running on Zero
Running on Zero
File size: 7,241 Bytes
64dfa83 a8b2c5c 64dfa83 a8b2c5c a7e01dd a8b2c5c 64dfa83 49dd498 9f61929 a8b2c5c 64dfa83 1b23046 02ee37a 64dfa83 02ee37a 1b23046 64dfa83 1b23046 64dfa83 1b23046 64dfa83 1b23046 64dfa83 9f61929 64dfa83 9f61929 49dd498 9f61929 64dfa83 9f61929 1b23046 a8b2c5c 02ee37a 9f61929 a8b2c5c 9f61929 64dfa83 49dd498 9f61929 1b23046 64dfa83 1b23046 a8b2c5c 64dfa83 a8b2c5c 64dfa83 1b23046 64dfa83 a8b2c5c 1b23046 64dfa83 1b23046 64dfa83 1b23046 02ee37a 1b23046 02ee37a 1b23046 02ee37a 1b23046 02ee37a 64dfa83 9f61929 49dd498 9f61929 64dfa83 02ee37a 1b23046 02ee37a 64dfa83 a8b2c5c 02ee37a de1de04 64dfa83 a8b2c5c 64dfa83 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | import gradio as gr
import spaces
import torch
import re
from transformers import pipeline
# Initialize the lightweight LiquidAI Thinking Model
MODEL_ID = "LiquidAI/LFM2.5-1.2B-Thinking"
generator = pipeline(
"text-generation",
model=MODEL_ID,
dtype=torch.bfloat16
)
def generate_with_chat_template(messages, max_new_tokens=1536, do_sample=True, temperature=0.7, num_return_sequences=1):
"""
Applies the model's chat template to structure the prompts properly,
preventing prompt injection or completion confusion.
"""
tokenizer = generator.tokenizer
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
outputs = generator(
prompt,
max_new_tokens=max_new_tokens,
max_length=None,
generation_config=None,
num_return_sequences=num_return_sequences,
do_sample=do_sample,
temperature=temperature if do_sample else None
)
results = []
for out in outputs:
gen_text = out['generated_text']
# Extract only the newly generated text following the prompt
if gen_text.startswith(prompt):
gen_text = gen_text[len(prompt):]
results.append(gen_text.strip())
return results
@spaces.GPU(duration=60) # 60s is plenty because LiquidAI is blindingly fast
def tot_search(problem: str, branches: int = 3, max_depth: int = 3) -> str:
"""
Executes a Tree of Thoughts (ToT) search using the LiquidAI 1.2B Thinking model
and returns ONLY the final clean answer to the client.
"""
# Track statistics for server-side logs
stats = {
"nodes_generated": 0,
"nodes_evaluated": 0,
"nodes_pruned": 0,
"actual_depth_reached": 0
}
current_paths = [{"history": [problem], "score": 1.0}]
tree_history_log = []
for depth in range(max_depth):
stats["actual_depth_reached"] = depth + 1
new_paths = []
depth_log = []
for p_idx, path in enumerate(current_paths):
latest_thought = path["history"][-1]
# 1. GENERATE BRANCHES
messages = [
{
"role": "system",
"content": "You are a helpful reasoning assistant. Provide a single, distinct, and logical next step to solve the user's problem. Be extremely concise, direct, and focused."
},
{
"role": "user",
"content": f"Problem: {problem}\nCurrent progress: {latest_thought}\nWhat is the single next logical step?"
}
]
outputs = generate_with_chat_template(
messages,
max_new_tokens=1536,
do_sample=True,
temperature=0.7,
num_return_sequences=branches
)
# 2. EVALUATE/SCORE BRANCHES
for out_text in outputs:
stats["nodes_generated"] += 1
# LiquidAI wraps internal thoughts in <think> tags. Extract clean step.
next_step = re.sub(r'<think>.*?</think>', '', out_text, flags=re.DOTALL).strip()
if not next_step:
next_step = out_text # Fallback
eval_messages = [
{
"role": "system",
"content": "You are an evaluator. Your task is to rate whether a proposed next step is helpful for solving the given problem. You must respond with exactly one of these words: 'Good', 'Maybe', or 'Bad'. Do not explain your choice."
},
{
"role": "user",
"content": f"Problem: {problem}\nProposed Next Step: {next_step}\nIs this step 'Good', 'Maybe', or 'Bad'?"
}
]
eval_outs = generate_with_chat_template(eval_messages, max_new_tokens=1536, do_sample=False)
eval_text = eval_outs[0].lower()
stats["nodes_evaluated"] += 1
# Strip thinking tags from evaluation
eval_text = re.sub(r'<think>.*?</think>', '', eval_text, flags=re.DOTALL).strip()
score = 0.0
if "good" in eval_text:
score = 1.0
elif "maybe" in eval_text:
score = 0.5
depth_log.append({
"parent_node": p_idx,
"thought": next_step[:120] + "...",
"evaluation": eval_text,
"score": score
})
if score > 0:
new_paths.append({
"history": path["history"] + [next_step],
"score": score
})
# 3. PRUNE (Keep top 2 paths)
original_count = len(new_paths)
current_paths = sorted(new_paths, key=lambda x: x["score"], reverse=True)[:2]
stats["nodes_pruned"] += (original_count - len(current_paths))
tree_history_log.append((depth + 1, depth_log))
if not current_paths:
break
# Print execution trace to the background Hugging Face Space console logs
print("\n--- Tree of Thoughts Execution Logs ---")
for d, logs in tree_history_log:
print(f"Depth {d}:")
for l in logs:
print(f" - [{l['evaluation'].upper()}] Thought: {l['thought']}")
print(f"Stats: Depth={stats['actual_depth_reached']}, Generated={stats['nodes_generated']}, Pruned={stats['nodes_pruned']}\n")
if not current_paths:
return "Error: All reasoning paths hit a dead end."
# 4. SYNTHESIZE THE WINNING PATH
best_chain = " -> ".join(current_paths[0]["history"])
final_messages = [
{
"role": "system",
"content": "You are a helpful assistant. Synthesize the final, concise answer to the problem based on the provided reasoning path. Do not include any meta-reasoning, instruction-following placeholders, or thinking tags. Provide only the clean, final direct answer."
},
{
"role": "user",
"content": f"Problem: {problem}\nReasoning path: {best_chain}\nWhat is the final concise answer?"
}
]
final_outs = generate_with_chat_template(final_messages, max_new_tokens=1536, do_sample=False)
final_response = final_outs[0]
# Strip everything down to get just the clean answer
clean_answer = re.sub(r'<think>.*?</think>', '', final_response, flags=re.DOTALL).strip()
return clean_answer
# Define the Gradio Interface
demo = gr.Interface(
fn=tot_search,
inputs=[
gr.Textbox(label="Problem"),
gr.Slider(2, 4, value=3, step=1, label="Branches"),
gr.Slider(2, 4, value=3, step=1, label="Max Depth")
],
outputs="text",
title="DeepThoughTree --- Tree of Thoughts (ToT) Orchestrator"
)
# Launch with MCP enabled
demo.launch(mcp_server=True) |