deepcode-hku 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cli/__init__.py +18 -0
- cli/cli_app.py +296 -0
- cli/cli_interface.py +744 -0
- cli/cli_launcher.py +155 -0
- cli/main_cli.py +243 -0
- cli/workflows/__init__.py +11 -0
- cli/workflows/cli_workflow_adapter.py +336 -0
- deepcode.py +219 -0
- deepcode_hku-1.0.1.dist-info/METADATA +695 -0
- deepcode_hku-1.0.1.dist-info/RECORD +44 -0
- deepcode_hku-1.0.1.dist-info/WHEEL +5 -0
- deepcode_hku-1.0.1.dist-info/entry_points.txt +2 -0
- deepcode_hku-1.0.1.dist-info/licenses/LICENSE +21 -0
- deepcode_hku-1.0.1.dist-info/top_level.txt +6 -0
- tools/__init__.py +0 -0
- tools/code_implementation_server.py +1045 -0
- tools/code_indexer.py +1657 -0
- tools/code_reference_indexer.py +486 -0
- tools/command_executor.py +324 -0
- tools/git_command.py +356 -0
- tools/pdf_converter.py +640 -0
- tools/pdf_downloader.py +1370 -0
- tools/pdf_utils.py +52 -0
- ui/__init__.py +43 -0
- ui/app.py +13 -0
- ui/components.py +1450 -0
- ui/handlers.py +773 -0
- ui/layout.py +106 -0
- ui/streamlit_app.py +38 -0
- ui/styles.py +2116 -0
- utils/__init__.py +17 -0
- utils/cli_interface.py +459 -0
- utils/dialogue_logger.py +671 -0
- utils/file_processor.py +426 -0
- utils/simple_llm_logger.py +198 -0
- workflows/__init__.py +31 -0
- workflows/agent_orchestration_engine.py +1371 -0
- workflows/agents/__init__.py +13 -0
- workflows/agents/code_implementation_agent.py +1093 -0
- workflows/agents/memory_agent_concise.py +923 -0
- workflows/agents/memory_agent_concise_index.py +935 -0
- workflows/code_implementation_workflow.py +924 -0
- workflows/code_implementation_workflow_index.py +931 -0
- workflows/codebase_index_workflow.py +726 -0
utils/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utils package for paper processing tools.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .file_processor import FileProcessor
|
|
6
|
+
from .dialogue_logger import (
|
|
7
|
+
DialogueLogger,
|
|
8
|
+
create_dialogue_logger,
|
|
9
|
+
extract_paper_id_from_path,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"FileProcessor",
|
|
14
|
+
"DialogueLogger",
|
|
15
|
+
"create_dialogue_logger",
|
|
16
|
+
"extract_paper_id_from_path",
|
|
17
|
+
]
|
utils/cli_interface.py
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Professional CLI Interface Module
|
|
4
|
+
专业CLI界面模块 - 包含logo、颜色定义和界面组件
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import time
|
|
9
|
+
import platform
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Optional
|
|
12
|
+
import tkinter as tk
|
|
13
|
+
from tkinter import filedialog
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Colors:
|
|
17
|
+
"""ANSI color codes for terminal styling"""
|
|
18
|
+
|
|
19
|
+
HEADER = "\033[95m"
|
|
20
|
+
OKBLUE = "\033[94m"
|
|
21
|
+
OKCYAN = "\033[96m"
|
|
22
|
+
OKGREEN = "\033[92m"
|
|
23
|
+
WARNING = "\033[93m"
|
|
24
|
+
FAIL = "\033[91m"
|
|
25
|
+
ENDC = "\033[0m"
|
|
26
|
+
BOLD = "\033[1m"
|
|
27
|
+
UNDERLINE = "\033[4m"
|
|
28
|
+
|
|
29
|
+
# Gradient colors
|
|
30
|
+
PURPLE = "\033[35m"
|
|
31
|
+
MAGENTA = "\033[95m"
|
|
32
|
+
BLUE = "\033[34m"
|
|
33
|
+
CYAN = "\033[36m"
|
|
34
|
+
GREEN = "\033[32m"
|
|
35
|
+
YELLOW = "\033[33m"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CLIInterface:
|
|
39
|
+
"""Professional CLI interface with modern styling"""
|
|
40
|
+
|
|
41
|
+
def __init__(self):
|
|
42
|
+
self.uploaded_file = None
|
|
43
|
+
self.is_running = True
|
|
44
|
+
|
|
45
|
+
# Check tkinter availability
|
|
46
|
+
self.tkinter_available = True
|
|
47
|
+
try:
|
|
48
|
+
import tkinter as tk
|
|
49
|
+
|
|
50
|
+
# Test if tkinter can create a window (some systems have tkinter but no display)
|
|
51
|
+
test_root = tk.Tk()
|
|
52
|
+
test_root.withdraw()
|
|
53
|
+
test_root.destroy()
|
|
54
|
+
except Exception:
|
|
55
|
+
self.tkinter_available = False
|
|
56
|
+
|
|
57
|
+
def clear_screen(self):
|
|
58
|
+
"""Clear terminal screen"""
|
|
59
|
+
os.system("cls" if os.name == "nt" else "clear")
|
|
60
|
+
|
|
61
|
+
def print_logo(self):
|
|
62
|
+
"""Print a beautiful ASCII logo with gradient colors and tech elements"""
|
|
63
|
+
# 确保每行总共79个字符(不包括颜色代码),边框完美对齐
|
|
64
|
+
logo = f"""
|
|
65
|
+
{Colors.CYAN}╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
66
|
+
║ ║
|
|
67
|
+
║ {Colors.BOLD}{Colors.MAGENTA}██████╗ ███████╗██████╗ ██████╗ ██████╗ █████╗ ██╗{Colors.CYAN} ║
|
|
68
|
+
║ {Colors.BOLD}{Colors.PURPLE}██╔══██╗ ██╔════╝██╔══██╗██╔══██╗██╔═══██╗ ██╔══██╗██║{Colors.CYAN} ║
|
|
69
|
+
║ {Colors.BOLD}{Colors.BLUE}██████╔╝ █████╗ ██████╔╝██████╔╝██║ ██║ ███████║██║{Colors.CYAN} ║
|
|
70
|
+
║ {Colors.BOLD}{Colors.OKBLUE}██╔══██╗ ██╔══╝ ██╔═══╝ ██╔══██╗██║ ██║ ██╔══██║██║{Colors.CYAN} ║
|
|
71
|
+
║ {Colors.BOLD}{Colors.OKCYAN}██║ ██║ ███████╗██║ ██║ ██║╚██████╔╝ ██║ ██║██║{Colors.CYAN} ║
|
|
72
|
+
║ {Colors.BOLD}{Colors.GREEN}╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝{Colors.CYAN} ║
|
|
73
|
+
║ ║
|
|
74
|
+
║ {Colors.BOLD}{Colors.YELLOW}┌─────────────────────────────────────────────────────────────────────────┐{Colors.CYAN} ║
|
|
75
|
+
║ {Colors.BOLD}{Colors.YELLOW}│ 🤖 AI-POWERED RESEARCH PAPER REPRODUCTION ENGINE 🚀 │{Colors.CYAN} ║
|
|
76
|
+
║ {Colors.BOLD}{Colors.YELLOW}│ ⚡ INTELLIGENT • AUTOMATED • CUTTING-EDGE ⚡ │{Colors.CYAN} ║
|
|
77
|
+
║ {Colors.BOLD}{Colors.YELLOW}└─────────────────────────────────────────────────────────────────────────┘{Colors.CYAN} ║
|
|
78
|
+
║ ║
|
|
79
|
+
║ {Colors.BOLD}{Colors.GREEN}💎 CORE CAPABILITIES:{Colors.ENDC} {Colors.CYAN}║
|
|
80
|
+
║ {Colors.BOLD}{Colors.OKCYAN}▶ Neural PDF Analysis & Code Extraction {Colors.CYAN}║
|
|
81
|
+
║ {Colors.BOLD}{Colors.OKCYAN}▶ Advanced Document Processing Engine {Colors.CYAN}║
|
|
82
|
+
║ {Colors.BOLD}{Colors.OKCYAN}▶ Multi-Format Support (PDF•DOCX•PPTX•HTML) {Colors.CYAN}║
|
|
83
|
+
║ {Colors.BOLD}{Colors.OKCYAN}▶ Smart File Upload Interface {Colors.CYAN}║
|
|
84
|
+
║ {Colors.BOLD}{Colors.OKCYAN}▶ Automated Repository Management {Colors.CYAN}║
|
|
85
|
+
║ ║
|
|
86
|
+
║ {Colors.BOLD}{Colors.PURPLE}🔬 TECH STACK: Python•AI•MCP•Docling•LLM {Colors.CYAN}║
|
|
87
|
+
║ ║
|
|
88
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}
|
|
89
|
+
"""
|
|
90
|
+
print(logo)
|
|
91
|
+
|
|
92
|
+
def print_welcome_banner(self):
|
|
93
|
+
"""Print welcome banner with version info"""
|
|
94
|
+
banner = f"""
|
|
95
|
+
{Colors.BOLD}{Colors.CYAN}╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
96
|
+
║ WELCOME TO ReproAI ║
|
|
97
|
+
╠═══════════════════════════════════════════════════════════════════════════════╣
|
|
98
|
+
║ ║
|
|
99
|
+
║ {Colors.YELLOW}Version: 2.0.0 | Build: Professional Edition {Colors.CYAN}║
|
|
100
|
+
║ {Colors.GREEN}Status: Ready | Engine: Initialized {Colors.CYAN}║
|
|
101
|
+
║ {Colors.PURPLE}Author: AI Research Team | License: MIT {Colors.CYAN}║
|
|
102
|
+
║ ║
|
|
103
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}
|
|
104
|
+
"""
|
|
105
|
+
print(banner)
|
|
106
|
+
|
|
107
|
+
def print_separator(self, char="═", length=79, color=Colors.CYAN):
|
|
108
|
+
"""Print a styled separator line"""
|
|
109
|
+
print(f"{color}{char * length}{Colors.ENDC}")
|
|
110
|
+
|
|
111
|
+
def print_status(self, message: str, status_type: str = "info"):
|
|
112
|
+
"""Print status message with appropriate styling"""
|
|
113
|
+
status_styles = {
|
|
114
|
+
"success": f"{Colors.OKGREEN}✅",
|
|
115
|
+
"error": f"{Colors.FAIL}❌",
|
|
116
|
+
"warning": f"{Colors.WARNING}⚠️ ",
|
|
117
|
+
"info": f"{Colors.OKBLUE}ℹ️ ",
|
|
118
|
+
"processing": f"{Colors.YELLOW}⏳",
|
|
119
|
+
"upload": f"{Colors.PURPLE}📁",
|
|
120
|
+
"download": f"{Colors.CYAN}📥",
|
|
121
|
+
"analysis": f"{Colors.MAGENTA}🔍",
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
icon = status_styles.get(status_type, status_styles["info"])
|
|
125
|
+
print(f"{icon} {Colors.BOLD}{message}{Colors.ENDC}")
|
|
126
|
+
|
|
127
|
+
def create_menu(self):
|
|
128
|
+
"""Create an interactive menu"""
|
|
129
|
+
menu = f"""
|
|
130
|
+
{Colors.BOLD}{Colors.CYAN}╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
131
|
+
║ MAIN MENU ║
|
|
132
|
+
╠═══════════════════════════════════════════════════════════════════════════════╣
|
|
133
|
+
║ ║
|
|
134
|
+
║ {Colors.OKGREEN}🌐 [U] Process URL {Colors.CYAN}│ {Colors.PURPLE}📁 [F] Upload File {Colors.CYAN}│ {Colors.FAIL}❌ [Q] Quit{Colors.CYAN} ║
|
|
135
|
+
║ ║
|
|
136
|
+
║ {Colors.YELLOW}📝 Enter a research paper URL (arXiv, IEEE, ACM, etc.) {Colors.CYAN}║
|
|
137
|
+
║ {Colors.YELLOW} or upload a PDF/DOC file for intelligent analysis {Colors.CYAN}║
|
|
138
|
+
║ ║
|
|
139
|
+
║ {Colors.OKCYAN}💡 Tip: Press 'F' to open file browser or 'U' to enter URL manually {Colors.CYAN}║
|
|
140
|
+
║ ║
|
|
141
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}
|
|
142
|
+
"""
|
|
143
|
+
print(menu)
|
|
144
|
+
|
|
145
|
+
def get_user_input(self):
|
|
146
|
+
"""Get user input with styled prompt"""
|
|
147
|
+
print(f"\n{Colors.BOLD}{Colors.OKCYAN}➤ Your choice: {Colors.ENDC}", end="")
|
|
148
|
+
return input().strip().lower()
|
|
149
|
+
|
|
150
|
+
def upload_file_gui(self) -> Optional[str]:
|
|
151
|
+
"""Modern file upload interface using tkinter with cross-platform compatibility"""
|
|
152
|
+
# Check if tkinter is available
|
|
153
|
+
if not self.tkinter_available:
|
|
154
|
+
self.print_status("GUI file dialog not available on this system", "warning")
|
|
155
|
+
self.print_status("Using manual file path input instead", "info")
|
|
156
|
+
return self._get_manual_file_path()
|
|
157
|
+
|
|
158
|
+
def select_file():
|
|
159
|
+
try:
|
|
160
|
+
# Create a hidden root window
|
|
161
|
+
root = tk.Tk()
|
|
162
|
+
root.withdraw() # Hide the main window
|
|
163
|
+
|
|
164
|
+
# Platform-specific configurations
|
|
165
|
+
system = platform.system()
|
|
166
|
+
|
|
167
|
+
if system == "Darwin": # macOS
|
|
168
|
+
# macOS specific settings
|
|
169
|
+
try:
|
|
170
|
+
root.call("wm", "attributes", ".", "-topmost", True)
|
|
171
|
+
except Exception:
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
# macOS compatible file types
|
|
175
|
+
file_types = [
|
|
176
|
+
("PDF Files", ".pdf"),
|
|
177
|
+
("Word Documents", ".docx .doc"),
|
|
178
|
+
("PowerPoint Files", ".pptx .ppt"),
|
|
179
|
+
("HTML Files", ".html .htm"),
|
|
180
|
+
("Text Files", ".txt .md"),
|
|
181
|
+
("All Files", ".*"),
|
|
182
|
+
]
|
|
183
|
+
else:
|
|
184
|
+
# Windows and Linux
|
|
185
|
+
root.attributes("-topmost", True)
|
|
186
|
+
|
|
187
|
+
# Windows/Linux compatible file types
|
|
188
|
+
file_types = [
|
|
189
|
+
("PDF Files", "*.pdf"),
|
|
190
|
+
("Word Documents", "*.docx;*.doc"),
|
|
191
|
+
("PowerPoint Files", "*.pptx;*.ppt"),
|
|
192
|
+
("HTML Files", "*.html;*.htm"),
|
|
193
|
+
("Text Files", "*.txt;*.md"),
|
|
194
|
+
("All Files", "*.*"),
|
|
195
|
+
]
|
|
196
|
+
|
|
197
|
+
# Set window title
|
|
198
|
+
root.title("Repro-AI - File Selector")
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
# Open file dialog with platform-appropriate settings
|
|
202
|
+
file_path = filedialog.askopenfilename(
|
|
203
|
+
title="Select Research Paper File",
|
|
204
|
+
filetypes=file_types,
|
|
205
|
+
initialdir=os.getcwd(),
|
|
206
|
+
)
|
|
207
|
+
except Exception as e:
|
|
208
|
+
self.print_status(f"File dialog error: {str(e)}", "error")
|
|
209
|
+
return None
|
|
210
|
+
finally:
|
|
211
|
+
# Clean up
|
|
212
|
+
try:
|
|
213
|
+
root.destroy()
|
|
214
|
+
except Exception:
|
|
215
|
+
pass
|
|
216
|
+
|
|
217
|
+
return file_path
|
|
218
|
+
|
|
219
|
+
except Exception as e:
|
|
220
|
+
# Fallback: destroy root if it exists
|
|
221
|
+
try:
|
|
222
|
+
if "root" in locals():
|
|
223
|
+
root.destroy()
|
|
224
|
+
except Exception:
|
|
225
|
+
pass
|
|
226
|
+
|
|
227
|
+
# Print error and suggest alternative
|
|
228
|
+
self.print_status(f"GUI file dialog failed: {str(e)}", "error")
|
|
229
|
+
self.print_status(
|
|
230
|
+
"Please use manual file path input instead", "warning"
|
|
231
|
+
)
|
|
232
|
+
return self._get_manual_file_path()
|
|
233
|
+
|
|
234
|
+
self.print_status("Opening file browser dialog...", "upload")
|
|
235
|
+
file_path = select_file()
|
|
236
|
+
|
|
237
|
+
if file_path:
|
|
238
|
+
# Validate file
|
|
239
|
+
if not os.path.exists(file_path):
|
|
240
|
+
self.print_status("File not found!", "error")
|
|
241
|
+
return None
|
|
242
|
+
|
|
243
|
+
file_size = os.path.getsize(file_path) / (1024 * 1024) # Size in MB
|
|
244
|
+
file_ext = Path(file_path).suffix.lower()
|
|
245
|
+
|
|
246
|
+
# Display file info with beautiful formatting
|
|
247
|
+
file_name = Path(file_path).name
|
|
248
|
+
directory = str(Path(file_path).parent)
|
|
249
|
+
|
|
250
|
+
# Truncate long paths for display
|
|
251
|
+
if len(file_name) > 50:
|
|
252
|
+
display_name = file_name[:47] + "..."
|
|
253
|
+
else:
|
|
254
|
+
display_name = file_name
|
|
255
|
+
|
|
256
|
+
if len(directory) > 49:
|
|
257
|
+
display_dir = "..." + directory[-46:]
|
|
258
|
+
else:
|
|
259
|
+
display_dir = directory
|
|
260
|
+
|
|
261
|
+
print(f"""
|
|
262
|
+
{Colors.OKGREEN}╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
263
|
+
║ FILE SELECTED ║
|
|
264
|
+
╠═══════════════════════════════════════════════════════════════════════════════╣
|
|
265
|
+
║ ║
|
|
266
|
+
║ {Colors.BOLD}📄 File Name:{Colors.ENDC} {Colors.CYAN}{display_name:<50}{Colors.OKGREEN}║
|
|
267
|
+
║ {Colors.BOLD}📁 Directory:{Colors.ENDC} {Colors.YELLOW}{display_dir:<49}{Colors.OKGREEN}║
|
|
268
|
+
║ {Colors.BOLD}📊 File Size:{Colors.ENDC} {Colors.PURPLE}{file_size:.2f} MB{Colors.OKGREEN} ║
|
|
269
|
+
║ {Colors.BOLD}🔖 File Type:{Colors.ENDC} {Colors.MAGENTA}{file_ext.upper():<50}{Colors.OKGREEN}║
|
|
270
|
+
║ ║
|
|
271
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}
|
|
272
|
+
""")
|
|
273
|
+
|
|
274
|
+
self.print_status(f"File successfully selected: {file_name}", "success")
|
|
275
|
+
return file_path
|
|
276
|
+
else:
|
|
277
|
+
self.print_status("No file selected", "warning")
|
|
278
|
+
return None
|
|
279
|
+
|
|
280
|
+
def _get_manual_file_path(self) -> Optional[str]:
|
|
281
|
+
"""Fallback method for manual file path input when GUI fails"""
|
|
282
|
+
print(
|
|
283
|
+
f"\n{Colors.BOLD}{Colors.CYAN}╔═══════════════════════════════════════════════════════════════════════════════╗"
|
|
284
|
+
)
|
|
285
|
+
print(
|
|
286
|
+
"║ MANUAL FILE INPUT ║"
|
|
287
|
+
)
|
|
288
|
+
print(
|
|
289
|
+
f"╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
print(f"\n{Colors.YELLOW}📝 Supported file types:{Colors.ENDC}")
|
|
293
|
+
print(f" {Colors.CYAN}• PDF files (.pdf)")
|
|
294
|
+
print(f" {Colors.CYAN}• Word documents (.docx, .doc)")
|
|
295
|
+
print(f" {Colors.CYAN}• PowerPoint files (.pptx, .ppt)")
|
|
296
|
+
print(f" {Colors.CYAN}• HTML files (.html, .htm)")
|
|
297
|
+
print(f" {Colors.CYAN}• Text files (.txt, .md){Colors.ENDC}")
|
|
298
|
+
|
|
299
|
+
print(
|
|
300
|
+
f"\n{Colors.BOLD}{Colors.OKCYAN}📁 Enter file path (or drag & drop): {Colors.ENDC}",
|
|
301
|
+
end="",
|
|
302
|
+
)
|
|
303
|
+
file_path = input().strip()
|
|
304
|
+
|
|
305
|
+
# Clean up the path (remove quotes if present)
|
|
306
|
+
file_path = file_path.strip("\"'")
|
|
307
|
+
|
|
308
|
+
if file_path:
|
|
309
|
+
# Expand user directory if needed
|
|
310
|
+
file_path = os.path.expanduser(file_path)
|
|
311
|
+
|
|
312
|
+
# Check if file exists
|
|
313
|
+
if os.path.exists(file_path):
|
|
314
|
+
self.print_status(
|
|
315
|
+
f"File found: {os.path.basename(file_path)}", "success"
|
|
316
|
+
)
|
|
317
|
+
return file_path
|
|
318
|
+
else:
|
|
319
|
+
self.print_status("File not found at the specified path", "error")
|
|
320
|
+
return None
|
|
321
|
+
else:
|
|
322
|
+
self.print_status("No file path provided", "warning")
|
|
323
|
+
return None
|
|
324
|
+
|
|
325
|
+
def get_url_input(self) -> str:
|
|
326
|
+
"""Get URL input with validation and examples"""
|
|
327
|
+
print(
|
|
328
|
+
f"\n{Colors.BOLD}{Colors.CYAN}╔═══════════════════════════════════════════════════════════════════════════════╗"
|
|
329
|
+
)
|
|
330
|
+
print(
|
|
331
|
+
"║ URL INPUT ║"
|
|
332
|
+
)
|
|
333
|
+
print(
|
|
334
|
+
f"╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}"
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
print(f"\n{Colors.YELLOW}📝 Supported URL Examples:{Colors.ENDC}")
|
|
338
|
+
print(f" {Colors.CYAN}• arXiv: https://arxiv.org/pdf/2403.00813")
|
|
339
|
+
print(f" {Colors.CYAN}• arXiv: @https://arxiv.org/pdf/2403.00813")
|
|
340
|
+
print(f" {Colors.CYAN}• IEEE: https://ieeexplore.ieee.org/document/...")
|
|
341
|
+
print(f" {Colors.CYAN}• ACM: https://dl.acm.org/doi/...")
|
|
342
|
+
print(
|
|
343
|
+
f" {Colors.CYAN}• Direct PDF: https://example.com/paper.pdf{Colors.ENDC}"
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
print(
|
|
347
|
+
f"\n{Colors.BOLD}{Colors.OKCYAN}🌐 Enter paper URL: {Colors.ENDC}", end=""
|
|
348
|
+
)
|
|
349
|
+
url = input().strip()
|
|
350
|
+
|
|
351
|
+
if url:
|
|
352
|
+
# Basic URL validation
|
|
353
|
+
if any(
|
|
354
|
+
domain in url.lower()
|
|
355
|
+
for domain in ["arxiv.org", "ieee", "acm.org", ".pdf", "researchgate"]
|
|
356
|
+
):
|
|
357
|
+
self.print_status(f"URL received: {url}", "success")
|
|
358
|
+
return url
|
|
359
|
+
else:
|
|
360
|
+
self.print_status("URL appears valid, proceeding...", "info")
|
|
361
|
+
return url
|
|
362
|
+
else:
|
|
363
|
+
self.print_status("No URL provided", "warning")
|
|
364
|
+
return ""
|
|
365
|
+
|
|
366
|
+
def show_progress_bar(self, message: str, duration: float = 2.0):
|
|
367
|
+
"""Show a progress animation with enhanced styling"""
|
|
368
|
+
print(f"\n{Colors.YELLOW}{message}{Colors.ENDC}")
|
|
369
|
+
|
|
370
|
+
# Progress bar animation with different styles
|
|
371
|
+
bar_length = 50
|
|
372
|
+
for i in range(bar_length + 1):
|
|
373
|
+
percent = (i / bar_length) * 100
|
|
374
|
+
filled = "█" * i
|
|
375
|
+
empty = "░" * (bar_length - i)
|
|
376
|
+
|
|
377
|
+
# Color gradient effect
|
|
378
|
+
if percent < 33:
|
|
379
|
+
color = Colors.FAIL
|
|
380
|
+
elif percent < 66:
|
|
381
|
+
color = Colors.WARNING
|
|
382
|
+
else:
|
|
383
|
+
color = Colors.OKGREEN
|
|
384
|
+
|
|
385
|
+
print(
|
|
386
|
+
f"\r{color}[{filled}{empty}] {percent:6.1f}%{Colors.ENDC}",
|
|
387
|
+
end="",
|
|
388
|
+
flush=True,
|
|
389
|
+
)
|
|
390
|
+
time.sleep(duration / bar_length)
|
|
391
|
+
|
|
392
|
+
print(f"\n{Colors.OKGREEN}✅ {message} completed!{Colors.ENDC}\n")
|
|
393
|
+
|
|
394
|
+
def show_spinner(self, message: str, duration: float = 1.0):
|
|
395
|
+
"""Show a spinner animation"""
|
|
396
|
+
spinner_chars = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
397
|
+
end_time = time.time() + duration
|
|
398
|
+
|
|
399
|
+
while time.time() < end_time:
|
|
400
|
+
for char in spinner_chars:
|
|
401
|
+
print(
|
|
402
|
+
f"\r{Colors.CYAN}{char} {Colors.BOLD}{message}{Colors.ENDC}",
|
|
403
|
+
end="",
|
|
404
|
+
flush=True,
|
|
405
|
+
)
|
|
406
|
+
time.sleep(0.1)
|
|
407
|
+
if time.time() >= end_time:
|
|
408
|
+
break
|
|
409
|
+
|
|
410
|
+
print(f"\r{Colors.OKGREEN}✅ {Colors.BOLD}{message} - Done!{Colors.ENDC}")
|
|
411
|
+
|
|
412
|
+
def print_results_header(self):
|
|
413
|
+
"""Print results section header"""
|
|
414
|
+
header = f"""
|
|
415
|
+
{Colors.OKGREEN}╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
416
|
+
║ PROCESSING RESULTS ║
|
|
417
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}
|
|
418
|
+
"""
|
|
419
|
+
print(header)
|
|
420
|
+
|
|
421
|
+
def print_error_box(self, title: str, error_msg: str):
|
|
422
|
+
"""Print error message in a styled box"""
|
|
423
|
+
print(f"""
|
|
424
|
+
{Colors.FAIL}╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
425
|
+
║ ERROR ║
|
|
426
|
+
╠═══════════════════════════════════════════════════════════════════════════════╣
|
|
427
|
+
║ ║
|
|
428
|
+
║ {Colors.BOLD}Title: {title:<66}{Colors.FAIL}║
|
|
429
|
+
║ {Colors.BOLD}Error: {error_msg:<66}{Colors.FAIL}║
|
|
430
|
+
║ ║
|
|
431
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}
|
|
432
|
+
""")
|
|
433
|
+
|
|
434
|
+
def print_goodbye(self):
|
|
435
|
+
"""Print goodbye message"""
|
|
436
|
+
goodbye = f"""
|
|
437
|
+
{Colors.BOLD}{Colors.YELLOW}╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
438
|
+
║ GOODBYE! ║
|
|
439
|
+
╠═══════════════════════════════════════════════════════════════════════════════╣
|
|
440
|
+
║ ║
|
|
441
|
+
║ {Colors.CYAN}Thank you for using ReproAI! {Colors.YELLOW}║
|
|
442
|
+
║ {Colors.GREEN}🌟 Star us on GitHub: https://github.com/your-repo {Colors.YELLOW}║
|
|
443
|
+
║ {Colors.PURPLE}📧 Contact: support@reproai.com {Colors.YELLOW}║
|
|
444
|
+
║ {Colors.MAGENTA}🐛 Report issues: https://github.com/your-repo/issues {Colors.YELLOW}║
|
|
445
|
+
║ ║
|
|
446
|
+
║ {Colors.OKGREEN}✨ Happy coding! See you next time! ✨ {Colors.YELLOW}║
|
|
447
|
+
║ ║
|
|
448
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.ENDC}
|
|
449
|
+
"""
|
|
450
|
+
print(goodbye)
|
|
451
|
+
|
|
452
|
+
def ask_continue(self) -> bool:
|
|
453
|
+
"""Ask user if they want to continue"""
|
|
454
|
+
print(
|
|
455
|
+
f"\n{Colors.BOLD}{Colors.CYAN}Press Enter to continue or 'q' to quit: {Colors.ENDC}",
|
|
456
|
+
end="",
|
|
457
|
+
)
|
|
458
|
+
choice = input().strip().lower()
|
|
459
|
+
return choice not in ["q", "quit", "exit"]
|