-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathweb_app.py
More file actions
300 lines (247 loc) · 10.4 KB
/
web_app.py
File metadata and controls
300 lines (247 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
#!/usr/bin/env python3
"""
Web Interface for Enhanced Research Assistant
Provides a modern, interactive web UI for the research assistant
"""
import asyncio
import json
import os
from datetime import datetime
from flask import Flask, render_template, request, jsonify, session
from flask_socketio import SocketIO, emit
import uuid
from enhanced_research_assistant import EnhancedResearchAssistant
app = Flask(__name__)
app.config['SECRET_KEY'] = 'research_assistant_secret_key'
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')
# Global research assistant instance
research_assistant = None
active_sessions = {}
class WebResearchSession:
def __init__(self, session_id):
self.session_id = session_id
# Get OpenAI API key from environment
openai_api_key = os.getenv('OPENAI_API_KEY')
if not openai_api_key:
raise ValueError("OPENAI_API_KEY environment variable is required")
self.assistant = EnhancedResearchAssistant(openai_api_key)
self.is_processing = False
async def initialize(self):
"""Initialize the research assistant"""
self.assistant.setup_agents()
async def process_command(self, command, socketio_instance, session_id):
"""Process a command and emit updates via WebSocket"""
self.is_processing = True
try:
# Emit status update
socketio_instance.emit('status_update', {
'status': 'processing',
'message': f'Processing: {command[:50]}...'
}, room=session_id)
# Process the command
if command.lower().startswith('add '):
paper_input = command[4:].strip()
result = await self.assistant.add_new_paper(paper_input)
elif command.lower().startswith('search '):
query = command[7:].strip()
result = await self.assistant.search_related_papers(query)
elif command.lower().startswith('analyze '):
aspect = command[8:].strip()
result = await self.assistant.analyze_aspect(aspect)
elif command.lower() == 'summary':
result = await self.assistant.get_research_summary()
elif command.lower() == 'context':
result = self.assistant.get_context_summary()
elif command.lower().startswith('authors '):
author = command[8:].strip()
result = await self.assistant.investigate_authors(author)
elif command.lower() == 'refine proposal':
result = await self.assistant.refine_proposal()
elif command.lower().startswith('explore '):
direction = command[8:].strip()
result = await self.assistant.explore_direction(direction)
else:
result = await self.assistant.general_query(command)
# Emit the result
socketio_instance.emit('command_result', {
'command': command,
'result': result,
'timestamp': datetime.now().isoformat()
}, room=session_id)
# Update context summary
context_summary = self.assistant.get_context_summary()
socketio_instance.emit('context_update', {
'summary': context_summary
}, room=session_id)
except Exception as e:
socketio_instance.emit('error', {
'message': f'Error processing command: {str(e)}'
}, room=session_id)
finally:
self.is_processing = False
socketio_instance.emit('status_update', {
'status': 'ready',
'message': 'Ready for next command'
}, room=session_id)
@app.route('/')
def index():
"""Main page"""
return render_template('index.html')
@app.route('/api/session/new', methods=['POST'])
def new_session():
"""Create a new research session"""
session_id = str(uuid.uuid4())
session['session_id'] = session_id
# Create new research session
web_session = WebResearchSession(session_id)
active_sessions[session_id] = web_session
return jsonify({
'session_id': session_id,
'status': 'created'
})
@app.route('/api/context/load', methods=['POST'])
def load_context():
"""Load existing research context"""
session_id = session.get('session_id')
if not session_id or session_id not in active_sessions:
return jsonify({'error': 'No active session'}), 400
try:
web_session = active_sessions[session_id]
filename = request.json.get('filename', 'research_context.json')
# Load context in the assistant
if os.path.exists(filename):
web_session.assistant.load_context(filename)
context_summary = web_session.assistant.get_context_summary()
return jsonify({
'status': 'loaded',
'context_summary': context_summary
})
else:
return jsonify({'error': 'Context file not found'}), 404
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/context/save', methods=['POST'])
def save_context():
"""Save current research context"""
session_id = session.get('session_id')
if not session_id or session_id not in active_sessions:
return jsonify({'error': 'No active session'}), 400
try:
web_session = active_sessions[session_id]
filename = request.json.get('filename', 'research_context.json')
web_session.assistant.save_context(filename)
return jsonify({
'status': 'saved',
'filename': filename
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@socketio.on('connect')
def handle_connect():
"""Handle WebSocket connection"""
# Create a new session for this connection
session_id = str(uuid.uuid4())
session['session_id'] = session_id
# Create new research session
try:
openai_api_key = os.getenv('OPENAI_API_KEY')
if not openai_api_key:
emit('error', {'message': 'OPENAI_API_KEY not configured'})
return
web_session = WebResearchSession(session_id)
active_sessions[session_id] = web_session
# Join the session room
from flask_socketio import join_room
join_room(session_id)
emit('connected', {
'session_id': session_id,
'message': 'Connected to research assistant'
})
# Auto-initialize the session
def init_sync():
try:
# Initialize the research assistant
web_session.assistant.setup_agents()
# Try to load existing context
if os.path.exists('research_context.json'):
web_session.assistant.load_context('research_context.json')
context_summary = web_session.assistant.get_context_summary()
socketio.emit('session_initialized', {
'status': 'ready',
'context_loaded': True,
'context_summary': context_summary
}, room=session_id)
else:
socketio.emit('session_initialized', {
'status': 'ready',
'context_loaded': False,
'message': 'New research session started'
}, room=session_id)
except Exception as e:
socketio.emit('error', {
'message': f'Failed to initialize session: {str(e)}'
}, room=session_id)
# Run initialization in background thread
import threading
threading.Thread(target=init_sync).start()
except Exception as e:
emit('error', {'message': f'Failed to create session: {str(e)}'})
@socketio.on('execute_command')
def handle_execute_command(data):
"""Execute a research command"""
session_id = session.get('session_id')
if not session_id or session_id not in active_sessions:
emit('error', {'message': 'No active session'})
return
command = data.get('command', '').strip()
if not command:
emit('error', {'message': 'Empty command'})
return
web_session = active_sessions[session_id]
if web_session.is_processing:
emit('error', {'message': 'Another command is already being processed'})
return
def process_sync():
try:
# Run async command processing in new event loop
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(web_session.process_command(command, socketio, session_id))
except Exception as e:
socketio.emit('error', {
'message': f'Error processing command: {str(e)}'
}, room=session_id)
finally:
loop.close()
# Process command in background thread
import threading
threading.Thread(target=process_sync).start()
@socketio.on('add_paper')
def handle_add_paper(data):
"""Handle adding a new paper"""
session_id = session.get('session_id')
if not session_id or session_id not in active_sessions:
emit('error', {'message': 'No active session'})
return
paper_input = data.get('paper_input', '').strip()
if not paper_input:
emit('error', {'message': 'No paper input provided'})
return
# Execute add command
command = f"add {paper_input}"
handle_execute_command({'command': command})
@socketio.on('disconnect')
def handle_disconnect():
"""Handle WebSocket disconnection"""
session_id = session.get('session_id')
if session_id:
from flask_socketio import leave_room
leave_room(session_id)
def run_web_app(host='0.0.0.0', port=52609, debug=False):
"""Run the web application"""
print(f"🌐 Starting Research Assistant Web Interface...")
print(f"📍 Access at: http://localhost:{port}")
print(f"🔧 Debug mode: {debug}")
socketio.run(app, host=host, port=port, debug=debug, allow_unsafe_werkzeug=True)
if __name__ == '__main__':
run_web_app(debug=True)