Ashok75 commited on
Commit
ed4ef8c
·
verified ·
1 Parent(s): 2c13491

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -81
app.py CHANGED
@@ -1,121 +1,77 @@
1
  import torch
2
  import re
3
- from typing import Annotated, TypedDict, Union
4
  from flask import Flask, request, Response, render_template
5
  from transformers import AutoModelForCausalLM, AutoTokenizer
6
  from langgraph.graph import StateGraph, END
7
- from langchain_core.tools import tool
8
- from pydantic import BaseModel, Field
9
 
10
  app = Flask(__name__)
11
 
12
- # 1. DEFINE STRUCTURED TOOLS WITH PYDANTIC
13
- class CalcInput(BaseModel):
14
- expression: str = Field(description="The math expression to evaluate, e.g., '2 + 2'")
15
-
16
- @tool("simple_calculator", args_schema=CalcInput)
17
- def simple_calculator(expression: str):
18
- """Useful for basic math calculations."""
19
- try:
20
- # Source 351: Tools provide deterministic results for agents.
21
- return str(eval(expression, {"__builtins__": None}, {}))
22
- except Exception as e:
23
- return f"Error: {str(e)}"
24
-
25
- @tool("get_time")
26
- def get_time():
27
- """Returns the current system time."""
28
- from datetime import datetime
29
- return datetime.now().strftime("%H:%M:%S")
30
-
31
- tools = {"simple_calculator": simple_calculator, "get_time": get_time}
32
-
33
- # 2. LOAD REASONING ENGINE
34
  model_id = "AshokGakr/model-tiny"
35
  tokenizer = AutoTokenizer.from_pretrained(model_id)
36
  model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float16, device_map="auto")
37
 
38
- # 3. DEFINE THE AGENT STATE
39
  class AgentState(TypedDict):
40
- # Source 828: StateGraph acts as the system's real-time workflow tracker.
41
  messages: list[dict]
42
- next_step: str
43
 
44
- # 4. AGENT LOGIC NODES
 
 
 
 
 
 
45
  def call_model(state: AgentState):
46
- # 1. Apply Chat Template to format the history
47
- # This prepares the context for the reasoning engine [5].
48
- inputs = tokenizer.apply_chat_template(
49
- state['messages'],
50
- add_generation_prompt=True,
51
- return_tensors="pt"
52
- ).to(model.device)
53
-
54
- # 2. FIX: Unpack the inputs using ** to pass tensors correctly
55
- # This prevents the KeyError: 'shape' by giving generate the specific tensors it needs.
56
- output_ids = model.generate(
57
- **inputs, # <--- CRITICAL FIX: Unpack the dictionary
58
- max_new_tokens=256,
59
- do_sample=True,
60
- temperature=0.7
61
- )
62
 
63
- # 3. Decode only the newly generated tokens (skipping the original prompt)
64
- # inputs['input_ids'].shape[-1] provides the length of the input tokens.
65
- new_tokens = output_ids[inputs['input_ids'].shape[-1]:]
66
  response = tokenizer.decode(new_tokens, skip_special_tokens=True)
67
 
68
- # Identify if a tool needs to be called [1, 6]
69
  action_match = re.search(r"Action:\s*(\w+)", response)
70
-
71
  return {
72
  "messages": state['messages'] + [{"role": "assistant", "content": response}],
73
- "next_step": action_match.group(1) if action_match else "end"
74
  }
75
 
 
76
  def execute_tool(state: AgentState):
77
- tool_name = state['next_step']
78
- last_message = state['messages'][-1]['content']
79
-
80
- # Parse input (simplified for this model-tiny example)
81
- input_match = re.search(r"Action Input:\s*(.*)", last_message)
82
- arg = input_match.group(1).strip() if input_match else ""
83
-
84
- observation = tools[tool_name].run(arg)
85
- return {"messages": state['messages'] + [{"role": "user", "content": f"Observation: {observation}"}]}
86
 
87
- # 5. CONSTRUCT THE GRAPH
88
- # Source 96: Nodes represent actions; edges define the control flow.
89
  workflow = StateGraph(AgentState)
90
  workflow.add_node("agent", call_model)
91
  workflow.add_node("tools", execute_tool)
92
-
93
  workflow.set_entry_point("agent")
94
- workflow.add_conditional_edges(
95
- "agent",
96
- lambda x: "tools" if x["next_step"] in tools else "end",
97
- {"tools": "tools", "end": END}
98
- )
99
- workflow.add_edge("tools", "agent") # Create the ReAct Loop cycle [10]
100
-
101
- agent_app = workflow.compile()
102
- @app.route('/')
103
- def index():
104
- return render_template('index.html')
105
 
106
  @app.route('/chat', methods=['POST'])
107
  def chat():
108
- user_input = request.json.get("message")
109
- # Execute the graph [5, 11]
110
- inputs = {"messages": [{"role": "user", "content": user_input}]}
 
 
 
111
 
112
  def run():
113
- for output in agent_app.stream(inputs):
114
  for key, value in output.items():
115
- # Stream the latest message content to the UI [12]
116
  yield value['messages'][-1]['content'] + "\n"
117
 
118
  return Response(run(), mimetype='text/plain')
119
 
120
- if __name__ == '__main__':
121
- app.run(host='0.0.0.0', port=7860)
 
 
 
1
  import torch
2
  import re
 
3
  from flask import Flask, request, Response, render_template
4
  from transformers import AutoModelForCausalLM, AutoTokenizer
5
  from langgraph.graph import StateGraph, END
6
+ from typing import TypedDict
 
7
 
8
  app = Flask(__name__)
9
 
10
+ # 1. Loading the Cognitive Core [5, 6]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  model_id = "AshokGakr/model-tiny"
12
  tokenizer = AutoTokenizer.from_pretrained(model_id)
13
  model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float16, device_map="auto")
14
 
15
+ # 2. Defining State and Tools [7, 8]
16
  class AgentState(TypedDict):
 
17
  messages: list[dict]
18
+ next_action: str
19
 
20
+ def get_time(query: str):
21
+ from datetime import datetime
22
+ return f"Observation: The current time is {datetime.now().strftime('%H:%M:%S')}."
23
+
24
+ tools = {"get_time": get_time}
25
+
26
+ # 3. The Reasoning Node [9, 10]
27
  def call_model(state: AgentState):
28
+ # Context Engineering: Applying chat template for multi-turn coherence [11, 12]
29
+ inputs = tokenizer.apply_chat_template(state['messages'], add_generation_prompt=True, return_tensors="pt").to(model.device)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
+ # Generate and Slice: Correctly targeting the token dimension to avoid empty strings
32
+ output_ids = model.generate(**inputs, max_new_tokens=256, do_sample=True, temperature=0.7)
33
+ new_tokens = output_ids[0, inputs['input_ids'].shape[-1]:]
34
  response = tokenizer.decode(new_tokens, skip_special_tokens=True)
35
 
36
+ # Logic to identify if the agent needs a tool or has a Final Answer [13, 14]
37
  action_match = re.search(r"Action:\s*(\w+)", response)
 
38
  return {
39
  "messages": state['messages'] + [{"role": "assistant", "content": response}],
40
+ "next_action": action_match.group(1) if action_match else "end"
41
  }
42
 
43
+ # 4. The Action Node [14, 15]
44
  def execute_tool(state: AgentState):
45
+ tool_name = state['next_action']
46
+ observation = tools[tool_name]("")
47
+ return {"messages": state['messages'] + [{"role": "user", "content": observation}]}
 
 
 
 
 
 
48
 
49
+ # 5. Graph Construction [9, 16]
 
50
  workflow = StateGraph(AgentState)
51
  workflow.add_node("agent", call_model)
52
  workflow.add_node("tools", execute_tool)
 
53
  workflow.set_entry_point("agent")
54
+ workflow.add_conditional_edges("agent", lambda x: "tools" if x["next_action"] in tools else "end", {"tools": "tools", "end": END})
55
+ workflow.add_edge("tools", "agent")
56
+ agent_executor = workflow.compile()
 
 
 
 
 
 
 
 
57
 
58
  @app.route('/chat', methods=['POST'])
59
  def chat():
60
+ user_msg = request.json.get("message")
61
+ # System Prompt: Establishing identity and rules [17, 18]
62
+ inputs = {"messages": [
63
+ {"role": "system", "content": "You are a ReAct agent. Use Thought:, Action:, and Final Answer: tags."},
64
+ {"role": "user", "content": user_msg}
65
+ ]}
66
 
67
  def run():
68
+ for output in agent_executor.stream(inputs):
69
  for key, value in output.items():
 
70
  yield value['messages'][-1]['content'] + "\n"
71
 
72
  return Response(run(), mimetype='text/plain')
73
 
74
+ @app.route('/')
75
+ def index(): return render_template('index.html')
76
+
77
+ if __name__ == '__main__': app.run(host='0.0.0.0', port=7860)