| import os |
| import sys |
| import threading |
| from flask import Flask, request, Response, stream_with_context, jsonify, render_template_string |
| from flask_cors import CORS |
| from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer, BitsAndBytesConfig |
| import torch |
|
|
| print("LOG: Iniciando Motor Hydra 3.0 (Docker API - Hydra Software)...") |
| sys.stdout.flush() |
|
|
| app = Flask(__name__) |
| CORS(app) |
|
|
| model_id = "Mution/Hydra-AI-3B-Coder-Pro" |
| token = os.getenv("HF_TOKEN") |
|
|
| VALID_API_KEYS = { |
| "hydra-sk-master-9928374": "Master_Admin", |
| "hydra-sk-root-1122334": "Root_System", |
| "hydra-sk-dev-5566778": "Developer_Terminal", |
| "hydra-sk-bot-alpha-1029384": "Discord_Bot_Alpha", |
| "hydra-sk-bot-beta-2039485": "Discord_Bot_Beta", |
| "hydra-sk-bot-gamma-3049586": "Telegram_Bot", |
| "hydra-sk-bot-delta-4059687": "Twitch_Bot", |
| "hydra-sk-panel-main-5647382": "Web_Panel_Main", |
| "hydra-sk-panel-sec-6758493": "Web_Panel_Secundario", |
| "hydra-sk-panel-event-7869504": "Event_Dashboard", |
| "hydra-sk-vip-001-8970615": "VIP_User_1", |
| "hydra-sk-vip-002-9081726": "VIP_User_2", |
| "hydra-sk-vip-003-0192837": "VIP_User_3", |
| "hydra-sk-test-1203948": "Testing_Key_A", |
| "hydra-sk-test-2314059": "Testing_Key_B", |
| "hydra-sk-node-001-110022": "Node_Server_1", |
| "hydra-sk-node-002-334455": "Node_Server_2", |
| "hydra-sk-node-003-667788": "Node_Server_3", |
| "hydra-sk-node-004-990011": "Node_Server_4", |
| "hydra-sk-node-005-223344": "Node_Server_5", |
| "hydra-sk-app-mobile-1010": "Mobile_App_iOS", |
| "hydra-sk-app-mobile-2020": "Mobile_App_Android", |
| "hydra-sk-app-desktop-3030": "Desktop_App_Electron", |
| "hydra-sk-app-web-4040": "Web_Client_App", |
| "hydra-sk-service-auth-01": "Auth_Service", |
| "hydra-sk-service-db-02": "Database_Worker", |
| "hydra-sk-service-cache-03": "Redis_Cache_Worker", |
| "hydra-sk-service-queue-04": "RabbitMQ_Worker", |
| "hydra-sk-service-cron-05": "Cron_Task_Manager", |
| "hydra-sk-client-pro-1001": "Client_Pro_Tier_1", |
| "hydra-sk-client-pro-1002": "Client_Pro_Tier_2", |
| "hydra-sk-client-pro-1003": "Client_Pro_Tier_3", |
| "hydra-sk-client-pro-1004": "Client_Pro_Tier_4", |
| "hydra-sk-client-pro-1005": "Client_Pro_Tier_5", |
| "hydra-sk-client-enterprise-2001": "Enterprise_Client_A", |
| "hydra-sk-client-enterprise-2002": "Enterprise_Client_B", |
| "hydra-sk-client-enterprise-2003": "Enterprise_Client_C", |
| "hydra-sk-internal-tool-01": "Internal_Dev_Tool_1", |
| "hydra-sk-internal-tool-02": "Internal_Dev_Tool_2", |
| "hydra-sk-internal-tool-03": "Internal_Dev_Tool_3", |
| "hydra-sk-bot-v2-01": "Discord_Bot_v2_1", |
| "hydra-sk-bot-v2-02": "Discord_Bot_v2_2", |
| "hydra-sk-bot-v2-03": "Discord_Bot_v2_3", |
| "hydra-sk-bot-v2-04": "Discord_Bot_v2_4", |
| "hydra-sk-bot-v2-05": "Discord_Bot_v2_5", |
| "hydra-sk-integration-gh-01": "GitHub_Actions_Integration", |
| "hydra-sk-integration-gl-02": "GitLab_CI_Integration", |
| "hydra-sk-integration-docker-03": "Docker_Hub_Integration", |
| "hydra-sk-integration-aws-04": "AWS_Lambda_Integration", |
| "hydra-sk-integration-gcf-05": "GCP_Cloud_Functions", |
| "hydra-sk-vip-004-1234567": "VIP_User_4", |
| "hydra-sk-vip-005-2345678": "VIP_User_5", |
| "hydra-sk-vip-006-3456789": "VIP_User_6", |
| "hydra-sk-vip-007-4567890": "VIP_User_7", |
| "hydra-sk-vip-008-5678901": "VIP_User_8", |
| "hydra-sk-vip-009-6789012": "VIP_User_9", |
| "hydra-sk-vip-010-7890123": "VIP_User_10", |
| "hydra-sk-sec-audit-01": "Security_Audit_Tool_A", |
| "hydra-sk-sec-audit-02": "Security_Audit_Tool_B", |
| "hydra-sk-monitoring-01": "Prometheus_Monitoring", |
| "hydra-sk-monitoring-02": "Grafana_Dashboard_Agent", |
| "hydra-sk-ext-partner-01": "External_Partner_Alpha", |
| "hydra-sk-ext-partner-02": "External_Partner_Beta", |
| "hydra-sk-ext-partner-03": "External_Partner_Gamma", |
| "hydra-sk-sandbox-01": "Sandbox_Environment_1", |
| "hydra-sk-sandbox-02": "Sandbox_Environment_2", |
| "hydra-sk-sandbox-03": "Sandbox_Environment_3", |
| "hydra-sk-cluster-east-01": "Cluster_US_East_1", |
| "hydra-sk-cluster-east-02": "Cluster_US_East_2", |
| "hydra-sk-cluster-west-01": "Cluster_US_West_1", |
| "hydra-sk-cluster-eu-01": "Cluster_EU_Central_1", |
| "hydra-sk-cluster-sa-01": "Cluster_SA_East_1", |
| "hydra-sk-backup-01": "Backup_Worker_Node_1", |
| "hydra-sk-backup-02": "Backup_Worker_Node_2", |
| "hydra-sk-legacy-01": "Legacy_System_Adapter_1", |
| "hydra-sk-legacy-02": "Legacy_System_Adapter_2", |
| "hydra-sk-agent-ai-01": "AI_Agent_Code_Reviewer", |
| "hydra-sk-agent-ai-02": "AI_Agent_Bug_Fixer", |
| "hydra-sk-agent-ai-03": "AI_Agent_Refactorer", |
| "hydra-sk-agent-ai-04": "AI_Agent_Doc_Generator", |
| "hydra-sk-agent-ai-05": "AI_Agent_Unit_Tester", |
| "hydra-sk-gateway-01": "API_Gateway_Primary", |
| "hydra-sk-gateway-02": "API_Gateway_Secondary", |
| "hydra-sk-gateway-03": "API_Gateway_Failover", |
| "hydra-sk-custom-9001": "Custom_Deployment_Key_1", |
| "hydra-sk-custom-9002": "Custom_Deployment_Key_2", |
| "hydra-sk-custom-9003": "Custom_Deployment_Key_3", |
| "hydra-sk-custom-9004": "Custom_Deployment_Key_4", |
| "hydra-sk-custom-9005": "Custom_Deployment_Key_5", |
| "hydra-sk-custom-9006": "Custom_Deployment_Key_6", |
| "hydra-sk-custom-9007": "Custom_Deployment_Key_7", |
| "hydra-sk-custom-9008": "Custom_Deployment_Key_8", |
| "hydra-sk-custom-9009": "Custom_Deployment_Key_9", |
| "hydra-sk-custom-9010": "Custom_Deployment_Key_10" |
| } |
|
|
| try: |
| print("LOG: Cargando Tokenizador Hydra 3B...") |
| tokenizer = AutoTokenizer.from_pretrained(model_id, token=token) |
|
|
| print("LOG: Configurando cuantizaci贸n 4-bit...") |
| bnb_config = BitsAndBytesConfig( |
| load_in_4bit=True, |
| bnb_4bit_compute_dtype=torch.float16, |
| llm_int8_enable_fp32_cpu_offload=True |
| ) |
|
|
| print("LOG: Cargando modelo fusionado Hydra 3B...") |
| model = AutoModelForCausalLM.from_pretrained( |
| model_id, |
| token=token, |
| quantization_config=bnb_config, |
| device_map="auto", |
| torch_dtype=torch.float16, |
| low_cpu_mem_usage=True, |
| offload_folder="offload_dir" |
| ) |
|
|
| print("LOG: IA cargada y lista.") |
| except Exception as e: |
| print(f"LOG CR脥TICO: Error al cargar el modelo: {e}") |
| sys.exit(1) |
|
|
| HTML_PAGE = """ |
| <!DOCTYPE html> |
| <html lang="es"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Hydra AI 3B - Private Console</title> |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
| <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@400;600;700&display=swap" rel="stylesheet"> |
| <style> |
| :root { |
| --bg-main: #0b0f19; |
| --bg-card: #111827; |
| --bg-chat: #070a12; |
| --border-color: #1f293d; |
| --accent-cyan: #06b6d4; |
| --accent-emerald: #10b981; |
| --text-main: #f3f4f6; |
| --text-muted: #9ca3af; |
| } |
| * { box-sizing: border-box; margin: 0; padding: 0; } |
| body { |
| font-family: 'Inter', sans-serif; |
| background-color: var(--bg-main); |
| color: var(--text-main); |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| min-height: 100vh; |
| padding: 20px; |
| } |
| .wrapper { |
| width: 100%; |
| max-width: 1100px; |
| height: 90vh; |
| background: var(--bg-card); |
| border: 1px solid var(--border-color); |
| border-radius: 16px; |
| display: flex; |
| flex-direction: column; |
| overflow: hidden; |
| box-shadow: 0 20px 50px rgba(0,0,0,0.6); |
| } |
| .top-bar { |
| padding: 16px 24px; |
| background: #162032; |
| border-bottom: 1px solid var(--border-color); |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| flex-wrap: wrap; |
| gap: 12px; |
| } |
| .brand-title { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| font-weight: 700; |
| font-size: 1.15rem; |
| color: var(--accent-cyan); |
| letter-spacing: 0.5px; |
| } |
| .status-badge { |
| background: rgba(16, 185, 129, 0.15); |
| color: var(--accent-emerald); |
| border: 1px solid rgba(16, 185, 129, 0.3); |
| padding: 4px 10px; |
| border-radius: 20px; |
| font-size: 0.75rem; |
| font-weight: 600; |
| } |
| .key-auth-box { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| } |
| .key-auth-box input { |
| background: var(--bg-chat); |
| border: 1px solid var(--border-color); |
| color: var(--accent-cyan); |
| padding: 8px 12px; |
| border-radius: 8px; |
| font-family: 'Fira Code', monospace; |
| font-size: 0.85rem; |
| width: 260px; |
| outline: none; |
| } |
| .key-auth-box input:focus { |
| border-color: var(--accent-cyan); |
| } |
| .chat-area { |
| flex: 1; |
| background: var(--bg-chat); |
| padding: 24px; |
| overflow-y: auto; |
| display: flex; |
| flex-direction: column; |
| gap: 16px; |
| } |
| .message { |
| padding: 14px 18px; |
| border-radius: 10px; |
| max-width: 85%; |
| font-size: 0.95rem; |
| line-height: 1.6; |
| white-space: pre-wrap; |
| word-break: break-word; |
| } |
| .message.user { |
| background: #1d4ed8; |
| color: #ffffff; |
| align-self: flex-end; |
| border-bottom-right-radius: 2px; |
| } |
| .message.assistant { |
| background: #1e293b; |
| color: #e2e8f0; |
| align-self: flex-start; |
| border-left: 4px solid var(--accent-cyan); |
| border-bottom-left-radius: 2px; |
| font-family: 'Fira Code', monospace; |
| } |
| .controls-area { |
| padding: 16px 24px; |
| background: #162032; |
| border-top: 1px solid var(--border-color); |
| display: flex; |
| gap: 12px; |
| } |
| textarea { |
| flex: 1; |
| background: var(--bg-chat); |
| border: 1px solid var(--border-color); |
| border-radius: 10px; |
| color: #f3f4f6; |
| padding: 12px; |
| font-family: 'Inter', sans-serif; |
| font-size: 0.95rem; |
| resize: none; |
| height: 52px; |
| outline: none; |
| } |
| textarea:focus { |
| border-color: var(--accent-cyan); |
| } |
| button { |
| background: var(--accent-cyan); |
| color: #070a12; |
| border: none; |
| border-radius: 10px; |
| padding: 0 24px; |
| font-weight: 700; |
| cursor: pointer; |
| transition: all 0.2s ease; |
| } |
| button:hover { |
| background: #0891b2; |
| color: #ffffff; |
| } |
| </style> |
| </head> |
| <body> |
| <div class="wrapper"> |
| <div class="top-bar"> |
| <div class="brand-title"> |
| HYDRA AI 3B <span class="status-badge">ONLINE</span> |
| </div> |
| <div class="key-auth-box"> |
| <input type="password" id="apiKey" placeholder="Ingrese x-api-key para autenticar..." /> |
| </div> |
| </div> |
| <div class="chat-area" id="chat"> |
| <div class="message assistant">Consola privada activa. Ingrese su API Key en la parte superior para consultar al motor de IA.</div> |
| </div> |
| <div class="controls-area"> |
| <textarea id="promptInput" placeholder="Escriba su consulta o instrucci贸n de c贸digo..."></textarea> |
| <button onclick="sendPrompt()">Enviar</button> |
| </div> |
| </div> |
| |
| <script> |
| async function sendPrompt() { |
| const apiKeyInput = document.getElementById('apiKey').value.trim(); |
| const promptInput = document.getElementById('promptInput'); |
| const chat = document.getElementById('chat'); |
| const userText = promptInput.value.trim(); |
| |
| if (!apiKeyInput) { |
| alert('Ingrese una API Key v谩lida en la barra superior.'); |
| return; |
| } |
| if (!userText) return; |
| |
| const userMsgDiv = document.createElement('div'); |
| userMsgDiv.className = 'message user'; |
| userMsgDiv.textContent = userText; |
| chat.appendChild(userMsgDiv); |
| |
| promptInput.value = ''; |
| chat.scrollTop = chat.scrollHeight; |
| |
| const assistantMsgDiv = document.createElement('div'); |
| assistantMsgDiv.className = 'message assistant'; |
| assistantMsgDiv.textContent = ''; |
| chat.appendChild(assistantMsgDiv); |
| |
| try { |
| const response = await fetch('/ask', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'x-api-key': apiKeyInput |
| }, |
| body: JSON.stringify({ prompt: userText }) |
| }); |
| |
| if (!response.ok) { |
| const errData = await response.json().catch(() => ({})); |
| assistantMsgDiv.textContent = `Error (${response.status}): ${errData.error || 'Acceso Denegado'}`; |
| return; |
| } |
| |
| const reader = response.body.getReader(); |
| const decoder = new TextDecoder(); |
| |
| while (true) { |
| const { done, value } = await reader.read(); |
| if (done) break; |
| assistantMsgDiv.textContent += decoder.decode(value, { stream: true }); |
| chat.scrollTop = chat.scrollHeight; |
| } |
| } catch (err) { |
| assistantMsgDiv.textContent = 'Error de conexi贸n con el servidor.'; |
| } |
| } |
| |
| document.getElementById('promptInput').addEventListener('keydown', (e) => { |
| if (e.key === 'Enter' && !e.shiftKey) { |
| e.preventDefault(); |
| sendPrompt(); |
| } |
| }); |
| </script> |
| </body> |
| </html> |
| """ |
|
|
| @app.route('/ask', methods=['POST']) |
| def ask(): |
| api_key = request.headers.get("x-api-key") |
| if not api_key or api_key not in VALID_API_KEYS: |
| return jsonify({"error": "Acceso denegado. Llave invalida o inexistente."}), 401 |
|
|
| try: |
| data = request.json |
| user_prompt = data.get("prompt", "") |
| |
| prompt = f"<|im_start|>system\nEres Hydra 3.0, el motor de inteligencia artificial de Hydra Software. Eres un experto absoluto en programaci贸n y desarrollo de sistemas backend, bots y paneles web.<|im_end|>\n<|im_start|>user\n{user_prompt}<|im_end|>\n<|im_start|>assistant\n" |
| |
| inputs = tokenizer(prompt, return_tensors="pt").to(model.device) |
| streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True) |
|
|
| def generate_task(): |
| with torch.no_grad(): |
| model.generate( |
| **inputs, |
| max_new_tokens=4096, |
| do_sample=True, |
| temperature=0.7, |
| top_p=0.9, |
| repetition_penalty=1.15, |
| streamer=streamer |
| ) |
|
|
| thread = threading.Thread(target=generate_task) |
| thread.start() |
|
|
| def generate_stream(): |
| for text in streamer: |
| yield text |
|
|
| return Response(stream_with_context(generate_stream()), mimetype='text/plain') |
|
|
| except Exception as e: |
| return jsonify({"error": str(e)}), 500 |
|
|
| @app.route('/', methods=['GET']) |
| def health(): |
| return render_template_string(HTML_PAGE) |
|
|
| if __name__ == '__main__': |
| print("LOG: Iniciando servidor Flask en 0.0.0.0:7860") |
| app.run(host='0.0.0.0', port=7860, threaded=True) |