add errorrate

This commit is contained in:
Aron Petau 2025-12-15 17:04:14 +01:00
parent dd192c012a
commit 4845d5d0dc
3 changed files with 100 additions and 9 deletions

View file

@ -1,6 +1,13 @@
Copy this to BotFather when setting commands with /setcommands: Autopilot bot command list for @BotFather
autopilot - Toggle automatic applications (on/off) Use @BotFather -> /setcommands and paste the following lines exactly (one per line):
status - Show current status and stats
plot - Show weekly listing patterns /autopilot - Enable or disable automatic applications. Usage: `/autopilot on` or `/autopilot off`
help - Show available commands /status - Show current status and statistics (autopilot state, application counts by company)
/plot - Show weekly listing patterns (image)
/errorrate - Show autopilot success vs failure plot (image)
/help - Show help and command usage
Example: send `/setcommands` to @BotFather, then paste the above lines and confirm.
Security reminder: set your bot privacy and only allow the trusted chat id to issue commands. Keep your `TELEGRAM_BOT_TOKEN` secret.

View file

@ -91,10 +91,13 @@ python monitor.py
## Telegram Commands ## Telegram Commands
- `/status` - Show current status and recent listings - `/autopilot on|off` - Enable or disable automatic applications (use `/autopilot on` or `/autopilot off`).
- `/autopilot` - Toggle auto-apply on/off - `/status` - Show current status and statistics (autopilot state, application counts by company).
- `/listings` - Show current listings - `/plot` - Generate and send a weekly listing-patterns plot (`data/weekly_plot.png`).
- `/help` - Show available commands - `/errorrate` - Generate and send an autopilot success vs failure plot (`data/error_rate.png`).
- `/help` - Show available commands and usage information.
Note: The bot only processes commands from the configured `TELEGRAM_CHAT_ID`. Use `/autopilot off` while testing selector changes or after modifying configuration to avoid accidental submissions.
## Data files ## Data files

View file

@ -185,6 +185,8 @@ class TelegramBot:
self._handle_help_command() self._handle_help_command()
elif text == "/plot": elif text == "/plot":
self._handle_plot_command() self._handle_plot_command()
elif text == "/errorrate":
self._handle_error_rate_command()
elif text.startswith("/"): elif text.startswith("/"):
self._handle_unknown_command(text) self._handle_unknown_command(text)
@ -235,6 +237,85 @@ When autopilot is ON, I will automatically apply to new listings."""
def _handle_unknown_command(self, text): def _handle_unknown_command(self, text):
cmd = text.split()[0] if text else text cmd = text.split()[0] if text else text
def _handle_error_rate_command(self):
"""Generate and send a plot showing success vs failure ratio for autopilot applications."""
logger.info("Generating autopilot errorrate plot...")
try:
plot_path, summary = self._generate_error_rate_plot()
if plot_path:
caption = "📉 <b>Autopilot Success vs Failure</b>\n\n" + summary
self._send_photo(plot_path, caption)
else:
self._send_message("📉 Not enough application data to generate errorrate plot.")
except Exception as e:
logger.error(f"Error generating errorrate plot: {e}")
import traceback
logger.error(traceback.format_exc())
self._send_message(f"❌ Error generating errorrate plot: {str(e)}")
def _generate_error_rate_plot(self):
"""Read applications.json and produce a plot image + summary text.
Returns (plot_path, summary_text) or (None, "") if insufficient data.
"""
if not APPLICATIONS_FILE.exists():
logger.warning("No applications.json found for errorrate plot")
return None, ""
try:
with open(APPLICATIONS_FILE, 'r', encoding='utf-8') as f:
apps = json.load(f)
if not apps:
return None, ""
# Convert to DataFrame
rows = []
for _id, rec in apps.items():
ts = rec.get('timestamp')
try:
dt = pd.to_datetime(ts)
except Exception:
dt = pd.NaT
rows.append({'id': _id, 'company': rec.get('company'), 'success': bool(rec.get('success')), 'ts': dt})
df = pd.DataFrame(rows)
df = df.dropna(subset=['ts'])
if df.empty:
return None, ""
df['date'] = df['ts'].dt.floor('D')
grouped = df.groupby('date').agg(total=('id','count'), successes=('success', lambda x: x.sum()))
grouped['failures'] = grouped['total'] - grouped['successes']
grouped['error_rate'] = grouped['failures'] / grouped['total']
# Prepare plot
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
grouped[['successes','failures']].plot(kind='bar', stacked=True, ax=ax1, color=['#2E8B57','#C44A4A'])
ax1.set_ylabel('Count')
ax1.set_title('Autopilot: Successes vs Failures (by day)')
ax2.plot(grouped.index, grouped['error_rate'], marker='o', color='#3333AA')
ax2.set_ylim(0,1)
ax2.set_ylabel('Error rate')
ax2.set_xlabel('Date')
ax2.set_title('Daily Error Rate (failures / total)')
plt.tight_layout()
plot_path = DATA_DIR / 'error_rate.png'
fig.savefig(plot_path)
plt.close(fig)
# Summary
total_attempts = int(grouped['total'].sum())
total_success = int(grouped['successes'].sum())
total_fail = int(grouped['failures'].sum())
overall_error = (total_fail / total_attempts) if total_attempts>0 else 0.0
summary = f"<b>Total attempts:</b> {total_attempts}\n<b>Successes:</b> {total_success}\n<b>Failures:</b> {total_fail}\n<b>Overall error rate:</b> {overall_error:.1%}"
return str(plot_path), summary
except Exception as e:
logger.exception(f"Failed to generate error rate plot: {e}")
return None, ""
self._send_message(f"❓ Unknown command: <code>{cmd}</code>\n\nUse /help to see available commands.") self._send_message(f"❓ Unknown command: <code>{cmd}</code>\n\nUse /help to see available commands.")
def _handle_plot_command(self): def _handle_plot_command(self):