arionxiv 1.0.32__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.
- arionxiv/__init__.py +40 -0
- arionxiv/__main__.py +10 -0
- arionxiv/arxiv_operations/__init__.py +0 -0
- arionxiv/arxiv_operations/client.py +225 -0
- arionxiv/arxiv_operations/fetcher.py +173 -0
- arionxiv/arxiv_operations/searcher.py +122 -0
- arionxiv/arxiv_operations/utils.py +293 -0
- arionxiv/cli/__init__.py +4 -0
- arionxiv/cli/commands/__init__.py +1 -0
- arionxiv/cli/commands/analyze.py +587 -0
- arionxiv/cli/commands/auth.py +365 -0
- arionxiv/cli/commands/chat.py +714 -0
- arionxiv/cli/commands/daily.py +482 -0
- arionxiv/cli/commands/fetch.py +217 -0
- arionxiv/cli/commands/library.py +295 -0
- arionxiv/cli/commands/preferences.py +426 -0
- arionxiv/cli/commands/search.py +254 -0
- arionxiv/cli/commands/settings_unified.py +1407 -0
- arionxiv/cli/commands/trending.py +41 -0
- arionxiv/cli/commands/welcome.py +168 -0
- arionxiv/cli/main.py +407 -0
- arionxiv/cli/ui/__init__.py +1 -0
- arionxiv/cli/ui/global_theme_manager.py +173 -0
- arionxiv/cli/ui/logo.py +127 -0
- arionxiv/cli/ui/splash.py +89 -0
- arionxiv/cli/ui/theme.py +32 -0
- arionxiv/cli/ui/theme_system.py +391 -0
- arionxiv/cli/utils/__init__.py +54 -0
- arionxiv/cli/utils/animations.py +522 -0
- arionxiv/cli/utils/api_client.py +583 -0
- arionxiv/cli/utils/api_config.py +505 -0
- arionxiv/cli/utils/command_suggestions.py +147 -0
- arionxiv/cli/utils/db_config_manager.py +254 -0
- arionxiv/github_actions_runner.py +206 -0
- arionxiv/main.py +23 -0
- arionxiv/prompts/__init__.py +9 -0
- arionxiv/prompts/prompts.py +247 -0
- arionxiv/rag_techniques/__init__.py +8 -0
- arionxiv/rag_techniques/basic_rag.py +1531 -0
- arionxiv/scheduler_daemon.py +139 -0
- arionxiv/server.py +1000 -0
- arionxiv/server_main.py +24 -0
- arionxiv/services/__init__.py +73 -0
- arionxiv/services/llm_client.py +30 -0
- arionxiv/services/llm_inference/__init__.py +58 -0
- arionxiv/services/llm_inference/groq_client.py +469 -0
- arionxiv/services/llm_inference/llm_utils.py +250 -0
- arionxiv/services/llm_inference/openrouter_client.py +564 -0
- arionxiv/services/unified_analysis_service.py +872 -0
- arionxiv/services/unified_auth_service.py +457 -0
- arionxiv/services/unified_config_service.py +456 -0
- arionxiv/services/unified_daily_dose_service.py +823 -0
- arionxiv/services/unified_database_service.py +1633 -0
- arionxiv/services/unified_llm_service.py +366 -0
- arionxiv/services/unified_paper_service.py +604 -0
- arionxiv/services/unified_pdf_service.py +522 -0
- arionxiv/services/unified_prompt_service.py +344 -0
- arionxiv/services/unified_scheduler_service.py +589 -0
- arionxiv/services/unified_user_service.py +954 -0
- arionxiv/utils/__init__.py +51 -0
- arionxiv/utils/api_helpers.py +200 -0
- arionxiv/utils/file_cleanup.py +150 -0
- arionxiv/utils/ip_helper.py +96 -0
- arionxiv-1.0.32.dist-info/METADATA +336 -0
- arionxiv-1.0.32.dist-info/RECORD +69 -0
- arionxiv-1.0.32.dist-info/WHEEL +5 -0
- arionxiv-1.0.32.dist-info/entry_points.txt +4 -0
- arionxiv-1.0.32.dist-info/licenses/LICENSE +21 -0
- arionxiv-1.0.32.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import signal
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from .services.unified_scheduler_service import unified_scheduler
|
|
8
|
+
from .services.unified_config_service import unified_config_service
|
|
9
|
+
from .services.unified_database_service import unified_database_service
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
class SchedulerDaemon:
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self.running = False
|
|
16
|
+
self.scheduler = unified_scheduler
|
|
17
|
+
|
|
18
|
+
async def start(self):
|
|
19
|
+
try:
|
|
20
|
+
logger.info("Initializing scheduler daemon")
|
|
21
|
+
|
|
22
|
+
unified_config_service.setup_logging()
|
|
23
|
+
|
|
24
|
+
await unified_database_service.connect_mongodb()
|
|
25
|
+
logger.info("Connected to MongoDB")
|
|
26
|
+
|
|
27
|
+
await self.scheduler.start()
|
|
28
|
+
logger.info("Scheduler started successfully")
|
|
29
|
+
|
|
30
|
+
await self._schedule_user_daily_doses()
|
|
31
|
+
|
|
32
|
+
self.running = True
|
|
33
|
+
|
|
34
|
+
while self.running:
|
|
35
|
+
await asyncio.sleep(60)
|
|
36
|
+
await self._check_and_update_schedules()
|
|
37
|
+
|
|
38
|
+
except Exception as e:
|
|
39
|
+
logger.error(f"Scheduler daemon error: {e}", exc_info=True)
|
|
40
|
+
raise
|
|
41
|
+
|
|
42
|
+
async def _schedule_user_daily_doses(self):
|
|
43
|
+
"""Schedule daily doses for all users who have it enabled"""
|
|
44
|
+
try:
|
|
45
|
+
logger.info("Scheduling user daily doses")
|
|
46
|
+
|
|
47
|
+
users = await unified_database_service.get_all_active_users()
|
|
48
|
+
scheduled_count = 0
|
|
49
|
+
|
|
50
|
+
for user in users:
|
|
51
|
+
try:
|
|
52
|
+
user_id = str(user['_id'])
|
|
53
|
+
preferences = user.get('preferences', {})
|
|
54
|
+
|
|
55
|
+
if preferences.get('daily_dose_enabled', False):
|
|
56
|
+
daily_time = preferences.get('daily_dose_time', '08:00')
|
|
57
|
+
|
|
58
|
+
result = await self.scheduler.schedule_user_daily_dose(
|
|
59
|
+
user_id=user_id,
|
|
60
|
+
time_str=daily_time,
|
|
61
|
+
days_back=1
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if result['success']:
|
|
65
|
+
scheduled_count += 1
|
|
66
|
+
logger.info(f"Scheduled daily dose for user {user_id} at {daily_time}")
|
|
67
|
+
else:
|
|
68
|
+
logger.error(f"Failed to schedule daily dose for user {user_id}: {result.get('error')}")
|
|
69
|
+
|
|
70
|
+
except Exception as e:
|
|
71
|
+
logger.error(f"Error scheduling daily dose for user {user.get('_id')}: {e}")
|
|
72
|
+
|
|
73
|
+
logger.info(f"Scheduled daily doses for {scheduled_count} users")
|
|
74
|
+
|
|
75
|
+
except Exception as e:
|
|
76
|
+
logger.error(f"Error in _schedule_user_daily_doses: {e}", exc_info=True)
|
|
77
|
+
|
|
78
|
+
async def _check_and_update_schedules(self):
|
|
79
|
+
"""Periodically check and update user schedules"""
|
|
80
|
+
try:
|
|
81
|
+
users = await unified_database_service.get_all_active_users()
|
|
82
|
+
|
|
83
|
+
for user in users:
|
|
84
|
+
try:
|
|
85
|
+
user_id = str(user['_id'])
|
|
86
|
+
preferences = user.get('preferences', {})
|
|
87
|
+
|
|
88
|
+
job_id = f'daily_dose_{user_id}'
|
|
89
|
+
job_exists = self.scheduler.scheduler.get_job(job_id) is not None
|
|
90
|
+
|
|
91
|
+
if preferences.get('daily_dose_enabled', False):
|
|
92
|
+
if not job_exists:
|
|
93
|
+
daily_time = preferences.get('daily_dose_time', '08:00')
|
|
94
|
+
await self.scheduler.schedule_user_daily_dose(
|
|
95
|
+
user_id=user_id,
|
|
96
|
+
time_str=daily_time,
|
|
97
|
+
days_back=1
|
|
98
|
+
)
|
|
99
|
+
logger.info(f"Re-scheduled daily dose for user {user_id}")
|
|
100
|
+
else:
|
|
101
|
+
if job_exists:
|
|
102
|
+
await self.scheduler.cancel_user_daily_dose(user_id)
|
|
103
|
+
logger.info(f"Cancelled daily dose for user {user_id}")
|
|
104
|
+
|
|
105
|
+
except Exception as e:
|
|
106
|
+
logger.error(f"Error checking schedule for user {user.get('_id')}: {e}")
|
|
107
|
+
|
|
108
|
+
except Exception as e:
|
|
109
|
+
logger.error(f"Error in _check_and_update_schedules: {e}")
|
|
110
|
+
|
|
111
|
+
async def stop(self):
|
|
112
|
+
logger.info("Stopping scheduler daemon")
|
|
113
|
+
self.running = False
|
|
114
|
+
await self.scheduler.stop()
|
|
115
|
+
await unified_database_service.disconnect()
|
|
116
|
+
logger.info("Scheduler daemon stopped")
|
|
117
|
+
|
|
118
|
+
def handle_signal(self, sig, frame):
|
|
119
|
+
logger.info(f"Received signal {sig}, shutting down")
|
|
120
|
+
self.running = False
|
|
121
|
+
|
|
122
|
+
def main():
|
|
123
|
+
daemon = SchedulerDaemon()
|
|
124
|
+
|
|
125
|
+
signal.signal(signal.SIGINT, daemon.handle_signal)
|
|
126
|
+
signal.signal(signal.SIGTERM, daemon.handle_signal)
|
|
127
|
+
|
|
128
|
+
async def run():
|
|
129
|
+
try:
|
|
130
|
+
await daemon.start()
|
|
131
|
+
except KeyboardInterrupt:
|
|
132
|
+
logger.info("Keyboard interrupt received")
|
|
133
|
+
finally:
|
|
134
|
+
await daemon.stop()
|
|
135
|
+
|
|
136
|
+
asyncio.run(run())
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
main()
|