# ============================================ # OMNIS AI Backend - Hugging Face Spaces # ============================================ from flask import Flask, request, jsonify from flask_cors import CORS from gtts import gTTS import io import base64 import re import random from datetime import datetime from collections import Counter app = Flask(__name__) CORS(app) server_start_time = datetime.now() total_requests = 0 STOPWORDS = { 'il', 'lo', 'la', 'i', 'gli', 'le', 'un', 'una', 'uno', 'è', 'e', 'che', 'di', 'a', 'da', 'in', 'con', 'su', 'per', 'tra', 'fra', 'non', 'si', 'come', 'più', 'al', 'del', 'della', 'dei', 'delle', 'sono', 'ho', 'hai', 'ha', 'abbiamo', 'hanno', 'era', 'erano', 'sarà', 'cui', 'dal', 'dalla', 'nel', 'nella', 'questo', 'questa', 'molto', 'molta', 'molti', 'poco', 'the', 'and', 'for', 'are', 'but', 'not', 'you', 'all', 'can', 'has', 'have', 'been', 'some' } def extract_keywords(text, top_n=6): words = re.findall(r'\b[a-zA-ZÀ-ÿ]{4,}\b', text.lower()) filtered = [w for w in words if w not in STOPWORDS] return [w.capitalize() for w, _ in Counter(filtered).most_common(top_n)] def extract_sentences(text, min_len=20): return [s.strip() for s in re.split(r'[.!?]+', text) if len(s.strip()) > min_len] def generate_mermaid_code(text, keywords, sentences): main = keywords[0] if keywords else "Argomento" subs = keywords[1:5] if len(keywords) > 1 else ["Dettaglio"] mermaid = "graph TD\n" mermaid += f' A["{main[:30]}"]\n' colors = ['#8B5CF6', '#06B6D4', '#10B981', '#F59E0B'] for i, sub in enumerate(subs): node_id = chr(66 + i) sub_clean = sub[:30].replace('"', "'") mermaid += f' {node_id}["{sub_clean}"]\n' mermaid += f' A --> {node_id}\n' if i < len(sentences): detail = sentences[i][:50].replace('"', "'").strip() detail_id = f"{node_id}1" mermaid += f' {detail_id}["{detail}..."]\n' mermaid += f' {node_id} --> {detail_id}\n' mermaid += f' style A fill:#1a1a2e,stroke:#8B5CF6,stroke-width:3px,color:#fff\n' for i in range(len(subs)): node_id = chr(66 + i) color = colors[i % len(colors)] mermaid += f' style {node_id} fill:#1a1a2e,stroke:{color},stroke-width:2px,color:#fff\n' return mermaid # ============================================ # HEALTH # ============================================ @app.route('/api/health', methods=['GET']) def health(): return jsonify({ 'status': 'online', 'uptime': str(datetime.now() - server_start_time).split('.')[0], 'total_requests': total_requests, 'host': 'huggingface', 'online_24_7': True }) # ============================================ # GENERATE (Riassunto + Quiz) # ============================================ @app.route('/api/generate', methods=['POST']) def generate(): global total_requests total_requests += 1 try: service = request.form.get('service', 'summary') text_input = request.form.get('text_input', '') custom_prompt = request.form.get('custom_prompt', '') link = request.form.get('link', '') all_text = text_input[:3000] if text_input else "" if link: try: import requests as req from bs4 import BeautifulSoup resp = req.get(link, timeout=8, headers={'User-Agent': 'OMNIS/1.0'}) soup = BeautifulSoup(resp.text, 'html.parser') for tag in soup(['script', 'style']): tag.decompose() all_text += "\n" + soup.get_text(separator=' ', strip=True)[:2000] except: all_text += f"\n[Link: {link}]" if not all_text.strip(): return jsonify({'success': False, 'error': 'Nessun testo fornito'}), 400 sentences = extract_sentences(all_text) keywords = extract_keywords(all_text) if service == 'summary': result = f"📚 RIASSUNTO\n\n🔑 Concetti: {', '.join(keywords[:6])}\n\n" for i, s in enumerate(sentences[:10]): result += f"{i+1}. {s.strip()}.\n" result += f"\n📊 {len(all_text.split())} parole" elif service == 'quiz': if len(sentences) < 2: result = "Testo troppo corto per un quiz." else: result = "❓ QUIZ\n\n" for i, s in enumerate(sentences[:5]): correct = chr(65 + random.randint(0, 3)) result += f"DOMANDA {i+1}: {' '.join(s.split()[:5])}...\n\n" for opt in ['A', 'B', 'C', 'D']: result += f"{opt}) {'✓' if opt == correct else ''} {s[:60] if opt == correct else sentences[(i+1)%len(sentences)][:60]}...\n" result += f"\n✓ Risposta: {correct}\n\n" else: result = f"📚 RIASSUNTO\n\n" + '\n'.join(sentences[:10]) return jsonify({'success': True, 'content': result, 'service': service}) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 # ============================================ # MINDMAP (restituisce codice Mermaid) # ============================================ @app.route('/api/mindmap-image', methods=['POST']) def mindmap_image(): global total_requests total_requests += 1 try: text = request.form.get('text_input', '') if not text: return jsonify({'success': False, 'error': 'Nessun testo'}), 400 text = text[:2000] keywords = extract_keywords(text, 6) sentences = extract_sentences(text, 6) if not keywords: return jsonify({'success': False, 'error': 'Testo insufficiente'}), 400 mermaid_code = generate_mermaid_code(text, keywords, sentences) return jsonify({ 'success': True, 'mermaid_code': mermaid_code, 'format': 'mermaid' }) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 # ============================================ # TEXT TO SPEECH # ============================================ @app.route('/api/text-to-speech', methods=['POST']) def text_to_speech(): try: text = request.form.get('text', '')[:3000] if not text: return jsonify({'success': False, 'error': 'Nessun testo'}), 400 tts = gTTS(text=text, lang='it', slow=False) buf = io.BytesIO() tts.write_to_fp(buf) buf.seek(0) return jsonify({ 'success': True, 'audio_base64': base64.b64encode(buf.read()).decode('utf-8'), 'format': 'mp3' }) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 if __name__ == '__main__': print("🚀 OMNIS Backend - Hugging Face") app.run(host='0.0.0.0', port=7860)