Update index.html
Browse files- index.html +96 -18
index.html
CHANGED
|
@@ -1,19 +1,97 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="es">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
| 5 |
+
<title>Cursor Clone - Qwen</title>
|
| 6 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 7 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
| 8 |
+
</head>
|
| 9 |
+
<body class="bg-[#1e1e1e] text-[#ccc] h-screen flex flex-col overflow-hidden">
|
| 10 |
+
|
| 11 |
+
<div class="h-9 bg-[#181818] flex items-center px-3 gap-2 border-b border-[#2d2d2d] text-sm">
|
| 12 |
+
<i class="bi bi-cursor-fill text-white"></i> <b>CURSOR CLONE</b> <span class="text-zinc-500">— Qwen 2.5 Coder</span>
|
| 13 |
+
<div class="ml-auto flex gap-2">
|
| 14 |
+
<input id="token" placeholder="hf_... pon tu token" class="bg-[#252526] border border-[#3d3d3d] rounded px-2 py-1 text-xs w-48"/>
|
| 15 |
+
<button onclick="download()" class="bg-white text-black px-3 py-1 rounded text-xs font-bold">Descargar</button>
|
| 16 |
+
</div>
|
| 17 |
+
</div>
|
| 18 |
+
|
| 19 |
+
<div class="flex flex-1 overflow-hidden">
|
| 20 |
+
<div class="w-12 bg-[#181818] flex flex-col items-center py-3 gap-5 border-r border-[#2d2d2d] text-xl">
|
| 21 |
+
<i class="bi bi-files text-white"></i><i class="bi bi-chat-left text-blue-400"></i>
|
| 22 |
+
</div>
|
| 23 |
+
|
| 24 |
+
<div class="flex-1 flex">
|
| 25 |
+
<!-- EDITOR -->
|
| 26 |
+
<div class="flex-1 flex flex-col border-r border-[#2d2d2d]">
|
| 27 |
+
<div class="h-8 bg-[#252526] flex items-center px-3 text-xs gap-2"><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 para aceptar</span></div>
|
| 28 |
+
<div id="monaco" class="flex-1"></div>
|
| 29 |
+
</div>
|
| 30 |
+
|
| 31 |
+
<!-- CHAT -->
|
| 32 |
+
<div class="w-[380px] bg-[#252526] flex flex-col">
|
| 33 |
+
<div class="p-3 font-bold text-xs uppercase tracking-widest border-b border-[#2d2d2d]">Qwen Chat</div>
|
| 34 |
+
<div id="chat" class="flex-1 overflow-y-auto p-3 space-y-3 text-sm">
|
| 35 |
+
<div class="bg-[#2d2d2d] p-3 rounded-lg">Hola! Soy tu Cursor casero. Puedo:<br>• Explicar código<br>• Generar funciones<br>• Refactorizar<br><br>Selecciona código y pregunta.</div>
|
| 36 |
+
</div>
|
| 37 |
+
<div class="p-2 border-t border-[#2d2d2d] flex gap-2">
|
| 38 |
+
<select id="lang" class="bg-[#3c3c3c] rounded px-2 py-2 text-xs"><option value="python">PY</option><option value="javascript">JS</option></select>
|
| 39 |
+
<input id="chatInput" placeholder="Ctrl+K para preguntar..." class="flex-1 bg-[#3c3c3c] rounded px-3 py-2 text-sm outline-none"/>
|
| 40 |
+
<button onclick="askChat()" class="bg-blue-600 px-3 rounded"><i class="bi bi-send"></i></button>
|
| 41 |
+
</div>
|
| 42 |
+
</div>
|
| 43 |
+
</div>
|
| 44 |
+
</div>
|
| 45 |
+
|
| 46 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.44.0/min/vs/loader.min.js"></script>
|
| 47 |
+
<script>
|
| 48 |
+
let editor, ghost="";
|
| 49 |
+
require.config({paths:{'vs':'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.44.0/min/vs'}});
|
| 50 |
+
require(['vs/editor/editor.main'],()=>{
|
| 51 |
+
editor=monaco.editor.create(document.getElementById('monaco'),{
|
| 52 |
+
value:"# Selecciona codigo y usa el chat ->\ndef quicksort(arr):\n pass",
|
| 53 |
+
language:'python', theme:'vs-dark', fontSize:14, minimap:{enabled:false}, automaticLayout:true, padding:{top:10}
|
| 54 |
+
});
|
| 55 |
+
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:()=>{}};
|
| 56 |
+
['python','javascript','cpp'].forEach(l=>monaco.languages.registerInlineCompletionsProvider(l,prov));
|
| 57 |
+
let t; editor.onDidChangeModelContent(()=>{clearTimeout(t); t=setTimeout(runCopilot,800);});
|
| 58 |
+
editor.addAction({id:'ask', label:'Preguntar a Qwen', keybindings:[monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK], run:()=>{document.getElementById('chatInput').focus();}});
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
+
async function runCopilot(){
|
| 62 |
+
const token=document.getElementById('token').value.trim(); if(!token) return;
|
| 63 |
+
let code=editor.getValue(); if(code.length<10) return;
|
| 64 |
+
document.getElementById('ghostStatus').textContent="Pensando...";
|
| 65 |
+
try{
|
| 66 |
+
const r=await fetch("https://api-inference.huggingface.co/models/Qwen/Qwen2.5-Coder-1.5B-Instruct",{method:"POST", headers:{"Content-Type":"application/json", Authorization:`Bearer ${token}`}, body:JSON.stringify({inputs:code.slice(-700), parameters:{max_new_tokens:80, return_full_text:false}})});
|
| 67 |
+
const d=await r.json(); ghost=(d[0]?.generated_text||"").slice(0,150);
|
| 68 |
+
if(ghost){ editor.trigger('k','editor.action.inlineSuggest.trigger',{}); document.getElementById('ghostStatus').textContent="Sugerencia: TAB"; }
|
| 69 |
+
}catch(e){}
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
async function askChat(){
|
| 73 |
+
const input=document.getElementById('chatInput'); const token=document.getElementById('token').value.trim();
|
| 74 |
+
const question=input.value; if(!question) return;
|
| 75 |
+
let selected = editor.getModel().getValueInRange(editor.getSelection()) || editor.getValue().slice(-500);
|
| 76 |
+
const chat=document.getElementById('chat');
|
| 77 |
+
chat.innerHTML+=`<div class="bg-blue-600 text-white p-3 rounded-lg ml-6">${question}</div>`;
|
| 78 |
+
input.value=""; chat.scrollTop=chat.scrollHeight;
|
| 79 |
+
|
| 80 |
+
const prompt = `Eres un asistente de codigo. Contexto:\n\`\`\`\n${selected}\n\`\`\`\nPregunta: ${question}\nResponde conciso con codigo si aplica.`;
|
| 81 |
+
const loading=document.createElement('div'); loading.className="bg-[#2d2d2d] p-3 rounded-lg"; loading.textContent="Escribiendo..."; chat.appendChild(loading);
|
| 82 |
+
|
| 83 |
+
try{
|
| 84 |
+
const r=await fetch("https://api-inference.huggingface.co/models/Qwen/Qwen2.5-Coder-7B-Instruct",{method:"POST", headers:{"Content-Type":"application/json",...(token?{Authorization:`Bearer ${token}`}:{})}, body:JSON.stringify({inputs:prompt, parameters:{max_new_tokens:400, temperature:0.3}})});
|
| 85 |
+
const d=await r.json(); let answer = d[0]?.generated_text || "Error";
|
| 86 |
+
loading.innerHTML = `<pre class="whitespace-pre-wrap">${answer.replace(/</g,'<')}</pre><button onclick="insert('${answer.replace(/'/g,"\\'").slice(0,200)}')" class="mt-2 bg-[#3c3c3c] px-2 py-1 rounded text-xs">Insertar</button>`;
|
| 87 |
+
}catch(e){ loading.textContent="Pon tu token HF arriba, es gratis"; }
|
| 88 |
+
chat.scrollTop=chat.scrollHeight;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
function insert(t){ editor.executeEdits('', [{range: editor.getSelection(), text: t}]); }
|
| 92 |
+
function download(){ const b=new Blob([editor.getValue()],{type:"text/plain"}); const a=document.createElement('a'); a.href=URL.createObjectURL(b); a.download="main.py"; a.click(); }
|
| 93 |
+
document.getElementById('chatInput').addEventListener('keydown', e=>{ if(e.key==='Enter') askChat(); });
|
| 94 |
+
document.getElementById('lang').addEventListener('change', e=>{ monaco.editor.setModelLanguage(editor.getModel(), e.target.value); });
|
| 95 |
+
</script>
|
| 96 |
+
</body>
|
| 97 |
</html>
|