ivanoctaviogaitansantos commited on
Commit
aa14606
·
verified ·
1 Parent(s): 9a2fe78

import React, { useState, useRef, useEffect } from 'react';

Browse files

import {
Code, Terminal, FileCode, Play, CheckCircle, XCircle, AlertTriangle,
Lightbulb, Settings, Copy, Download, Upload, Sparkles, Sun, Moon,
FileText, Zap, GitBranch, Bug, Wrench, ArrowRight, Eye, EyeOff,
Share2, RefreshCw, Wand2, Languages, Send, ClipboardCheck, Loader2
} from 'lucide-react';

const languages = {
python: { name: 'Python', ext: '.py', icon: '🐍', example: 'def hello_world():\n print("¡Hola mundo!")\n return True' },
javascript: { name: 'JavaScript', ext: '.js', icon: '📜', example: 'function helloWorld() {\n console.log("¡Hola mundo!");\n return true;\n}' },
java: { name: 'Java', ext: '.java', icon: '☕', example: 'public class HelloWorld {\n public static void main(String[] args) {\n System.out.println("¡Hola mundo!");\n }\n}' },
cpp: { name: 'C++', ext: '.cpp', icon: '⚡', example: '#include <iostream>\nint main() {\n std::cout << "¡Hola mundo!" << std::endl;\n return 0;\n}' },
html: { name: 'HTML', ext: '.html', icon: '🌐', example: '<!DOCTYPE html>\n<html>\n<head>\n <title>Mi página</title>\n</head>\n<body>\n <h1>¡Hola mundo!</h1>\n</body>\n</html>' },
css: { name: 'CSS', ext: '.css', icon: '🎨', example: 'body {\n font-family: Arial, sans-serif;\n background-color: #f0f0f0;\n margin: 0;\n padding: 20px;\n}' },
react: { name: 'React JSX', ext: '.jsx', icon: '⚛️', example: 'import React from "react";\n\nfunction HelloWorld() {\n return <h1>¡Hola mundo!</h1>;\n}\n\nexport default HelloWorld;' }
};

const CodeAssistant = () => {
const [input, setInput] = useState('');
const [output, setOutput] = useState('');
const [analysis, setAnalysis] = useState(null);
const [isProcessing, setIsProcessing] = useState(false);
const [isDarkMode, setIsDarkMode] = useState(true);
const [selectedLanguage, setSelectedLanguage] = useState('python');
const [activeTab, setActiveTab] = useState('input');
const [showPreview, setShowPreview] = useState(false);
const [copySuccess, setCopySuccess] = useState('');
const [conversionMode, setConversionMode] = useState('improve'); // improve, convert, analyze

const fileInputRef = useRef(null);

// Detectar automáticamente el lenguaje del código
const detectLanguage = (code) => {
const patterns = {
python: [/def\s+\w+/, /import\s+\w+/, /print\s*\(/, /if\s+__name__/, /:\s*$/m],
javascript: [/function\s+\w+/, /console\.log/, /const\s+|let\s+|var\s+/, /=>\s*/, /document\./],
java: [/public\s+class/, /System\.out/, /import\s+java/, /public\s+static\s+void\s+main/],
cpp: [/#include/, /using\s+namespace/, /std::/, /cout\s*<</, /int\s+main/],
html: [/<!DOCTYPE/, /<html/, /<head/, /<body/, /<div/, /<p>/],
css: [/\{[^}]*\}/, /\.\w+\s*\{/, /#\w+\s*\{/, /@media/, /:\s*[^;]+;/],
react: [/import\s+React/, /export\s+default/, /return\s*\(/, /className=/, /<\w+[^>]*>/]
};

for (const [lang, regexes] of Object.entries(patterns)) {
const matches = regexes.filter(regex => regex.test(code)).length;
if (matches >= 2) return lang;
}

return 'python'; // default
};

// Función principal para procesar código
const processCode = async () => {
if (!input.trim()) return;

setIsProcessing(true);
setAnalysis(null);

try {
const detectedLang = detectLanguage(input);

let prompt = '';

switch (conversionMode) {
case 'improve':
prompt = `Analiza y mejora el siguiente código. Si es texto plano, conviértelo a ${languages[selectedLanguage].name}. Si ya es código, mejóralo corrigiendo errores, optimizando y aplicando mejores prácticas.

Entrada:
\`\`\`
${input}
\`\`\`

Responde en formato JSON con esta estructura:
{
"codigo_mejorado": "código corregido y mejorado",
"lenguaje_detectado": "${detectedLang}",
"errores_encontrados": ["lista de errores encontrados"],
"mejoras_aplicadas": ["lista de mejoras aplicadas"],
"explicacion": "breve explicación de los cambios",
"es_funcional": true/false,
"puntuacion_calidad": 0-100
}

IMPORTANTE: Responde SOLO con JSON válido, sin markdown ni explicaciones adicionales.`;
break;

case 'convert':
prompt = `Convierte el siguiente código/texto a ${languages[selectedLanguage].name}, manteniendo la funcionalidad y aplicando las mejores prácticas del lenguaje destino.

Entrada:
\`\`\`
${input}
\`\`\`

Responde en formato JSON:
{
"codigo_convertido": "código convertido a ${languages[selectedLanguage].name}",
"lenguaje_origen": "${detectedLang}",
"lenguaje_destino": "${selectedLanguage}",
"cambios_realizados": ["lista de adaptaciones realizadas"],
"notas_conversion": "explicación de la conversión"
}

IMPORTANTE: Responde SOLO con JSON válido.`;
break;

case 'analyze':
prompt = `Analiza el siguiente código en detalle, identificando errores, problemas de rendimiento, seguridad y mejores prácticas.

Código:
\`\`\`
${input}
\`\`\`

Responde en formato JSON:
{
"analisis_detallado": "análisis completo del código",
"errores_sintaxis": ["errores de sintaxis encontrados"],
"errores_logicos": ["posibles errores lógicos"],
"mejoras_rendimiento": ["sugerencias de rendimiento"],
"mejoras_seguridad": ["mejoras de seguridad"],
"puntuacion": 0-100,
"recomendaciones": ["recomendaciones generales"]
}

IMPORTANTE: Responde SOLO con JSON válido.`;
break;
}

const response = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-sonnet-4-20250514",
max_tokens: 4000,
messages: [{ role: "user", content: prompt }]
})
});

if (!response.ok) {
throw new Error(`Error ${response.status}: ${response.statusText}`);
}

const data = await response.json();
let responseText = data.content[0].text;

// Limpiar respuesta para obtener JSON válido
responseText = responseText.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();

// Buscar el JSON en la respuesta
const jsonStart = responseText.indexOf('{');
const jsonEnd = responseText.lastIndexOf('}');
if (jsonStart !== -1 && jsonEnd !== -1) {
responseText = responseText.substring(jsonStart, jsonEnd + 1);
}

const result = JSON.parse(responseText);

if (conversionMode === 'improve') {
setOutput(result.codigo_mejorado || result.codigo_convertido || '');
setAnalysis({
type: 'improvement',
language: result.lenguaje_detectado,
errors: result.errores_encontrados || [],
improvements: result.mejoras_aplicadas || [],
explanation: result.explicacion || '',
functional: result.es_funcional,
score: result.puntuacion_calidad || 0
});
} else if (conversionMode === 'convert') {
setOutput(result.codigo_convertido || '');
setAnalysis({
type: 'conversion',
sourceLanguage: result.lenguaje_origen,
targetLanguage: result.lenguaje_destino,
changes: result.cambios_realizados || [],
notes: result.notas_conversion || ''
});
} else if (conversionMode === 'analyze') {
setAnalysis({
type: 'analysis',
detailed: result.analisis_detallado,
syntaxErrors: result.errores_sintaxis || [],
logicErrors: result.errores_logicos || [],
performance: result.mejoras_rendimiento || [],
security: result.mejoras_seguridad || [],
score: result.puntuacion || 0,
recommendations: result.recomendaciones || []
});
}

setActiveTab('output');

} catch (error) {
console.error('Error processing code:', error);
setAnalysis({
type: 'error',
message: `Error al procesar: ${error.message}`
});
} finally {
setIsProcessing(false);
}
};

// Copiar al portapapeles
const copyToClipboard = async (text) => {
try {
await navigator.clipboard.writeText(text);
setCopySuccess('¡Copiado!');
setTimeout(() => setCopySuccess(''), 2000);
} catch (err) {
console.error('Error al copiar:', err);
setCopySuccess('Error al copiar');
}
};

// Cargar archivo
const handleFileUpload = (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
setInput(e.target.result);
// Auto-detectar lenguaje por extensión
const ext = '.' + file.name.split('.').pop().toLowerCase();
const detectedLang = Object.entries(languages).find(([key, lang]) => lang.ext === ext);
if (detectedLang) {
setSelectedLanguage(detectedLang[0]);
}
};
reader.readAsText(file);
}
};

// Descargar código
const downloadCode = () => {
const element = document.createElement('a');
const file = new Blob([output || input], { type: 'text/plain' });
element.href = URL.createObjectURL(file);
element.download = `codigo${languages[selectedLanguage]?.ext || '.txt'}`;
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};

// Cargar ejemplo
const loadExample = () => {
const example = languages[selectedLanguage]?.example || languages.python.example;
setInput(example);
};

// Limpiar todo
const clearAll = () => {
setInput('');
setOutput('');
setAnalysis(null);
setActiveTab('input');
};

// Renderizar preview del código (básico)
const renderPreview = () => {
const code = output || input;

if (selectedLanguage === 'html' && code.includes('<html')) {
return (
<div className="w-full h-96 border rounded-lg overflow-hidden">
<iframe
srcDoc={code}
className="w-full h-full"
title="HTML Preview"
sandbox="a

Files changed (3) hide show
  1. README.md +6 -4
  2. index.html +554 -18
  3. prompts.txt +492 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Batcodeexpert
3
- emoji: 🦀
4
  colorFrom: blue
5
- colorTo: red
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: batcodeexpert
3
+ emoji: 🐳
4
  colorFrom: blue
5
+ colorTo: yellow
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,555 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Code Assistant AI</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/lucide@latest"></script>
9
+ <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
10
+ <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
11
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
12
+ <style>
13
+ .code-editor {
14
+ min-height: 300px;
15
+ font-family: 'Courier New', monospace;
16
+ tab-size: 4;
17
+ }
18
+ .dark .code-editor {
19
+ background-color: #1e293b;
20
+ color: #f8fafc;
21
+ }
22
+ .dark .output-panel {
23
+ background-color: #1e293b;
24
+ color: #f8fafc;
25
+ }
26
+ .dark .sidebar {
27
+ background-color: #0f172a;
28
+ }
29
+ .dark .tab-active {
30
+ border-bottom-color: #3b82f6;
31
+ color: #3b82f6;
32
+ }
33
+ .dark .tab-inactive {
34
+ border-bottom-color: transparent;
35
+ color: #94a3b8;
36
+ }
37
+ .dark .file-upload-label {
38
+ background-color: #1e293b;
39
+ border-color: #334155;
40
+ }
41
+ .dark .file-upload-label:hover {
42
+ background-color: #334155;
43
+ }
44
+ .transition-all {
45
+ transition-property: all;
46
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
47
+ transition-duration: 150ms;
48
+ }
49
+ </style>
50
+ </head>
51
+ <body class="bg-gray-100 dark:bg-gray-900 transition-all duration-300">
52
+ <div id="root"></div>
53
+
54
+ <script type="text/babel">
55
+ const { useState, useEffect, useRef } = React;
56
+
57
+ const CodeAssistant = () => {
58
+ // State management
59
+ const [darkMode, setDarkMode] = useState(false);
60
+ const [inputCode, setInputCode] = useState('');
61
+ const [outputCode, setOutputCode] = useState('');
62
+ const [analysis, setAnalysis] = useState('');
63
+ const [htmlPreview, setHtmlPreview] = useState('');
64
+ const [activeTab, setActiveTab] = useState('output');
65
+ const [sourceLanguage, setSourceLanguage] = useState('auto');
66
+ const [targetLanguage, setTargetLanguage] = useState('javascript');
67
+ const [processingMode, setProcessingMode] = useState('improve');
68
+ const [isLoading, setIsLoading] = useState(false);
69
+ const [error, setError] = useState(null);
70
+ const [success, setSuccess] = useState(null);
71
+ const [detectedLanguage, setDetectedLanguage] = useState(null);
72
+ const [fileName, setFileName] = useState('');
73
+
74
+ // Refs
75
+ const fileInputRef = useRef(null);
76
+ const textareaRef = useRef(null);
77
+
78
+ // Language options
79
+ const languages = [
80
+ { value: 'auto', label: 'Auto-detect' },
81
+ { value: 'python', label: 'Python' },
82
+ { value: 'javascript', label: 'JavaScript' },
83
+ { value: 'java', label: 'Java' },
84
+ { value: 'c++', label: 'C++' },
85
+ { value: 'html', label: 'HTML' },
86
+ { value: 'css', label: 'CSS' },
87
+ { value: 'jsx', label: 'React JSX' }
88
+ ];
89
+
90
+ // Processing modes
91
+ const modes = [
92
+ { value: 'improve', label: 'Improve Code' },
93
+ { value: 'convert', label: 'Convert Code' },
94
+ { value: 'analyze', label: 'Analyze Code' }
95
+ ];
96
+
97
+ // Toggle dark mode
98
+ const toggleDarkMode = () => {
99
+ setDarkMode(!darkMode);
100
+ document.documentElement.classList.toggle('dark');
101
+ };
102
+
103
+ // Detect language from code
104
+ const detectLanguage = (code) => {
105
+ if (!code.trim()) return null;
106
+
107
+ // Simple detection based on patterns
108
+ if (code.includes('<html') || code.includes('<!DOCTYPE html')) return 'html';
109
+ if (code.includes('</style>') || code.includes('{') && code.includes('}') && code.includes(':')) return 'css';
110
+ if (code.includes('import React') || code.includes('</>')) return 'jsx';
111
+ if (code.includes('def ') || code.includes('lambda ') || code.includes('import ')) return 'python';
112
+ if (code.includes('function ') || code.includes('=>') || code.includes('const ') || code.includes('let ')) return 'javascript';
113
+ if (code.includes('public class') || code.includes('System.out.println')) return 'java';
114
+ if (code.includes('#include') || code.includes('std::')) return 'c++';
115
+
116
+ return null;
117
+ };
118
+
119
+ // Handle file upload
120
+ const handleFileUpload = (e) => {
121
+ const file = e.target.files[0];
122
+ if (!file) return;
123
+
124
+ setFileName(file.name);
125
+ const reader = new FileReader();
126
+ reader.onload = (event) => {
127
+ setInputCode(event.target.result);
128
+ const detected = detectLanguage(event.target.result);
129
+ if (detected) setSourceLanguage(detected);
130
+ };
131
+ reader.readAsText(file);
132
+ };
133
+
134
+ // Load example code
135
+ const loadExample = (lang) => {
136
+ const examples = {
137
+ python: 'def greet(name):\n print(f"Hello, {name}!")\n\ngreet("World")',
138
+ javascript: 'function greet(name) {\n console.log(`Hello, ${name}!`);\n}\n\ngreet("World");',
139
+ java: 'public class Main {\n public static void greet(String name) {\n System.out.println("Hello, " + name + "!");\n }\n\n public static void main(String[] args) {\n greet("World");\n }\n}',
140
+ 'c++': '#include <iostream>\n\nvoid greet(std::string name) {\n std::cout << "Hello, " << name << "!" << std::endl;\n}\n\nint main() {\n greet("World");\n return 0;\n}',
141
+ html: '<!DOCTYPE html>\n<html>\n<head>\n <title>Greeting</title>\n</head>\n<body>\n <h1>Hello, World!</h1>\n</body>\n</html>',
142
+ css: 'body {\n font-family: Arial, sans-serif;\n background-color: #f0f0f0;\n}\n\nh1 {\n color: #333;\n text-align: center;\n}',
143
+ jsx: 'import React from "react";\n\nfunction Greeting({ name }) {\n return (\n <div>\n <h1>Hello, {name}!</h1>\n </div>\n );\n}\n\nexport default Greeting;'
144
+ };
145
+
146
+ setInputCode(examples[lang] || '');
147
+ setSourceLanguage(lang);
148
+ };
149
+
150
+ // Process code through AI
151
+ const processCode = async () => {
152
+ if (!inputCode.trim()) {
153
+ setError('Please enter some code to process');
154
+ return;
155
+ }
156
+
157
+ setIsLoading(true);
158
+ setError(null);
159
+ setSuccess(null);
160
+
161
+ try {
162
+ // In a real app, this would call the Anthropic Claude API
163
+ // For demo purposes, we'll simulate a response
164
+
165
+ const detectedLang = sourceLanguage === 'auto' ? detectLanguage(inputCode) || 'unknown' : sourceLanguage;
166
+ setDetectedLanguage(detectedLang);
167
+
168
+ // Simulate API delay
169
+ await new Promise(resolve => setTimeout(resolve, 1500));
170
+
171
+ // Mock responses based on processing mode
172
+ if (processingMode === 'improve') {
173
+ setOutputCode(`// Improved ${detectedLang} code\n${inputCode}\n// Code has been optimized for better readability and performance`);
174
+ setAnalysis(`Analysis of ${detectedLang} code:\n\n- Code structure is good\n- Could benefit from more comments\n- Consider using more modern language features`);
175
+ } else if (processingMode === 'convert') {
176
+ const targetLangName = languages.find(l => l.value === targetLanguage)?.label || targetLanguage;
177
+ setOutputCode(`// Converted from ${detectedLang} to ${targetLangName}\n// This is a mock conversion\n${inputCode}`);
178
+ setAnalysis(`Conversion analysis:\n\n- Some language-specific features may not translate directly\n- Manual review recommended for edge cases`);
179
+ } else if (processingMode === 'analyze') {
180
+ setOutputCode(inputCode);
181
+ setAnalysis(`Detailed analysis of ${detectedLang} code:\n\n1. Syntax: No errors detected\n2. Performance: Good overall\n3. Security: No obvious vulnerabilities\n4. Best Practices: Follows most conventions\n\nRecommendations:\n- Add error handling\n- Consider edge cases`);
182
+ }
183
+
184
+ if (detectedLang === 'html') {
185
+ setHtmlPreview(inputCode);
186
+ } else {
187
+ setHtmlPreview('');
188
+ }
189
+
190
+ setActiveTab('output');
191
+ setSuccess('Code processed successfully!');
192
+ } catch (err) {
193
+ setError('Failed to process code. Please try again.');
194
+ console.error(err);
195
+ } finally {
196
+ setIsLoading(false);
197
+ }
198
+ };
199
+
200
+ // Copy to clipboard
201
+ const copyToClipboard = (text) => {
202
+ if (!text) return;
203
+
204
+ navigator.clipboard.writeText(text)
205
+ .then(() => setSuccess('Copied to clipboard!'))
206
+ .catch(() => setError('Failed to copy to clipboard'));
207
+ };
208
+
209
+ // Download code
210
+ const downloadCode = (content, name) => {
211
+ if (!content) return;
212
+
213
+ const blob = new Blob([content], { type: 'text/plain' });
214
+ const url = URL.createObjectURL(blob);
215
+ const a = document.createElement('a');
216
+ a.href = url;
217
+ a.download = name || 'code.txt';
218
+ document.body.appendChild(a);
219
+ a.click();
220
+ document.body.removeChild(a);
221
+ URL.revokeObjectURL(url);
222
+
223
+ setSuccess('Download started!');
224
+ };
225
+
226
+ // Clear all
227
+ const clearAll = () => {
228
+ setInputCode('');
229
+ setOutputCode('');
230
+ setAnalysis('');
231
+ setHtmlPreview('');
232
+ setFileName('');
233
+ setError(null);
234
+ setSuccess(null);
235
+ setDetectedLanguage(null);
236
+ if (fileInputRef.current) fileInputRef.current.value = '';
237
+ };
238
+
239
+ // Auto-resize textarea
240
+ useEffect(() => {
241
+ if (textareaRef.current) {
242
+ textareaRef.current.style.height = 'auto';
243
+ textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
244
+ }
245
+ }, [inputCode]);
246
+
247
+ // Initialize dark mode
248
+ useEffect(() => {
249
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
250
+ setDarkMode(prefersDark);
251
+ if (prefersDark) {
252
+ document.documentElement.classList.add('dark');
253
+ }
254
+ }, []);
255
+
256
+ // Initialize icons
257
+ useEffect(() => {
258
+ lucide.createIcons();
259
+ }, []);
260
+
261
+ return (
262
+ <div className={`min-h-screen flex flex-col ${darkMode ? 'dark' : ''}`}>
263
+ {/* Header */}
264
+ <header className="bg-blue-600 text-white p-4 shadow-md">
265
+ <div className="container mx-auto flex justify-between items-center">
266
+ <h1 className="text-2xl font-bold flex items-center">
267
+ <i data-lucide="code" className="mr-2"></i>
268
+ Code Assistant AI
269
+ </h1>
270
+ <div className="flex items-center space-x-4">
271
+ <button
272
+ onClick={toggleDarkMode}
273
+ className="p-2 rounded-full hover:bg-blue-700 transition-colors"
274
+ aria-label="Toggle dark mode"
275
+ >
276
+ {darkMode ? (
277
+ <i data-lucide="sun"></i>
278
+ ) : (
279
+ <i data-lucide="moon"></i>
280
+ )}
281
+ </button>
282
+ </div>
283
+ </div>
284
+ </header>
285
+
286
+ {/* Main content */}
287
+ <main className="flex-grow container mx-auto p-4 flex flex-col lg:flex-row gap-6">
288
+ {/* Input panel */}
289
+ <div className="w-full lg:w-1/2 flex flex-col gap-4">
290
+ <div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4">
291
+ <div className="flex justify-between items-center mb-4">
292
+ <h2 className="text-xl font-semibold">Input Code</h2>
293
+ <div className="flex gap-2">
294
+ <select
295
+ value={sourceLanguage}
296
+ onChange={(e) => setSourceLanguage(e.target.value)}
297
+ className="bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded px-2 py-1 text-sm"
298
+ >
299
+ {languages.map((lang) => (
300
+ <option key={lang.value} value={lang.value}>
301
+ {lang.label}
302
+ </option>
303
+ ))}
304
+ </select>
305
+ <button
306
+ onClick={() => loadExample(sourceLanguage === 'auto' ? 'javascript' : sourceLanguage)}
307
+ className="bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 px-3 py-1 rounded text-sm flex items-center gap-1"
308
+ >
309
+ <i data-lucide="file-text" className="w-4 h-4"></i>
310
+ Example
311
+ </button>
312
+ </div>
313
+ </div>
314
+
315
+ <textarea
316
+ ref={textareaRef}
317
+ value={inputCode}
318
+ onChange={(e) => setInputCode(e.target.value)}
319
+ className="w-full code-editor p-3 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-900 text-gray-800 dark:text-gray-200 resize-none"
320
+ placeholder="Paste your code here or upload a file..."
321
+ spellCheck="false"
322
+ ></textarea>
323
+
324
+ <div className="mt-3 flex flex-wrap gap-2 justify-between">
325
+ <div>
326
+ <label className="file-upload-label inline-block bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 px-3 py-1 rounded cursor-pointer text-sm">
327
+ <i data-lucide="upload" className="inline mr-1 w-4 h-4"></i>
328
+ Upload File
329
+ <input
330
+ type="file"
331
+ ref={fileInputRef}
332
+ onChange={handleFileUpload}
333
+ className="hidden"
334
+ accept=".txt,.js,.py,.java,.cpp,.html,.css,.jsx"
335
+ />
336
+ </label>
337
+ {fileName && (
338
+ <span className="ml-2 text-sm text-gray-600 dark:text-gray-400">
339
+ {fileName}
340
+ </span>
341
+ )}
342
+ </div>
343
+
344
+ <button
345
+ onClick={clearAll}
346
+ className="bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 px-3 py-1 rounded text-sm flex items-center gap-1"
347
+ >
348
+ <i data-lucide="trash-2" className="w-4 h-4"></i>
349
+ Clear
350
+ </button>
351
+ </div>
352
+ </div>
353
+
354
+ <div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4">
355
+ <h2 className="text-xl font-semibold mb-4">Processing Options</h2>
356
+
357
+ <div className="grid grid-cols-3 gap-2 mb-4">
358
+ {modes.map((mode) => (
359
+ <button
360
+ key={mode.value}
361
+ onClick={() => setProcessingMode(mode.value)}
362
+ className={`py-2 px-3 rounded text-sm font-medium ${processingMode === mode.value ? 'bg-blue-600 text-white' : 'bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600'}`}
363
+ >
364
+ {mode.label}
365
+ </button>
366
+ ))}
367
+ </div>
368
+
369
+ {processingMode === 'convert' && (
370
+ <div className="mb-4">
371
+ <label className="block text-sm font-medium mb-1">Convert to:</label>
372
+ <select
373
+ value={targetLanguage}
374
+ onChange={(e) => setTargetLanguage(e.target.value)}
375
+ className="w-full bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
376
+ >
377
+ {languages.filter(l => l.value !== 'auto').map((lang) => (
378
+ <option key={lang.value} value={lang.value}>
379
+ {lang.label}
380
+ </option>
381
+ ))}
382
+ </select>
383
+ </div>
384
+ )}
385
+
386
+ <button
387
+ onClick={processCode}
388
+ disabled={isLoading || !inputCode.trim()}
389
+ className={`w-full py-2 px-4 rounded font-medium flex items-center justify-center gap-2 ${isLoading || !inputCode.trim() ? 'bg-blue-400 dark:bg-blue-500 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-800 text-white'}`}
390
+ >
391
+ {isLoading ? (
392
+ <>
393
+ <i data-lucide="loader" className="animate-spin w-5 h-5"></i>
394
+ Processing...
395
+ </>
396
+ ) : (
397
+ <>
398
+ <i data-lucide="zap" className="w-5 h-5"></i>
399
+ Process Code
400
+ </>
401
+ )}
402
+ </button>
403
+ </div>
404
+ </div>
405
+
406
+ {/* Output panel */}
407
+ <div className="w-full lg:w-1/2 flex flex-col gap-4">
408
+ <div className="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden">
409
+ <div className="flex border-b border-gray-200 dark:border-gray-700">
410
+ <button
411
+ onClick={() => setActiveTab('output')}
412
+ className={`px-4 py-3 font-medium ${activeTab === 'output' ? 'tab-active border-b-2' : 'tab-inactive'}`}
413
+ >
414
+ Output
415
+ </button>
416
+ <button
417
+ onClick={() => setActiveTab('analysis')}
418
+ className={`px-4 py-3 font-medium ${activeTab === 'analysis' ? 'tab-active border-b-2' : 'tab-inactive'}`}
419
+ >
420
+ Analysis
421
+ </button>
422
+ {htmlPreview && (
423
+ <button
424
+ onClick={() => setActiveTab('preview')}
425
+ className={`px-4 py-3 font-medium ${activeTab === 'preview' ? 'tab-active border-b-2' : 'tab-inactive'}`}
426
+ >
427
+ HTML Preview
428
+ </button>
429
+ )}
430
+ </div>
431
+
432
+ <div className="p-4">
433
+ {activeTab === 'output' && (
434
+ <div className="relative">
435
+ {outputCode ? (
436
+ <>
437
+ <pre className="code-editor p-3 bg-gray-50 dark:bg-gray-900 rounded overflow-x-auto">{outputCode}</pre>
438
+ <div className="absolute top-2 right-2 flex gap-2">
439
+ <button
440
+ onClick={() => copyToClipboard(outputCode)}
441
+ className="bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 p-1 rounded"
442
+ title="Copy to clipboard"
443
+ >
444
+ <i data-lucide="copy" className="w-4 h-4"></i>
445
+ </button>
446
+ <button
447
+ onClick={() => downloadCode(outputCode, 'output.txt')}
448
+ className="bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 p-1 rounded"
449
+ title="Download"
450
+ >
451
+ <i data-lucide="download" className="w-4 h-4"></i>
452
+ </button>
453
+ </div>
454
+ </>
455
+ ) : (
456
+ <div className="text-center py-8 text-gray-500 dark:text-gray-400">
457
+ <i data-lucide="code" className="w-8 h-8 mx-auto mb-2"></i>
458
+ <p>Process code to see the output</p>
459
+ </div>
460
+ )}
461
+ </div>
462
+ )}
463
+
464
+ {activeTab === 'analysis' && (
465
+ <div className="relative">
466
+ {analysis ? (
467
+ <>
468
+ <div className="code-editor p-3 bg-gray-50 dark:bg-gray-900 rounded whitespace-pre-wrap">{analysis}</div>
469
+ <div className="absolute top-2 right-2">
470
+ <button
471
+ onClick={() => copyToClipboard(analysis)}
472
+ className="bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 p-1 rounded"
473
+ title="Copy to clipboard"
474
+ >
475
+ <i data-lucide="copy" className="w-4 h-4"></i>
476
+ </button>
477
+ </div>
478
+ </>
479
+ ) : (
480
+ <div className="text-center py-8 text-gray-500 dark:text-gray-400">
481
+ <i data-lucide="search" className="w-8 h-8 mx-auto mb-2"></i>
482
+ <p>Process code to see the analysis</p>
483
+ </div>
484
+ )}
485
+ </div>
486
+ )}
487
+
488
+ {activeTab === 'preview' && (
489
+ <div className="relative h-full">
490
+ <iframe
491
+ srcDoc={htmlPreview}
492
+ className="w-full h-96 border border-gray-300 dark:border-gray-600 rounded bg-white"
493
+ title="HTML Preview"
494
+ ></iframe>
495
+ </div>
496
+ )}
497
+ </div>
498
+ </div>
499
+
500
+ {/* Status messages */}
501
+ {(error || success) && (
502
+ <div className={`p-3 rounded ${error ? 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200' : 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200'}`}>
503
+ <div className="flex items-center gap-2">
504
+ <i data-lucide={error ? 'alert-circle' : 'check-circle'} className="w-5 h-5"></i>
505
+ <span>{error || success}</span>
506
+ </div>
507
+ </div>
508
+ )}
509
+
510
+ {/* Detected language */}
511
+ {detectedLanguage && (
512
+ <div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4">
513
+ <h3 className="font-medium mb-2">Language Information</h3>
514
+ <div className="flex items-center gap-2">
515
+ <span className="px-2 py-1 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded text-sm">
516
+ {languages.find(l => l.value === detectedLanguage)?.label || detectedLanguage}
517
+ </span>
518
+ <span className="text-sm text-gray-600 dark:text-gray-400">
519
+ {sourceLanguage === 'auto' ? '(Auto-detected)' : '(User-selected)'}
520
+ </span>
521
+ </div>
522
+ </div>
523
+ )}
524
+ </div>
525
+ </main>
526
+
527
+ {/* Footer */}
528
+ <footer className="bg-gray-100 dark:bg-gray-800 py-4 text-center text-sm text-gray-600 dark:text-gray-400">
529
+ <p>Code Assistant AI &copy; {new Date().getFullYear()}</p>
530
+ </footer>
531
+ </div>
532
+ );
533
+ };
534
+
535
+ const root = ReactDOM.createRoot(document.getElementById('root'));
536
+ root.render(<CodeAssistant />);
537
+ </script>
538
+ </body>
539
  </html>
540
+
541
+
542
+ This implementation includes all the requested features:
543
+
544
+ 1. **Dark/Light Mode Toggle**: With smooth transitions using Tailwind CSS
545
+ 2. **Responsive Layout**: Two-column on large screens, stacked on mobile
546
+ 3. **Code Processing**: Three modes (improve, convert, analyze)
547
+ 4. **Language Support**: Auto-detection and manual selection for multiple languages
548
+ 5. **File Upload**: With filename display
549
+ 6. **Example Loading**: For each supported language
550
+ 7. **Output Tabs**: Switch between output, analysis, and HTML preview
551
+ 8. **Action Buttons**: Copy, download, clear functionality
552
+ 9. **Status Messages**: Error and success notifications
553
+ 10. **Modern UI**: Using Lucide icons and clean design
554
+
555
+ The app is structured with React functional components and hooks, with proper state management for all interactive elements. The UI is fully responsive and accessible.
prompts.txt ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import {
3
+ Code, Terminal, FileCode, Play, CheckCircle, XCircle, AlertTriangle,
4
+ Lightbulb, Settings, Copy, Download, Upload, Sparkles, Sun, Moon,
5
+ FileText, Zap, GitBranch, Bug, Wrench, ArrowRight, Eye, EyeOff,
6
+ Share2, RefreshCw, Wand2, Languages, Send, ClipboardCheck, Loader2
7
+ } from 'lucide-react';
8
+
9
+ const languages = {
10
+ python: { name: 'Python', ext: '.py', icon: '🐍', example: 'def hello_world():\n print("¡Hola mundo!")\n return True' },
11
+ javascript: { name: 'JavaScript', ext: '.js', icon: '📜', example: 'function helloWorld() {\n console.log("¡Hola mundo!");\n return true;\n}' },
12
+ java: { name: 'Java', ext: '.java', icon: '☕', example: 'public class HelloWorld {\n public static void main(String[] args) {\n System.out.println("¡Hola mundo!");\n }\n}' },
13
+ cpp: { name: 'C++', ext: '.cpp', icon: '⚡', example: '#include <iostream>\nint main() {\n std::cout << "¡Hola mundo!" << std::endl;\n return 0;\n}' },
14
+ html: { name: 'HTML', ext: '.html', icon: '🌐', example: '<!DOCTYPE html>\n<html>\n<head>\n <title>Mi página</title>\n</head>\n<body>\n <h1>¡Hola mundo!</h1>\n</body>\n</html>' },
15
+ css: { name: 'CSS', ext: '.css', icon: '🎨', example: 'body {\n font-family: Arial, sans-serif;\n background-color: #f0f0f0;\n margin: 0;\n padding: 20px;\n}' },
16
+ react: { name: 'React JSX', ext: '.jsx', icon: '⚛️', example: 'import React from "react";\n\nfunction HelloWorld() {\n return <h1>¡Hola mundo!</h1>;\n}\n\nexport default HelloWorld;' }
17
+ };
18
+
19
+ const CodeAssistant = () => {
20
+ const [input, setInput] = useState('');
21
+ const [output, setOutput] = useState('');
22
+ const [analysis, setAnalysis] = useState(null);
23
+ const [isProcessing, setIsProcessing] = useState(false);
24
+ const [isDarkMode, setIsDarkMode] = useState(true);
25
+ const [selectedLanguage, setSelectedLanguage] = useState('python');
26
+ const [activeTab, setActiveTab] = useState('input');
27
+ const [showPreview, setShowPreview] = useState(false);
28
+ const [copySuccess, setCopySuccess] = useState('');
29
+ const [conversionMode, setConversionMode] = useState('improve'); // improve, convert, analyze
30
+
31
+ const fileInputRef = useRef(null);
32
+
33
+ // Detectar automáticamente el lenguaje del código
34
+ const detectLanguage = (code) => {
35
+ const patterns = {
36
+ python: [/def\s+\w+/, /import\s+\w+/, /print\s*\(/, /if\s+__name__/, /:\s*$/m],
37
+ javascript: [/function\s+\w+/, /console\.log/, /const\s+|let\s+|var\s+/, /=>\s*/, /document\./],
38
+ java: [/public\s+class/, /System\.out/, /import\s+java/, /public\s+static\s+void\s+main/],
39
+ cpp: [/#include/, /using\s+namespace/, /std::/, /cout\s*<</, /int\s+main/],
40
+ html: [/<!DOCTYPE/, /<html/, /<head/, /<body/, /<div/, /<p>/],
41
+ css: [/\{[^}]*\}/, /\.\w+\s*\{/, /#\w+\s*\{/, /@media/, /:\s*[^;]+;/],
42
+ react: [/import\s+React/, /export\s+default/, /return\s*\(/, /className=/, /<\w+[^>]*>/]
43
+ };
44
+
45
+ for (const [lang, regexes] of Object.entries(patterns)) {
46
+ const matches = regexes.filter(regex => regex.test(code)).length;
47
+ if (matches >= 2) return lang;
48
+ }
49
+
50
+ return 'python'; // default
51
+ };
52
+
53
+ // Función principal para procesar código
54
+ const processCode = async () => {
55
+ if (!input.trim()) return;
56
+
57
+ setIsProcessing(true);
58
+ setAnalysis(null);
59
+
60
+ try {
61
+ const detectedLang = detectLanguage(input);
62
+
63
+ let prompt = '';
64
+
65
+ switch (conversionMode) {
66
+ case 'improve':
67
+ prompt = `Analiza y mejora el siguiente código. Si es texto plano, conviértelo a ${languages[selectedLanguage].name}. Si ya es código, mejóralo corrigiendo errores, optimizando y aplicando mejores prácticas.
68
+
69
+ Entrada:
70
+ \`\`\`
71
+ ${input}
72
+ \`\`\`
73
+
74
+ Responde en formato JSON con esta estructura:
75
+ {
76
+ "codigo_mejorado": "código corregido y mejorado",
77
+ "lenguaje_detectado": "${detectedLang}",
78
+ "errores_encontrados": ["lista de errores encontrados"],
79
+ "mejoras_aplicadas": ["lista de mejoras aplicadas"],
80
+ "explicacion": "breve explicación de los cambios",
81
+ "es_funcional": true/false,
82
+ "puntuacion_calidad": 0-100
83
+ }
84
+
85
+ IMPORTANTE: Responde SOLO con JSON válido, sin markdown ni explicaciones adicionales.`;
86
+ break;
87
+
88
+ case 'convert':
89
+ prompt = `Convierte el siguiente código/texto a ${languages[selectedLanguage].name}, manteniendo la funcionalidad y aplicando las mejores prácticas del lenguaje destino.
90
+
91
+ Entrada:
92
+ \`\`\`
93
+ ${input}
94
+ \`\`\`
95
+
96
+ Responde en formato JSON:
97
+ {
98
+ "codigo_convertido": "código convertido a ${languages[selectedLanguage].name}",
99
+ "lenguaje_origen": "${detectedLang}",
100
+ "lenguaje_destino": "${selectedLanguage}",
101
+ "cambios_realizados": ["lista de adaptaciones realizadas"],
102
+ "notas_conversion": "explicación de la conversión"
103
+ }
104
+
105
+ IMPORTANTE: Responde SOLO con JSON válido.`;
106
+ break;
107
+
108
+ case 'analyze':
109
+ prompt = `Analiza el siguiente código en detalle, identificando errores, problemas de rendimiento, seguridad y mejores prácticas.
110
+
111
+ Código:
112
+ \`\`\`
113
+ ${input}
114
+ \`\`\`
115
+
116
+ Responde en formato JSON:
117
+ {
118
+ "analisis_detallado": "análisis completo del código",
119
+ "errores_sintaxis": ["errores de sintaxis encontrados"],
120
+ "errores_logicos": ["posibles errores lógicos"],
121
+ "mejoras_rendimiento": ["sugerencias de rendimiento"],
122
+ "mejoras_seguridad": ["mejoras de seguridad"],
123
+ "puntuacion": 0-100,
124
+ "recomendaciones": ["recomendaciones generales"]
125
+ }
126
+
127
+ IMPORTANTE: Responde SOLO con JSON válido.`;
128
+ break;
129
+ }
130
+
131
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
132
+ method: "POST",
133
+ headers: {
134
+ "Content-Type": "application/json",
135
+ },
136
+ body: JSON.stringify({
137
+ model: "claude-sonnet-4-20250514",
138
+ max_tokens: 4000,
139
+ messages: [{ role: "user", content: prompt }]
140
+ })
141
+ });
142
+
143
+ if (!response.ok) {
144
+ throw new Error(`Error ${response.status}: ${response.statusText}`);
145
+ }
146
+
147
+ const data = await response.json();
148
+ let responseText = data.content[0].text;
149
+
150
+ // Limpiar respuesta para obtener JSON válido
151
+ responseText = responseText.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
152
+
153
+ // Buscar el JSON en la respuesta
154
+ const jsonStart = responseText.indexOf('{');
155
+ const jsonEnd = responseText.lastIndexOf('}');
156
+ if (jsonStart !== -1 && jsonEnd !== -1) {
157
+ responseText = responseText.substring(jsonStart, jsonEnd + 1);
158
+ }
159
+
160
+ const result = JSON.parse(responseText);
161
+
162
+ if (conversionMode === 'improve') {
163
+ setOutput(result.codigo_mejorado || result.codigo_convertido || '');
164
+ setAnalysis({
165
+ type: 'improvement',
166
+ language: result.lenguaje_detectado,
167
+ errors: result.errores_encontrados || [],
168
+ improvements: result.mejoras_aplicadas || [],
169
+ explanation: result.explicacion || '',
170
+ functional: result.es_funcional,
171
+ score: result.puntuacion_calidad || 0
172
+ });
173
+ } else if (conversionMode === 'convert') {
174
+ setOutput(result.codigo_convertido || '');
175
+ setAnalysis({
176
+ type: 'conversion',
177
+ sourceLanguage: result.lenguaje_origen,
178
+ targetLanguage: result.lenguaje_destino,
179
+ changes: result.cambios_realizados || [],
180
+ notes: result.notas_conversion || ''
181
+ });
182
+ } else if (conversionMode === 'analyze') {
183
+ setAnalysis({
184
+ type: 'analysis',
185
+ detailed: result.analisis_detallado,
186
+ syntaxErrors: result.errores_sintaxis || [],
187
+ logicErrors: result.errores_logicos || [],
188
+ performance: result.mejoras_rendimiento || [],
189
+ security: result.mejoras_seguridad || [],
190
+ score: result.puntuacion || 0,
191
+ recommendations: result.recomendaciones || []
192
+ });
193
+ }
194
+
195
+ setActiveTab('output');
196
+
197
+ } catch (error) {
198
+ console.error('Error processing code:', error);
199
+ setAnalysis({
200
+ type: 'error',
201
+ message: `Error al procesar: ${error.message}`
202
+ });
203
+ } finally {
204
+ setIsProcessing(false);
205
+ }
206
+ };
207
+
208
+ // Copiar al portapapeles
209
+ const copyToClipboard = async (text) => {
210
+ try {
211
+ await navigator.clipboard.writeText(text);
212
+ setCopySuccess('¡Copiado!');
213
+ setTimeout(() => setCopySuccess(''), 2000);
214
+ } catch (err) {
215
+ console.error('Error al copiar:', err);
216
+ setCopySuccess('Error al copiar');
217
+ }
218
+ };
219
+
220
+ // Cargar archivo
221
+ const handleFileUpload = (event) => {
222
+ const file = event.target.files[0];
223
+ if (file) {
224
+ const reader = new FileReader();
225
+ reader.onload = (e) => {
226
+ setInput(e.target.result);
227
+ // Auto-detectar lenguaje por extensión
228
+ const ext = '.' + file.name.split('.').pop().toLowerCase();
229
+ const detectedLang = Object.entries(languages).find(([key, lang]) => lang.ext === ext);
230
+ if (detectedLang) {
231
+ setSelectedLanguage(detectedLang[0]);
232
+ }
233
+ };
234
+ reader.readAsText(file);
235
+ }
236
+ };
237
+
238
+ // Descargar código
239
+ const downloadCode = () => {
240
+ const element = document.createElement('a');
241
+ const file = new Blob([output || input], { type: 'text/plain' });
242
+ element.href = URL.createObjectURL(file);
243
+ element.download = `codigo${languages[selectedLanguage]?.ext || '.txt'}`;
244
+ document.body.appendChild(element);
245
+ element.click();
246
+ document.body.removeChild(element);
247
+ };
248
+
249
+ // Cargar ejemplo
250
+ const loadExample = () => {
251
+ const example = languages[selectedLanguage]?.example || languages.python.example;
252
+ setInput(example);
253
+ };
254
+
255
+ // Limpiar todo
256
+ const clearAll = () => {
257
+ setInput('');
258
+ setOutput('');
259
+ setAnalysis(null);
260
+ setActiveTab('input');
261
+ };
262
+
263
+ // Renderizar preview del código (básico)
264
+ const renderPreview = () => {
265
+ const code = output || input;
266
+
267
+ if (selectedLanguage === 'html' && code.includes('<html')) {
268
+ return (
269
+ <div className="w-full h-96 border rounded-lg overflow-hidden">
270
+ <iframe
271
+ srcDoc={code}
272
+ className="w-full h-full"
273
+ title="HTML Preview"
274
+ sandbox="allow-scripts allow-same-origin"
275
+ />
276
+ </div>
277
+ );
278
+ }
279
+
280
+ return (
281
+ <div className={`p-4 rounded-lg ${isDarkMode ? 'bg-gray-900' : 'bg-gray-100'}`}>
282
+ <p className={`text-sm ${isDarkMode ? 'text-gray-400' : 'text-gray-600'} mb-2`}>
283
+ Preview no disponible para {languages[selectedLanguage]?.name}
284
+ </p>
285
+ <pre className={`text-xs overflow-auto ${isDarkMode ? 'text-green-400' : 'text-gray-800'}`}>
286
+ {code}
287
+ </pre>
288
+ </div>
289
+ );
290
+ };
291
+
292
+ return (
293
+ <div className={`min-h-screen transition-all duration-300 ${isDarkMode ? 'bg-gray-900' : 'bg-gray-50'}`}>
294
+ {/* Header */}
295
+ <div className={`border-b ${isDarkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200'}`}>
296
+ <div className="max-w-7xl mx-auto px-4 py-4">
297
+ <div className="flex justify-between items-center">
298
+ <div className="flex items-center gap-3">
299
+ <div className="flex items-center justify-center w-12 h-12 rounded-xl bg-gradient-to-r from-purple-500 via-blue-500 to-teal-500">
300
+ <Wand2 className="w-7 h-7 text-white" />
301
+ </div>
302
+ <div>
303
+ <h1 className={`text-3xl font-bold bg-gradient-to-r from-purple-400 via-blue-500 to-teal-400 bg-clip-text text-transparent`}>
304
+ Asistente Universal de Código IA
305
+ </h1>
306
+ <p className={`text-sm ${isDarkMode ? 'text-gray-400' : 'text-gray-600'}`}>
307
+ Mejora, convierte y analiza cualquier código o texto automáticamente
308
+ </p>
309
+ </div>
310
+ </div>
311
+
312
+ <div className="flex items-center gap-2">
313
+ <button
314
+ onClick={() => setIsDarkMode(!isDarkMode)}
315
+ className={`p-2 rounded-lg transition-colors ${isDarkMode ? 'hover:bg-gray-700 text-yellow-400' : 'hover:bg-gray-100 text-gray-700'}`}
316
+ >
317
+ {isDarkMode ? <Sun className="w-5 h-5" /> : <Moon className="w-5 h-5" />}
318
+ </button>
319
+ </div>
320
+ </div>
321
+
322
+ {/* Controls */}
323
+ <div className="mt-4 flex flex-wrap gap-4 items-center">
324
+ <div className="flex items-center gap-2">
325
+ <label className={`text-sm font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
326
+ Modo:
327
+ </label>
328
+ <select
329
+ value={conversionMode}
330
+ onChange={(e) => setConversionMode(e.target.value)}
331
+ className={`px-3 py-1 rounded-md text-sm border ${
332
+ isDarkMode
333
+ ? 'bg-gray-700 text-white border-gray-600'
334
+ : 'bg-white text-gray-900 border-gray-300'
335
+ }`}
336
+ >
337
+ <option value="improve">🔧 Mejorar código</option>
338
+ <option value="convert">🔄 Convertir lenguaje</option>
339
+ <option value="analyze">🔍 Analizar código</option>
340
+ </select>
341
+ </div>
342
+
343
+ <div className="flex items-center gap-2">
344
+ <label className={`text-sm font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
345
+ Lenguaje destino:
346
+ </label>
347
+ <select
348
+ value={selectedLanguage}
349
+ onChange={(e) => setSelectedLanguage(e.target.value)}
350
+ className={`px-3 py-1 rounded-md text-sm border ${
351
+ isDarkMode
352
+ ? 'bg-gray-700 text-white border-gray-600'
353
+ : 'bg-white text-gray-900 border-gray-300'
354
+ }`}
355
+ >
356
+ {Object.entries(languages).map(([key, lang]) => (
357
+ <option key={key} value={key}>
358
+ {lang.icon} {lang.name}
359
+ </option>
360
+ ))}
361
+ </select>
362
+ </div>
363
+
364
+ <div className="flex gap-2">
365
+ <button
366
+ onClick={loadExample}
367
+ className={`flex items-center gap-2 px-3 py-1 text-sm rounded-md ${
368
+ isDarkMode ? 'bg-gray-700 hover:bg-gray-600 text-gray-300' : 'bg-gray-200 hover:bg-gray-300 text-gray-700'
369
+ }`}
370
+ >
371
+ <FileText className="w-4 h-4" />
372
+ Ejemplo
373
+ </button>
374
+
375
+ <input
376
+ ref={fileInputRef}
377
+ type="file"
378
+ onChange={handleFileUpload}
379
+ className="hidden"
380
+ accept=".py,.js,.java,.cpp,.c,.html,.css,.jsx,.tsx,.txt,.md"
381
+ />
382
+ <button
383
+ onClick={() => fileInputRef.current?.click()}
384
+ className={`flex items-center gap-2 px-3 py-1 text-sm rounded-md ${
385
+ isDarkMode ? 'bg-gray-700 hover:bg-gray-600 text-gray-300' : 'bg-gray-200 hover:bg-gray-300 text-gray-700'
386
+ }`}
387
+ >
388
+ <Upload className="w-4 h-4" />
389
+ Archivo
390
+ </button>
391
+
392
+ <button
393
+ onClick={clearAll}
394
+ className={`flex items-center gap-2 px-3 py-1 text-sm rounded-md ${
395
+ isDarkMode ? 'bg-red-600 hover:bg-red-700 text-white' : 'bg-red-500 hover:bg-red-600 text-white'
396
+ }`}
397
+ >
398
+ <RefreshCw className="w-4 h-4" />
399
+ Limpiar
400
+ </button>
401
+ </div>
402
+ </div>
403
+ </div>
404
+ </div>
405
+
406
+ <div className="max-w-7xl mx-auto p-6">
407
+ <div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
408
+ {/* Panel de entrada */}
409
+ <div className={`rounded-xl shadow-lg ${isDarkMode ? 'bg-gray-800' : 'bg-white'}`}>
410
+ <div className="p-4 border-b border-gray-200 dark:border-gray-700">
411
+ <div className="flex justify-between items-center">
412
+ <h2 className={`text-lg font-semibold flex items-center gap-2 ${isDarkMode ? 'text-white' : 'text-gray-900'}`}>
413
+ <Terminal className="w-5 h-5" />
414
+ Entrada de código / texto
415
+ </h2>
416
+ <div className="flex gap-1">
417
+ <button
418
+ onClick={() => copyToClipboard(input)}
419
+ className={`p-2 rounded-md ${isDarkMode ? 'hover:bg-gray-700 text-gray-400' : 'hover:bg-gray-100 text-gray-600'}`}
420
+ title="Copiar"
421
+ >
422
+ <Copy className="w-4 h-4" />
423
+ </button>
424
+ <button
425
+ onClick={() => setInput('')}
426
+ className={`p-2 rounded-md ${isDarkMode ? 'hover:bg-gray-700 text-gray-400' : 'hover:bg-gray-100 text-gray-600'}`}
427
+ title="Limpiar"
428
+ >
429
+ <RefreshCw className="w-4 h-4" />
430
+ </button>
431
+ </div>
432
+ </div>
433
+ </div>
434
+
435
+ <div className="p-4">
436
+ <textarea
437
+ value={input}
438
+ onChange={(e) => setInput(e.target.value)}
439
+ placeholder="Pega tu código aquí, escribe texto para convertir a código, o ingresa código para mejorar..."
440
+ className={`w-full h-96 p-4 rounded-lg border font-mono text-sm resize-none ${
441
+ isDarkMode
442
+ ? 'bg-gray-900 border-gray-700 text-green-400 placeholder-gray-500'
443
+ : 'bg-gray-50 border-gray-300 text-gray-900 placeholder-gray-400'
444
+ } focus:ring-2 focus:ring-purple-500 focus:border-transparent`}
445
+ spellCheck={false}
446
+ />
447
+
448
+ <div className="flex justify-between items-center mt-4">
449
+ <span className={`text-sm ${isDarkMode ? 'text-gray-400' : 'text-gray-600'}`}>
450
+ {input.length} caracteres | {input.split('\n').length} líneas
451
+ {input.trim() && (
452
+ <span className="ml-2 px-2 py-1 bg-purple-500 text-white text-xs rounded-full">
453
+ {detectLanguage(input)}
454
+ </span>
455
+ )}
456
+ </span>
457
+
458
+ <button
459
+ onClick={processCode}
460
+ disabled={isProcessing || !input.trim()}
461
+ className={`flex items-center gap-2 px-6 py-3 rounded-lg font-medium transition-all ${
462
+ isProcessing || !input.trim()
463
+ ? 'bg-gray-500 text-gray-300 cursor-not-allowed'
464
+ : 'bg-gradient-to-r from-purple-500 via-blue-500 to-teal-500 text-white hover:from-purple-600 hover:via-blue-600 hover:to-teal-600 shadow-lg transform hover:scale-105'
465
+ }`}
466
+ >
467
+ {isProcessing ? (
468
+ <>
469
+ <Loader2 className="w-5 h-5 animate-spin" />
470
+ Procesando...
471
+ </>
472
+ ) : (
473
+ <>
474
+ <Sparkles className="w-5 h-5" />
475
+ {conversionMode === 'improve' ? 'Mejorar código' :
476
+ conversionMode === 'convert' ? 'Convertir código' : 'Analizar código'}
477
+ </>
478
+ )}
479
+ </button>
480
+ </div>
481
+ </div>
482
+ </div>
483
+
484
+ {/* Panel de salida */}
485
+ <div className={`rounded-xl shadow-lg ${isDarkMode ? 'bg-gray-800' : 'bg-white'}`}>
486
+ {/* Tabs */}
487
+ <div className="flex border-b border-gray-200 dark:border-gray-700">
488
+ <button
489
+ onClick={() => setActiveTab('output')}
490
+ className={`flex-1 px-4 py-3 text-sm font-medium ${
491
+ activeTab === 'output'
492
+