shukdevdatta123 commited on
Commit
db2fe70
·
verified ·
1 Parent(s): ac6cdbf

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +828 -0
app.py ADDED
@@ -0,0 +1,828 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import time
4
+ import gradio as gr
5
+ from datetime import datetime
6
+ from pathlib import Path
7
+ from typing import List, Dict, Any, Optional, Union
8
+
9
+ # Import Groq - we'll install it in requirements.txt
10
+ from groq import Groq
11
+
12
+ class PersonalAIResearchAssistant:
13
+ """
14
+ Personal AI Research Assistant (PARA) using Groq's compound models with agentic capabilities.
15
+ """
16
+
17
+ def __init__(self, api_key: str,
18
+ knowledge_base_path: str = "knowledge_base.json",
19
+ model: str = "compound-beta"):
20
+ """
21
+ Initialize the PARA system.
22
+
23
+ Args:
24
+ api_key: Groq API key
25
+ knowledge_base_path: Path to store persistent knowledge
26
+ model: Which Groq model to use ('compound-beta' or 'compound-beta-mini')
27
+ """
28
+ self.api_key = api_key
29
+ if not self.api_key:
30
+ raise ValueError("No API key provided")
31
+
32
+ self.client = Groq(api_key=self.api_key)
33
+ self.model = model
34
+ self.knowledge_base_path = Path(knowledge_base_path)
35
+ self.knowledge_base = self._load_knowledge_base()
36
+
37
+ def _load_knowledge_base(self) -> Dict:
38
+ """Load existing knowledge base or create a new one"""
39
+ if self.knowledge_base_path.exists():
40
+ with open(self.knowledge_base_path, 'r') as f:
41
+ return json.load(f)
42
+ else:
43
+ # Initialize with empty collections
44
+ kb = {
45
+ "topics": {},
46
+ "research_digests": [],
47
+ "code_analyses": [],
48
+ "concept_connections": [],
49
+ "metadata": {
50
+ "created_at": datetime.now().isoformat(),
51
+ "last_updated": datetime.now().isoformat()
52
+ }
53
+ }
54
+ self._save_knowledge_base(kb)
55
+ return kb
56
+
57
+ def _save_knowledge_base(self, kb: Dict = None) -> None:
58
+ """Save the knowledge base to disk"""
59
+ if kb is None:
60
+ kb = self.knowledge_base
61
+
62
+ # Update metadata
63
+ kb["metadata"]["last_updated"] = datetime.now().isoformat()
64
+
65
+ with open(self.knowledge_base_path, 'w') as f:
66
+ json.dump(kb, f, indent=2)
67
+
68
+ def research_digest(self, topic: str,
69
+ include_domains: List[str] = None,
70
+ exclude_domains: List[str] = None,
71
+ max_results: int = 5) -> Dict:
72
+ """
73
+ Generate a research digest on a specific topic
74
+
75
+ Args:
76
+ topic: The research topic to investigate
77
+ include_domains: List of domains to include (e.g., ["arxiv.org", "*.edu"])
78
+ exclude_domains: List of domains to exclude
79
+ max_results: Maximum number of key findings to include
80
+
81
+ Returns:
82
+ Research digest including key findings and references
83
+ """
84
+ # Build the prompt
85
+ prompt = f"""Generate a research digest on the topic: {topic}
86
+
87
+ Please find the most recent and relevant information, focusing on:
88
+ 1. Key findings or breakthroughs
89
+ 2. Current trends and methodologies
90
+ 3. Influential researchers or organizations
91
+ 4. Practical applications
92
+
93
+ Structure your response as a concise summary with {max_results} key points maximum.
94
+ Include source information where possible.
95
+ """
96
+
97
+ # Set up API parameters
98
+ params = {
99
+ "messages": [
100
+ {"role": "system", "content": "You are a research assistant tasked with finding and summarizing the latest information on specific topics."},
101
+ {"role": "user", "content": prompt}
102
+ ],
103
+ "model": self.model
104
+ }
105
+
106
+ # Add domain filtering if specified
107
+ if include_domains and include_domains[0].strip():
108
+ params["include_domains"] = [domain.strip() for domain in include_domains]
109
+ if exclude_domains and exclude_domains[0].strip():
110
+ params["exclude_domains"] = [domain.strip() for domain in exclude_domains]
111
+
112
+ # Make the API call
113
+ response = self.client.chat.completions.create(**params)
114
+ content = response.choices[0].message.content
115
+
116
+ # Extract tool usage information if available
117
+ tool_info = None
118
+ if hasattr(response.choices[0].message, 'executed_tools'):
119
+ tool_info = response.choices[0].message.executed_tools
120
+
121
+ # Create digest entry
122
+ digest = {
123
+ "topic": topic,
124
+ "timestamp": datetime.now().isoformat(),
125
+ "content": content,
126
+ "tool_usage": tool_info,
127
+ "parameters": {
128
+ "include_domains": include_domains,
129
+ "exclude_domains": exclude_domains,
130
+ }
131
+ }
132
+
133
+ # Add to knowledge base
134
+ self.knowledge_base["research_digests"].append(digest)
135
+
136
+ # Update topic entry in knowledge base
137
+ if topic not in self.knowledge_base["topics"]:
138
+ self.knowledge_base["topics"][topic] = {
139
+ "first_researched": datetime.now().isoformat(),
140
+ "research_count": 1,
141
+ "related_topics": []
142
+ }
143
+ else:
144
+ self.knowledge_base["topics"][topic]["research_count"] += 1
145
+ self.knowledge_base["topics"][topic]["last_researched"] = datetime.now().isoformat()
146
+
147
+ # Save updated knowledge base
148
+ self._save_knowledge_base()
149
+
150
+ return digest
151
+
152
+ def evaluate_code(self, code_snippet: str, language: str = "python",
153
+ analysis_type: str = "full") -> Dict:
154
+ """
155
+ Evaluate a code snippet for issues and suggest improvements
156
+
157
+ Args:
158
+ code_snippet: The code to evaluate
159
+ language: Programming language of the code
160
+ analysis_type: Type of analysis to perform ('full', 'security', 'performance', 'style')
161
+
162
+ Returns:
163
+ Analysis results including issues and suggestions
164
+ """
165
+ # Build the prompt
166
+ prompt = f"""Analyze the following {language} code:
167
+
168
+ ```{language}
169
+ {code_snippet}
170
+ ```
171
+
172
+ Please perform a {analysis_type} analysis, including:
173
+ 1. Identifying any bugs or potential issues
174
+ 2. Security vulnerabilities (if applicable)
175
+ 3. Performance considerations
176
+ 4. Style and best practices
177
+ 5. Suggested improvements
178
+
179
+ If possible, execute the code to verify functionality.
180
+ """
181
+
182
+ # Make the API call
183
+ response = self.client.chat.completions.create(
184
+ messages=[
185
+ {"role": "system", "content": f"You are a code analysis expert specializing in {language}."},
186
+ {"role": "user", "content": prompt}
187
+ ],
188
+ model=self.model
189
+ )
190
+
191
+ content = response.choices[0].message.content
192
+
193
+ # Extract tool usage information if available
194
+ tool_info = None
195
+ if hasattr(response.choices[0].message, 'executed_tools'):
196
+ tool_info = response.choices[0].message.executed_tools
197
+
198
+ # Create code analysis entry
199
+ analysis = {
200
+ "code_snippet": code_snippet,
201
+ "language": language,
202
+ "analysis_type": analysis_type,
203
+ "timestamp": datetime.now().isoformat(),
204
+ "content": content,
205
+ "tool_usage": tool_info
206
+ }
207
+
208
+ # Add to knowledge base
209
+ self.knowledge_base["code_analyses"].append(analysis)
210
+ self._save_knowledge_base()
211
+
212
+ return analysis
213
+
214
+ def connect_concepts(self, concept_a: str, concept_b: str) -> Dict:
215
+ """
216
+ Identify connections between two seemingly different concepts
217
+
218
+ Args:
219
+ concept_a: First concept
220
+ concept_b: Second concept
221
+
222
+ Returns:
223
+ Analysis of connections between the concepts
224
+ """
225
+ # Build the prompt
226
+ prompt = f"""Explore the connections between these two concepts:
227
+
228
+ Concept A: {concept_a}
229
+ Concept B: {concept_b}
230
+
231
+ Please identify:
232
+ 1. Direct connections or shared principles
233
+ 2. Historical influences between them
234
+ 3. Common applications or use cases
235
+ 4. How insights from one field might benefit the other
236
+ 5. Potential for innovative combinations
237
+
238
+ Search for the most up-to-date information that might connect these concepts.
239
+ """
240
+
241
+ # Make the API call
242
+ response = self.client.chat.completions.create(
243
+ messages=[
244
+ {"role": "system", "content": "You are a cross-disciplinary research assistant specialized in finding connections between different fields and concepts."},
245
+ {"role": "user", "content": prompt}
246
+ ],
247
+ model=self.model
248
+ )
249
+
250
+ content = response.choices[0].message.content
251
+
252
+ # Extract tool usage information if available
253
+ tool_info = None
254
+ if hasattr(response.choices[0].message, 'executed_tools'):
255
+ tool_info = response.choices[0].message.executed_tools
256
+
257
+ # Create connection entry
258
+ connection = {
259
+ "concept_a": concept_a,
260
+ "concept_b": concept_b,
261
+ "timestamp": datetime.now().isoformat(),
262
+ "content": content,
263
+ "tool_usage": tool_info
264
+ }
265
+
266
+ # Add to knowledge base
267
+ self.knowledge_base["concept_connections"].append(connection)
268
+
269
+ # Update topic entries
270
+ for concept in [concept_a, concept_b]:
271
+ if concept not in self.knowledge_base["topics"]:
272
+ self.knowledge_base["topics"][concept] = {
273
+ "first_researched": datetime.now().isoformat(),
274
+ "research_count": 1,
275
+ "related_topics": [concept_a if concept == concept_b else concept_b]
276
+ }
277
+ else:
278
+ if concept_a if concept == concept_b else concept_b not in self.knowledge_base["topics"][concept]["related_topics"]:
279
+ self.knowledge_base["topics"][concept]["related_topics"].append(
280
+ concept_a if concept == concept_b else concept_b
281
+ )
282
+
283
+ self._save_knowledge_base()
284
+
285
+ return connection
286
+
287
+ def ask_knowledge_base(self, query: str) -> Dict:
288
+ """
289
+ Query the accumulated knowledge base
290
+
291
+ Args:
292
+ query: Question about topics in the knowledge base
293
+
294
+ Returns:
295
+ Response based on accumulated knowledge
296
+ """
297
+ # Create a temporary context from the knowledge base
298
+ context = {
299
+ "topics_researched": list(self.knowledge_base["topics"].keys()),
300
+ "research_count": len(self.knowledge_base["research_digests"]),
301
+ "code_analyses_count": len(self.knowledge_base["code_analyses"]),
302
+ "concept_connections_count": len(self.knowledge_base["concept_connections"]),
303
+ "last_updated": self.knowledge_base["metadata"]["last_updated"]
304
+ }
305
+
306
+ # Add recent research digests (limited to keep context manageable)
307
+ recent_digests = self.knowledge_base["research_digests"][-3:] if self.knowledge_base["research_digests"] else []
308
+ context["recent_research"] = recent_digests
309
+
310
+ # Build the prompt
311
+ prompt = f"""Query: {query}
312
+
313
+ Please answer based on the following knowledge base context:
314
+ {json.dumps(context, indent=2)}
315
+
316
+ If the knowledge base doesn't contain relevant information, please indicate this and suggest how we might research this topic.
317
+ """
318
+
319
+ # Make the API call
320
+ response = self.client.chat.completions.create(
321
+ messages=[
322
+ {"role": "system", "content": "You are a research assistant with access to a personal knowledge base. Answer questions based on the accumulated knowledge."},
323
+ {"role": "user", "content": prompt}
324
+ ],
325
+ model=self.model
326
+ )
327
+
328
+ content = response.choices[0].message.content
329
+
330
+ return {
331
+ "query": query,
332
+ "timestamp": datetime.now().isoformat(),
333
+ "response": content,
334
+ "knowledge_base_state": context
335
+ }
336
+
337
+ def generate_weekly_report(self) -> Dict:
338
+ """
339
+ Generate a weekly summary of research and insights
340
+
341
+ Returns:
342
+ Weekly report of activity and key findings
343
+ """
344
+ # Get weekly statistics
345
+ one_week_ago = datetime.now().isoformat() # Simplified, should subtract 7 days
346
+
347
+ # Count activities in the last week
348
+ recent_research = [d for d in self.knowledge_base["research_digests"]
349
+ if d["timestamp"] > one_week_ago]
350
+ recent_code = [c for c in self.knowledge_base["code_analyses"]
351
+ if c["timestamp"] > one_week_ago]
352
+ recent_connections = [c for c in self.knowledge_base["concept_connections"]
353
+ if c["timestamp"] > one_week_ago]
354
+
355
+ # Build context for the report
356
+ context = {
357
+ "period": "weekly",
358
+ "research_count": len(recent_research),
359
+ "code_analyses_count": len(recent_code),
360
+ "concept_connections_count": len(recent_connections),
361
+ "topics_explored": list(set([r["topic"] for r in recent_research])),
362
+ "recent_research": recent_research[:3], # Include only top 3
363
+ "recent_connections": recent_connections[:3]
364
+ }
365
+
366
+ # Build the prompt
367
+ prompt = f"""Generate a weekly research summary based on the following activity:
368
+
369
+ {json.dumps(context, indent=2)}
370
+
371
+ Please include:
372
+ 1. Overview of research activity
373
+ 2. Key findings and insights
374
+ 3. Emerging patterns or trends
375
+ 4. Suggestions for further exploration
376
+
377
+ Format as a concise weekly report.
378
+ """
379
+
380
+ # Make the API call
381
+ response = self.client.chat.completions.create(
382
+ messages=[
383
+ {"role": "system", "content": "You are a research assistant generating a weekly summary of research activities and findings."},
384
+ {"role": "user", "content": prompt}
385
+ ],
386
+ model=self.model
387
+ )
388
+
389
+ content = response.choices[0].message.content
390
+
391
+ report = {
392
+ "type": "weekly_report",
393
+ "timestamp": datetime.now().isoformat(),
394
+ "content": content,
395
+ "stats": context
396
+ }
397
+
398
+ return report
399
+
400
+ def get_kb_stats(self):
401
+ """Get statistics about the knowledge base"""
402
+ return {
403
+ "topics_count": len(self.knowledge_base["topics"]),
404
+ "research_count": len(self.knowledge_base["research_digests"]),
405
+ "code_analyses_count": len(self.knowledge_base["code_analyses"]),
406
+ "concept_connections_count": len(self.knowledge_base["concept_connections"]),
407
+ "created": self.knowledge_base["metadata"]["created_at"],
408
+ "last_updated": self.knowledge_base["metadata"]["last_updated"],
409
+ "topics": list(self.knowledge_base["topics"].keys())
410
+ }
411
+
412
+ # Global variables for the Gradio app
413
+ para_instance = None
414
+ api_key_status = "Not Set"
415
+
416
+ # Helper functions for Gradio
417
+ def validate_api_key(api_key):
418
+ """Validate Groq API key"""
419
+ global para_instance, api_key_status
420
+
421
+ if not api_key or len(api_key.strip()) < 10:
422
+ return "❌ Please enter a valid API key"
423
+
424
+ try:
425
+ # Try to initialize with minimal actions
426
+ client = Groq(api_key=api_key)
427
+ # Create PARA instance
428
+ para_instance = PersonalAIResearchAssistant(
429
+ api_key=api_key,
430
+ knowledge_base_path="para_knowledge.json"
431
+ )
432
+ api_key_status = "Valid ✅"
433
+
434
+ # Get KB stats
435
+ stats = para_instance.get_kb_stats()
436
+ kb_info = f"**Knowledge Base Stats:**\n\n" \
437
+ f"- Topics: {stats['topics_count']}\n" \
438
+ f"- Research Digests: {stats['research_count']}\n" \
439
+ f"- Code Analyses: {stats['code_analyses_count']}\n" \
440
+ f"- Concept Connections: {stats['concept_connections_count']}\n" \
441
+ f"- Last Updated: {stats['last_updated'][:10]}\n\n" \
442
+ f"**Topics Explored:** {', '.join(stats['topics'][:10])}" + \
443
+ ("..." if len(stats['topics']) > 10 else "")
444
+
445
+ return f"✅ API Key Valid! PARA is ready.\n\n{kb_info}"
446
+ except Exception as e:
447
+ api_key_status = "Invalid ❌"
448
+ para_instance = None
449
+ return f"❌ Error: {str(e)}"
450
+
451
+ def check_api_key():
452
+ """Check if API key is set"""
453
+ if para_instance is None:
454
+ return "Please set your Groq API key first"
455
+ return None
456
+
457
+ def update_model_selection(model_choice):
458
+ """Update model selection"""
459
+ global para_instance
460
+
461
+ if para_instance:
462
+ para_instance.model = model_choice
463
+ return f"Model updated to: {model_choice}"
464
+ else:
465
+ return "Set API key first"
466
+
467
+ def research_topic(topic, include_domains, exclude_domains):
468
+ """Research a topic with domain filters"""
469
+ # Check if API key is set
470
+ check_result = check_api_key()
471
+ if check_result:
472
+ return check_result
473
+
474
+ if not topic:
475
+ return "Please enter a topic to research"
476
+
477
+ # Process domain lists
478
+ include_list = [d.strip() for d in include_domains.split(",")] if include_domains else []
479
+ exclude_list = [d.strip() for d in exclude_domains.split(",")] if exclude_domains else []
480
+
481
+ try:
482
+ # Perform research
483
+ result = para_instance.research_digest(
484
+ topic=topic,
485
+ include_domains=include_list if include_list and include_list[0] else None,
486
+ exclude_domains=exclude_list if exclude_list and exclude_list[0] else None
487
+ )
488
+
489
+ # Format response
490
+ response = f"# Research: {topic}\n\n{result['content']}"
491
+
492
+ # Add tool usage info if available
493
+ if result.get("tool_usage"):
494
+ response += f"\n\n*Tool Usage: {result['tool_usage']}*"
495
+
496
+ return response
497
+ except Exception as e:
498
+ return f"Error: {str(e)}"
499
+
500
+ def analyze_code(code_snippet, language, analysis_type):
501
+ """Analyze code with Groq"""
502
+ # Check if API key is set
503
+ check_result = check_api_key()
504
+ if check_result:
505
+ return check_result
506
+
507
+ if not code_snippet:
508
+ return "Please enter code to analyze"
509
+
510
+ try:
511
+ # Perform analysis
512
+ result = para_instance.evaluate_code(
513
+ code_snippet=code_snippet,
514
+ language=language,
515
+ analysis_type=analysis_type
516
+ )
517
+
518
+ # Format response
519
+ response = f"# Code Analysis ({language}, {analysis_type})\n\n{result['content']}"
520
+
521
+ # Add tool usage info if available
522
+ if result.get("tool_usage"):
523
+ response += f"\n\n*Tool Usage: {result['tool_usage']}*"
524
+
525
+ return response
526
+ except Exception as e:
527
+ return f"Error: {str(e)}"
528
+
529
+ def connect_concepts_handler(concept_a, concept_b):
530
+ """Connect two concepts"""
531
+ # Check if API key is set
532
+ check_result = check_api_key()
533
+ if check_result:
534
+ return check_result
535
+
536
+ if not concept_a or not concept_b:
537
+ return "Please enter both concepts"
538
+
539
+ try:
540
+ # Find connections
541
+ result = para_instance.connect_concepts(
542
+ concept_a=concept_a,
543
+ concept_b=concept_b
544
+ )
545
+
546
+ # Format response
547
+ response = f"# Connection: {concept_a} & {concept_b}\n\n{result['content']}"
548
+
549
+ # Add tool usage info if available
550
+ if result.get("tool_usage"):
551
+ response += f"\n\n*Tool Usage: {result['tool_usage']}*"
552
+
553
+ return response
554
+ except Exception as e:
555
+ return f"Error: {str(e)}"
556
+
557
+ def query_knowledge_base(query):
558
+ """Query the knowledge base"""
559
+ # Check if API key is set
560
+ check_result = check_api_key()
561
+ if check_result:
562
+ return check_result
563
+
564
+ if not query:
565
+ return "Please enter a query"
566
+
567
+ try:
568
+ # Query knowledge base
569
+ result = para_instance.ask_knowledge_base(query=query)
570
+
571
+ # Format response
572
+ response = f"# Knowledge Base Query: {query}\n\n{result['response']}"
573
+
574
+ # Add KB stats
575
+ stats = result.get("knowledge_base_state", {})
576
+ if stats:
577
+ topics = stats.get("topics_researched", [])
578
+ response += f"\n\n*Knowledge Base contains {len(topics)} topics: {', '.join(topics[:5])}" + \
579
+ ("..." if len(topics) > 5 else "") + "*"
580
+
581
+ return response
582
+ except Exception as e:
583
+ return f"Error: {str(e)}"
584
+
585
+ def generate_report_handler():
586
+ """Generate weekly report"""
587
+ # Check if API key is set
588
+ check_result = check_api_key()
589
+ if check_result:
590
+ return check_result
591
+
592
+ try:
593
+ # Generate report
594
+ result = para_instance.generate_weekly_report()
595
+
596
+ # Format response
597
+ response = f"# Weekly Research Report\n\n{result['content']}"
598
+
599
+ return response
600
+ except Exception as e:
601
+ return f"Error: {str(e)}"
602
+
603
+ # Create the Gradio interface
604
+ def create_gradio_app():
605
+ # Define CSS for styling
606
+ css = """
607
+ .title-container {
608
+ text-align: center;
609
+ margin-bottom: 20px;
610
+ }
611
+ .container {
612
+ margin: 0 auto;
613
+ max-width: 1200px;
614
+ }
615
+ .tab-content {
616
+ padding: 20px;
617
+ border-radius: 10px;
618
+ background-color: #f9f9f9;
619
+ }
620
+ """
621
+
622
+ with gr.Blocks(css=css, title="PARA - Personal AI Research Assistant") as app:
623
+ gr.Markdown(
624
+ """
625
+ <div class="title-container">
626
+ # 🧠 PARA - Personal AI Research Assistant
627
+ *Powered by Groq's Compound Beta models for intelligent research*
628
+ </div>
629
+ """
630
+ )
631
+
632
+ with gr.Row():
633
+ with gr.Column(scale=4):
634
+ api_key_input = gr.Textbox(
635
+ label="Groq API Key",
636
+ placeholder="Enter your Groq API key here...",
637
+ type="password"
638
+ )
639
+ with gr.Column(scale=2):
640
+ model_choice = gr.Radio(
641
+ ["compound-beta", "compound-beta-mini"],
642
+ label="Model Selection",
643
+ value="compound-beta"
644
+ )
645
+ with gr.Column(scale=1):
646
+ validate_btn = gr.Button("Validate & Connect")
647
+
648
+ api_status = gr.Markdown("### Status: Not connected")
649
+
650
+ # Connect validation button
651
+ validate_btn.click(
652
+ fn=validate_api_key,
653
+ inputs=[api_key_input],
654
+ outputs=[api_status]
655
+ )
656
+
657
+ # Connect model selection
658
+ model_choice.change(
659
+ fn=update_model_selection,
660
+ inputs=[model_choice],
661
+ outputs=[api_status]
662
+ )
663
+
664
+ # Tabs for different features
665
+ with gr.Tabs() as tabs:
666
+ # Research Tab
667
+ with gr.Tab("Research Topics"):
668
+ with gr.Row():
669
+ with gr.Column(scale=1):
670
+ research_topic_input = gr.Textbox(
671
+ label="Research Topic",
672
+ placeholder="Enter a topic to research..."
673
+ )
674
+ with gr.Column(scale=1):
675
+ include_domains = gr.Textbox(
676
+ label="Include Domains (comma-separated)",
677
+ placeholder="arxiv.org, *.edu, example.com"
678
+ )
679
+ exclude_domains = gr.Textbox(
680
+ label="Exclude Domains (comma-separated)",
681
+ placeholder="wikipedia.org, twitter.com"
682
+ )
683
+ research_btn = gr.Button("Research Topic")
684
+ research_output = gr.Markdown("Results will appear here...")
685
+
686
+ research_btn.click(
687
+ fn=research_topic,
688
+ inputs=[research_topic_input, include_domains, exclude_domains],
689
+ outputs=[research_output]
690
+ )
691
+
692
+ gr.Markdown("""
693
+ ### Examples:
694
+ - "Latest developments in quantum computing"
695
+ - "Climate change mitigation strategies"
696
+ - "Advancements in protein folding algorithms"
697
+
698
+ *Include domains like "arxiv.org, *.edu" for academic sources*
699
+ """)
700
+
701
+ # Code Analysis Tab
702
+ with gr.Tab("Code Analysis"):
703
+ code_input = gr.Code(
704
+ label="Code Snippet",
705
+ language="python",
706
+ lines=10
707
+ )
708
+ with gr.Row():
709
+ language_select = gr.Dropdown(
710
+ ["python", "javascript", "java", "c++", "go", "rust", "typescript", "sql", "bash"],
711
+ label="Language",
712
+ value="python"
713
+ )
714
+ analysis_type = gr.Dropdown(
715
+ ["full", "security", "performance", "style"],
716
+ label="Analysis Type",
717
+ value="full"
718
+ )
719
+ analyze_btn = gr.Button("Analyze Code")
720
+ analysis_output = gr.Markdown("Results will appear here...")
721
+
722
+ analyze_btn.click(
723
+ fn=analyze_code,
724
+ inputs=[code_input, language_select, analysis_type],
725
+ outputs=[analysis_output]
726
+ )
727
+
728
+ gr.Markdown("""
729
+ ### Example Python Code:
730
+ ```python
731
+ def fibonacci(n):
732
+ if n <= 0:
733
+ return []
734
+ elif n == 1:
735
+ return [0]
736
+ else:
737
+ result = [0, 1]
738
+ for i in range(2, n):
739
+ result.append(result[i-1] + result[i-2])
740
+ return result
741
+
742
+ print(fibonacci(10))
743
+ ```
744
+ """)
745
+
746
+ # Concept Connections Tab
747
+ with gr.Tab("Connect Concepts"):
748
+ with gr.Row():
749
+ concept_a = gr.Textbox(
750
+ label="Concept A",
751
+ placeholder="First concept or field..."
752
+ )
753
+ concept_b = gr.Textbox(
754
+ label="Concept B",
755
+ placeholder="Second concept or field..."
756
+ )
757
+ connect_btn = gr.Button("Find Connections")
758
+ connection_output = gr.Markdown("Results will appear here...")
759
+
760
+ connect_btn.click(
761
+ fn=connect_concepts_handler,
762
+ inputs=[concept_a, concept_b],
763
+ outputs=[connection_output]
764
+ )
765
+
766
+ gr.Markdown("""
767
+ ### Example Concept Pairs:
768
+ - "quantum computing" and "machine learning"
769
+ - "blockchain" and "supply chain management"
770
+ - "gene editing" and "ethics"
771
+ """)
772
+
773
+ # Knowledge Base Tab
774
+ with gr.Tab("Knowledge Base"):
775
+ kb_query = gr.Textbox(
776
+ label="Query Knowledge Base",
777
+ placeholder="Ask about topics in your knowledge base..."
778
+ )
779
+ kb_btn = gr.Button("Query Knowledge Base")
780
+ kb_output = gr.Markdown("Results will appear here...")
781
+
782
+ kb_btn.click(
783
+ fn=query_knowledge_base,
784
+ inputs=[kb_query],
785
+ outputs=[kb_output]
786
+ )
787
+
788
+ report_btn = gr.Button("Generate Weekly Report")
789
+ report_output = gr.Markdown("Report will appear here...")
790
+
791
+ report_btn.click(
792
+ fn=generate_report_handler,
793
+ inputs=[],
794
+ outputs=[report_output]
795
+ )
796
+
797
+ gr.Markdown("""
798
+ ### Example Queries:
799
+ - "What have we learned about quantum computing?"
800
+ - "Summarize our research on AI safety"
801
+ - "What connections exist between the topics we've studied?"
802
+ """)
803
+
804
+ gr.Markdown("""
805
+ ## About PARA
806
+
807
+ PARA (Personal AI Research Assistant) leverages Groq's compound models with agentic capabilities to help you research topics, analyze code, find connections between concepts, and build a personalized knowledge base.
808
+
809
+ **How it works:**
810
+ 1. Set your Groq API key
811
+ 2. Choose between compound-beta (more powerful) and compound-beta-mini (faster)
812
+ 3. Use the tabs to access different features
813
+ 4. Your research is automatically saved to a knowledge base for future reference
814
+
815
+ **Features:**
816
+ - Web search with domain filtering
817
+ - Code execution and analysis
818
+ - Concept connections discovery
819
+ - Persistent knowledge base
820
+ - Weekly research reports
821
+ """)
822
+
823
+ return app
824
+
825
+ # Launch the app
826
+ if __name__ == "__main__":
827
+ app = create_gradio_app()
828
+ app.launch()