diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d9875ed --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +# Telegram Bot Configuration +# Get your bot token from @BotFather on Telegram +# Format: 123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11 +TELEGRAM_TOKEN=your_bot_token_here + +# Optional: Production environment flag +ENVIRONMENT=development \ No newline at end of file diff --git a/README.md b/README.md index 8d1c8b6..d8acecf 100644 --- a/README.md +++ b/README.md @@ -1 +1,203 @@ - +# 🚀 DataBot Analytics + +A powerful Telegram bot and Streamlit web application for data analytics, visualization, and machine learning analysis. + +## ✨ Features + +- **📊 Telegram Bot**: Upload CSV/Excel files and get instant analysis via Telegram +- **🌐 Web Interface**: Comprehensive Streamlit dashboard for data exploration +- **📈 Advanced Analytics**: Statistical analysis, ML clustering, A/B testing +- **🎨 Rich Visualizations**: Interactive charts with Plotly and Seaborn +- **☁️ Railway Ready**: Optimized for cloud deployment with health checks + +## 🤖 Telegram Bot Commands + +- `/start` - Get welcome message and instructions +- `/help` - Show available commands +- `/analyze` - Detailed data analysis +- `/visualize` - Quick data visualization +- `/charts` - Generate multiple chart types + +Simply send CSV or Excel files to get instant analytics! + +## 🚀 Quick Start + +### Local Development + +1. **Clone and setup**: +```bash +git clone https://github.com/Artisa111/databot-analytics.git +cd databot-analytics +pip install -r requirements.txt +``` + +2. **Configure environment**: +```bash +cp .env.example .env +# Edit .env and add your TELEGRAM_TOKEN +``` + +3. **Get Telegram Bot Token**: + - Message [@BotFather](https://t.me/botfather) on Telegram + - Create new bot with `/newbot` + - Copy the token (format: `123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`) + - Add to `.env` file + +4. **Run locally**: +```bash +# Just the bot +python bot.py + +# Or with web interface +streamlit run app.py +``` + +### 🚄 Railway Deployment + +[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new) + +1. **Fork this repository** +2. **Deploy to Railway**: + - Connect your GitHub account + - Select this repository + - Railway will auto-detect and deploy + +3. **Set Environment Variables** in Railway dashboard: + ``` + TELEGRAM_TOKEN=your_bot_token_here + ``` + + ⚠️ **Important**: Make sure your token has NO trailing spaces or newlines! + +4. **Configure Service** (if needed): + - Service Type: Web Service + - Start Command: `python main.py` (auto-detected from railway.toml) + - Port: $PORT (auto-configured) + +## 📋 Environment Variables + +| Variable | Description | Required | Example | +|----------|-------------|----------|---------| +| `TELEGRAM_TOKEN` | Bot token from @BotFather | ✅ Yes | `123456789:ABC-DEF1234ghIkl...` | +| `PORT` | Server port (auto-set by Railway) | ❌ No | `3000` | +| `ENVIRONMENT` | Environment flag | ❌ No | `production` | + +## 🛠️ Architecture + +### Railway Deployment + +The application runs with dual services: +- **HTTP Health Server**: Binds to `$PORT` for Railway health checks +- **Telegram Bot**: Runs concurrently in background thread + +``` +Railway → HTTP Health Check (Port $PORT) → ✅ Service Healthy + └→ Telegram Bot (Background) → 🤖 Handles messages +``` + +### File Structure + +``` +databot-analytics/ +├── main.py # Railway entry point with health server +├── bot.py # Telegram bot with data analytics +├── app.py # Streamlit web interface +├── bot_runner.py # Simple bot runner (legacy) +├── config.py # Configuration settings +├── requirements.txt # Python dependencies +├── railway.toml # Railway deployment config +├── .env.example # Environment template +└── README.md # This file +``` + +## 🔧 Troubleshooting + +### Common Issues + +#### 1. "Invalid non-printable ASCII character in URL" +**Cause**: TELEGRAM_TOKEN has trailing newlines or spaces +**Fix**: +- Copy token carefully from @BotFather +- Don't paste with extra whitespace +- Token format: `123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11` + +#### 2. Railway Service Crashes +**Cause**: Service not binding to $PORT +**Fix**: +- Use `python main.py` as start command +- Ensure railway.toml is present +- Check Railway logs for specific errors + +#### 3. Bot Not Responding +**Cause**: Invalid or missing token +**Fix**: +- Verify token with @BotFather using `/mybots` +- Check Railway environment variables +- Ensure token has no extra characters + +#### 4. File Upload Issues +**Mobile**: Use desktop browser or Telegram bot +**Large Files**: Use bot instead of web interface + +### Debug Steps + +1. **Check Railway Logs**: + ```bash + railway logs + ``` + +2. **Test Locally**: + ```bash + python bot.py + # Should show: "✅ Bot is ready!" + ``` + +3. **Validate Token Format**: + - Should be exactly 46 characters + - Format: `[8-10 digits]:[35 characters A-Z, a-z, 0-9, -, _]` + +4. **Health Check**: + ```bash + curl https://your-app.railway.app/health + # Should return: {"status": "healthy", ...} + ``` + +## 📊 Usage Examples + +### Data Analysis Flow + +1. **Upload Data**: Send CSV/Excel file to bot +2. **Get Overview**: Automatic summary statistics +3. **Visualizations**: Charts and graphs generated +4. **Advanced Analysis**: ML clustering, A/B testing +5. **Export**: Download reports and charts + +### Supported File Types + +- ✅ CSV files (.csv) +- ✅ Excel files (.xlsx, .xls) +- ✅ JSON files (via web interface) +- ❌ Large files >50MB (use data sampling) + +## 🤝 Contributing + +1. Fork the repository +2. Create feature branch: `git checkout -b feature-name` +3. Make changes and test locally +4. Commit: `git commit -m "Add feature"` +5. Push: `git push origin feature-name` +6. Create Pull Request + +## 📄 License + +This project is open source and available under the [MIT License](LICENSE). + +## 🆘 Support + +- 📧 Issues: [GitHub Issues](https://github.com/Artisa111/databot-analytics/issues) +- 💬 Telegram: [@maydatabot123_bot](https://t.me/maydatabot123_bot) +- 📖 Docs: Check this README and code comments + +--- + +**Made with ❤️ for data enthusiasts** \ No newline at end of file diff --git a/app.py b/app.py index 5aff5c8..f41c81d 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,3 @@ -st.warning("⚠️ Mobile Version Notice: Streamlit doesn't support large file uploads on mobile browsers. Please use desktop version or try our Telegram bot for better experience!") -st.warning("⚠️ Mobile file upload may not work. Use our bot: https://t.me/maydatabot123_bot") import streamlit as st import pandas as pd import plotly.express as px @@ -101,6 +99,7 @@ def main(): # Mobile warning st.warning("⚠️ For better performance with large files, use the desktop version!") + st.warning("⚠️ Mobile file upload may not work. Use our bot: https://t.me/maydatabot123_bot") with st.sidebar: st.markdown("### 🎯 Navigation") diff --git a/bot.py b/bot.py index 5774a61..9f9b5fc 100644 --- a/bot.py +++ b/bot.py @@ -4,6 +4,7 @@ import pandas as pd import io import os +import re from dotenv import load_dotenv import matplotlib.pyplot as plt import seaborn as sns @@ -16,16 +17,33 @@ # Load environment variables load_dotenv() -# Get token -TOKEN = os.getenv('TELEGRAM_TOKEN') +# Get token with validation +def validate_telegram_token(token): + """Validate Telegram bot token format""" + if not token: + return False, "TELEGRAM_TOKEN not found in environment variables!" + + # Strip whitespace and newlines + token = token.strip() + + # Telegram bot token pattern: digits:hash + # Real tokens: 8-10 digits, colon, 35+ chars (letters, numbers, underscore, hyphen) + pattern = r'^\d{8,10}:[a-zA-Z0-9_-]{30,}$' + if not re.match(pattern, token): + return False, f"Invalid TELEGRAM_TOKEN format. Expected: digits:hash (found: '{token[:20]}...')" + + return True, token + +raw_token = os.getenv('TELEGRAM_TOKEN', '') +is_valid, TOKEN = validate_telegram_token(raw_token) # Setup logging logging.basicConfig(level=logging.INFO) class DataAnalyticsBot: def __init__(self): - if not TOKEN: - raise ValueError("TELEGRAM_TOKEN not found in .env file!") + if not is_valid: + raise ValueError(TOKEN) # TOKEN now contains the error message self.application = Application.builder().token(TOKEN).build() self.setup_handlers() diff --git a/config.py b/config.py index 5783b35..21c4d5d 100644 --- a/config.py +++ b/config.py @@ -1,4 +1,4 @@ - import os +import os from dotenv import load_dotenv load_dotenv() diff --git a/main.py b/main.py index e53a643..a2fe31e 100644 --- a/main.py +++ b/main.py @@ -1,38 +1,92 @@ -# main.py -import subprocess -import sys +#!/usr/bin/env python3 +""" +Railway-compatible main entry point for DataBot Analytics. +Serves HTTP health check on $PORT while running Telegram bot concurrently. +""" import os import threading import time -import platform +import logging +from http.server import HTTPServer, BaseHTTPRequestHandler +from bot import DataAnalyticsBot -# Цветной вывод и эмодзи -import colorama -from colorama import Fore, Style -colorama.init() +# Setup logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) -# Настройка кодировки для Windows -if platform.system() == "Windows": - os.system("chcp 65001 > nul") # UTF-8 кодировка в терминале +class HealthHandler(BaseHTTPRequestHandler): + """Simple HTTP health check handler for Railway deployment""" + + def do_GET(self): + if self.path in ['/', '/health']: + self.send_response(200) + self.send_header('Content-type', 'application/json') + self.end_headers() + + status = { + 'status': 'healthy', + 'service': 'databot-analytics', + 'bot_status': 'running' if bot_status.get('running') else 'stopped' + } + self.wfile.write(str(status).encode()) + else: + self.send_response(404) + self.end_headers() + + def log_message(self, format, *args): + # Suppress default HTTP request logging to reduce noise + pass -# Запуск бота def run_bot(): - print(Fore.CYAN + "🤖 Запуск бота..." + Style.RESET_ALL) - subprocess.run([sys.executable, "bot.py"], check=True) + """Run the Telegram bot in a separate thread""" + global bot_status + + try: + logger.info("🤖 Starting Telegram bot...") + bot = DataAnalyticsBot() + bot_status['running'] = True + bot.run() + except ValueError as e: + logger.error(f"❌ Bot configuration error: {e}") + logger.info("💡 Check your Railway Variables and ensure TELEGRAM_TOKEN is set correctly") + logger.info("📝 TELEGRAM_TOKEN should be in format: 123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") + bot_status['running'] = False + except Exception as e: + logger.error(f"❌ Unexpected bot error: {e}") + logger.info("💡 Check your internet connection and bot token!") + bot_status['running'] = False -# Запуск Streamlit -def run_streamlit(): - print(Fore.GREEN + "📊 Запуск Streamlit..." + Style.RESET_ALL) - subprocess.run(["streamlit", "run", "app.py"], check=True) +def run_health_server(): + """Run HTTP health server for Railway""" + port = int(os.environ.get('PORT', 3000)) + + logger.info(f"🌐 Starting health server on 0.0.0.0:{port}") + + server = HTTPServer(('0.0.0.0', port), HealthHandler) + try: + server.serve_forever() + except KeyboardInterrupt: + logger.info("🛑 Health server stopped") + server.shutdown() + +# Global bot status tracker +bot_status = {'running': False} -# Основной запуск if __name__ == "__main__": + logger.info("🚀 Starting DataBot Analytics for Railway deployment") + + # Start bot in background thread bot_thread = threading.Thread(target=run_bot, daemon=True) - streamlit_thread = threading.Thread(target=run_streamlit, daemon=True) - bot_thread.start() - time.sleep(2) # Даем боту немного времени на старт - streamlit_thread.start() - - bot_thread.join() - streamlit_thread.join() \ No newline at end of file + + # Give bot a moment to initialize + time.sleep(2) + + # Start health server (blocks main thread - Railway needs this) + try: + run_health_server() + except KeyboardInterrupt: + logger.info("🛑 Shutting down DataBot Analytics") \ No newline at end of file diff --git a/railway.toml b/railway.toml new file mode 100644 index 0000000..8d15a7d --- /dev/null +++ b/railway.toml @@ -0,0 +1,6 @@ +[build] + +[deploy] +startCommand = "python main.py" +restartPolicyType = "ON_FAILURE" +restartPolicyMaxRetries = 3 \ No newline at end of file