CosmickVisions commited on
Commit
d04b52f
·
verified ·
1 Parent(s): 84384fc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +228 -354
app.py CHANGED
@@ -5,7 +5,7 @@ import tempfile
5
  import uuid
6
  from dotenv import load_dotenv
7
  from langchain_community.vectorstores import FAISS
8
- from langchain_community.embeddings import SentenceTransformerEmbeddings
9
  from langchain.text_splitter import RecursiveCharacterTextSplitter
10
  import fitz # PyMuPDF
11
  import base64
@@ -25,13 +25,21 @@ client = groq.Client(api_key=os.getenv("GROQ_TECH_API_KEY"))
25
 
26
  # Initialize embeddings with error handling
27
  try:
28
- embeddings = SentenceTransformerEmbeddings(
29
- model_name="all-MiniLM-L6-v2",
30
- model_kwargs={"device": "cpu"}
 
31
  )
32
  except Exception as e:
33
- print(f"Error loading embeddings: {e}")
34
- embeddings = None
 
 
 
 
 
 
 
35
 
36
  # Directory to store FAISS indexes with better naming
37
  FAISS_INDEX_DIR = "faiss_indexes_tech_cpu"
@@ -41,288 +49,69 @@ if not os.path.exists(FAISS_INDEX_DIR):
41
  # Dictionary to store user-specific vectorstores
42
  user_vectorstores = {}
43
 
44
- # Update the custom CSS for a more modern chat interface
45
  custom_css = """
46
- body {
47
- margin: 0;
48
- padding: 0;
49
- background-color: #f0f2f5;
50
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
 
 
 
 
51
  }
52
-
53
- /* Main app container */
54
- .main-app {
55
- width: 100%;
56
- max-width: 1200px;
57
- margin: 0 auto;
58
- padding: 20px;
59
  }
60
-
61
- /* Header styling */
62
- .app-header {
63
- background: linear-gradient(135deg, #0061ff 0%, #60efff 100%);
64
- padding: 30px;
65
- border-radius: 16px;
 
 
 
66
  margin-bottom: 20px;
67
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
68
- color: white;
69
- text-align: center;
70
  }
71
-
72
- .app-header h1 {
73
- margin: 0;
74
- font-size: 2.5rem;
75
  font-weight: 700;
76
- background: linear-gradient(to right, #fff, #e0e0e0);
77
- -webkit-background-clip: text;
78
- -webkit-text-fill-color: transparent;
79
- }
80
-
81
- /* Chat container styling */
82
- .chat-container {
83
- background-color: #ffffff;
84
- border-radius: 16px;
85
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
86
- overflow: hidden;
87
- height: 700px !important;
88
- display: flex !important;
89
- flex-direction: column !important;
90
- transition: all 0.3s ease;
91
- }
92
-
93
- /* Message container */
94
- .message-wrap {
95
- flex-grow: 1 !important;
96
- overflow-y: auto !important;
97
- padding: 24px !important;
98
- scroll-behavior: smooth;
99
- }
100
-
101
- .message-wrap::-webkit-scrollbar {
102
- width: 6px;
103
- }
104
-
105
- .message-wrap::-webkit-scrollbar-track {
106
- background: #f1f1f1;
107
- border-radius: 3px;
108
- }
109
-
110
- .message-wrap::-webkit-scrollbar-thumb {
111
- background: #c1c1c1;
112
- border-radius: 3px;
113
- }
114
-
115
- /* Message bubbles */
116
- .message {
117
- max-width: 85% !important;
118
- margin: 12px 0 !important;
119
- padding: 16px 20px !important;
120
- line-height: 1.5 !important;
121
- font-size: 15px !important;
122
- transition: all 0.2s ease;
123
- }
124
-
125
- .user-message {
126
- background: linear-gradient(135deg, #0061ff 0%, #60a5fa 100%) !important;
127
- color: white !important;
128
- margin-left: auto !important;
129
- border-radius: 18px 18px 0 18px !important;
130
- box-shadow: 0 2px 8px rgba(0, 97, 255, 0.15) !important;
131
- }
132
-
133
- .bot-message {
134
- background: #f8f9fa !important;
135
- color: #1a1a1a !important;
136
- margin-right: auto !important;
137
- border-radius: 18px 18px 18px 0 !important;
138
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05) !important;
139
- border: 1px solid #e8e8e8 !important;
140
- }
141
-
142
- /* Code blocks in messages */
143
- .bot-message code {
144
- background: #2d3748 !important;
145
- color: #e2e8f0 !important;
146
- padding: 12px 16px !important;
147
- border-radius: 8px !important;
148
- font-family: 'Fira Code', monospace !important;
149
- margin: 8px 0 !important;
150
- display: block;
151
- white-space: pre-wrap;
152
- }
153
-
154
- /* Input area */
155
- .input-area {
156
- padding: 24px !important;
157
- background: #ffffff !important;
158
- border-top: 1px solid rgba(0, 0, 0, 0.06) !important;
159
- display: flex !important;
160
- align-items: center !important;
161
- gap: 12px !important;
162
- }
163
-
164
- .input-textbox {
165
- background: #f8f9fa !important;
166
- border: 1px solid #e8e8e8 !important;
167
- border-radius: 24px !important;
168
- padding: 16px 24px !important;
169
- font-size: 15px !important;
170
- transition: all 0.2s ease !important;
171
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.02) !important;
172
- }
173
-
174
- .input-textbox:focus {
175
- border-color: #0061ff !important;
176
- box-shadow: 0 2px 12px rgba(0, 97, 255, 0.1) !important;
177
- background: white !important;
178
- }
179
-
180
- .send-button {
181
- background: linear-gradient(135deg, #0061ff 0%, #60a5fa 100%) !important;
182
- color: white !important;
183
- border-radius: 50% !important;
184
- width: 46px !important;
185
- height: 46px !important;
186
- padding: 0 !important;
187
- display: flex !important;
188
- align-items: center !important;
189
- justify-content: center !important;
190
- cursor: pointer !important;
191
- transition: all 0.2s ease !important;
192
- box-shadow: 0 2px 8px rgba(0, 97, 255, 0.2) !important;
193
- }
194
-
195
- .send-button:hover {
196
- transform: translateY(-1px) !important;
197
- box-shadow: 0 4px 12px rgba(0, 97, 255, 0.3) !important;
198
- }
199
-
200
- /* File upload area */
201
- .file-upload-area {
202
- text-align: center !important;
203
- padding: 40px !important;
204
- border: 2px dashed #c1c1c1 !important;
205
- border-radius: 16px !important;
206
- margin: 24px !important;
207
- transition: all 0.3s ease !important;
208
- background: rgba(0, 97, 255, 0.02) !important;
209
- }
210
-
211
- .file-upload-area:hover {
212
- border-color: #0061ff !important;
213
- background: rgba(0, 97, 255, 0.05) !important;
214
  }
215
-
216
- /* Avatar styling */
217
- .avatar {
218
- width: 32px !important;
219
- height: 32px !important;
220
- border-radius: 50% !important;
221
- margin-right: 12px !important;
222
  }
223
-
224
- /* Message timestamp */
225
- .message-time {
226
- font-size: 12px !important;
227
- color: rgba(0, 0, 0, 0.4) !important;
228
- margin-top: 4px !important;
229
  }
230
-
231
- /* Loading indicator */
232
- .typing-indicator {
233
- display: flex;
234
- align-items: center;
235
- gap: 4px;
236
- padding: 8px 12px;
237
- background: #f8f9fa;
238
  border-radius: 12px;
239
- width: fit-content;
240
- }
241
-
242
- .typing-dot {
243
- width: 6px;
244
- height: 6px;
245
- background: #0061ff;
246
- border-radius: 50%;
247
- animation: typing 1.4s infinite;
248
- }
249
-
250
- @keyframes typing {
251
- 0%, 100% { transform: translateY(0); }
252
- 50% { transform: translateY(-4px); }
253
- }
254
- """
255
-
256
- # Custom JavaScript to enhance UI
257
- custom_js = """
258
- document.addEventListener('DOMContentLoaded', function() {
259
- // Add Font Awesome
260
- const fontAwesome = document.createElement('link');
261
- fontAwesome.rel = 'stylesheet';
262
- fontAwesome.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css';
263
- document.head.appendChild(fontAwesome);
264
-
265
- // Add Google Fonts
266
- const googleFonts = document.createElement('link');
267
- googleFonts.rel = 'stylesheet';
268
- googleFonts.href = 'https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&family=Roboto:wght@300;400;500&family=Roboto+Mono&display=swap';
269
- document.head.appendChild(googleFonts);
270
-
271
- // Initialize UI enhancements
272
- setTimeout(enhanceUI, 1000);
273
- });
274
-
275
- function enhanceUI() {
276
- // Add icons to headers
277
- addIconToHeader('Upload Code', 'fa-upload');
278
- addIconToHeader('Developer Tools', 'fa-tools');
279
- addIconToHeader('Tech Assistant', 'fa-robot');
280
-
281
- // Setup tabs
282
- setupTabs();
283
-
284
- // Setup file upload area
285
- setupFileUpload();
286
- }
287
-
288
- function addIconToHeader(text, iconClass) {
289
- document.querySelectorAll('h3').forEach(header => {
290
- if (header.textContent.includes(text)) {
291
- const icon = document.createElement('i');
292
- icon.className = `fas ${iconClass}`;
293
- header.insertBefore(icon, header.firstChild);
294
- header.style.display = 'flex';
295
- header.style.alignItems = 'center';
296
- header.style.gap = '8px';
297
- }
298
- });
299
- }
300
-
301
- function setupTabs() {
302
- const tabs = document.querySelectorAll('.tab');
303
- tabs.forEach(tab => {
304
- tab.addEventListener('click', () => {
305
- tabs.forEach(t => t.classList.remove('active'));
306
- tab.classList.add('active');
307
- });
308
- });
309
  }
310
-
311
- function setupFileUpload() {
312
- const dropzone = document.querySelector('.file-upload');
313
- if (!dropzone) return;
314
-
315
- dropzone.addEventListener('dragover', (e) => {
316
- e.preventDefault();
317
- dropzone.style.borderColor = 'var(--primary-color)';
318
- dropzone.style.backgroundColor = 'rgba(66, 133, 244, 0.05)';
319
- });
320
-
321
- dropzone.addEventListener('dragleave', (e) => {
322
- e.preventDefault();
323
- dropzone.style.borderColor = 'var(--border-color)';
324
- dropzone.style.backgroundColor = 'transparent';
325
- });
326
  }
327
  """
328
 
@@ -795,96 +584,181 @@ def process_code_file(file_obj):
795
  except Exception as e:
796
  return None, f"Error processing file: {str(e)}", {}
797
 
798
- # Update the Gradio interface layout
799
- with gr.Blocks(css=custom_css) as demo:
800
- with gr.Column(elem_classes="main-app"):
801
- # Header
802
- with gr.Column(elem_classes="app-header"):
803
- gr.Markdown("# Tech-Vision AI")
804
- gr.Markdown("Your AI-powered code analysis assistant")
805
-
806
- # Chat container
807
- with gr.Column(elem_classes="chat-container"):
808
- # File upload view
809
- with gr.Column(visible=True) as upload_view:
810
- file_upload = gr.File(
811
- label="Drop your code file here or click to upload",
812
- file_types=[".txt", ".py", ".js", ".java", ".cpp", ".html", ".css"],
813
- elem_classes="file-upload-area"
814
- )
 
 
 
 
 
 
 
 
 
815
 
816
- # Chat interface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
817
  chatbot = gr.Chatbot(
818
- elem_classes="message-wrap",
819
- show_label=False,
820
- height=550,
821
- avatar_images=["user.png", "bot.png"],
822
- bubble_full_width=False
823
  )
824
-
825
- with gr.Row(elem_classes="input-area"):
826
  msg = gr.Textbox(
827
- show_label=False,
828
- placeholder="Ask me anything about your code...",
829
- elem_classes="input-textbox",
830
- scale=20
831
  )
832
- send_btn = gr.Button("", elem_classes="send-button", scale=1)
833
-
834
- # State for tracking if file is uploaded
835
- file_uploaded = gr.State(False)
836
- current_session_id = gr.State(None)
837
 
838
- # Handle file upload
839
- def process_file_and_start_chat(file_obj):
840
- if file_obj is None:
841
- return None, gr.update(visible=True), gr.update(value="Please upload a file to begin.")
842
-
843
- try:
844
- session_id, summary = process_code_file(file_obj)
845
-
846
- # Generate initial message about the uploaded file
847
- initial_message = f"I've analyzed your uploaded file. Here's what I found:\n\n{summary}\n\nWhat would you like to know about it?"
848
-
849
- return (
850
- session_id,
851
- gr.update(visible=False), # Hide upload view
852
- [[None, initial_message]] # Add initial bot message
853
- )
854
- except Exception as e:
855
- return None, gr.update(visible=True), gr.update(value=f"Error processing file: {str(e)}")
856
-
857
- # Update chat handling
858
- def chat(message, history, session_id):
859
- if not message:
860
- return history
861
-
862
- try:
863
- # Use the existing generate_response function with the session context
864
- updated_history = generate_response(message, session_id, "llama3-70b-8192", history)
865
- return updated_history
866
- except Exception as e:
867
- history.append([message, f"Error: {str(e)}"])
868
- return history
869
-
870
- # Set up event handlers
871
- file_upload.upload(
872
- process_file_and_start_chat,
873
- inputs=[file_upload],
874
- outputs=[current_session_id, upload_view, chatbot]
875
  )
876
-
877
  msg.submit(
878
- chat,
879
- inputs=[msg, chatbot, current_session_id],
880
  outputs=[chatbot]
881
  ).then(lambda: "", None, [msg])
882
-
883
  send_btn.click(
884
- chat,
885
- inputs=[msg, chatbot, current_session_id],
886
  outputs=[chatbot]
887
  ).then(lambda: "", None, [msg])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
888
 
 
889
  if __name__ == "__main__":
890
  demo.launch()
 
5
  import uuid
6
  from dotenv import load_dotenv
7
  from langchain_community.vectorstores import FAISS
8
+ from langchain_community.embeddings import HuggingFaceInstructEmbeddings
9
  from langchain.text_splitter import RecursiveCharacterTextSplitter
10
  import fitz # PyMuPDF
11
  import base64
 
25
 
26
  # Initialize embeddings with error handling
27
  try:
28
+ # Force CPU usage for embeddings
29
+ embeddings = HuggingFaceInstructEmbeddings(
30
+ model_name="hkunlp/instructor-base",
31
+ model_kwargs={"device": "cpu"} # Force CPU usage
32
  )
33
  except Exception as e:
34
+ print(f"Warning: Failed to load primary embeddings model: {e}")
35
+ try:
36
+ embeddings = HuggingFaceInstructEmbeddings(
37
+ model_name="all-MiniLM-L6-v2",
38
+ model_kwargs={"device": "cpu"} # Force CPU usage
39
+ )
40
+ except Exception as e:
41
+ print(f"Warning: Failed to load fallback embeddings model: {e}")
42
+ embeddings = None
43
 
44
  # Directory to store FAISS indexes with better naming
45
  FAISS_INDEX_DIR = "faiss_indexes_tech_cpu"
 
49
  # Dictionary to store user-specific vectorstores
50
  user_vectorstores = {}
51
 
52
+ # Custom CSS for Tech theme
53
  custom_css = """
54
+ :root {
55
+ --primary-color: #4285F4;
56
+ --secondary-color: #34A853;
57
+ --accent-color: #EA4335;
58
+ --light-background: #F8F9FA;
59
+ --dark-text: #202124;
60
+ --white: #FFFFFF;
61
+ --border-color: #DADCE0;
62
+ --code-bg: #F1F3F4;
63
  }
64
+ body {
65
+ background-color: var(--light-background);
66
+ font-family: 'Google Sans', 'Roboto', sans-serif;
 
 
 
 
67
  }
68
+ .container {
69
+ max-width: 1200px !important;
70
+ margin: 0 auto !important;
71
+ padding: 10px;
72
+ }
73
+ .header {
74
+ background-color: var(--white);
75
+ border-bottom: 1px solid var(--border-color);
76
+ padding: 15px 0;
77
  margin-bottom: 20px;
78
+ border-radius: 12px 12px 0 0;
79
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
 
80
  }
81
+ .header-title {
82
+ color: var(--primary-color);
83
+ font-size: 1.8rem;
 
84
  font-weight: 700;
85
+ text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  }
87
+ .header-subtitle {
88
+ color: var(--dark-text);
89
+ font-size: 1rem;
90
+ text-align: center;
91
+ margin-top: 5px;
 
 
92
  }
93
+ .chat-container {
94
+ border-radius: 12px !important;
95
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1) !important;
96
+ background-color: var(--white) !important;
97
+ border: 1px solid var(--border-color) !important;
98
+ min-height: 500px;
99
  }
100
+ .tool-container {
101
+ background-color: var(--white);
 
 
 
 
 
 
102
  border-radius: 12px;
103
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
104
+ padding: 15px;
105
+ margin-bottom: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  }
107
+ .code-block {
108
+ background-color: var(--code-bg);
109
+ padding: 12px;
110
+ border-radius: 8px;
111
+ font-family: 'Roboto Mono', monospace;
112
+ overflow-x: auto;
113
+ margin: 10px 0;
114
+ border-left: 3px solid var(--primary-color);
 
 
 
 
 
 
 
 
115
  }
116
  """
117
 
 
584
  except Exception as e:
585
  return None, f"Error processing file: {str(e)}", {}
586
 
587
+ # Update the Gradio interface
588
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
589
+ current_session_id = gr.State(None)
590
+ code_state = gr.State({})
591
+
592
+ gr.HTML("""
593
+ <div class="header">
594
+ <div class="header-title">Tech-Vision AI</div>
595
+ <div class="header-subtitle">Advanced Code Analysis & Technical Assistant</div>
596
+ </div>
597
+ """)
598
+
599
+ with gr.Row(elem_classes="container"):
600
+ with gr.Column(scale=1, min_width=300):
601
+ file_input = gr.File(
602
+ label="Upload Code File",
603
+ file_types=[".py", ".js", ".java", ".cpp", ".c", ".cs", ".php", ".rb", ".go", ".ts"],
604
+ type="binary"
605
+ )
606
+ upload_button = gr.Button("Analyze Code", variant="primary")
607
+ file_status = gr.Markdown("No file uploaded yet")
608
+ model_dropdown = gr.Dropdown(
609
+ choices=["llama3-70b-8192", "mixtral-8x7b-32768", "gemma-7b-it"],
610
+ value="llama3-70b-8192",
611
+ label="Select Model"
612
+ )
613
 
614
+ # Developer Tools Section
615
+ gr.Markdown("### Developer Tools", elem_classes="tool-title")
616
+ with gr.Group(elem_classes="tool-container"): # Replace Box with Group
617
+ with gr.Tabs():
618
+ with gr.TabItem("GitHub Search"):
619
+ repo_query = gr.Textbox(label="Search Query", placeholder="Enter keywords to search for repositories")
620
+ with gr.Row():
621
+ language = gr.Dropdown(
622
+ choices=["any", "JavaScript", "Python", "Java", "C++", "TypeScript", "Go", "Rust", "PHP", "C#"],
623
+ value="any",
624
+ label="Language"
625
+ )
626
+ min_stars = gr.Dropdown(
627
+ choices=["0", "10", "50", "100", "1000", "10000"],
628
+ value="0",
629
+ label="Min Stars"
630
+ )
631
+ sort_by = gr.Dropdown(
632
+ choices=["stars", "forks", "updated"],
633
+ value="stars",
634
+ label="Sort By"
635
+ )
636
+ repo_search_btn = gr.Button("Search Repositories")
637
+
638
+ with gr.TabItem("Stack Overflow"):
639
+ stack_query = gr.Textbox(label="Search Query", placeholder="Enter your technical question")
640
+ with gr.Row():
641
+ tag = gr.Dropdown(
642
+ choices=["any", "python", "javascript", "java", "c++", "react", "node.js", "android", "ios", "sql"],
643
+ value="any",
644
+ label="Tag"
645
+ )
646
+ so_sort_by = gr.Dropdown(
647
+ choices=["votes", "newest", "activity"],
648
+ value="votes",
649
+ label="Sort By"
650
+ )
651
+ so_search_btn = gr.Button("Search Stack Overflow")
652
+
653
+ with gr.TabItem("Code Explainer"):
654
+ code_input = gr.Textbox(
655
+ label="Code to Explain",
656
+ placeholder="Paste your code here...",
657
+ lines=10
658
+ )
659
+ explain_btn = gr.Button("Explain Code")
660
+
661
+ with gr.Column(scale=2, min_width=600):
662
+ with gr.Tabs():
663
+ with gr.TabItem("Code Analysis"):
664
+ with gr.Column(elem_classes="code-viewer-container"):
665
+ code_metrics = gr.Markdown("No code analyzed yet", elem_classes="stats-box")
666
+ code_recommendations = gr.Markdown("", elem_classes="recommendations-box")
667
+
668
+ with gr.TabItem("GitHub Results"):
669
+ repo_results = gr.Markdown("Search for repositories to see results here")
670
+
671
+ with gr.TabItem("Stack Overflow Results"):
672
+ stack_results = gr.Markdown("Search for questions to see results here")
673
+
674
+ with gr.TabItem("Code Explanation"):
675
+ code_explanation = gr.Markdown("Paste your code and click 'Explain Code' to see an explanation here")
676
+
677
+ with gr.Row(elem_classes="container"):
678
+ with gr.Column(scale=2, min_width=600):
679
  chatbot = gr.Chatbot(
680
+ height=500,
681
+ show_copy_button=True,
682
+ elem_classes="chat-container",
683
+ type="messages"
 
684
  )
685
+ with gr.Row():
 
686
  msg = gr.Textbox(
687
+ show_label=False,
688
+ placeholder="Ask about your code, type /github to search repos, or /stack to search Stack Overflow...",
689
+ scale=5
 
690
  )
691
+ send_btn = gr.Button("Send", scale=1)
692
+ clear_btn = gr.Button("Clear Conversation")
 
 
 
693
 
694
+ # Update event handlers
695
+ upload_button.click(
696
+ lambda x: process_code_file(x),
697
+ inputs=[file_input],
698
+ outputs=[current_session_id, file_status, code_state]
699
+ ).then(
700
+ lambda state: (
701
+ f"### Code Analysis Results\n\n"
702
+ f"**Language:** {state.get('language', 'Unknown')}\n"
703
+ f"**Total Lines:** {state.get('total_lines', 0)}\n"
704
+ f"**Code Lines:** {state.get('code_lines', 0)}\n"
705
+ f"**Comment Lines:** {state.get('comments', 0)}\n"
706
+ f"**Functions:** {state.get('functions', 0)}\n"
707
+ f"**Classes:** {state.get('classes', 0)}\n"
708
+ f"**Complexity Score:** {state.get('cyclomatic_complexity', 0)}\n"
709
+ ),
710
+ inputs=[code_state],
711
+ outputs=[code_metrics]
712
+ ).then(
713
+ lambda state: generate_recommendations(state),
714
+ inputs=[code_state],
715
+ outputs=[code_recommendations]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716
  )
717
+
718
  msg.submit(
719
+ generate_response,
720
+ inputs=[msg, current_session_id, model_dropdown, chatbot],
721
  outputs=[chatbot]
722
  ).then(lambda: "", None, [msg])
723
+
724
  send_btn.click(
725
+ generate_response,
726
+ inputs=[msg, current_session_id, model_dropdown, chatbot],
727
  outputs=[chatbot]
728
  ).then(lambda: "", None, [msg])
729
+
730
+ clear_btn.click(
731
+ lambda: ([], None, "No file uploaded", {}, None),
732
+ None,
733
+ [chatbot, current_session_id, file_status, code_state, code_metrics]
734
+ )
735
+
736
+ # Tech tool handlers
737
+ repo_search_btn.click(
738
+ perform_repo_search,
739
+ inputs=[repo_query, language, sort_by, min_stars],
740
+ outputs=[repo_results]
741
+ )
742
+
743
+ so_search_btn.click(
744
+ perform_stack_search,
745
+ inputs=[stack_query, tag, so_sort_by],
746
+ outputs=[stack_results]
747
+ )
748
+
749
+ explain_btn.click(
750
+ explain_code,
751
+ inputs=[code_input],
752
+ outputs=[code_explanation]
753
+ )
754
+
755
+ # Add footer with attribution
756
+ gr.HTML("""
757
+ <div style="text-align: center; margin-top: 20px; padding: 10px; color: #666; font-size: 0.8rem; border-top: 1px solid #eee;">
758
+ Created by Calvin Allen Crawford
759
+ </div>
760
+ """)
761
 
762
+ # Launch the app
763
  if __name__ == "__main__":
764
  demo.launch()