acecalisto3 commited on
Commit
d7ff1c4
·
verified ·
1 Parent(s): 12852b4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +881 -232
app.py CHANGED
@@ -1,254 +1,903 @@
1
- import gradio as gr
2
- import os
3
- import requests
4
- from git import Repo, GitCommandError
5
- from pathlib import Path
6
- from datetime import datetime
7
- import shutil
8
- import time
9
  import json
10
- import aiohttp
11
- import asyncio
12
- from typing import Dict, Optional, Tuple
13
- import logging
14
-
15
- # ========== Configuration ==========
16
- REPO_OWNER = "enricoros"
17
- REPO_NAME = "big-agi"
18
- MIAGI_FORK = "https://github.com/Ig0tU/miagi.git"
19
- WORKSPACE = Path("/tmp/issue_workspace")
20
- WORKSPACE.mkdir(exist_ok=True)
21
- HF_SPACE_API = "https://huggingface.co/api/spaces" # Hypothetical HF Space API
22
-
23
- # Setup logging
24
- logging.basicConfig(level=logging.INFO)
25
- logger = logging.getLogger(__name__)
26
-
27
- # ========== Enhanced Theme ==========
28
- theme = gr.themes.Default(
29
- primary_hue="emerald",
30
- secondary_hue="zinc",
31
- radius_size="lg",
32
- ).set(
33
- button_primary_background_fill="*primary_500",
34
- button_primary_background_fill_hover="*primary_400",
35
- button_primary_text_color="white",
36
- block_label_background_fill="*primary_500",
37
- block_label_text_color="white",
38
- body_background_fill="gray_100",
39
- )
40
-
41
- # ========== State Management with Spaces Integration ==========
42
- class EnhancedIssueManager:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  def __init__(self):
44
- self.issues: Dict[int, dict] = {}
45
- self.last_fetched: Optional[datetime] = None
46
- self.current_issue: Optional[int] = None
47
- self.repo: Optional[Repo] = None
48
- self.space_status: Dict = {}
49
- self.progress_tracker = {}
50
-
51
- async def fetch_issues(self) -> Tuple[bool, str]:
52
- if self.last_fetched and (datetime.now() - self.last_fetched).seconds < 300:
53
- return True, "Using cached issues"
 
 
 
 
54
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  try:
56
- headers = {"Authorization": f"Bearer {os.environ.get('GITHUB_TOKEN', '')}"}
57
- async with aiohttp.ClientSession() as session:
58
- async with session.get(f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/issues",
59
- headers=headers) as response:
60
- response.raise_for_status()
61
- self.issues = {issue['number']: issue for issue in await response.json()}
62
- self.last_fetched = datetime.now()
63
- return True, "Successfully fetched issues"
 
 
 
 
64
  except Exception as e:
65
- logger.error(f"Error fetching issues: {e}")
66
- return False, f"Failed to fetch issues: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- async def check_space_status(self, issue_number: int) -> Dict:
69
- """Check if issue relates to a Hugging Face Space"""
70
  try:
71
- headers = {"Authorization": f"Bearer {os.environ.get('HF_TOKEN', '')}"}
72
- async with aiohttp.ClientSession() as session:
73
- async with session.get(f"{HF_SPACE_API}/{REPO_OWNER}/{REPO_NAME}",
74
- headers=headers) as response:
75
- if response.status == 200:
76
- space_data = await response.json()
77
- self.space_status[issue_number] = space_data
78
- return {"space_found": True, "data": space_data}
79
- return {"space_found": False}
 
 
 
 
 
 
80
  except Exception as e:
81
- logger.error(f"Space check failed: {e}")
82
- return {"space_found": False, "error": str(e)}
 
 
83
 
84
- issue_manager = EnhancedIssueManager()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
- # ========== Core Functions with Space Handling ==========
87
- async def replicate_issue(issue_number: str) -> Tuple[Dict, str, gr.update]:
88
- try:
89
- issue_number = int(issue_number)
90
- success, fetch_message = await issue_manager.fetch_issues()
91
- if not success:
92
- return {"error": f"⚠️ {fetch_message}"}, None, None
93
-
94
- if issue_number not in issue_manager.issues:
95
- return {"error": f"❌ Issue #{issue_number} not found"}, None, None
96
-
97
- issue = issue_manager.issues[issue_number]
98
- repo_path = WORKSPACE / f"miagi-{issue_number}"
99
- issue_manager.progress_tracker[issue_number] = {"status": "initializing"}
100
-
101
- # Check Space status
102
- space_status = await issue_manager.check_space_status(issue_number)
103
-
104
- # Clone with progress
105
  try:
106
- issue_manager.progress_tracker[issue_number] = {"status": "cloning"}
107
- repo = Repo.clone_from(MIAGI_FORK, repo_path, branch="main",
108
- progress=lambda x: issue_manager.progress_tracker[issue_number].update({"progress": x}))
109
- except GitCommandError:
110
- repo = Repo(repo_path)
111
-
112
- branch_name = f"issue-{issue_number}"
113
- repo.git.checkout('-b', branch_name)
114
-
115
- # Handle Space replication if applicable
116
- issues_dir = repo_path / "issues" / str(issue_number)
117
- issues_dir.mkdir(parents=True, exist_ok=True)
118
-
119
- replication_details = {
120
- "timestamp": datetime.utcnow().isoformat(),
121
- "space_status": space_status
122
- }
123
- (issues_dir / "replication.json").write_text(json.dumps(replication_details))
124
-
125
- issue_manager.repo = repo
126
- issue_manager.current_issue = issue_number
127
-
128
- return {
129
- "success": f"🚀 Replicated issue #{issue_number}",
130
- "space": space_status,
131
- "progress": issue_manager.progress_tracker[issue_number]
132
- }, issue["body"], gr.update(selected=1)
133
-
134
- except Exception as e:
135
- logger.error(f"Replication error: {e}")
136
- return {"error": f"⛔ Critical error: {str(e)}"}, None, None
 
137
 
138
- async def resolve_issue(resolution_notes: str, space_config: Optional[str] = None) -> Tuple[Dict, gr.update]:
139
- if not issue_manager.current_issue:
140
- return {"error": "⚠️ No active issue selected"}, None
141
-
142
- try:
143
- repo = issue_manager.repo
144
- issue_number = issue_manager.current_issue
145
- resolution_dir = repo.working_dir / "issues" / str(issue_number)
146
-
147
- timestamp = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
148
- resolution_data = {
149
- "notes": resolution_notes,
150
- "space_config": space_config,
151
- "resolved_at": timestamp
152
- }
153
-
154
- (resolution_dir / f"resolution_{timestamp}.json").write_text(json.dumps(resolution_data))
155
- (resolution_dir / "RESOLVED").touch()
156
-
157
- return {"success": "🔧 Resolution saved"}, gr.update(visible=True)
158
- except Exception as e:
159
- return {"error": f"⛔ Resolution failed: {str(e)}"}, None
160
 
161
- async def submit_resolution() -> Dict:
162
- if not issue_manager.current_issue:
163
- return {"error": "⚠️ No active issue selected"}
164
-
165
- try:
166
- repo = issue_manager.repo
167
- issue_number = issue_manager.current_issue
168
-
169
- repo.git.add(all=True)
170
- commit_message = f"Resolve #{issue_number}: {issue_manager.issues[issue_number]['title']}"
171
- repo.index.commit(commit_message)
172
-
173
- origin = repo.remote(name='origin')
174
- branch_name = f"issue-{issue_number}"
175
- origin.push(refspec=f"{branch_name}:{branch_name}")
176
-
177
- # Space-specific submission if applicable
178
- if issue_manager.space_status.get(issue_number, {}).get("space_found"):
179
- await self._update_space_config(issue_number)
180
-
181
- pr_url = f"https://github.com/Ig0tU/miagi/compare/{branch_name}?expand=1"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  return {
183
- "success": f"🚀 Resolution submitted!\n\n[Review PR]({pr_url})",
184
- "pr_url": pr_url
 
185
  }
186
- except Exception as e:
187
- return {"error": f"⛔ Submission failed: {str(e)}"}
188
 
189
- async def _update_space_config(self, issue_number: int):
190
- """Update Hugging Face Space configuration"""
191
  try:
192
- headers = {"Authorization": f"Bearer {os.environ.get('HF_TOKEN', '')}"}
193
- config = {"issue_number": issue_number, "status": "resolved"}
194
- async with aiohttp.ClientSession() as session:
195
- await session.post(
196
- f"{HF_SPACE_API}/{REPO_OWNER}/{REPO_NAME}/config",
197
- json=config,
198
- headers=headers
199
- )
200
  except Exception as e:
201
- logger.error(f"Space config update failed: {e}")
202
-
203
- # ========== Enhanced UI ==========
204
- def create_enhanced_ui():
205
- with gr.Blocks(theme=theme, css="footer {visibility: hidden}") as app:
206
- gr.Markdown("# 🚀 Enhanced Repository Manager\n### With Hugging Face Spaces Integration")
207
-
208
- with gr.Tabs() as tabs:
209
- with gr.Tab("🔍 Investigate"):
210
- with gr.Row():
211
- issue_input = gr.Number(label="Issue Number")
212
- replicate_btn = gr.Button("⚡ Replicate", variant="primary")
213
- status_output = gr.JSON(label="Replication Status")
214
- progress_bar = gr.Progress()
215
 
216
- with gr.Tab("🔧 Resolve"):
217
- with gr.Row():
218
- with gr.Column():
219
- issue_desc = gr.Markdown()
220
- resolution_input = gr.Textbox(lines=8, label="Resolution Notes")
221
- space_config = gr.Textbox(lines=2, label="Space Config (if applicable)")
222
- resolve_btn = gr.Button("💾 Save", variant="primary")
223
- with gr.Column():
224
- file_explorer = gr.FileExplorer()
225
-
226
- with gr.Tab("🚀 Deploy"):
227
- deploy_btn = gr.Button("🔥 Submit", variant="primary")
228
- pr_output = gr.Markdown()
229
- space_status = gr.JSON(label="Space Status")
230
-
231
- # Event handlers with async support
232
- replicate_btn.click(
233
- fn=replicate_issue,
234
- inputs=issue_input,
235
- outputs=[status_output, issue_desc, tabs]
236
- )
237
-
238
- resolve_btn.click(
239
- fn=resolve_issue,
240
- inputs=[resolution_input, space_config],
241
- outputs=[status_output, deploy_btn]
242
- )
243
-
244
- deploy_btn.click(
245
- fn=submit_resolution,
246
- outputs=[status_output, pr_output, space_status]
247
- )
248
 
249
- return app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
 
251
- # ========== Execution ==========
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  if __name__ == "__main__":
253
- app = create_enhanced_ui()
254
- app.launch(server_port=7860, share=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import difflib
3
+ import hashlib
4
+ import pickle
5
+ import random
 
 
 
6
  import json
7
+ from datetime import datetime
8
+ from typing import Dict, Any, List, Callable, Optional
9
+
10
+ from marshmallow import Schema, fields, ValidationError, EXCLUDE
11
+ from semantic_version import Version
12
+ import gradio as gr
13
+
14
+ # ---------- Constants & Helpers ----------
15
+ from examples import EXAMPLES
16
+
17
+ COLOR_SCHEMES = [
18
+ ["#FF6B6B", "#4ECDC4", "#45B7D1"], # Ocean Breeze
19
+ ["#2A9D8F", "#E9C46A", "#F4A261"], # Desert Sunset
20
+ ["#264653", "#2A9D8F", "#E9C46A"], # Forest Dawn
21
+ ["#F4A261", "#E76F51", "#2A9D8F"], # Coral Reef
22
+ ["#8338EC", "#3A86FF", "#FF006E"], # Neon Nights
23
+ ["#06D6A0", "#118AB2", "#073B4C"], # Deep Ocean
24
+ ["#FFB4A2", "#E5989B", "#B5838D"], # Rose Garden
25
+ ["#22223B", "#4A4E69", "#9A8C98"] # Midnight Purple
26
+ ]
27
+
28
+ def generate_gradient(colors: List[str]) -> str:
29
+ """Generate modern gradient styling with enhanced visual effects"""
30
+ return f"""
31
+ /* Modern gradient background with enhanced visual effects */
32
+ .gradio-container {{
33
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
34
+ }}
35
+
36
+ .container {{
37
+ background: linear-gradient(135deg, {colors[0]}, {colors[1]}, {colors[2]});
38
+ background-size: 300% 300%;
39
+ animation: gradient-shift 15s ease infinite;
40
+ border-radius: 12px;
41
+ padding: 24px;
42
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
43
+ transition: all 0.3s ease;
44
+ margin-bottom: 1rem;
45
+ }}
46
+
47
+ .chat-message {{
48
+ padding: 12px 16px;
49
+ border-radius: 8px;
50
+ margin: 8px 0;
51
+ max-width: 85%;
52
+ transition: transform 0.2s ease;
53
+ }}
54
+
55
+ .user-message {{
56
+ background: rgba(255, 255, 255, 0.95);
57
+ color: #333;
58
+ margin-left: auto;
59
+ border-top-right-radius: 2px;
60
+ }}
61
+
62
+ .assistant-message {{
63
+ background: rgba(0, 0, 0, 0.05);
64
+ color: #fff;
65
+ margin-right: auto;
66
+ border-top-left-radius: 2px;
67
+ }}
68
+
69
+ .system-message {{
70
+ background: rgba(0, 0, 0, 0.2);
71
+ color: #fff;
72
+ margin: 8px auto;
73
+ font-style: italic;
74
+ text-align: center;
75
+ }}
76
+
77
+ .notification {{
78
+ position: fixed;
79
+ top: 20px;
80
+ right: 20px;
81
+ padding: 12px 24px;
82
+ border-radius: 8px;
83
+ background: rgba(0, 0, 0, 0.8);
84
+ color: white;
85
+ z-index: 1000;
86
+ animation: slide-in 0.3s ease;
87
+ }}
88
+
89
+ .typing-indicator {{
90
+ display: inline-block;
91
+ padding: 8px 16px;
92
+ background: rgba(0, 0, 0, 0.1);
93
+ border-radius: 16px;
94
+ color: rgba(255, 255, 255, 0.8);
95
+ font-style: italic;
96
+ margin: 8px 0;
97
+ }}
98
+
99
+ .control-panel {{
100
+ background: rgba(255, 255, 255, 0.2);
101
+ border-radius: 12px;
102
+ padding: 20px;
103
+ position: fixed;
104
+ right: -250px;
105
+ top: 50%;
106
+ transform: translateY(-50%);
107
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
108
+ z-index: 1000;
109
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
110
+ width: 220px;
111
+ backdrop-filter: blur(10px);
112
+ border: 1px solid rgba(255, 255, 255, 0.1);
113
+ pointer-events: auto;
114
+ }}
115
+
116
+ /* Make the panel accessible via keyboard focus */
117
+ .control-panel:focus-within,
118
+ .control-panel:hover {{
119
+ right: 20px;
120
+ outline: none;
121
+ }}
122
+
123
+ /* Ensure the panel is keyboard navigable */
124
+ .control-panel button:focus {{
125
+ outline: 2px solid rgba(255, 255, 255, 0.5);
126
+ outline-offset: 2px;
127
+ }}
128
+
129
+ /* Improve button hover states */
130
+ .control-panel button:hover {{
131
+ background: rgba(255, 255, 255, 0.25);
132
+ transform: translateX(5px);
133
+ }}
134
+
135
+ /* Make the panel accessible via keyboard focus */
136
+ .control-panel:hover,
137
+ .control-panel:focus-within {{
138
+ right: 20px;
139
+ outline: none;
140
+ background: rgba(255, 255, 255, 0.3);
141
+ box-shadow: 0 6px 25px rgba(0, 0, 0, 0.3);
142
+ }}
143
+
144
+ .control-panel:hover ~ .chat-window {{
145
+ transform: translateX(-110px);
146
+ }}
147
+
148
+ .control-panel::before {{
149
+ content: "☰ Settings";
150
+ position: fixed;
151
+ right: 0;
152
+ top: 50%;
153
+ transform: translateY(-50%);
154
+ background: rgba(255, 255, 255, 0.5);
155
+ padding: 15px 35px 15px 25px;
156
+ border-radius: 12px 0 0 12px;
157
+ font-size: 16px;
158
+ font-weight: bold;
159
+ color: white;
160
+ cursor: pointer;
161
+ transition: all 0.3s ease;
162
+ box-shadow: -2px 0 15px rgba(0, 0, 0, 0.2);
163
+ z-index: 999;
164
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
165
+ white-space: nowrap;
166
+ border: 1px solid rgba(255, 255, 255, 0.3);
167
+ border-right: none;
168
+ animation: pulse 2s infinite;
169
+ }}
170
+
171
+ .control-panel:hover::before {{
172
+ opacity: 0;
173
+ transform: translateY(-50%) translateX(-20px);
174
+ }}
175
+
176
+ .control-panel:hover ~ .chat-window {{
177
+ transform: translateX(-110px);
178
+ transition: transform 0.3s ease;
179
+ }}
180
+
181
+ .control-panel:hover::before {{
182
+ opacity: 0;
183
+ transform: translateY(-50%) translateX(-20px);
184
+ }}
185
+
186
+ /* Menu trigger tab with pulsing effect */
187
+ .control-panel::before {{
188
+ content: "☰ Settings";
189
+ position: fixed;
190
+ right: 0;
191
+ top: 50%;
192
+ transform: translateY(-50%);
193
+ background: rgba(255, 255, 255, 0.5);
194
+ padding: 15px 35px 15px 25px;
195
+ border-radius: 12px 0 0 12px;
196
+ font-size: 16px;
197
+ font-weight: bold;
198
+ color: white;
199
+ cursor: pointer;
200
+ transition: all 0.3s ease;
201
+ box-shadow: -2px 0 15px rgba(0, 0, 0, 0.2);
202
+ z-index: 999;
203
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
204
+ white-space: nowrap;
205
+ border: 1px solid rgba(255, 255, 255, 0.3);
206
+ border-right: none;
207
+ animation: pulse 2s infinite;
208
+ }}
209
+
210
+ .control-panel:hover::before {{
211
+ background: rgba(255, 255, 255, 0.6);
212
+ padding-right: 45px;
213
+ transform: translateY(-50%) translateX(-10px);
214
+ }}
215
+
216
+ /* Add hover trigger area */
217
+ .control-panel::after {{
218
+ content: "";
219
+ position: fixed;
220
+ right: 0;
221
+ top: 0;
222
+ width: 100px; /* Even wider hover area */
223
+ height: 100%;
224
+ z-index: 998;
225
+ background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.05));
226
+ pointer-events: none; /* Allow clicks to pass through */
227
+ }}
228
+
229
+ /* Ensure the menu is interactive */
230
+ .control-panel:hover {{
231
+ pointer-events: auto;
232
+ }}
233
+
234
+ /* Hide trigger area when menu is open */
235
+ .control-panel:hover::after {{
236
+ opacity: 0;
237
+ width: 0;
238
+ }}
239
+
240
+ @keyframes pulse {{
241
+ 0% {{ box-shadow: -2px 0 15px rgba(0, 0, 0, 0.2); }}
242
+ 50% {{ box-shadow: -2px 0 20px rgba(255, 255, 255, 0.3); }}
243
+ 100% {{ box-shadow: -2px 0 15px rgba(0, 0, 0, 0.2); }}
244
+ }}
245
+
246
+ .control-panel:hover::before {{
247
+ opacity: 0;
248
+ transform: translateY(-50%) translateX(-10px);
249
+ pointer-events: none;
250
+ background: rgba(255, 255, 255, 0.5);
251
+ padding-right: 35px;
252
+ }}
253
+
254
+ .control-panel:not(:hover)::before {{
255
+ opacity: 1;
256
+ pointer-events: auto;
257
+ }}
258
+
259
+ /* Menu trigger tab */
260
+ .control-panel::before {{
261
+ content: "☰ Settings →";
262
+ position: fixed;
263
+ right: 0;
264
+ top: 50%;
265
+ transform: translateY(-50%);
266
+ background: rgba(255, 255, 255, 0.4);
267
+ padding: 15px 25px;
268
+ border-radius: 12px 0 0 12px;
269
+ font-size: 16px;
270
+ font-weight: bold;
271
+ color: white;
272
+ cursor: pointer;
273
+ transition: all 0.3s ease;
274
+ box-shadow: -2px 0 15px rgba(0, 0, 0, 0.2);
275
+ z-index: 999;
276
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
277
+ white-space: nowrap;
278
+ border: 1px solid rgba(255, 255, 255, 0.2);
279
+ border-right: none;
280
+ }}
281
+
282
+ .control-panel:hover::before {{
283
+ background: rgba(255, 255, 255, 0.5);
284
+ padding-right: 35px;
285
+ opacity: 0;
286
+ transform: translateY(-50%) translateX(-10px);
287
+ }}
288
+
289
+ .control-panel button {{
290
+ width: 100%;
291
+ margin: 8px 0;
292
+ transition: all 0.2s ease;
293
+ }}
294
+
295
+ .control-panel button:hover {{
296
+ transform: translateX(5px);
297
+ background: rgba(255, 255, 255, 0.1);
298
+ }}
299
+
300
+ button {{
301
+ transition: all 0.2s ease;
302
+ padding: 12px 20px;
303
+ background: rgba(255, 255, 255, 0.2);
304
+ border: none;
305
+ border-radius: 8px;
306
+ color: white;
307
+ font-size: 14px;
308
+ font-weight: 500;
309
+ cursor: pointer;
310
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
311
+ margin: 5px 0;
312
+ display: flex;
313
+ align-items: center;
314
+ justify-content: center;
315
+ width: 100%;
316
+ }}
317
+
318
+ button[aria-label="Show Examples"] {{
319
+ background: rgba(255, 255, 255, 0.3);
320
+ font-weight: 600;
321
+ border: 1px solid rgba(255, 255, 255, 0.3);
322
+ }}
323
+
324
+ button[aria-label="Show Examples"]:hover {{
325
+ background: rgba(255, 255, 255, 0.4);
326
+ transform: translateY(-2px);
327
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
328
+ }}
329
+
330
+ button:hover {{
331
+ transform: translateX(5px);
332
+ background: rgba(255, 255, 255, 0.3);
333
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
334
+ }}
335
+
336
+ button:active {{
337
+ transform: translateX(2px);
338
+ background: rgba(255, 255, 255, 0.25);
339
+ }}
340
+
341
+ @keyframes gradient-shift {{
342
+ 0% {{ background-position: 0% 50%; }}
343
+ 50% {{ background-position: 100% 50%; }}
344
+ 100% {{ background-position: 0% 50%; }}
345
+ }}
346
+
347
+ @keyframes slide-in {{
348
+ from {{ transform: translateX(100%); opacity: 0; }}
349
+ to {{ transform: translateX(0); opacity: 1; }}
350
+ }}
351
+
352
+ /* Responsive adjustments */
353
+ @media (max-width: 768px) {{
354
+ .container {{ padding: 16px; }}
355
+ .chat-message {{ max-width: 95%; }}
356
+ }}
357
+ """
358
+
359
+ # ---------- Core System ----------
360
+ class AppState:
361
+ def __init__(self):
362
+ self.chat_history = []
363
+ self.color_scheme = random.choice(COLOR_SCHEMES)
364
+ self.ui_elements = []
365
+ self.version = "1.0.0"
366
+ self.last_modified = datetime.now()
367
+ self.error_log = []
368
+ self.notifications = []
369
+ self.settings = {
370
+ "show_timestamps": True,
371
+ "show_version_info": True,
372
+ "enable_animations": True,
373
+ "theme_name": "Default",
374
+ "search_filter": ""
375
+ }
376
+
377
+ def log_error(self, error_message: str, error_type: str = "general"):
378
+ """Log an error with timestamp and type"""
379
+ self.error_log.append({
380
+ "timestamp": datetime.now(),
381
+ "type": error_type,
382
+ "message": error_message
383
+ })
384
+ self.add_notification(f"Error: {error_message}", "error")
385
+
386
+ def add_notification(self, message: str, level: str = "info"):
387
+ """Add a notification with level (info, warning, error)"""
388
+ self.notifications.append({
389
+ "timestamp": datetime.now(),
390
+ "level": level,
391
+ "message": message,
392
+ "id": hashlib.md5(f"{message}{datetime.now()}".encode()).hexdigest()[:8]
393
+ })
394
+
395
+ class StateVersionManager:
396
  def __init__(self):
397
+ self.versions: Dict[str, Dict] = {}
398
+ self.current_state = AppState()
399
+ self.history = []
400
+ self.max_versions = 50
401
+
402
+ def create_version(self, description: str = "") -> Optional[Dict]:
403
+ try:
404
+ state_hash = hashlib.sha256(pickle.dumps(self.current_state)).hexdigest()[:8]
405
+ version_data = {
406
+ "state": copy.deepcopy(self.current_state),
407
+ "timestamp": datetime.now(),
408
+ "description": description,
409
+ "hash": state_hash
410
+ }
411
 
412
+ if len(self.history) >= self.max_versions:
413
+ oldest_version = self.history.pop(0)
414
+ self.versions.pop(oldest_version["hash"], None)
415
+
416
+ self.versions[version_data["hash"]] = version_data
417
+ self.history.append(version_data)
418
+ return version_data
419
+ except Exception as e:
420
+ self.current_state.log_error(f"Failed to create version: {str(e)}", "version_creation")
421
+ return None
422
+
423
+ def restore_version(self, version_hash: str) -> bool:
424
  try:
425
+ if version_hash in self.versions:
426
+ self.current_state = copy.deepcopy(self.versions[version_hash]["state"])
427
+ self.current_state.add_notification(
428
+ f"Successfully restored to version {version_hash[:6]}",
429
+ "success"
430
+ )
431
+ return True
432
+ self.current_state.add_notification(
433
+ f"Version {version_hash[:6]} not found",
434
+ "warning"
435
+ )
436
+ return False
437
  except Exception as e:
438
+ self.current_state.log_error(f"Failed to restore version: {str(e)}", "version_restoration")
439
+ return False
440
+
441
+ def get_version_list(self) -> List[Dict]:
442
+ return [{
443
+ "hash": v["hash"],
444
+ "label": f"{v['description']} ({v['timestamp'].strftime('%Y-%m-%d %H:%M')})",
445
+ "timestamp": v["timestamp"].strftime("%Y-%m-%d %H:%M:%S"),
446
+ "description": v["description"]
447
+ } for v in self.history]
448
+
449
+ # ---------- Chat Application ----------
450
+ class EvolvableChatApp:
451
+ def __init__(self):
452
+ self.state_manager = StateVersionManager()
453
+ self.current_gradient = generate_gradient(self.state_manager.current_state.color_scheme)
454
+ self.setup_initial_state()
455
+ self.typing_indicator_visible = False
456
 
457
+ def setup_initial_state(self):
 
458
  try:
459
+ initial_state = self.state_manager.current_state
460
+ initial_state.ui_elements = [
461
+ {"type": "button", "label": "🎨 Change Theme", "action": self.change_theme},
462
+ {"type": "button", "label": "🗑️ Clear Chat", "action": self.clear_chat},
463
+ {"type": "button", "label": "📤 Export Chat", "action": self.export_chat},
464
+ {"type": "button", "label": "🔄 Reset State", "action": self.reset_state}
465
+ ]
466
+
467
+ welcome_message = self.format_message(
468
+ "system",
469
+ "👋 Welcome to the Enhanced Chat Assistant! I'm here to help and learn from our interactions."
470
+ )
471
+ initial_state.chat_history.append(welcome_message)
472
+
473
+ self.state_manager.create_version("Initial state")
474
  except Exception as e:
475
+ self.state_manager.current_state.log_error(
476
+ f"Failed to setup initial state: {str(e)}",
477
+ "initialization"
478
+ )
479
 
480
+ def update_state(self, new_chat: Optional[Dict] = None, description: str = "") -> Optional[Dict]:
481
+ try:
482
+ if new_chat:
483
+ if self.state_manager.current_state.settings["show_timestamps"]:
484
+ timestamp = datetime.now().strftime("%H:%M:%S")
485
+ new_chat["content"] = f"[{timestamp}] {new_chat['content']}"
486
+ self.state_manager.current_state.chat_history.append(new_chat)
487
+
488
+ self.state_manager.current_state.last_modified = datetime.now()
489
+ return self.state_manager.create_version(description)
490
+ except Exception as e:
491
+ self.state_manager.current_state.log_error(
492
+ f"Failed to update state: {str(e)}",
493
+ "state_update"
494
+ )
495
+ return None
496
 
497
+ def change_theme(self):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498
  try:
499
+ current_scheme = self.state_manager.current_state.color_scheme
500
+ available_schemes = [scheme for scheme in COLOR_SCHEMES if scheme != current_scheme]
501
+ new_scheme = random.choice(available_schemes)
502
+
503
+ theme_names = [
504
+ "Ocean Breeze", "Desert Sunset", "Forest Dawn", "Coral Reef",
505
+ "Neon Nights", "Deep Ocean", "Rose Garden", "Midnight Purple"
506
+ ]
507
+ theme_name = next(
508
+ (name for i, colors in enumerate(COLOR_SCHEMES)
509
+ if colors == new_scheme and i < len(theme_names)),
510
+ "Custom"
511
+ )
512
+
513
+ self.state_manager.current_state.color_scheme = new_scheme
514
+ self.state_manager.current_state.settings["theme_name"] = theme_name
515
+ self.current_gradient = generate_gradient(new_scheme)
516
+
517
+ theme_message = self.format_message(
518
+ "system",
519
+ f"🎨 Theme changed to: {theme_name}"
520
+ )
521
+ self.update_state(theme_message, f"Changed theme to {theme_name}")
522
+
523
+ return self.get_chat_history_tuples(), f"Current Theme: {theme_name}"
524
+ except Exception as e:
525
+ error_message = self.format_message(
526
+ "system",
527
+ f"❌ Failed to change theme: {str(e)}"
528
+ )
529
+ self.update_state(error_message, "Theme change failed")
530
+ return self.get_chat_history_tuples(), "Theme change failed"
531
 
532
+ def clear_chat(self):
533
+ try:
534
+ self.state_manager.current_state.chat_history = []
535
+ welcome_message = self.format_message(
536
+ "system",
537
+ "💫 Chat history cleared"
538
+ )
539
+ self.update_state(welcome_message, "Cleared chat history")
540
+ return self.get_chat_history_tuples()
541
+ except Exception as e:
542
+ self.state_manager.current_state.log_error(
543
+ f"Failed to clear chat: {str(e)}",
544
+ "clear_chat"
545
+ )
546
+ return self.get_chat_history_tuples(), self.create_ui()
 
 
 
 
 
 
 
547
 
548
+ def export_chat(self):
549
+ try:
550
+ chat_export = {
551
+ "timestamp": datetime.now().isoformat(),
552
+ "version": self.state_manager.current_state.version,
553
+ "messages": self.state_manager.current_state.chat_history
554
+ }
555
+
556
+ export_message = self.format_message(
557
+ "system",
558
+ "📤 Chat history exported successfully"
559
+ )
560
+ self.update_state(export_message, "Exported chat history")
561
+
562
+ return (
563
+ json.dumps(chat_export, indent=2),
564
+ self.get_chat_history_tuples()
565
+ )
566
+ except Exception as e:
567
+ self.state_manager.current_state.log_error(
568
+ f"Failed to export chat: {str(e)}",
569
+ "export_chat"
570
+ )
571
+ return "", self.get_chat_history_tuples()
572
+
573
+ def search_messages(self, query: str):
574
+ try:
575
+ if not query:
576
+ return self.get_chat_history_tuples()
577
+
578
+ filtered_messages = [
579
+ msg for msg in self.state_manager.current_state.chat_history
580
+ if query.lower() in msg["content"].lower()
581
+ ]
582
+
583
+ return [(msg["role"] == "user", msg["content"])
584
+ for msg in filtered_messages
585
+ if msg["role"] in ["user", "assistant"]]
586
+ except Exception as e:
587
+ self.state_manager.current_state.log_error(
588
+ f"Failed to search messages: {str(e)}",
589
+ "search_messages"
590
+ )
591
+ return self.get_chat_history_tuples()
592
+
593
+ def reset_state(self):
594
+ try:
595
+ self.state_manager.current_state = AppState()
596
+ self.setup_initial_state()
597
+ self.current_gradient = generate_gradient(
598
+ self.state_manager.current_state.color_scheme
599
+ )
600
+ return self.get_chat_history_tuples(), self.create_ui()
601
+ except Exception as e:
602
+ self.state_manager.current_state.log_error(
603
+ f"Failed to reset state: {str(e)}",
604
+ "reset_state"
605
+ )
606
+ return self.get_chat_history_tuples(), self.create_ui()
607
+
608
+ def show_examples(self):
609
+ """Display example messages and commands"""
610
+ try:
611
+ # Format examples with better styling
612
+ formatted_examples = EXAMPLES.replace(":", ":\n").replace("\n\n", "\n")
613
+ examples_message = self.format_message(
614
+ "system",
615
+ f"📝 Available Commands and Examples\n\n"
616
+ f"Here are some example messages you can try:\n\n"
617
+ f"{formatted_examples}\n\n"
618
+ f"Try any of these messages or commands to explore the chat assistant's capabilities!"
619
+ )
620
+ self.update_state(examples_message, "Showed examples")
621
+ return self.get_chat_history_tuples(), self.create_ui()
622
+ except Exception as e:
623
+ self.state_manager.current_state.log_error(
624
+ f"Failed to show examples: {str(e)}",
625
+ "show_examples"
626
+ )
627
+ return self.get_chat_history_tuples(), self.create_ui()
628
+
629
+ def create_ui(self):
630
+ with gr.Blocks(css=self.current_gradient) as interface:
631
+ with gr.Row(elem_classes="container"):
632
+ with gr.Column(scale=2):
633
+ gr.Markdown(f"""
634
+ # 🤖 Enhanced Chat Assistant
635
+ <p class="theme-text">Current Theme: {self.state_manager.current_state.settings['theme_name']}</p>
636
+ """)
637
+ with gr.Column(scale=1):
638
+ version_dropdown = gr.Dropdown(
639
+ label="Version History",
640
+ choices=[v["label"] for v in self.state_manager.get_version_list()],
641
+ interactive=True
642
+ )
643
+
644
+ # Main chat area with full width
645
+ with gr.Column(scale=1):
646
+ chat_window = gr.Chatbot(
647
+ value=self.get_chat_history_tuples(),
648
+ height=500, # Increased height
649
+ elem_classes="chat-window",
650
+ type="messages"
651
+ )
652
+
653
+ # Message input area
654
+ with gr.Row():
655
+ message_input = gr.Textbox(
656
+ placeholder="Type your message...",
657
+ scale=4, # Increased scale
658
+ container=False
659
+ )
660
+ submit_btn = gr.Button("Send", scale=1)
661
+
662
+ # Search functionality
663
+ with gr.Row():
664
+ search_input = gr.Textbox(
665
+ placeholder="Search messages...",
666
+ scale=4, # Increased scale
667
+ container=False
668
+ )
669
+ search_btn = gr.Button("🔍 Search", scale=1)
670
+
671
+ # Floating control panel
672
+ with gr.Group(elem_classes="control-panel"):
673
+ gr.Markdown("### Control Panel")
674
+
675
+ theme_info = gr.Markdown(
676
+ f"Current Theme: {self.state_manager.current_state.settings['theme_name']}",
677
+ elem_classes="theme-text"
678
+ )
679
+
680
+ # Control buttons with proper event handling
681
+ examples_btn = gr.Button("📝 Show Examples", elem_classes=["control-button"])
682
+ change_theme_btn = gr.Button("🎨 Change Theme")
683
+ clear_chat_btn = gr.Button("🗑️ Clear Chat")
684
+ export_chat_btn = gr.Button("📤 Export Chat")
685
+ reset_state_btn = gr.Button("🔄 Reset State")
686
+
687
+ # Event handlers for examples
688
+ examples_btn.click(
689
+ self.show_examples,
690
+ outputs=[chat_window]
691
+ )
692
+
693
+ export_text = gr.Textbox(
694
+ label="Exported Chat Data",
695
+ visible=False
696
+ )
697
+
698
+ # Event handlers for control buttons
699
+ change_theme_btn.click(
700
+ self.change_theme,
701
+ outputs=[chat_window, theme_info]
702
+ )
703
+
704
+ clear_chat_btn.click(
705
+ self.clear_chat,
706
+ outputs=[chat_window]
707
+ )
708
+
709
+ export_chat_btn.click(
710
+ self.export_chat,
711
+ outputs=[export_text, chat_window]
712
+ )
713
+
714
+ reset_state_btn.click(
715
+ self.reset_state,
716
+ outputs=[chat_window]
717
+ )
718
+
719
+ # Event handlers for message submission
720
+ def handle_message(message):
721
+ if not message.strip():
722
+ return self.get_chat_history_tuples(), ""
723
+
724
+ # Add user message
725
+ user_message = self.format_message("user", message)
726
+ self.update_state(user_message, "User message")
727
+
728
+ # Generate and add AI response
729
+ response = self.generate_response(message)
730
+ ai_message = self.format_message("assistant", response)
731
+ self.update_state(ai_message, "AI response")
732
+
733
+ return self.get_chat_history_tuples(), ""
734
+
735
+ submit_btn.click(
736
+ fn=handle_message,
737
+ inputs=[message_input],
738
+ outputs=[chat_window, message_input]
739
+ )
740
+
741
+ search_btn.click(
742
+ self.search_messages,
743
+ inputs=[search_input],
744
+ outputs=[chat_window]
745
+ )
746
+
747
+ version_dropdown.change(
748
+ self.restore_version,
749
+ inputs=[version_dropdown],
750
+ outputs=[chat_window]
751
+ )
752
+
753
+ return interface
754
+
755
+ def format_message(self, role: str, content: str) -> Dict[str, str]:
756
  return {
757
+ "role": role,
758
+ "content": content,
759
+ "timestamp": datetime.now().isoformat()
760
  }
 
 
761
 
762
+ def get_chat_history_tuples(self):
 
763
  try:
764
+ formatted_messages = self.ensure_message_format(
765
+ self.state_manager.current_state.chat_history
766
+ )
767
+ return [
768
+ (msg["role"] == "user", msg["content"]) # Tuple format for Gradio
769
+ for msg in formatted_messages
770
+ if msg["role"] in ["user", "assistant", "system"]
771
+ ]
772
  except Exception as e:
773
+ self.state_manager.current_state.log_error(
774
+ f"Failed to format chat history: {str(e)}",
775
+ "format_history"
776
+ )
777
+ return []
 
 
 
 
 
 
 
 
 
778
 
779
+ def process_message(self, message: str):
780
+ """Process a user message and generate a response"""
781
+ try:
782
+ if not message.strip():
783
+ return self.get_chat_history_tuples(), ""
784
+
785
+ # Format and add user message
786
+ user_message = self.format_message("user", message)
787
+ self.update_state(user_message, "User message")
788
+
789
+ # Generate and format AI response
790
+ response = self.generate_response(message)
791
+ ai_message = self.format_message("assistant", response)
792
+ self.update_state(ai_message, "AI response")
793
+
794
+ # Return updated chat history and clear input
795
+ return self.get_chat_history_tuples(), ""
796
+ except Exception as e:
797
+ self.state_manager.current_state.log_error(
798
+ f"Failed to process message: {str(e)}",
799
+ "message_processing"
800
+ )
801
+ error_message = self.format_message(
802
+ "system",
803
+ "❌ I apologize, but I encountered an error processing your message. Please try again."
804
+ )
805
+ self.update_state(error_message, "Error processing message")
806
+ return self.get_chat_history_tuples(), ""
 
 
 
 
807
 
808
+ def generate_response(self, message: str):
809
+ try:
810
+ # Enhanced responses with more variety and context
811
+ responses = [
812
+ "I've analyzed your message and here's what I think:",
813
+ "Based on our conversation history, I suggest:",
814
+ "That's interesting! Here's my perspective:",
815
+ "I've evolved to understand that:",
816
+ "Let me share my thoughts on that:",
817
+ "After processing your input, I believe:",
818
+ "My evolving knowledge suggests:",
819
+ "Here's my enhanced response:"
820
+ ]
821
+
822
+ # Add contextual information
823
+ response = random.choice(responses)
824
+ if self.state_manager.current_state.settings["show_version_info"]:
825
+ response += f" (v{self.state_manager.current_state.version})"
826
+
827
+ # Add a random insight or suggestion
828
+ insights = [
829
+ "Consider exploring this further.",
830
+ "This could lead to interesting developments.",
831
+ "I'm learning from our interaction.",
832
+ "Your input helps me evolve.",
833
+ "This adds to my growing understanding."
834
+ ]
835
+ response += f" {random.choice(insights)}"
836
+
837
+ return response
838
+ except Exception as e:
839
+ self.state_manager.current_state.log_error(
840
+ f"Failed to generate response: {str(e)}",
841
+ "response_generation"
842
+ )
843
+ return "I apologize, but I encountered an error generating a response."
844
 
845
+ def ensure_message_format(self, messages: List[Any]) -> List[Dict[str, str]]:
846
+ formatted_messages = []
847
+ for msg in messages:
848
+ if isinstance(msg, dict) and "role" in msg and "content" in msg:
849
+ formatted_messages.append(msg)
850
+ elif isinstance(msg, str):
851
+ if msg.startswith("User: "):
852
+ formatted_messages.append({"role": "user", "content": msg[6:]})
853
+ elif msg.startswith("AI: "):
854
+ formatted_messages.append({"role": "assistant", "content": msg[4:]})
855
+ elif msg.startswith("System: "):
856
+ formatted_messages.append({"role": "system", "content": msg[8:]})
857
+ else:
858
+ formatted_messages.append({"role": "system", "content": msg})
859
+ elif isinstance(msg, (list, tuple)) and len(msg) == 2:
860
+ role = "user" if msg[0] else "assistant"
861
+ formatted_messages.append({"role": role, "content": msg[1]})
862
+ return formatted_messages
863
+
864
+ def restore_version(self, version_label: str):
865
+ try:
866
+ version_info = next(
867
+ (v for v in self.state_manager.get_version_list()
868
+ if v["label"] == version_label),
869
+ None
870
+ )
871
+
872
+ if version_info and self.state_manager.restore_version(version_info["hash"]):
873
+ self.current_gradient = generate_gradient(
874
+ self.state_manager.current_state.color_scheme
875
+ )
876
+ return self.get_chat_history_tuples()
877
+
878
+ return self.get_chat_history_tuples()
879
+ except Exception as e:
880
+ self.state_manager.current_state.log_error(
881
+ f"Failed to restore version: {str(e)}",
882
+ "version_restoration"
883
+ )
884
+ return self.get_chat_history_tuples()
885
+
886
+ # ---------- Main Execution ----------
887
  if __name__ == "__main__":
888
+ try:
889
+ print("Starting Enhanced Chat Assistant...")
890
+ print("Initializing application state...")
891
+ app = EvolvableChatApp()
892
+ print("Creating user interface...")
893
+ interface = app.create_ui()
894
+ print("Launching interface on http://localhost:8000")
895
+ interface.launch(
896
+ share=False,
897
+ # server_name="0.0.0.0",
898
+ # server_port=8000,
899
+ show_api=False
900
+ )
901
+ except Exception as e:
902
+ print(f"Error starting application: {str(e)}")
903
+ print("Please ensure all requirements are installed: pip install -r requirements.txt")