devchavda11 commited on
Commit
c2dd056
·
verified ·
1 Parent(s): e0b3935

Update chat_langraph.py

Browse files
Files changed (1) hide show
  1. chat_langraph.py +126 -187
chat_langraph.py CHANGED
@@ -1,187 +1,126 @@
1
- from langchain_google_genai import ChatGoogleGenerativeAI
2
- from langchain_ollama import ChatOllama
3
- from langchain_core.messages import BaseMessage,ChatMessage,ToolMessage,AIMessage,SystemMessage,HumanMessage,messages_from_dict
4
- from langgraph.graph import StateGraph
5
- from langgraph.graph import add_messages , START , END
6
- from langgraph.checkpoint.base import CheckpointTuple
7
- from typing import TypedDict,Annotated , List
8
- from langchain_core.tools import tool
9
- from langgraph.prebuilt.tool_node import ToolNode
10
- from langgraph.checkpoint.sqlite import SqliteSaver
11
- from langchain_core.prompts import ChatPromptTemplate
12
- import sqlite3
13
- import subprocess
14
- import requests
15
- from chat_image_analyser import image_analyser
16
- from erpfunctionalities import *
17
- from htmltomarkdown import *
18
- from datetime import datetime , date
19
- class chatstate(TypedDict):
20
- messages : Annotated[List[BaseMessage], add_messages]
21
-
22
- user_id = "23IT441"
23
- password = "09122005"
24
- api = "AIzaSyA5zvErF4vUmAoslVzkOBUfvSCSoW0vjEA"
25
- LANGSEARCH_API_KEY = "sk-f1a8f996f9e44b43adf9943e43e8582b"
26
-
27
- # llm = ChatOllama(model = "qwen3:8b" , temperature = 0.5)
28
- llm = ChatGoogleGenerativeAI(model = "gemini-2.5-flash" , temperature = 0.2 , api_key = api)
29
- system = SystemMessage(
30
- content=
31
- f"""
32
- --> Todays date is : {datetime.today()} + " \n" + Dayno : {datetime.today().date().weekday()}
33
- You are an assistant that is practical, tool-aware, and outcome-oriented. Aim for correctness and clarity; avoid hallucinations.
34
- Rules (short & general):
35
-
36
- 1. Prefer text answers and code when the user only asks for examples or explanations.
37
- 2. If the user explicitly asks you to *create, save, run, or modify* a file or perform a system action (e.g., "create sales.xlsx", "save as report.py", "run this script now"), **call the appropriate tool(s) generally go with python tool to achieve the tasks which are not available directly.** to make that happen. Do not return code only in those cases.
38
- 3. If you produce code via a tool, and the user has asked for the file/action to be created or executed, write the file and execute it (write_file + run_cmd_command or the relevant tools) unless the user explicitly says "only give code".
39
- 4. Do not run or write obviously destructive commands (delete, format, rm -rf, wipe, format C:, etc.) without explicit, separate confirmation from the user. For any command that could be destructive, always ask one short confirmation (yes/no).
40
- 5. Keep tool inputs minimal and focused. When calling a tool, include only the parameters needed. After the tool returns, always validate the result and summarize it for the user (one-line result + any errors).
41
- 6. If a requested action fails (permission, path, syntax error), explain the failure, propose a fix, and offer to retry when the user approves.
42
- 7. Do not make assumptions — ask the user if in doubt. If you need clarification, ask a single short question; otherwise make a best-effort decision to proceed.
43
- 8. If you are unsure whether to call a tool, prefer asking a *single* clarifying question; otherwise make a best-effort decision to proceed.
44
- 9. Do not make assumptions about the system of the user , u have command prompt access it to gather the information about the system of the user..
45
- 10. Respond in the same language as the user.
46
-
47
- Tone: concise, helpful, and decisive.
48
-
49
- """
50
- )
51
-
52
- conn = sqlite3.connect("chatbot.db" , check_same_thread=False)
53
- checkpointer = SqliteSaver(conn=conn)
54
- @tool
55
- def add(a : int , b:int):
56
- """Adds two numbers """
57
- return a+b
58
- @tool
59
- def reverse(string : str):
60
- """Reverses a string..."""
61
- return string[::-1]
62
- @tool
63
- def evaluate(string : str):
64
- """Evaluates a simple mathematical expression but it should be passed as a string..."""
65
- print(eval(string))
66
- return eval(string)
67
- @tool
68
- def write_file(name : str , extension : str , content : str):
69
- """Writes a file given name extension and content of the file ,
70
- it only supports txt files and coding files currently , Use the python script to create other file types."""
71
- with open(f"{name}.{extension}" , "w" , encoding='utf-8') as f:
72
- f.write(content)
73
- return f"Content : {content} is writtened and saved to {name}.{extension} ."
74
-
75
-
76
- @tool
77
- def run_python_file(filename:str):
78
- """Runs the python file when given the filename of it."""
79
- if(filename[-1:-3:-1] != "py"):
80
- filename += ".py"
81
- msg = run_cmd_command(f"python {filename}")
82
- return msg
83
- @tool
84
- def run_cmd_command(command: str) -> str:
85
-
86
- """Any windows command is allowed"""
87
- try:
88
- # Execute the command and capture the output
89
- result = subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
90
- print(result)
91
- return result
92
- except subprocess.CalledProcessError as e:
93
- return f"An error occurred while executing the command: {e} "
94
- @tool
95
- def search_tool(query:str):
96
- """Searches the query on web and gives brief description (in json) and url names...."""
97
- response = requests.post("https://api.langsearch.com/v1/web-search",
98
- headers={
99
- "Authorization": f"Bearer {LANGSEARCH_API_KEY}",
100
- "Content-Type":"application/json"
101
- },
102
- json={
103
- "query":query,
104
- "num_results":2
105
- })
106
-
107
- return response.json()
108
-
109
- @tool
110
- def image_analysis(query : str)->str:
111
- """Analyzes an image given a query and generates a description based on conversational context.
112
- It only analyses the file present in the current directory named as image.png , so if user asks for specific file rename the file and save to curr dir , otherwise just use this tool directly if not said anything...
113
- Args: query : Any query regarding the image...
114
- You dont have to worry about image name and anything it will be handled automatically. Finally just explain the returned text nicely .
115
- Returns: str: A textual description of the image. Please give the final ans in detail and in your own words..."""
116
- return image_analyser(query)
117
-
118
-
119
- @tool
120
- def get_fees_tool() -> str:
121
- """Gives the fees detail of the student who is chatting..."""
122
- return get_fees_details(user_id, password)
123
- @tool
124
- def get_attendance_tool() -> str:
125
- """Gives the attendance details of the student who is chatting."""
126
- return attendance(user_id, password)
127
- @tool
128
- def get_timetable_tool(target: str) -> str:
129
- """Gives the timetable details of the student who is chatting when given a date in dd-mm-yy format
130
- Timetable contains the holidays information as well."""
131
- return timetable(user_id, password, target)
132
- @tool
133
- def get_student_details_tool() -> str:
134
- """Gives the information about the student who is chatting."""
135
- return student_details(user_id, password)
136
- @tool
137
- def get_result_tool(semester: int) -> str:
138
- """Gets the result of the student who is chatting."""
139
- return get_result_details(user_id, password, semester)
140
- def shouldcontinue(state:chatstate):
141
- if(state['messages'][-1].content == 'end'):
142
- return 'end'
143
- else:
144
- return 'llmresponse'
145
- def input_node(state:chatstate):
146
- return {"messages":state['messages']}
147
- def llmresponse(state:chatstate):
148
- response = llm.invoke(state['messages'])
149
- print(response.content)
150
- return {'messages':[response]}
151
- def checktool(state: chatstate):
152
- last_msg = state['messages'][-1]
153
- if hasattr(last_msg, "tool_calls") and last_msg.tool_calls:
154
- fc = last_msg.additional_kwargs.get('function_call')
155
- if fc and 'name' in fc:
156
- print("Calling the tool", fc['name'])
157
- elif last_msg.tool_calls[0]['name'] :
158
- print("Calling the tool " ,last_msg.tool_calls[0]['name'] )
159
- return "tool_node"
160
- return "end"
161
-
162
- tools = [add,reverse,evaluate,run_cmd_command,search_tool,write_file,image_analysis]
163
- tool_node = ToolNode(tools=tools)
164
- llm = llm.bind_tools(tools)
165
- graph = StateGraph(chatstate)
166
- graph.add_node('input_node' , input_node)
167
- graph.add_node('llmresponse',llmresponse)
168
- graph.add_node('tool_node',tool_node)
169
- graph.add_edge(START , "input_node")
170
- graph.add_edge("input_node" , "llmresponse")
171
- graph.add_conditional_edges(
172
- "llmresponse",
173
- checktool,
174
- {
175
- "tool_node" : "tool_node",
176
- "end":END
177
- }
178
- )
179
- graph.add_edge("tool_node", "llmresponse")
180
-
181
- workflow = graph.compile(checkpointer=checkpointer)
182
- res = checkpointer.list(None)
183
- def get_all_chat_ids():
184
- s = set()
185
- for chkpoint in res:
186
- s.add(chkpoint.config.get('configurable').get('thread_id'))
187
- return list(s)
 
1
+ from langchain_google_genai import ChatGoogleGenerativeAI
2
+ from langchain_core.messages import BaseMessage, ToolMessage, AIMessage, SystemMessage, HumanMessage
3
+ from langgraph.graph import StateGraph, add_messages, START, END
4
+ from langgraph.checkpoint.sqlite import SqliteSaver
5
+ from typing import TypedDict, Annotated, List
6
+ from langchain_core.tools import tool
7
+ from langgraph.prebuilt.tool_node import ToolNode
8
+ import sqlite3
9
+ import subprocess
10
+ import requests
11
+ from datetime import datetime
12
+
13
+ class chatstate(TypedDict):
14
+ messages: Annotated[List[BaseMessage], add_messages]
15
+
16
+
17
+ api = "AIzaSyA5zvErF4vUmAoslVzkOBUfvSCSoW0vjEA"
18
+ LANGSEARCH_API_KEY = "sk-f1a8f996f9e44b43adf9943e43e8582b"
19
+
20
+ llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", temperature=0.2, api_key=api)
21
+
22
+ system = SystemMessage(
23
+ content=f"""
24
+ --> Today's date: {datetime.today()}
25
+ Day number: {datetime.today().date().weekday()}
26
+ You are a practical, tool-aware assistant. Aim for correctness and clarity. Avoid hallucinations.
27
+ Do not provide internal information of the system .
28
+ Rules:
29
+ 1. Prefer text answers and code when examples/explanations are asked.
30
+ 2. Explicit requests to create/run files → call appropriate tool.
31
+ 3. Avoid destructive commands without confirmation.
32
+ 4. Keep tool inputs minimal.
33
+ Tone: concise, helpful, decisive.
34
+ """
35
+ )
36
+
37
+ conn = sqlite3.connect("chatbot.db", check_same_thread=False)
38
+ checkpointer = SqliteSaver(conn=conn)
39
+
40
+
41
+ @tool
42
+ def add(a: int, b: int):
43
+ return a + b
44
+
45
+
46
+ @tool
47
+ def reverse(string: str):
48
+ return string[::-1]
49
+
50
+
51
+ @tool
52
+ def evaluate(string: str):
53
+ return eval(string)
54
+
55
+
56
+ @tool
57
+ def write_file(name: str, extension: str, content: str):
58
+ with open(f"{name}.{extension}", "w", encoding="utf-8") as f:
59
+ f.write(content)
60
+ return f"Content saved to {name}.{extension}"
61
+
62
+
63
+ @tool
64
+ def run_cmd_command(command: str) -> str:
65
+ """Run a safe shell command on linux """
66
+ try:
67
+ result = subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
68
+ return result.stdout
69
+ except subprocess.CalledProcessError as e:
70
+ return f"Error: {e}"
71
+
72
+
73
+ @tool
74
+ def search_tool(query: str):
75
+ response = requests.post(
76
+ "https://api.langsearch.com/v1/web-search",
77
+ headers={
78
+ "Authorization": f"Bearer {LANGSEARCH_API_KEY}",
79
+ "Content-Type": "application/json"
80
+ },
81
+ json={"query": query, "num_results": 2}
82
+ )
83
+ return response.json()
84
+
85
+
86
+ def shouldcontinue(state: chatstate):
87
+ return "end" if state["messages"][-1].content == "end" else "llmresponse"
88
+
89
+
90
+ def input_node(state: chatstate):
91
+ return {"messages": state["messages"]}
92
+
93
+
94
+ def llmresponse(state: chatstate):
95
+ response = llm.invoke(state["messages"])
96
+ return {"messages": [response]}
97
+
98
+
99
+ def checktool(state: chatstate):
100
+ last_msg = state["messages"][-1]
101
+ if hasattr(last_msg, "tool_calls") and last_msg.tool_calls:
102
+ return "tool_node"
103
+ return "end"
104
+
105
+
106
+ tools = [add, reverse, evaluate, run_cmd_command, search_tool, write_file]
107
+ tool_node = ToolNode(tools=tools)
108
+ llm = llm.bind_tools(tools)
109
+
110
+ graph = StateGraph(chatstate)
111
+ graph.add_node("input_node", input_node)
112
+ graph.add_node("llmresponse", llmresponse)
113
+ graph.add_node("tool_node", tool_node)
114
+ graph.add_edge(START, "input_node")
115
+ graph.add_edge("input_node", "llmresponse")
116
+ graph.add_conditional_edges("llmresponse", checktool, {"tool_node": "tool_node", "end": END})
117
+ graph.add_edge("tool_node", "llmresponse")
118
+
119
+ workflow = graph.compile(checkpointer=checkpointer)
120
+
121
+
122
+ def get_all_chat_ids():
123
+ s = set()
124
+ for chkpoint in checkpointer.list(None):
125
+ s.add(chkpoint.config.get("configurable").get("thread_id"))
126
+ return list(s)