SaiPavankumar22 commited on
Commit
bd34882
Β·
0 Parent(s):

full project complete code

Browse files
Files changed (2) hide show
  1. README.md +86 -0
  2. app.py +873 -0
README.md ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Construction Company AI Assistant
2
+
3
+ An expert, construction-only AI assistant with a modern Gradio UI, powered by DeepSeek R1 via OpenRouter, optional live web search (Serper), and CrewAI agents.
4
+
5
+ ## Features
6
+
7
+ - **Construction-only assistant**: Politely declines non-construction queries
8
+ - **DeepSeek R1 reasoning model**: Via OpenRouter
9
+ - **Optional live web search**: Uses Serper to fetch current prices, codes, and updates
10
+ - **Memory**: Remembers the last 5 Q&A pairs
11
+ - **CrewAI agents**: Expert assistant + optional research agent
12
+ - **Modern UI**: Construction-themed styling, examples, and status indicators
13
+
14
+ ## What’s inside (tech)
15
+
16
+ - **Model**: DeepSeek R1 (OpenRouter)
17
+ - **Agent framework**: CrewAI (`Agent`, `Task`, `Crew`, `LLM`)
18
+ - **Web search tool**: `SerperDevTool` (optional)
19
+ - **UI**: Gradio (messages format), auto-launches browser
20
+
21
+ ## Installation
22
+
23
+ 1) Create/activate a Python 3.10+ environment.
24
+
25
+ 2) Install dependencies:
26
+ ```bash
27
+ pip install gradio crewai crewai-tools langchain-openai
28
+ ```
29
+
30
+ ## Configuration
31
+
32
+ The app is preconfigured in `app.py` to use:
33
+ - OpenRouter (DeepSeek R1) for responses
34
+ - Optional Serper for web search (set `SERPER_API_KEY` to enable)
35
+
36
+ Set Serper (optional) if you want live web search:
37
+ - Windows (PowerShell):
38
+ ```powershell
39
+ $env:SERPER_API_KEY="your-serper-api-key"
40
+ ```
41
+ - Linux/Mac:
42
+ ```bash
43
+ export SERPER_API_KEY="your-serper-api-key"
44
+ ```
45
+
46
+ If you prefer, you can also run the optional setup helper:
47
+ ```bash
48
+ python setup_env.py
49
+ ```
50
+
51
+ ## Run
52
+
53
+ ```bash
54
+ python app.py
55
+ ```
56
+
57
+ By default the app launches on:
58
+ - Local: `http://localhost:7863`
59
+ - A public Gradio share link (shown in the console)
60
+
61
+ The UI auto-opens in your browser (`inbrowser=True`).
62
+
63
+ ## How it works (high-level)
64
+
65
+ - Incoming questions are first filtered to ensure they are construction-related.
66
+ - For time-sensitive questions (e.g., β€œcurrent”, β€œlatest”, β€œ2024/2025”, β€œprice”, β€œcost”, β€œregulation”), a research agent may search the web (if Serper is enabled) and pass findings to the expert agent.
67
+ - If anything fails, a direct LLM fallback path still answers construction questions.
68
+
69
+ ## Example questions
70
+
71
+ - β€œLatest fire safety codes for high-rise buildings (2024)?”
72
+ - β€œCurrent price of M30 ready-mix concrete per mΒ³ in my area?”
73
+ - β€œOSHA requirements for scaffolding on construction sites?”
74
+ - β€œHow to size rebar for a medium-span concrete beam?”
75
+ - β€œBest project management approach for a multi-tower site?”
76
+
77
+ ## Troubleshooting
78
+
79
+ - **Port already in use**: Change `server_port` in `app.py` (default is 7863).
80
+ - **Web search disabled**: Set `SERPER_API_KEY` and restart.
81
+ - **Import errors**: Run the install command again and ensure your environment is active.
82
+
83
+ ## Notes
84
+
85
+ - The assistant strictly answers construction-related topics (building, safety, materials, project management, engineering). Non-construction queries are declined by design.
86
+
app.py ADDED
@@ -0,0 +1,873 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from langchain_openai import ChatOpenAI
4
+ from crewai import Agent, Task, Crew, LLM
5
+ from crewai_tools import SerperDevTool
6
+ from typing import List, Tuple
7
+ import time
8
+
9
+ # Environment variables setup
10
+ OPENROUTER_API_KEY = "your api key"
11
+ SERPER_API_KEY = "your api key"
12
+
13
+ # Set environment variable for serper
14
+ os.environ["SERPER_API_KEY"] = SERPER_API_KEY
15
+
16
+ # Initialize CrewAI LLM with OpenRouter (DeepSeek R1)
17
+ crew_llm = LLM(
18
+ model="openrouter/deepseek/deepseek-r1",
19
+ base_url="https://openrouter.ai/api/v1",
20
+ api_key=OPENROUTER_API_KEY,
21
+ temperature=0.7
22
+ )
23
+
24
+ # Initialize direct LangChain LLM for fallback using OpenRouter
25
+ direct_llm = ChatOpenAI(
26
+ model="deepseek/deepseek-r1",
27
+ openai_api_key=OPENROUTER_API_KEY,
28
+ openai_api_base="https://openrouter.ai/api/v1",
29
+ temperature=0.7,
30
+ max_tokens=2000
31
+ )
32
+
33
+ class ConstructionChatbot:
34
+ def __init__(self):
35
+ self.memory: List[Tuple[str, str]] = [] # Rolling window of 5 messages
36
+ self.setup_tools()
37
+ self.setup_crew()
38
+
39
+ def setup_tools(self):
40
+ """Set up web search tools"""
41
+ try:
42
+ self.search_tool = SerperDevTool() # Will use environment variable
43
+ print("βœ… Web search tool initialized successfully")
44
+ except Exception as e:
45
+ self.search_tool = None
46
+ print(f"⚠️ Warning: Could not initialize web search tool: {e}")
47
+
48
+ def setup_crew(self):
49
+ """Set up CrewAI agents and tasks"""
50
+ # Tools list
51
+ tools = []
52
+ if self.search_tool:
53
+ tools.append(self.search_tool)
54
+
55
+ # Construction Expert Agent with improved prompt
56
+ self.construction_agent = Agent(
57
+ role='Construction Expert Assistant',
58
+ goal='Provide accurate construction-related information ONLY. Reject all non-construction queries.',
59
+ backstory="""You are a specialized construction industry expert with deep knowledge in:
60
+ - Building safety and regulations
61
+ - Fire safety codes and compliance
62
+ - Construction materials and costs
63
+ - Project management methodologies
64
+ - Heavy machinery and equipment
65
+ - Civil engineering principles
66
+ - Structural design and analysis
67
+ - Site management and safety protocols
68
+
69
+ IMPORTANT: You MUST ONLY respond to construction-related questions.
70
+ If a user asks about anything not related to construction, building,
71
+ engineering, safety, materials, or project management, you must respond
72
+ with EXACTLY: "I can only assist with construction-related queries. Please ask about building, safety, materials, project management, or engineering topics."
73
+
74
+ When you need current information about construction topics, use the search tool.""",
75
+ llm=crew_llm,
76
+ tools=tools,
77
+ verbose=True,
78
+ allow_delegation=False,
79
+ max_iter=3,
80
+ max_execution_time=45
81
+ )
82
+
83
+ # Web Search Research Agent (for construction-related research)
84
+ if self.search_tool:
85
+ self.research_agent = Agent(
86
+ role='Construction Research Specialist',
87
+ goal='Search and gather current construction-related information from the internet ONLY',
88
+ backstory="""You are a specialized researcher focused exclusively on construction industry topics.
89
+ You search for the most current information about:
90
+ - Construction practices and regulations
91
+ - Building costs and material prices
92
+ - Safety standards and compliance requirements
93
+ - Industry trends and new technologies
94
+ - Engineering standards and best practices
95
+
96
+ You ONLY research construction-related topics. If asked to research non-construction
97
+ topics, decline politely and redirect to construction subjects.""",
98
+ llm=crew_llm,
99
+ tools=[self.search_tool],
100
+ verbose=True,
101
+ allow_delegation=False,
102
+ max_iter=2,
103
+ max_execution_time=30
104
+ )
105
+ else:
106
+ self.research_agent = None
107
+
108
+ def add_to_memory(self, user_query: str, response: str):
109
+ """Add interaction to rolling memory window"""
110
+ self.memory.append((user_query, response))
111
+ if len(self.memory) > 5:
112
+ self.memory.pop(0) # Remove oldest message
113
+
114
+ def get_chat_history(self) -> str:
115
+ """Format chat history for prompt"""
116
+ if not self.memory:
117
+ return "No previous conversation."
118
+
119
+ history = ""
120
+ for i, (user_msg, bot_msg) in enumerate(self.memory, 1):
121
+ history += f"Message {i}:\nUser: {user_msg}\nAssistant: {bot_msg}\n\n"
122
+ return history.strip()
123
+
124
+ def is_construction_related(self, query: str) -> bool:
125
+ """Simple check if query is construction-related"""
126
+ construction_keywords = [
127
+ 'construction', 'building', 'concrete', 'steel', 'foundation', 'safety',
128
+ 'project management', 'engineering', 'structure', 'material', 'cost',
129
+ 'regulation', 'fire safety', 'osha', 'machinery', 'equipment', 'site',
130
+ 'contractor', 'cement', 'rebar', 'excavation', 'blueprint', 'architect',
131
+ 'electrical', 'plumbing', 'hvac', 'roofing', 'insulation', 'drywall'
132
+ ]
133
+
134
+ query_lower = query.lower()
135
+ return any(keyword in query_lower for keyword in construction_keywords)
136
+
137
+ def generate_response_with_crew(self, user_query: str) -> str:
138
+ """Generate response using CrewAI with web search capabilities"""
139
+ # First check if query is construction-related
140
+ if not self.is_construction_related(user_query):
141
+ response = "I can only assist with construction-related queries. Please ask about building, safety, materials, project management, or engineering topics."
142
+ self.add_to_memory(user_query, response)
143
+ return response
144
+
145
+ chat_history = self.get_chat_history()
146
+
147
+ try:
148
+ # Determine if web search is needed for construction topics
149
+ search_keywords = ['current', 'latest', 'recent', 'today', '2024', '2025', 'price', 'cost', 'regulation', 'new', 'trend']
150
+ needs_search = any(keyword in user_query.lower() for keyword in search_keywords)
151
+
152
+ if needs_search and self.research_agent:
153
+ # Create research task first
154
+ research_task = Task(
155
+ description=f"""Search for current construction-related information about: {user_query}
156
+
157
+ Focus on finding:
158
+ - Latest construction industry data
159
+ - Current material prices and costs
160
+ - Recent regulations and safety updates
161
+ - New construction technologies and methods
162
+ - Industry trends and market information
163
+
164
+ Search query should be concise and focused on construction industry information.
165
+ """,
166
+ expected_output="Current, accurate construction industry information and data",
167
+ agent=self.research_agent
168
+ )
169
+
170
+ # Create response task
171
+ response_task = Task(
172
+ description=f"""Based on research findings and chat history, provide a comprehensive response to: {user_query}
173
+
174
+ Chat history: {chat_history}
175
+
176
+ Guidelines:
177
+ - Use the research data to provide accurate, current information
178
+ - Focus on construction industry expertise
179
+ - Provide practical, actionable advice
180
+ - Include specific details like prices, regulations, or technical specifications when available
181
+ - Structure the response clearly and professionally
182
+ """,
183
+ expected_output="Detailed, informative construction industry response with current data",
184
+ agent=self.construction_agent,
185
+ context=[research_task]
186
+ )
187
+
188
+ # Create crew with both agents
189
+ crew = Crew(
190
+ agents=[self.research_agent, self.construction_agent],
191
+ tasks=[research_task, response_task],
192
+ verbose=False # Reduce verbose output
193
+ )
194
+
195
+ else:
196
+ # Create direct response task
197
+ response_task = Task(
198
+ description=f"""Provide expert construction advice for: {user_query}
199
+
200
+ Chat history: {chat_history}
201
+
202
+ Guidelines:
203
+ - Draw from your construction industry expertise
204
+ - Provide detailed, accurate information
205
+ - Include relevant safety considerations
206
+ - Suggest best practices and standards
207
+ - Structure the response professionally
208
+ """,
209
+ expected_output="Expert construction industry advice and information",
210
+ agent=self.construction_agent
211
+ )
212
+
213
+ # Create crew with single agent
214
+ crew = Crew(
215
+ agents=[self.construction_agent],
216
+ tasks=[response_task],
217
+ verbose=False
218
+ )
219
+
220
+ # Execute crew
221
+ result = crew.kickoff()
222
+ response = str(result).strip()
223
+
224
+ # Clean up response if needed
225
+ if not response or len(response) < 10:
226
+ response = "I apologize, but I'm having trouble generating a proper response. Could you please rephrase your construction-related question?"
227
+
228
+ # Add to memory
229
+ self.add_to_memory(user_query, response)
230
+ return response
231
+
232
+ except Exception as e:
233
+ print(f"CrewAI Error: {e}")
234
+ # Fallback to direct LLM
235
+ return self.generate_response_direct(user_query)
236
+
237
+ def generate_response_direct(self, user_query: str) -> str:
238
+ """Fallback method using direct LLM with construction filtering"""
239
+ if not self.is_construction_related(user_query):
240
+ response = "I can only assist with construction-related queries. Please ask about building, safety, materials, project management, or engineering topics."
241
+ self.add_to_memory(user_query, response)
242
+ return response
243
+
244
+ chat_history = self.get_chat_history()
245
+
246
+ prompt = f"""You are a specialized construction industry AI assistant with expertise in building, safety, materials, project management, and engineering.
247
+
248
+ Chat history: {chat_history}
249
+
250
+ User question: {user_query}
251
+
252
+ Provide a detailed, professional response focusing on construction industry knowledge. Include specific information about safety standards, building codes, material specifications, cost estimates, or project management advice as relevant to the question.
253
+
254
+ Response:"""
255
+
256
+ try:
257
+ response = direct_llm.invoke(prompt)
258
+ if hasattr(response, 'content'):
259
+ response_text = response.content
260
+ else:
261
+ response_text = str(response)
262
+
263
+ self.add_to_memory(user_query, response_text)
264
+ return response_text
265
+
266
+ except Exception as e:
267
+ fallback_response = f"""I apologize, but I'm experiencing technical difficulties. However, I can still help with construction-related questions about safety, materials, project management, and engineering. Please try rephrasing your question.
268
+
269
+ Technical error: {str(e)[:100]}..."""
270
+
271
+ self.add_to_memory(user_query, fallback_response)
272
+ return fallback_response
273
+
274
+ def generate_response(self, user_query: str) -> str:
275
+ """Main response generation method"""
276
+ try:
277
+ return self.generate_response_with_crew(user_query)
278
+ except Exception as e:
279
+ print(f"Crew method failed, using direct method: {e}")
280
+ return self.generate_response_direct(user_query)
281
+
282
+ # Initialize chatbot
283
+ chatbot = ConstructionChatbot()
284
+
285
+ # Custom CSS for construction-themed interface with vibrant colors
286
+ custom_css = """
287
+ /* Construction-themed color palette */
288
+ :root {
289
+ --construction-orange: #ff6b1a;
290
+ --construction-yellow: #ffc107;
291
+ --construction-blue: #1e88e5;
292
+ --construction-green: #4caf50;
293
+ --construction-red: #f44336;
294
+ --construction-dark: #2d3436;
295
+ --construction-darker: #1a1a1a;
296
+ --construction-light-gray: #ecf0f1;
297
+ --construction-medium-gray: #95a5a6;
298
+ --construction-steel: #34495e;
299
+ }
300
+
301
+ /* Main container styling */
302
+ .gradio-container {
303
+ background: linear-gradient(135deg, var(--construction-dark) 0%, var(--construction-darker) 100%);
304
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
305
+ min-height: 100vh;
306
+ }
307
+
308
+ /* Header styling */
309
+ .construction-header {
310
+ background: linear-gradient(45deg, var(--construction-orange), var(--construction-yellow));
311
+ color: #000;
312
+ text-align: center;
313
+ padding: 25px;
314
+ font-weight: bold;
315
+ font-size: 28px;
316
+ border-radius: 15px;
317
+ margin-bottom: 25px;
318
+ box-shadow: 0 8px 25px rgba(255, 107, 26, 0.4);
319
+ border: 3px solid var(--construction-yellow);
320
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
321
+ }
322
+
323
+ /* Chat container - Custom styling */
324
+ .chatbot {
325
+ border: 3px solid var(--construction-orange) !important;
326
+ border-radius: 15px !important;
327
+ background: linear-gradient(135deg, var(--construction-steel), #2c3e50) !important;
328
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3) !important;
329
+ }
330
+
331
+ /* Message bubbles styling */
332
+ .message-wrap {
333
+ margin: 15px 0 !important;
334
+ }
335
+
336
+ .message-wrap.svelte-1lcyrx4.user {
337
+ justify-content: flex-end !important;
338
+ }
339
+
340
+ .message-wrap.svelte-1lcyrx4.bot {
341
+ justify-content: flex-start !important;
342
+ }
343
+
344
+ /* User message styling */
345
+ .message-wrap.user .message {
346
+ background: linear-gradient(135deg, var(--construction-orange), var(--construction-yellow)) !important;
347
+ color: #000 !important;
348
+ border-radius: 20px 20px 5px 20px !important;
349
+ padding: 15px 20px !important;
350
+ max-width: 75% !important;
351
+ font-weight: 500 !important;
352
+ box-shadow: 0 4px 15px rgba(255, 107, 26, 0.3) !important;
353
+ border: 2px solid var(--construction-yellow) !important;
354
+ }
355
+
356
+ /* Bot message styling */
357
+ .message-wrap.bot .message {
358
+ background: linear-gradient(135deg, var(--construction-blue), #1565c0) !important;
359
+ color: #ffffff !important;
360
+ border-radius: 20px 20px 20px 5px !important;
361
+ padding: 15px 20px !important;
362
+ max-width: 75% !important;
363
+ box-shadow: 0 4px 15px rgba(30, 136, 229, 0.3) !important;
364
+ border-left: 5px solid var(--construction-green) !important;
365
+ }
366
+
367
+ /* Input styling */
368
+ .input-container {
369
+ background: linear-gradient(135deg, var(--construction-steel), #2c3e50);
370
+ border-radius: 25px;
371
+ padding: 15px;
372
+ border: 3px solid var(--construction-orange);
373
+ margin-top: 20px;
374
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2);
375
+ }
376
+
377
+ /* Textbox styling */
378
+ .textbox {
379
+ background: var(--construction-dark) !important;
380
+ border: 2px solid var(--construction-orange) !important;
381
+ border-radius: 20px !important;
382
+ color: var(--construction-light-gray) !important;
383
+ padding: 15px 20px !important;
384
+ font-size: 16px !important;
385
+ }
386
+
387
+ .textbox:focus {
388
+ border-color: var(--construction-yellow) !important;
389
+ box-shadow: 0 0 15px rgba(255, 193, 7, 0.3) !important;
390
+ }
391
+
392
+ /* Button styling */
393
+ .btn-primary {
394
+ background: linear-gradient(135deg, var(--construction-orange), var(--construction-yellow)) !important;
395
+ color: #000 !important;
396
+ border: none !important;
397
+ border-radius: 20px !important;
398
+ padding: 15px 25px !important;
399
+ font-weight: bold !important;
400
+ font-size: 16px !important;
401
+ cursor: pointer !important;
402
+ transition: all 0.3s ease !important;
403
+ box-shadow: 0 4px 15px rgba(255, 107, 26, 0.3) !important;
404
+ }
405
+
406
+ .btn-primary:hover {
407
+ background: linear-gradient(135deg, var(--construction-yellow), #ffeb3b) !important;
408
+ transform: translateY(-2px) !important;
409
+ box-shadow: 0 6px 20px rgba(255, 193, 7, 0.4) !important;
410
+ }
411
+
412
+ .btn-secondary {
413
+ background: linear-gradient(135deg, var(--construction-steel), #34495e) !important;
414
+ color: var(--construction-light-gray) !important;
415
+ border: 2px solid var(--construction-medium-gray) !important;
416
+ border-radius: 15px !important;
417
+ padding: 12px 20px !important;
418
+ font-weight: bold !important;
419
+ transition: all 0.3s ease !important;
420
+ }
421
+
422
+ .btn-secondary:hover {
423
+ background: linear-gradient(135deg, var(--construction-blue), #1976d2) !important;
424
+ border-color: var(--construction-blue) !important;
425
+ transform: translateY(-2px) !important;
426
+ }
427
+
428
+ /* Status and info styling */
429
+ .status-info {
430
+ background: linear-gradient(135deg, rgba(76, 175, 80, 0.1), rgba(30, 136, 229, 0.1));
431
+ border: 2px solid var(--construction-green);
432
+ border-radius: 12px;
433
+ padding: 15px;
434
+ margin: 15px 0;
435
+ color: var(--construction-light-gray);
436
+ font-size: 14px;
437
+ box-shadow: 0 3px 10px rgba(76, 175, 80, 0.2);
438
+ }
439
+
440
+ /* Warning/info boxes */
441
+ .warning-box {
442
+ background: linear-gradient(135deg, rgba(244, 67, 54, 0.1), rgba(255, 107, 26, 0.1));
443
+ border: 2px solid var(--construction-red);
444
+ border-radius: 12px;
445
+ padding: 20px;
446
+ margin: 20px 0;
447
+ color: var(--construction-light-gray);
448
+ box-shadow: 0 4px 15px rgba(244, 67, 54, 0.2);
449
+ }
450
+
451
+ .info-box {
452
+ background: linear-gradient(135deg, rgba(30, 136, 229, 0.1), rgba(255, 193, 7, 0.1));
453
+ border: 2px solid var(--construction-blue);
454
+ border-radius: 12px;
455
+ padding: 20px;
456
+ margin: 20px 0;
457
+ color: var(--construction-light-gray);
458
+ box-shadow: 0 4px 15px rgba(30, 136, 229, 0.2);
459
+ }
460
+
461
+ .success-box {
462
+ background: linear-gradient(135deg, rgba(76, 175, 80, 0.1), rgba(255, 193, 7, 0.1));
463
+ border: 2px solid var(--construction-green);
464
+ border-radius: 12px;
465
+ padding: 20px;
466
+ margin: 20px 0;
467
+ color: var(--construction-light-gray);
468
+ box-shadow: 0 4px 15px rgba(76, 175, 80, 0.2);
469
+ }
470
+
471
+ /* Headings */
472
+ h1, h2, h3, h4 {
473
+ color: var(--construction-orange) !important;
474
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3) !important;
475
+ font-weight: bold !important;
476
+ }
477
+
478
+ /* Links */
479
+ a {
480
+ color: var(--construction-yellow) !important;
481
+ text-decoration: none !important;
482
+ font-weight: bold !important;
483
+ }
484
+
485
+ a:hover {
486
+ color: var(--construction-orange) !important;
487
+ text-decoration: underline !important;
488
+ }
489
+
490
+ /* Code styling */
491
+ code {
492
+ background: var(--construction-darker) !important;
493
+ color: var(--construction-yellow) !important;
494
+ padding: 2px 6px !important;
495
+ border-radius: 4px !important;
496
+ font-family: 'Courier New', monospace !important;
497
+ }
498
+
499
+ /* Lists */
500
+ ul, ol {
501
+ color: var(--construction-light-gray);
502
+ }
503
+
504
+ li {
505
+ margin: 8px 0;
506
+ padding-left: 5px;
507
+ border-left: 3px solid var(--construction-orange);
508
+ padding-left: 10px;
509
+ margin-left: 10px;
510
+ }
511
+
512
+ /* Status indicators */
513
+ .status-indicator {
514
+ display: inline-block;
515
+ width: 12px;
516
+ height: 12px;
517
+ border-radius: 50%;
518
+ margin-right: 10px;
519
+ animation: pulse 2s infinite;
520
+ }
521
+
522
+ .status-online {
523
+ background: var(--construction-green);
524
+ box-shadow: 0 0 15px rgba(76, 175, 80, 0.6);
525
+ }
526
+
527
+ .status-offline {
528
+ background: var(--construction-red);
529
+ box-shadow: 0 0 15px rgba(244, 67, 54, 0.6);
530
+ }
531
+
532
+ @keyframes pulse {
533
+ 0% { opacity: 1; }
534
+ 50% { opacity: 0.5; }
535
+ 100% { opacity: 1; }
536
+ }
537
+
538
+ /* Badge styling */
539
+ .badge {
540
+ background: linear-gradient(135deg, var(--construction-blue), #1565c0);
541
+ color: white;
542
+ padding: 6px 12px;
543
+ border-radius: 15px;
544
+ font-size: 12px;
545
+ font-weight: bold;
546
+ display: inline-block;
547
+ margin: 2px;
548
+ box-shadow: 0 2px 8px rgba(30, 136, 229, 0.3);
549
+ }
550
+
551
+ /* Scrollbar styling */
552
+ ::-webkit-scrollbar {
553
+ width: 10px;
554
+ }
555
+
556
+ ::-webkit-scrollbar-track {
557
+ background: var(--construction-darker);
558
+ border-radius: 5px;
559
+ }
560
+
561
+ ::-webkit-scrollbar-thumb {
562
+ background: linear-gradient(135deg, var(--construction-orange), var(--construction-yellow));
563
+ border-radius: 5px;
564
+ }
565
+
566
+ ::-webkit-scrollbar-thumb:hover {
567
+ background: linear-gradient(135deg, var(--construction-yellow), #ffeb3b);
568
+ }
569
+
570
+ /* Responsive design */
571
+ @media (max-width: 768px) {
572
+ .construction-header {
573
+ font-size: 20px;
574
+ padding: 20px 15px;
575
+ }
576
+
577
+ .message {
578
+ max-width: 90% !important;
579
+ padding: 12px 15px !important;
580
+ }
581
+ }
582
+
583
+ /* Animation for new messages */
584
+ .message-wrap {
585
+ animation: slideIn 0.3s ease-out;
586
+ }
587
+
588
+ @keyframes slideIn {
589
+ from {
590
+ opacity: 0;
591
+ transform: translateY(20px);
592
+ }
593
+ to {
594
+ opacity: 1;
595
+ transform: translateY(0);
596
+ }
597
+ }
598
+ """
599
+
600
+ def create_interface():
601
+ """Create the Gradio interface with construction theme"""
602
+
603
+ with gr.Blocks(css=custom_css, title="πŸ—οΈ Construction AI Assistant - DeepSeek R1 πŸ—οΈ") as interface:
604
+
605
+ # Header with construction theme
606
+ gr.HTML("""
607
+ <div class="construction-header">
608
+ πŸ—οΈ CONSTRUCTION COMPANY AI ASSISTANT πŸ—οΈ
609
+ <br>
610
+ <small style="font-size: 18px; font-weight: normal; opacity: 0.9;">
611
+ Powered by <span class="badge">DeepSeek R1</span> | Expert Construction Guidance with Live Web Search
612
+ </small>
613
+ </div>
614
+ """)
615
+
616
+ # Status display with construction styling
617
+ def get_status_info():
618
+ search_status = "🌐 Web Search: ONLINE" if chatbot.search_tool else "🌐 Web Search: OFFLINE"
619
+ search_class = "status-online" if chatbot.search_tool else "status-offline"
620
+ memory_count = len(chatbot.memory)
621
+
622
+ return f"""
623
+ <div class="status-info">
624
+ <span class="status-indicator {search_class}"></span>
625
+ <strong>🧠 DeepSeek R1 ACTIVE</strong> |
626
+ <strong>{search_status}</strong> |
627
+ <strong>πŸ’­ Memory: {memory_count}/5</strong> |
628
+ <strong>πŸ—οΈ Construction Expert Ready</strong>
629
+ <br>
630
+ <small>πŸ” Real-time construction data | πŸ“Š Current prices & regulations | ⚑ Lightning fast responses</small>
631
+ </div>
632
+ """
633
+
634
+ memory_status = gr.HTML(get_status_info())
635
+
636
+ # Main chat interface
637
+ with gr.Row():
638
+ with gr.Column():
639
+ chatbot_interface = gr.Chatbot(
640
+ [],
641
+ height=500,
642
+ show_label=False,
643
+ container=True,
644
+ avatar_images=("πŸ‘€", "πŸ—οΈ"),
645
+ bubble_full_width=False,
646
+ type="messages",
647
+ show_copy_button=True,
648
+ elem_classes=["chatbot"]
649
+ )
650
+
651
+ # Input section with construction styling
652
+ with gr.Row():
653
+ with gr.Column(scale=8):
654
+ msg_input = gr.Textbox(
655
+ placeholder="πŸ—οΈ Ask me about construction, safety, materials, project management, engineering, costs, regulations... (Non-construction queries will be declined)",
656
+ show_label=False,
657
+ container=False,
658
+ lines=2,
659
+ max_lines=4,
660
+ elem_classes=["textbox"]
661
+ )
662
+ with gr.Column(scale=2, min_width=120):
663
+ send_btn = gr.Button(
664
+ "πŸš€ SEND",
665
+ variant="primary",
666
+ size="lg",
667
+ elem_classes=["btn-primary"]
668
+ )
669
+
670
+ # Quick action buttons
671
+ with gr.Row():
672
+ with gr.Column(scale=1):
673
+ clear_btn = gr.Button("πŸ—‘οΈ Clear Chat", variant="secondary", elem_classes=["btn-secondary"])
674
+ with gr.Column(scale=1):
675
+ examples_btn = gr.Button("πŸ’‘ Examples", variant="secondary", elem_classes=["btn-secondary"])
676
+
677
+ # Example questions and features
678
+ examples_html = f"""
679
+ <div class="success-box">
680
+ <h4>βœ… CONSTRUCTION QUESTIONS I CAN ANSWER {'(with Live Web Search!)' if chatbot.search_tool else ''}:</h4>
681
+ <ul>
682
+ <li><strong>πŸ“Š Current Costs:</strong> "What are today's steel and concrete prices for construction?"</li>
683
+ <li><strong>πŸ”₯ Safety Regulations:</strong> "Latest fire safety codes for high-rise buildings in 2024?"</li>
684
+ <li><strong>πŸ—οΈ Engineering:</strong> "How to calculate foundation requirements for a 10-story building?"</li>
685
+ <li><strong>⚠️ Safety Equipment:</strong> "OSHA requirements for construction site safety equipment?"</li>
686
+ <li><strong>πŸ“‹ Project Management:</strong> "Best methodologies for managing large construction projects?"</li>
687
+ <li><strong>🌱 Sustainable Materials:</strong> "Latest trends in eco-friendly construction materials?"</li>
688
+ <li><strong>πŸ”§ Equipment:</strong> "Heavy machinery recommendations for excavation projects?"</li>
689
+ <li><strong>πŸ“ Structural Design:</strong> "Load-bearing calculations for steel frame buildings?"</li>
690
+ </ul>
691
+ </div>
692
+
693
+ <div class="warning-box">
694
+ <h4>❌ NON-CONSTRUCTION TOPICS (Will Be Politely Declined):</h4>
695
+ <ul>
696
+ <li>Sports, entertainment, cooking, general knowledge</li>
697
+ <li>Programming, medicine, finance (unless construction-related)</li>
698
+ <li>Personal advice, relationship help</li>
699
+ <li>Any topic not related to construction, building, or engineering</li>
700
+ </ul>
701
+ </div>
702
+
703
+ <div class="info-box">
704
+ <h4>πŸ’‘ PRO TIPS FOR BEST RESULTS:</h4>
705
+ <ul>
706
+ <li><strong>πŸ” Trigger Web Search:</strong> Use words like "current", "latest", "2024", "price", "cost" for real-time data</li>
707
+ <li><strong>πŸ“ Be Specific:</strong> Mention location, building type, or specific materials for targeted advice</li>
708
+ <li><strong>πŸ“‹ Multiple Questions:</strong> I remember our last 5 conversations for context</li>
709
+ <li><strong>🎯 Focus:</strong> Stay within construction topics for the best expert guidance</li>
710
+ </ul>
711
+ </div>
712
+ """
713
+
714
+ examples_display = gr.HTML(examples_html, visible=False)
715
+
716
+ # Event handlers
717
+ def update_memory_display():
718
+ return get_status_info()
719
+
720
+ def respond(message, history):
721
+ if not message.strip():
722
+ return history, "", update_memory_display()
723
+
724
+ # Add typing indicator (simulation)
725
+ if history is None:
726
+ history = []
727
+
728
+ # Add user message
729
+ history.append({"role": "user", "content": message})
730
+
731
+ # Generate bot response
732
+ try:
733
+ response = chatbot.generate_response(message)
734
+ history.append({"role": "assistant", "content": response})
735
+ except Exception as e:
736
+ error_response = f"🚨 I apologize, but I encountered an error while processing your construction query. Please try again or rephrase your question.\n\nError: {str(e)[:100]}..."
737
+ history.append({"role": "assistant", "content": error_response})
738
+
739
+ return history, "", update_memory_display()
740
+
741
+ def clear_chat():
742
+ chatbot.memory.clear()
743
+ return [], update_memory_display()
744
+
745
+ def toggle_examples(current_visibility):
746
+ return not current_visibility
747
+
748
+ # Wire up events
749
+ msg_input.submit(respond, [msg_input, chatbot_interface], [chatbot_interface, msg_input, memory_status])
750
+ send_btn.click(respond, [msg_input, chatbot_interface], [chatbot_interface, msg_input, memory_status])
751
+ clear_btn.click(clear_chat, outputs=[chatbot_interface, memory_status])
752
+ examples_btn.click(toggle_examples, inputs=examples_display, outputs=examples_display)
753
+
754
+ # Web search status info
755
+ if chatbot.search_tool:
756
+ gr.HTML(f"""
757
+ <div class="success-box">
758
+ <h4>🌐 WEB SEARCH ENABLED - REAL-TIME CONSTRUCTION DATA!</h4>
759
+ <p><strong>βœ… Connected to Serper API</strong> - I can fetch the latest construction industry information including:</p>
760
+ <ul>
761
+ <li>Current material prices and market trends</li>
762
+ <li>Latest building codes and regulations</li>
763
+ <li>New construction technologies and methods</li>
764
+ <li>Industry news and safety updates</li>
765
+ <li>Equipment specifications and pricing</li>
766
+ </ul>
767
+ <p><small>πŸ’‘ <strong>Tip:</strong> Ask questions with "current", "latest", "2024", "price" to automatically trigger web search!</small></p>
768
+ </div>
769
+ """)
770
+ else:
771
+ gr.HTML(f"""
772
+ <div class="warning-box">
773
+ <h4>⚠️ WEB SEARCH CURRENTLY DISABLED</h4>
774
+ <p><strong>Reason:</strong> Serper API key not properly configured</p>
775
+ <p><strong>Impact:</strong> I can still answer construction questions using my knowledge base, but won't have access to real-time data.</p>
776
+
777
+ <h5>πŸ”§ To Enable Web Search:</h5>
778
+ <ol>
779
+ <li>Visit <a href="https://serper.dev" target="_blank">serper.dev</a> and get a free API key</li>
780
+ <li>Set environment variable: <code>export SERPER_API_KEY='your-key-here'</code></li>
781
+ <li>Restart the application</li>
782
+ </ol>
783
+ <p><small>πŸ’‘ Even without web search, I'm still a comprehensive construction expert ready to help!</small></p>
784
+ </div>
785
+ """)
786
+
787
+ # DeepSeek R1 and model information
788
+ gr.HTML(f"""
789
+ <div class="info-box">
790
+ <h4>🧠 POWERED BY DEEPSEEK R1 - ADVANCED REASONING AI</h4>
791
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 15px; margin-top: 15px;">
792
+ <div>
793
+ <h5>πŸ”¬ Model Capabilities:</h5>
794
+ <ul>
795
+ <li>Advanced reasoning and problem-solving</li>
796
+ <li>Deep construction industry knowledge</li>
797
+ <li>Complex calculation capabilities</li>
798
+ <li>Multi-step project planning</li>
799
+ </ul>
800
+ </div>
801
+ <div>
802
+ <h5>🎯 Specialized Features:</h5>
803
+ <ul>
804
+ <li>Construction-only query filtering</li>
805
+ <li>Memory of last 5 conversations</li>
806
+ <li>Web search integration for current data</li>
807
+ <li>Professional construction advice</li>
808
+ </ul>
809
+ </div>
810
+ <div>
811
+ <h5>πŸ›‘οΈ Safety & Compliance:</h5>
812
+ <ul>
813
+ <li>OSHA regulation expertise</li>
814
+ <li>Building code compliance</li>
815
+ <li>Fire safety standards</li>
816
+ <li>Risk assessment guidance</li>
817
+ </ul>
818
+ </div>
819
+ </div>
820
+ </div>
821
+ """)
822
+
823
+ # Footer with additional information
824
+ gr.HTML("""
825
+ <div style="text-align: center; margin-top: 30px; padding: 20px; background: linear-gradient(135deg, rgba(255, 107, 26, 0.1), rgba(255, 193, 7, 0.1)); border-radius: 15px; border: 2px solid var(--construction-orange);">
826
+ <h5 style="color: var(--construction-orange); margin-bottom: 10px;">πŸ—οΈ PROFESSIONAL CONSTRUCTION AI ASSISTANT πŸ—οΈ</h5>
827
+ <p style="color: var(--construction-light-gray); margin: 0;">
828
+ <strong>Specialized in:</strong> Building Safety β€’ Material Costs β€’ Project Management β€’ Engineering β€’ Regulations β€’ Equipment
829
+ <br>
830
+ <small>⚑ Powered by DeepSeek R1 via OpenRouter β€’ 🌐 Enhanced with Web Search β€’ 🎯 Construction-Focused AI</small>
831
+ </p>
832
+ </div>
833
+ """)
834
+
835
+ return interface
836
+
837
+ # Launch the application
838
+ if __name__ == "__main__":
839
+ print("πŸ—οΈ" + "="*80)
840
+ print("πŸ—οΈ STARTING CONSTRUCTION COMPANY AI ASSISTANT")
841
+ print("πŸ—οΈ" + "="*80)
842
+ print("🧠 AI Model: DeepSeek R1 (Advanced Reasoning)")
843
+ print("🌐 API Provider: OpenRouter")
844
+ print("πŸ” Web Search: Serper API")
845
+ print(f"πŸ“‘ Search Status: {'βœ… ENABLED' if chatbot.search_tool else '❌ DISABLED (Check API Key)'}")
846
+ print("πŸ€– Agent Framework: CrewAI")
847
+ print("πŸ’¬ Interface: Gradio with Construction Theme")
848
+ print("🚨 Query Filter: Construction Topics ONLY")
849
+ print("πŸ’­ Memory: Rolling window of 5 conversations")
850
+ print("πŸ—οΈ" + "="*80)
851
+ print("πŸš€ Launching interface...")
852
+
853
+ # Test web search capability
854
+ if chatbot.search_tool:
855
+ print("βœ… Web search tool initialized successfully!")
856
+ print("πŸ’‘ Users can get real-time construction data")
857
+ else:
858
+ print("⚠️ Web search disabled - check SERPER_API_KEY")
859
+ print("πŸ’‘ Assistant will work with knowledge base only")
860
+
861
+ print("πŸ—οΈ" + "="*80)
862
+
863
+ # Create and launch the interface
864
+ interface = create_interface()
865
+ interface.launch(
866
+ share=True,
867
+ server_name="0.0.0.0",
868
+ server_port=7863,
869
+ show_error=True,
870
+ debug=False,
871
+ favicon_path=None,
872
+ inbrowser=True
873
+ )