File size: 6,568 Bytes
bc56771 8d8f38b bc56771 65b49a4 bc56771 65b49a4 bc56771 65b49a4 8d8f38b 65b49a4 bc56771 65b49a4 bc56771 65b49a4 bc56771 65b49a4 bc56771 65b49a4 bc56771 65b49a4 bc56771 65b49a4 bc56771 65b49a4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | <!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/>
<title>Code</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
</head>
<body class="bg-[#1e1e1e] text-[#ccc] h-screen flex flex-col overflow-hidden">
<div class="bg-[#181818] border-b border-[#2d2d2d] p-2 flex flex-wrap gap-2 items-center text-xs">
<span class="font-bold text-white"><i class="bi bi-cpu"></i> fiel1986/Code</span>
<select id="modelSelect" class="bg-[#252526] border border-[#3d3d3d] rounded px-2 py-1.5">
<option value="groq-llama-3.3-70b">⚡ Groq Llama 3.3 70B</option>
<option value="groq-llama3-8b">Groq Llama3 8B (rápido)</option>
<option value="groq-mixtral">Groq Mixtral 8x7B</option>
<option value="hf-qwen-1.5b">HF Qwen 1.5B Coder (gratis)</option>
</select>
<input id="groqKey" placeholder="gsk_... Groq API (tuya)" class="bg-[#252526] border border-[#3d3d3d] rounded px-2 py-1.5 w-44"/>
<input id="hfKey" placeholder="hf_... HF Token (tuyo)" class="bg-[#252526] border border-[#3d3d3d] rounded px-2 py-1.5 w-44"/>
<span class="text-[10px] text-zinc-500">🔒 Tus keys se guardan solo en tu navegador (localStorage), no en mi server</span>
<button onclick="saveKeys()" class="ml-auto bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded font-bold">Guardar Keys</button>
</div>
<div class="flex flex-1 overflow-hidden">
<div class="flex-1 flex flex-col border-r border-[#2d2d2d]">
<div class="h-8 bg-[#252526] flex items-center px-3 text-xs"><span class="bg-[#1e1e1e] px-3 py-1 border-t-2 border-blue-500">main.py</span><span id="ghostStatus" class="ml-auto text-zinc-500">TAB = aceptar</span></div>
<div id="monaco" class="flex-1"></div>
</div>
<div class="w-[380px] bg-[#252526] flex flex-col">
<div class="p-3 font-bold text-xs uppercase tracking-widest border-b border-[#2d2d2d]">Chat</div>
<div id="chat" class="flex-1 overflow-y-auto p-3 space-y-3 text-sm"><div class="bg-[#2d2d2d] p-3 rounded-lg">Pon tus keys arriba → Guarda → Selecciona modelo.<br></div></div>
<div class="p-2 border-t border-[#2d2d2d] flex gap-2">
<input id="chatInput" placeholder="Pregunta..." class="flex-1 bg-[#3c3c3c] rounded px-3 py-2 text-sm outline-none"/>
<button onclick="askChat()" class="bg-blue-600 px-3 rounded"><i class="bi bi-send"></i></button>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.44.0/min/vs/loader.min.js"></script>
<script>
let editor, ghost="";
const MODELS = {
"groq-llama-3.3-70b": { api:"groq", model:"llama-3.3-70b-versatile" },
"groq-llama3-8b": { api:"groq", model:"llama3-8b-8192" },
"groq-mixtral": { api:"groq", model:"mixtral-8x7b-32768" },
"hf-qwen-1.5b": { api:"hf", model:"Qwen/Qwen2.5-Coder-1.5B-Instruct" }
}
window.onload = ()=>{
document.getElementById('groqKey').value = localStorage.getItem('groq_key')||"";
document.getElementById('hfKey').value = localStorage.getItem('hf_key')||"";
}
function saveKeys(){
localStorage.setItem('groq_key', document.getElementById('groqKey').value.trim());
localStorage.setItem('hf_key', document.getElementById('hfKey').value.trim());
alert("Keys guardadas en tu navegador!");
}
require.config({paths:{'vs':'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.44.0/min/vs'}});
require(['vs/editor/editor.main'],()=>{
editor=monaco.editor.create(document.getElementById('monaco'),{value:"# Escribe codigo\ndef fibonacci(n):\n ", language:'python', theme:'vs-dark', fontSize:14, minimap:{enabled:false}, automaticLayout:true});
const prov={provideInlineCompletions:async(m,p)=>{if(!ghost) return {items:[]}; return {items:[{insertText:ghost, range:new monaco.Range(p.lineNumber,p.column,p.lineNumber,p.column)}]}},freeInlineCompletions:()=>{}};
['python','javascript','cpp'].forEach(l=>monaco.languages.registerInlineCompletionsProvider(l,prov));
let t; editor.onDidChangeModelContent(()=>{clearTimeout(t); t=setTimeout(runCopilot,700);});
});
async function callAI(prompt){
const modelKey = document.getElementById('modelSelect').value;
const cfg = MODELS[modelKey];
if(cfg.api==="groq"){
const key = localStorage.getItem('groq_key') || document.getElementById('groqKey').value;
if(!key) throw "Pon tu gsk_... Groq key arriba";
const r = await fetch("https://api.groq.com/openai/v1/chat/completions",{method:"POST", headers:{"Content-Type":"application/json", Authorization:`Bearer ${key}`}, body:JSON.stringify({model:cfg.model, messages:[{role:"user", content:prompt}], max_tokens:300, temperature:0.2})});
const d = await r.json(); return d.choices[0].message.content;
} else {
const key = localStorage.getItem('hf_key') || document.getElementById('hfKey').value;
const r = await fetch(`https://router.huggingface.co/hf-inference/models/${cfg.model}`,{method:"POST", headers:{"Content-Type":"application/json",...(key?{Authorization:`Bearer ${key}`}:{})}, body:JSON.stringify({inputs:prompt, parameters:{max_new_tokens:120, return_full_text:false}})});
const d = await r.json(); return d[0]?.generated_text || "";
}
}
async function runCopilot(){
try{ const code=editor.getValue(); if(code.length<10) return; document.getElementById('ghostStatus').textContent="Pensando..."; let out=await callAI(code.slice(-600)); ghost=out.slice(0,150); if(ghost){ editor.trigger('k','editor.action.inlineSuggest.trigger',{}); document.getElementById('ghostStatus').textContent="TAB para aceptar"; }}catch(e){ document.getElementById('ghostStatus').textContent=e; }
}
async function askChat(){
const input=document.getElementById('chatInput'); const q=input.value; if(!q) return; const chat=document.getElementById('chat'); const sel=editor.getModel().getValueInRange(editor.getSelection())||editor.getValue().slice(-600);
chat.innerHTML+=`<div class="bg-blue-600 text-white p-3 rounded-lg ml-6">${q}</div>`; input.value="";
const load=document.createElement('div'); load.className="bg-[#2d2d2d] p-3 rounded-lg"; load.textContent="Escribiendo..."; chat.appendChild(load); chat.scrollTop=chat.scrollHeight;
try{ let ans=await callAI(`Codigo:\n${sel}\n\nPregunta:${q}`); load.innerHTML=`<pre class="whitespace-pre-wrap">${ans.replace(/</g,'<')}</pre>`; }catch(e){ load.textContent="Error: "+e; }
}
document.getElementById('chatInput').addEventListener('keydown', e=>{ if(e.key==='Enter') askChat(); });
</script>
</body>
</html> |