namish10 commited on
Commit
ced3aa7
·
verified ·
1 Parent(s): 1f5632d

Upload app/api/main.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app/api/main.py +889 -0
app/api/main.py ADDED
@@ -0,0 +1,889 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ API Blueprint
3
+ Main API routes for ContextFlow Research
4
+ """
5
+
6
+ from flask import Blueprint, request, jsonify
7
+ from ..agents.study_orchestrator import StudyOrchestrator
8
+ from ..agents.doubt_predictor import DoubtPredictorAgent
9
+ from ..agents.behavioral_agent import BehavioralAgent
10
+ from ..agents.knowledge_graph_agent import KnowledgeGraphAgent
11
+ from ..agents.recall_agent import RecallAgent
12
+ from ..agents.peer_learning_agent import PeerLearningAgent
13
+ from ..agents.hand_gesture_agent import HandGestureAgent, GestureSignalMapper
14
+ from datetime import datetime
15
+ import uuid
16
+
17
+ api = Blueprint('api', __name__)
18
+
19
+ orchestrators = {}
20
+ gesture_agents = {}
21
+ gesture_mappers = {}
22
+
23
+
24
+ def get_orchestrator(user_id: str) -> StudyOrchestrator:
25
+ """Get or create orchestrator for user"""
26
+ if user_id not in orchestrators:
27
+ orchestrators[user_id] = StudyOrchestrator(user_id)
28
+ return orchestrators[user_id]
29
+
30
+
31
+ @api.route('/session/start', methods=['POST'])
32
+ def start_session():
33
+ """Start a new learning session"""
34
+ data = request.json
35
+ user_id = data.get('user_id', 'anonymous')
36
+ topic = data.get('topic', 'General')
37
+ subtopic = data.get('subtopic', '')
38
+
39
+ orchestrator = get_orchestrator(user_id)
40
+ session = orchestrator.start_session(topic, subtopic)
41
+
42
+ return jsonify({
43
+ 'session_id': session.session_id,
44
+ 'topic': topic,
45
+ 'predictions': [
46
+ {
47
+ 'doubt': p.predicted_doubt,
48
+ 'confidence': p.confidence,
49
+ 'explanation': p.suggested_explanation,
50
+ 'priority': p.priority
51
+ }
52
+ for p in session.predictions
53
+ ],
54
+ 'pending_reviews': len(orchestrator.state.pending_recalls),
55
+ 'peer_insights_count': len(orchestrator.state.peer_insights)
56
+ })
57
+
58
+
59
+ @api.route('/session/update', methods=['POST'])
60
+ def update_session():
61
+ """Update session with behavioral data"""
62
+ data = request.json
63
+ user_id = data.get('user_id', 'anonymous')
64
+ behavioral_data = data.get('behavioral_data', {})
65
+ captured_doubt = data.get('captured_doubt')
66
+
67
+ orchestrator = get_orchestrator(user_id)
68
+ orchestrator.update_session(behavioral_data, captured_doubt)
69
+
70
+ return jsonify({
71
+ 'status': 'updated',
72
+ 'active_predictions': orchestrator.state.active_predictions[-3:],
73
+ 'confusion_level': orchestrator.behavioral_agent.calculate_confusion_score(
74
+ orchestrator.state.current_session.behavioral_signals[-5:]
75
+ ) if orchestrator.state.current_session else 0
76
+ })
77
+
78
+
79
+ @api.route('/session/end', methods=['POST'])
80
+ def end_session():
81
+ """End learning session"""
82
+ data = request.json
83
+ user_id = data.get('user_id', 'anonymous')
84
+
85
+ orchestrator = get_orchestrator(user_id)
86
+ summary = orchestrator.end_session()
87
+
88
+ return jsonify(summary)
89
+
90
+
91
+ @api.route('/session/insights', methods=['GET'])
92
+ def get_insights():
93
+ """Get current session insights"""
94
+ user_id = request.args.get('user_id', 'anonymous')
95
+
96
+ orchestrator = get_orchestrator(user_id)
97
+ insights = orchestrator.get_active_insights()
98
+
99
+ return jsonify(insights)
100
+
101
+
102
+ @api.route('/predict/doubts', methods=['POST'])
103
+ def predict_doubts():
104
+ """Predict doubts for learning context"""
105
+ data = request.json
106
+ user_id = data.get('user_id', 'anonymous')
107
+ context = data.get('context', {})
108
+
109
+ agent = DoubtPredictorAgent(user_id)
110
+ predictions = agent.predict_doubts(context, top_k=5)
111
+
112
+ return jsonify({
113
+ 'predictions': [
114
+ {
115
+ 'doubt': p.predicted_doubt,
116
+ 'confidence': p.confidence,
117
+ 'explanation': p.suggested_explanation,
118
+ 'related_concepts': p.related_concepts,
119
+ 'priority': p.priority,
120
+ 'estimated_time': p.estimated_resolution_time,
121
+ 'prerequisites': p.prerequisite_topics
122
+ }
123
+ for p in predictions
124
+ ]
125
+ })
126
+
127
+
128
+ @api.route('/recommendations', methods=['POST'])
129
+ def get_recommendations():
130
+ """Get learning recommendations"""
131
+ data = request.json
132
+ user_id = data.get('user_id', 'anonymous')
133
+ context = data.get('context', {})
134
+
135
+ agent = DoubtPredictorAgent(user_id)
136
+ recommendations = agent.get_learning_recommendations(context)
137
+
138
+ return jsonify(recommendations)
139
+
140
+
141
+ @api.route('/behavior/track', methods=['POST'])
142
+ def track_behavior():
143
+ """Track behavioral signals"""
144
+ data = request.json
145
+ user_id = data.get('user_id', 'anonymous')
146
+ signals = data.get('signals', {})
147
+
148
+ agent = BehavioralAgent(user_id)
149
+ processed = agent.process_signals(signals)
150
+
151
+ confusion = agent.calculate_confusion_score(processed)
152
+
153
+ return jsonify({
154
+ 'signals_processed': len(processed),
155
+ 'confusion_score': confusion,
156
+ 'should_capture_doubt': confusion > 0.7,
157
+ 'summary': agent.get_behavior_summary()
158
+ })
159
+
160
+
161
+ @api.route('/behavior/heatmap', methods=['GET'])
162
+ def get_heatmap():
163
+ """Get heatmap data"""
164
+ user_id = request.args.get('user_id', 'anonymous')
165
+
166
+ agent = BehavioralAgent(user_id)
167
+ heatmap = agent.generate_heatmap_data()
168
+
169
+ return jsonify({
170
+ 'heatmap': heatmap
171
+ })
172
+
173
+
174
+ @api.route('/graph/add', methods=['POST'])
175
+ def add_to_graph():
176
+ """Add doubt to knowledge graph"""
177
+ data = request.json
178
+ user_id = data.get('user_id', 'anonymous')
179
+ doubt_data = data.get('doubt', {})
180
+
181
+ agent = KnowledgeGraphAgent(user_id)
182
+ node = agent.add_doubt_to_graph(doubt_data)
183
+
184
+ return jsonify({
185
+ 'node_id': node.node_id,
186
+ 'type': node.node_type,
187
+ 'label': node.label
188
+ })
189
+
190
+
191
+ @api.route('/graph/query', methods=['POST'])
192
+ def query_graph():
193
+ """Query knowledge graph"""
194
+ data = request.json
195
+ user_id = data.get('user_id', 'anonymous')
196
+ query = data.get('query', '')
197
+ top_k = data.get('top_k', 5)
198
+
199
+ agent = KnowledgeGraphAgent(user_id)
200
+ results = agent.graphrag_retrieve(query, top_k)
201
+
202
+ return jsonify({
203
+ 'results': results
204
+ })
205
+
206
+
207
+ @api.route('/graph/stats', methods=['GET'])
208
+ def get_graph_stats():
209
+ """Get graph statistics"""
210
+ user_id = request.args.get('user_id', 'anonymous')
211
+
212
+ agent = KnowledgeGraphAgent(user_id)
213
+ stats = agent.get_graph_stats()
214
+
215
+ return jsonify(stats)
216
+
217
+
218
+ @api.route('/graph/path', methods=['GET'])
219
+ def find_learning_path():
220
+ """Find learning path between topics"""
221
+ from_topic = request.args.get('from', '')
222
+ to_topic = request.args.get('to', '')
223
+ user_id = request.args.get('user_id', 'anonymous')
224
+
225
+ agent = KnowledgeGraphAgent(user_id)
226
+ path = agent.find_learning_path(from_topic, to_topic)
227
+
228
+ return jsonify({
229
+ 'path': path,
230
+ 'steps': len(path)
231
+ })
232
+
233
+
234
+ @api.route('/review/due', methods=['GET'])
235
+ def get_due_reviews():
236
+ """Get cards due for review"""
237
+ user_id = request.args.get('user_id', 'anonymous')
238
+ topic = request.args.get('topic')
239
+
240
+ agent = RecallAgent(user_id)
241
+ recalls = agent.get_due_recalls(topic)
242
+
243
+ return jsonify({
244
+ 'due_count': len(recalls),
245
+ 'cards': [
246
+ {
247
+ 'card_id': c.card_id,
248
+ 'front': c.front,
249
+ 'back': c.back,
250
+ 'topic': c.topic,
251
+ 'interval': c.interval,
252
+ 'ease_factor': c.ease_factor
253
+ }
254
+ for c in recalls[:20]
255
+ ]
256
+ })
257
+
258
+
259
+ @api.route('/review/complete', methods=['POST'])
260
+ def complete_review():
261
+ """Complete a review"""
262
+ data = request.json
263
+ user_id = data.get('user_id', 'anonymous')
264
+ card_id = data.get('card_id')
265
+ quality = data.get('quality', 3)
266
+
267
+ agent = RecallAgent(user_id)
268
+ result = agent.complete_review(card_id, quality)
269
+
270
+ if result:
271
+ return jsonify({
272
+ 'card_id': result.card_id,
273
+ 'quality': result.quality,
274
+ 'xp_earned': result.xp_earned,
275
+ 'next_interval': result.new_interval,
276
+ 'next_review': result.next_review.isoformat()
277
+ })
278
+
279
+ return jsonify({'error': 'Card not found'}), 404
280
+
281
+
282
+ @api.route('/review/stats', methods=['GET'])
283
+ def get_review_stats():
284
+ """Get review statistics"""
285
+ user_id = request.args.get('user_id', 'anonymous')
286
+
287
+ agent = RecallAgent(user_id)
288
+ stats = agent.get_review_stats()
289
+ progress = agent.get_learning_progress()
290
+
291
+ return jsonify({
292
+ 'stats': stats,
293
+ 'progress': progress
294
+ })
295
+
296
+
297
+ @api.route('/peer/insights', methods=['GET'])
298
+ def get_peer_insights():
299
+ """Get peer insights"""
300
+ topic = request.args.get('topic', 'General')
301
+
302
+ agent = PeerLearningAgent('anonymous')
303
+ insights = agent.get_peer_insights(topic)
304
+
305
+ return jsonify({
306
+ 'insights': [
307
+ {
308
+ 'type': i.insight_type,
309
+ 'content': i.content,
310
+ 'related_topics': i.related_topics,
311
+ 'confidence': i.confidence,
312
+ 'peer_count': i.peer_count
313
+ }
314
+ for i in insights
315
+ ]
316
+ })
317
+
318
+
319
+ @api.route('/peer/doubts', methods=['GET'])
320
+ def get_peer_doubts():
321
+ """Get peer doubts"""
322
+ topic = request.args.get('topic', 'General')
323
+ limit = int(request.args.get('limit', 10))
324
+
325
+ agent = PeerLearningAgent('anonymous')
326
+ doubts = agent.get_peer_doubts(topic, limit)
327
+
328
+ return jsonify({
329
+ 'doubts': [
330
+ {
331
+ 'id': d.doubt_id,
332
+ 'content': d.content,
333
+ 'resolved': d.resolved,
334
+ 'upvotes': d.upvotes,
335
+ 'similarity': d.similarity_score
336
+ }
337
+ for d in doubts
338
+ ]
339
+ })
340
+
341
+
342
+ @api.route('/peer/trending', methods=['GET'])
343
+ def get_trending():
344
+ """Get trending topics"""
345
+ agent = PeerLearningAgent('anonymous')
346
+ trending = agent.get_trending_topics()
347
+
348
+ return jsonify({
349
+ 'trending': trending
350
+ })
351
+
352
+
353
+ @api.route('/health', methods=['GET'])
354
+ def health():
355
+ """Health check"""
356
+ return jsonify({
357
+ 'status': 'healthy',
358
+ 'service': 'ContextFlow Research API',
359
+ 'timestamp': datetime.now().isoformat(),
360
+ 'active_sessions': len(orchestrators)
361
+ })
362
+
363
+
364
+ # ===== Hand Gesture Training API =====
365
+
366
+ def get_gesture_agent(user_id: str) -> HandGestureAgent:
367
+ """Get or create gesture agent for user"""
368
+ if user_id not in gesture_agents:
369
+ gesture_agents[user_id] = HandGestureAgent(user_id)
370
+ return gesture_agents[user_id]
371
+
372
+
373
+ def get_gesture_mapper(user_id: str) -> GestureSignalMapper:
374
+ """Get or create gesture mapper for user"""
375
+ if user_id not in gesture_mappers:
376
+ gesture_mappers[user_id] = GestureSignalMapper()
377
+ return gesture_mappers[user_id]
378
+
379
+
380
+ @api.route('/gesture/list', methods=['GET'])
381
+ def list_gestures():
382
+ """List all available gestures"""
383
+ user_id = request.args.get('user_id', 'anonymous')
384
+ agent = get_gesture_agent(user_id)
385
+ gestures = agent.get_trained_gestures()
386
+ return jsonify({
387
+ 'gestures': gestures,
388
+ 'count': len(gestures)
389
+ })
390
+
391
+
392
+ @api.route('/gesture/add', methods=['POST'])
393
+ def add_gesture():
394
+ """Add a new custom gesture to train"""
395
+ data = request.json
396
+ user_id = data.get('user_id', 'anonymous')
397
+ name = data.get('name', 'Custom Gesture')
398
+ description = data.get('description', '')
399
+ gesture_type = data.get('type', 'custom')
400
+
401
+ agent = get_gesture_agent(user_id)
402
+ gesture_id = agent.add_custom_gesture(name, description, gesture_type)
403
+
404
+ return jsonify({
405
+ 'gesture_id': gesture_id,
406
+ 'name': name,
407
+ 'message': f"Added '{name}'. Start training to teach the model."
408
+ })
409
+
410
+
411
+ @api.route('/gesture/training/start', methods=['POST'])
412
+ def start_gesture_training():
413
+ """Start training a gesture"""
414
+ data = request.json
415
+ user_id = data.get('user_id', 'anonymous')
416
+ gesture_id = data.get('gesture_id')
417
+
418
+ agent = get_gesture_agent(user_id)
419
+ result = agent.start_training(gesture_id)
420
+
421
+ return jsonify(result)
422
+
423
+
424
+ @api.route('/gesture/training/sample', methods=['POST'])
425
+ def add_gesture_sample():
426
+ """Add a training sample (hand landmarks)"""
427
+ data = request.json
428
+ user_id = data.get('user_id', 'anonymous')
429
+ landmarks = data.get('landmarks', [])
430
+
431
+ agent = get_gesture_agent(user_id)
432
+ result = agent.add_training_sample(landmarks)
433
+
434
+ return jsonify(result)
435
+
436
+
437
+ @api.route('/gesture/training/cancel', methods=['POST'])
438
+ def cancel_gesture_training():
439
+ """Cancel current training"""
440
+ user_id = request.json.get('user_id', 'anonymous')
441
+ agent = get_gesture_agent(user_id)
442
+ agent.cancel_training()
443
+ return jsonify({'message': 'Training cancelled'})
444
+
445
+
446
+ @api.route('/gesture/recognition/enable', methods=['POST'])
447
+ def enable_gesture_recognition():
448
+ """Enable real-time gesture recognition"""
449
+ data = request.json
450
+ user_id = data.get('user_id', 'anonymous')
451
+
452
+ agent = get_gesture_agent(user_id)
453
+ result = agent.enable_recognition()
454
+
455
+ return jsonify(result)
456
+
457
+
458
+ @api.route('/gesture/recognition/disable', methods=['POST'])
459
+ def disable_gesture_recognition():
460
+ """Disable gesture recognition"""
461
+ user_id = request.json.get('user_id', 'anonymous')
462
+ agent = get_gesture_agent(user_id)
463
+ result = agent.disable_recognition()
464
+ return jsonify(result)
465
+
466
+
467
+ @api.route('/gesture/recognize', methods=['POST'])
468
+ def recognize_gesture():
469
+ """Recognize gesture from landmarks"""
470
+ data = request.json
471
+ user_id = data.get('user_id', 'anonymous')
472
+ landmarks = data.get('landmarks', [])
473
+
474
+ agent = get_gesture_agent(user_id)
475
+ recognition = agent.recognize(landmarks)
476
+
477
+ if recognition:
478
+ mapper = get_gesture_mapper(user_id)
479
+ signal = mapper.map_to_signal(recognition)
480
+
481
+ return jsonify({
482
+ 'recognized': True,
483
+ 'gesture': {
484
+ 'name': recognition.gesture_name,
485
+ 'confidence': recognition.confidence,
486
+ 'type': recognition.gesture_type
487
+ },
488
+ 'signal': signal
489
+ })
490
+
491
+ return jsonify({'recognized': False})
492
+
493
+
494
+ @api.route('/gesture/delete', methods=['POST'])
495
+ def delete_gesture():
496
+ """Delete a gesture"""
497
+ data = request.json
498
+ user_id = data.get('user_id', 'anonymous')
499
+ gesture_id = data.get('gesture_id')
500
+
501
+ agent = get_gesture_agent(user_id)
502
+ result = agent.delete_gesture(gesture_id)
503
+ return jsonify(result)
504
+
505
+
506
+ @api.route('/gesture/export', methods=['GET'])
507
+ def export_gestures():
508
+ """Export gesture model"""
509
+ user_id = request.args.get('user_id', 'anonymous')
510
+ agent = get_gesture_agent(user_id)
511
+ model = agent.export_model()
512
+ return jsonify(model)
513
+
514
+
515
+ @api.route('/gesture/import', methods=['POST'])
516
+ def import_gestures():
517
+ """Import gesture model"""
518
+ data = request.json
519
+ user_id = data.get('user_id', 'anonymous')
520
+ model_data = data.get('model', {})
521
+
522
+ agent = get_gesture_agent(user_id)
523
+ agent.import_model(model_data)
524
+
525
+ return jsonify({'success': True, 'message': 'Gesture model imported'})
526
+
527
+
528
+ # ===== LLM Flow API =====
529
+
530
+ from ..agents.llm_orchestrator_agent import LLMOrchestrator, LLMRequest, LLMProvider
531
+ from ..agents.gesture_action_agent import GestureActionMapper, RLLearningLoop, GestureAction
532
+ from ..agents.prompt_agent import PromptAgent, AutoSubmitAgent
533
+
534
+ llm_orchestrators = {}
535
+ gesture_action_mappers = {}
536
+ rl_loops = {}
537
+ prompt_agents = {}
538
+ auto_submit_agents = {}
539
+
540
+
541
+ def get_llm_orchestrator(user_id: str) -> LLMOrchestrator:
542
+ """Get or create LLM orchestrator for user"""
543
+ if user_id not in llm_orchestrators:
544
+ llm_orchestrators[user_id] = LLMOrchestrator()
545
+ return llm_orchestrators[user_id]
546
+
547
+
548
+ def get_gesture_action_mapper(user_id: str) -> GestureActionMapper:
549
+ """Get or create gesture action mapper for user"""
550
+ if user_id not in gesture_action_mappers:
551
+ gesture_action_mappers[user_id] = GestureActionMapper()
552
+ return gesture_action_mappers[user_id]
553
+
554
+
555
+ def get_rl_loop(user_id: str) -> RLLearningLoop:
556
+ """Get or create RL learning loop for user"""
557
+ if user_id not in rl_loops:
558
+ rl_loops[user_id] = RLLearningLoop(user_id)
559
+ return rl_loops[user_id]
560
+
561
+
562
+ def get_prompt_agent(user_id: str) -> PromptAgent:
563
+ """Get or create prompt agent for user"""
564
+ if user_id not in prompt_agents:
565
+ prompt_agents[user_id] = PromptAgent()
566
+ return prompt_agents[user_id]
567
+
568
+
569
+ def get_auto_submit_agent(user_id: str) -> AutoSubmitAgent:
570
+ """Get or create auto submit agent for user"""
571
+ if user_id not in auto_submit_agents:
572
+ prompt_agent = get_prompt_agent(user_id)
573
+ auto_submit_agents[user_id] = AutoSubmitAgent(prompt_agent)
574
+ return auto_submit_agents[user_id]
575
+
576
+
577
+ @api.route('/llm/query', methods=['POST'])
578
+ def llm_query():
579
+ """Query LLM with prompt"""
580
+ data = request.json
581
+ user_id = data.get('user_id', 'anonymous')
582
+ prompt = data.get('prompt', '')
583
+ system_prompt = data.get('system_prompt', 'You are a helpful learning assistant.')
584
+ providers = data.get('providers', ['chatgpt', 'gemini'])
585
+ api_keys = data.get('api_keys', {})
586
+ models = data.get('models', {})
587
+
588
+ llm_provider_map = {
589
+ 'chatgpt': LLMProvider.CHATGPT,
590
+ 'gemini': LLMProvider.GEMINI,
591
+ 'claude': LLMProvider.CLAUDE,
592
+ 'deepseek': LLMProvider.DEEPSEEK,
593
+ 'ollama': LLMProvider.OLLAMA,
594
+ 'groq': LLMProvider.GROQ
595
+ }
596
+
597
+ provider_enums = [llm_provider_map.get(p, LLMProvider.CHATGPT) for p in providers]
598
+
599
+ orchestrator = get_llm_orchestrator(user_id)
600
+
601
+ for provider_name, api_key in api_keys.items():
602
+ if api_key:
603
+ orchestrator.api_keys[provider_name] = api_key
604
+
605
+ for provider_name, model in models.items():
606
+ if provider_name in orchestrator.provider_configs:
607
+ config = orchestrator.provider_configs[provider_name]
608
+ if isinstance(config, dict):
609
+ config['model'] = model
610
+ config['model_name'] = model
611
+
612
+ request_obj = LLMRequest(
613
+ prompt=prompt,
614
+ system_prompt=system_prompt,
615
+ providers=provider_enums,
616
+ user_id=user_id,
617
+ models=models
618
+ )
619
+
620
+ responses = orchestrator.query_parallel(request_obj)
621
+
622
+ return jsonify({
623
+ 'responses': [
624
+ {
625
+ 'provider': r.provider.value,
626
+ 'content': r.content,
627
+ 'success': r.success,
628
+ 'error': r.error,
629
+ 'latency_ms': r.latency_ms
630
+ }
631
+ for r in responses
632
+ ],
633
+ 'rate_limits': orchestrator.get_rate_limit_status()
634
+ })
635
+
636
+
637
+ @api.route('/llm/rate-limits', methods=['GET'])
638
+ def get_rate_limits():
639
+ """Get current rate limit status"""
640
+ user_id = request.args.get('user_id', 'anonymous')
641
+ orchestrator = get_llm_orchestrator(user_id)
642
+ return jsonify(orchestrator.get_rate_limit_status())
643
+
644
+
645
+ @api.route('/llm/gesture-action', methods=['POST'])
646
+ def gesture_action():
647
+ """Process gesture and trigger LLM action"""
648
+ data = request.json
649
+ user_id = data.get('user_id', 'anonymous')
650
+ landmarks = data.get('landmarks', [])
651
+ context = data.get('context', {})
652
+
653
+ mapper = get_gesture_action_mapper(user_id)
654
+ events = mapper.process_landmarks(landmarks, context)
655
+
656
+ results = []
657
+ for event in events:
658
+ orchestrator = get_llm_orchestrator(user_id)
659
+ rl_loop = get_rl_loop(user_id)
660
+ executed_event = mapper.execute_action(event, orchestrator, rl_loop)
661
+
662
+ results.append({
663
+ 'action': executed_event.action.value,
664
+ 'gesture': executed_event.gesture_name,
665
+ 'confidence': executed_event.confidence,
666
+ 'llm_responses': executed_event.llm_responses,
667
+ 'rl_feedback': executed_event.rl_feedback
668
+ })
669
+
670
+ return jsonify({
671
+ 'events': results,
672
+ 'available_actions': mapper.get_available_actions()
673
+ })
674
+
675
+
676
+ @api.route('/llm/gesture-actions', methods=['GET'])
677
+ def get_available_gesture_actions():
678
+ """Get available gesture actions"""
679
+ user_id = request.args.get('user_id', 'anonymous')
680
+ mapper = get_gesture_action_mapper(user_id)
681
+ return jsonify({
682
+ 'actions': mapper.get_available_actions()
683
+ })
684
+
685
+
686
+ @api.route('/llm/rl/start', methods=['POST'])
687
+ def start_rl_loop():
688
+ """Start RL learning loop"""
689
+ data = request.json
690
+ user_id = data.get('user_id', 'anonymous')
691
+ context = data.get('context', {})
692
+
693
+ rl_loop = get_rl_loop(user_id)
694
+ rl_loop.start_loop(context)
695
+
696
+ return jsonify({
697
+ 'status': 'started',
698
+ 'user_id': user_id
699
+ })
700
+
701
+
702
+ @api.route('/llm/rl/interact', methods=['POST'])
703
+ def rl_interact():
704
+ """Add interaction to RL loop"""
705
+ data = request.json
706
+ user_id = data.get('user_id', 'anonymous')
707
+ action = data.get('action', '')
708
+ response = data.get('response', '')
709
+
710
+ rl_loop = get_rl_loop(user_id)
711
+ rl_loop.add_interaction(action, response)
712
+
713
+ return jsonify({
714
+ 'status': 'recorded',
715
+ 'total_interactions': len(rl_loop.conversation_history)
716
+ })
717
+
718
+
719
+ @api.route('/llm/rl/feedback', methods=['POST'])
720
+ def rl_feedback():
721
+ """Add feedback to RL loop"""
722
+ data = request.json
723
+ user_id = data.get('user_id', 'anonymous')
724
+ quality = data.get('quality', 3)
725
+ comment = data.get('comment')
726
+
727
+ rl_loop = get_rl_loop(user_id)
728
+ rl_loop.add_feedback(quality, comment)
729
+
730
+ return jsonify({
731
+ 'status': 'feedback_recorded',
732
+ 'average_reward': sum(rl_loop.reward_history) / len(rl_loop.reward_history) if rl_loop.reward_history else 0
733
+ })
734
+
735
+
736
+ @api.route('/llm/rl/status', methods=['GET'])
737
+ def get_rl_status():
738
+ """Get RL loop status"""
739
+ user_id = request.args.get('user_id', 'anonymous')
740
+ rl_loop = get_rl_loop(user_id)
741
+ return jsonify(rl_loop.get_status())
742
+
743
+
744
+ @api.route('/llm/rl/end', methods=['POST'])
745
+ def end_rl_loop():
746
+ """End RL learning loop"""
747
+ data = request.json
748
+ user_id = data.get('user_id', 'anonymous')
749
+
750
+ rl_loop = get_rl_loop(user_id)
751
+ rl_loop.end_loop()
752
+
753
+ return jsonify({
754
+ 'status': 'ended',
755
+ 'summary': rl_loop.get_status()
756
+ })
757
+
758
+
759
+ @api.route('/llm/prompt/generate', methods=['POST'])
760
+ def generate_prompt():
761
+ """Generate prompt from template"""
762
+ data = request.json
763
+ user_id = data.get('user_id', 'anonymous')
764
+ template = data.get('template', 'learning_explain')
765
+ context = data.get('context', {})
766
+
767
+ prompt_agent = get_prompt_agent(user_id)
768
+ prompt_agent.update_context(context)
769
+
770
+ prompt = prompt_agent.generate_prompt(template, context)
771
+
772
+ return jsonify({
773
+ 'prompt': prompt.content,
774
+ 'template': prompt.template_used,
775
+ 'llm_targets': prompt.llm_targets,
776
+ 'auto_submit': prompt.auto_submit
777
+ })
778
+
779
+
780
+ @api.route('/llm/prompt/from-gesture', methods=['POST'])
781
+ def generate_prompt_from_gesture():
782
+ """Generate prompt based on gesture action"""
783
+ data = request.json
784
+ user_id = data.get('user_id', 'anonymous')
785
+ gesture = data.get('gesture', '')
786
+ context = data.get('context', {})
787
+
788
+ prompt_agent = get_prompt_agent(user_id)
789
+ prompt = prompt_agent.generate_from_gesture(gesture, context)
790
+
791
+ return jsonify({
792
+ 'prompt': prompt.content,
793
+ 'template': prompt.template_used,
794
+ 'llm_targets': prompt.llm_targets,
795
+ 'auto_submit': prompt.auto_submit
796
+ })
797
+
798
+
799
+ @api.route('/llm/prompt/suggest', methods=['GET'])
800
+ def suggest_prompts():
801
+ """Get suggested prompts based on context"""
802
+ user_id = request.args.get('user_id', 'anonymous')
803
+ context_str = request.args.get('context', '{}')
804
+
805
+ import json
806
+ context = json.loads(context_str)
807
+
808
+ prompt_agent = get_prompt_agent(user_id)
809
+ suggestions = prompt_agent.get_suggested_prompts(context)
810
+
811
+ return jsonify({
812
+ 'suggestions': [
813
+ {
814
+ 'prompt': s.content,
815
+ 'template': s.template_used,
816
+ 'llm_targets': s.llm_targets
817
+ }
818
+ for s in suggestions
819
+ ]
820
+ })
821
+
822
+
823
+ @api.route('/llm/auto-submit/prepare', methods=['POST'])
824
+ def prepare_auto_submit():
825
+ """Prepare prompt for auto submission"""
826
+ data = request.json
827
+ user_id = data.get('user_id', 'anonymous')
828
+ prompt_content = data.get('prompt', '')
829
+ template = data.get('template')
830
+
831
+ prompt_agent = get_prompt_agent(user_id)
832
+ from ..agents.prompt_agent import GeneratedPrompt
833
+
834
+ prompt = GeneratedPrompt(
835
+ content=prompt_content,
836
+ template_used=template,
837
+ context={},
838
+ llm_targets=['chatgpt'],
839
+ auto_submit=True
840
+ )
841
+
842
+ auto_submit = get_auto_submit_agent(user_id)
843
+ submission = auto_submit.prepare_submission(prompt)
844
+
845
+ return jsonify({
846
+ 'status': 'ready',
847
+ 'submission_id': len(submission)
848
+ })
849
+
850
+
851
+ @api.route('/llm/auto-submit/status', methods=['GET'])
852
+ def get_auto_submit_status():
853
+ """Get auto submit status"""
854
+ user_id = request.args.get('user_id', 'anonymous')
855
+ auto_submit = get_auto_submit_agent(user_id)
856
+ return jsonify(auto_submit.get_submission_status())
857
+
858
+
859
+ @api.route('/llm/gesture-training/swipe', methods=['POST'])
860
+ def train_swipe_gesture():
861
+ """Train a swipe gesture"""
862
+ data = request.json
863
+ user_id = data.get('user_id', 'anonymous')
864
+ gesture_name = data.get('gesture_name', 'swipe_right')
865
+ action = data.get('action', 'query_multi_llm')
866
+ finger_count = data.get('finger_count', 2)
867
+
868
+ mapper = get_gesture_action_mapper(user_id)
869
+
870
+ gesture_pattern = {
871
+ 'type': 'swipe',
872
+ 'finger_count': finger_count,
873
+ 'name': gesture_name
874
+ }
875
+
876
+ action_enum = GestureAction(action) if action in [a.value for a in GestureAction] else GestureAction.CUSTOM
877
+
878
+ mapper.add_custom_mapping(
879
+ name=gesture_name,
880
+ gesture_pattern=gesture_pattern,
881
+ action=action_enum,
882
+ parameters={'user_defined': True}
883
+ )
884
+
885
+ return jsonify({
886
+ 'success': True,
887
+ 'gesture_name': gesture_name,
888
+ 'action': action_enum.value
889
+ })