import requests from datetime import datetime import gradio as gr import os import tempfile import sys class IntelligentCVAgent: def __init__(self): # Sinônimos dinâmicos - não limitam as tecnologias do usuário self.tech_synonyms = { 'react': ['react', 'reactjs', 'react.js', 'frontend', 'ui'], 'javascript': ['javascript', 'js', 'ecmascript'], 'typescript': ['typescript', 'ts'], 'node': ['node', 'nodejs', 'node.js', 'backend'], 'python': ['python', 'py'], 'java': ['java', 'spring'], 'html': ['html', 'html5'], 'css': ['css', 'css3', 'stylesheet'], 'sql': ['sql', 'database', 'mysql', 'postgresql'], 'mongodb': ['mongodb', 'mongo', 'nosql'], 'docker': ['docker', 'container'], 'aws': ['aws', 'amazon web services', 'cloud'], 'azure': ['azure', 'microsoft azure'], 'git': ['git', 'github', 'gitlab'], 'rest': ['rest', 'restful', 'api'], 'graphql': ['graphql', 'gql'], 'vue': ['vue', 'vuejs', 'vue.js'], 'angular': ['angular', 'angularjs'], 'php': ['php'], 'ruby': ['ruby', 'rails'], 'go': ['go', 'golang'], 'rust': ['rust'], 'kotlin': ['kotlin'], 'swift': ['swift'], 'flutter': ['flutter', 'dart'], 'nextjs': ['next', 'nextjs', 'next.js'], 'nestjs': ['nest', 'nestjs', 'nest.js'], 'express': ['express', 'expressjs'], 'django': ['django'], 'flask': ['flask'], 'fastapi': ['fastapi'], 'postgresql': ['postgres', 'postgresql'], 'mysql': ['mysql'], 'redis': ['redis'], 'kubernetes': ['kubernetes', 'k8s'], 'terraform': ['terraform'], 'jenkins': ['jenkins'], 'ci/cd': ['ci/cd', 'cicd', 'continuous integration'], } def analyze_project_complexity(self, project): """Analisa a complexidade do projeto baseado em múltiplos fatores""" score = 0 if project.get('size', 0) > 1000: score += 2 if project.get('forks_count', 0) > 0: score += 1 if project.get('stargazers_count', 0) > 0: score += 1 if project.get('has_issues', False): score += 1 if project.get('has_projects', False): score += 1 if project.get('has_wiki', False): score += 1 if project.get('language') and project['language'].lower() != 'html': score += 2 return min(score, 5) def generate_project_description(self, project, technologies): """Gera descrição inteligente para o projeto""" name = project.get('name', '') description = project.get('description', '') or '' language = project.get('language', '') complexity = self.analyze_project_complexity(project) project_type = self.detect_project_type(name, description, language) relevant_techs = self.find_relevant_technologies(description, language, technologies) if complexity >= 4: return self._generate_complex_project_desc(name, description, relevant_techs, project_type) elif complexity >= 2: return self._generate_medium_project_desc(name, description, relevant_techs, project_type) else: return self._generate_simple_project_desc(name, description, relevant_techs, project_type) def detect_project_type(self, name, description, language): """Detecta o tipo de projeto baseado no nome e descrição""" text = f"{name} {description}".lower() if any(word in text for word in ['web app', 'website', 'frontend', 'interface']): return 'web_application' elif any(word in text for word in ['api', 'rest', 'backend', 'server']): return 'api' elif any(word in text for word in ['mobile', 'react native', 'flutter']): return 'mobile' elif any(word in text for word in ['cli', 'command line', 'terminal']): return 'cli_tool' elif any(word in text for word in ['library', 'package', 'module']): return 'library' elif any(word in text for word in ['data', 'analysis', 'processing']): return 'data_processing' else: return 'general' def find_relevant_technologies(self, description, language, target_techs): """Encontra tecnologias relevantes baseado em sinônimos e busca flexível""" relevant = [] text = f"{description} {language}".lower() for tech in target_techs: tech_lower = tech.lower() # Verifica correspondência direta if tech_lower in text: relevant.append(tech) continue # Verifica sinônimos se existirem if tech_lower in self.tech_synonyms: synonyms = self.tech_synonyms[tech_lower] if any(synonym in text for synonym in synonyms): relevant.append(tech) continue # Busca parcial flexível para tecnologias não mapeadas tech_parts = tech_lower.replace('.', '').replace('-', ' ').split() if any(part in text for part in tech_parts if len(part) > 2): relevant.append(tech) return relevant def _generate_complex_project_desc(self, name, description, techs, project_type): if not techs: tech_list = "tecnologias modernas" elif len(techs) > 1: tech_list = ", ".join(techs[:-1]) + " e " + techs[-1] else: tech_list = techs[0] templates = [ f"Desenvolvimento completo do projeto {name} utilizando {tech_list}, implementando arquitetura escalável e boas práticas de engenharia de software. {description}", f"Liderança técnica no projeto {name} com stack tecnológica baseada em {tech_list}, entregando solução robusta e de alta performance. {description}", ] return templates[hash(name) % len(templates)] def _generate_medium_project_desc(self, name, description, techs, project_type): tech_list = ", ".join(techs) if techs else "tecnologias apropriadas" templates = [ f"Implementação do projeto {name} utilizando {tech_list}, desenvolvendo funcionalidades principais e integrações necessárias. {description}", f"Desenvolvimento da aplicação {name} com {tech_list}, focando na experiência do usuário e funcionalidades essenciais. {description}", ] return templates[hash(name) % len(templates)] def _generate_simple_project_desc(self, name, description, techs, project_type): tech_list = ", ".join(techs) if techs else "tecnologias web" templates = [ f"Desenvolvimento do projeto {name} utilizando {tech_list}, implementando conceitos fundamentais e funcionalidades básicas. {description}", f"Criação da aplicação {name} com {tech_list}, explorando boas práticas de desenvolvimento e padrões de projeto. {description}", ] return templates[hash(name) % len(templates)] def generate_professional_summary(self, projects_count, top_technologies): """Gera resumo profissional inteligente""" if not top_technologies: tech_string = "tecnologias modernas" else: tech_string = ", ".join(top_technologies[:3]) templates = [ f"Desenvolvedor com portfolio de {projects_count} projetos públicos, especializado em {tech_string}. " f"Transição de carreira consolidada através de projetos hands-on aplicando melhores práticas de engenharia de software.", f"Profissional com {projects_count} projetos desenvolvidos utilizando tecnologias como {tech_string}. " f"Experiência prática em desenvolvimento full-stack, arquitetura de sistemas e metodologias ágeis.", ] return templates[hash(str(top_technologies)) % len(templates)] def buscar_projetos_github(username): """Busca todos os repositórios do GitHub com paginação""" url = f"https://api.github.com/users/{username}/repos" repositorios = [] page = 1 while True: try: response = requests.get(url, params={'page': page, 'per_page': 100}) if response.status_code == 200: repos = response.json() if not repos: break repositorios.extend(repos) page += 1 else: print(f"❌ Erro na API GitHub: {response.status_code}") break except Exception as e: print(f"❌ Exceção na busca GitHub: {e}") break return repositorios def gerar_experiencias_inteligentes(projetos, techs, agent): """Gera experiências otimizadas usando o agente inteligente""" experiencias = {tech: [] for tech in techs} for projeto in projetos: linguagem = projeto.get('language', 'Não especificada') descricao = projeto.get('description', '') nome = projeto.get('name', 'Projeto sem nome') url = projeto.get('html_url', '') stars = projeto.get('stargazers_count', 0) forks = projeto.get('forks_count', 0) if descricao is None: descricao = '' relevant_techs = agent.find_relevant_technologies(descricao, linguagem, techs) for tech in relevant_techs: descricao_otimizada = agent.generate_project_description(projeto, [tech]) experiencia = { 'nome': nome, 'descricao_otimizada': descricao_otimizada, 'url': url, 'stars': stars, 'forks': forks, 'linguagem': linguagem } experiencias[tech].append(experiencia) return experiencias def criar_cv_markdown(nome, contato, linkedin, github, portfolio, educacao, experiencias, techs, agent): """Cria versão Markdown do CV""" markdown_content = f"# {nome}\n\n" markdown_content += f"{contato}\n" markdown_content += f"LinkedIn: {linkedin} | GitHub: {github}" if portfolio: markdown_content += f" | Portfólio: {portfolio}" markdown_content += "\n\n" total_projetos = sum(len(exp) for exp in experiencias.values()) top_techs = [tech for tech in techs if len(experiencias[tech]) > 0][:5] resumo = agent.generate_professional_summary(total_projetos, top_techs) markdown_content += "## Resumo Profissional\n\n" markdown_content += f"{resumo}\n\n" markdown_content += "## Experiência Técnica - Projetos\n\n" for tech in techs: projetos_tech = experiencias[tech] if projetos_tech: markdown_content += f"### {tech}\n\n" for projeto in projetos_tech[:3]: markdown_content += f"**{projeto['nome']}**\n\n" markdown_content += f"{projeto['descricao_otimizada']}\n\n" if projeto['stars'] > 0 or projeto['forks'] > 0: markdown_content += f"*Estatísticas: {projeto['stars']} ⭐ {projeto['forks']} 🍴*\n\n" markdown_content += f"**Repositório:** {projeto['url']}\n\n" markdown_content += "## Formação Acadêmica\n\n" markdown_content += f"{educacao}\n\n" markdown_content += "## Competências Técnicas\n\n" frontend = [tech for tech in techs if any(t in tech.lower() for t in ['react', 'angular', 'vue', 'html', 'css', 'javascript', 'typescript', 'svelte', 'next'])] backend = [tech for tech in techs if any(t in tech.lower() for t in ['node', 'python', 'java', 'spring', 'sql', 'api', 'express', 'django', 'flask', 'fastapi', 'nest', 'php', 'ruby', 'go', 'rust', '.net', 'c#'])] tools = [tech for tech in techs if any(t in tech.lower() for t in ['git', 'docker', 'aws', 'azure', 'linux', 'kubernetes', 'terraform', 'jenkins', 'ci/cd', 'gcp'])] if frontend: markdown_content += f"**Front-end:** {', '.join(frontend)}\n\n" if backend: markdown_content += f"**Back-end:** {', '.join(backend)}\n\n" if tools: markdown_content += f"**Ferramentas & DevOps:** {', '.join(tools)}\n\n" outras = [tech for tech in techs if tech not in frontend and tech not in backend and tech not in tools] if outras: markdown_content += f"**Outras Tecnologias:** {', '.join(outras)}\n\n" markdown_content += "## Idiomas\n\n" markdown_content += "- Português: Nativo\n" markdown_content += "- Inglês: Leitura e Escrita - Avançado | Audição - Intermediário | Conversação - Básico\n" markdown_content += "- Espanhol: Leitura e Escrita - Avançado | Audição - Intermediário | Conversação - Básico\n\n" markdown_content += "---\n" markdown_content += f"*CV gerado automaticamente - {datetime.now().strftime('%d/%m/%Y')}*\n" return markdown_content def gerar_cv_completo(nome, contato, linkedin, github_user, portfolio, educacao, tecnologias): """Função principal que gera o CV completo""" try: print("\n" + "="*60) print("🚀 INICIANDO GERAÇÃO DO CV") print("="*60) # Sigma 1: Validações robustas if not nome or not nome.strip(): return "❌ Erro: Nome é obrigatório.", "" if not github_user or not github_user.strip(): return "❌ Erro: Usuário do GitHub é obrigatório.", "" # Sigma 2: Processamento flexível de tecnologias techs = [tech.strip() for tech in tecnologias.split(',') if tech.strip()] if not techs: return "❌ Erro: Por favor, insira pelo menos uma tecnologia.", "" print(f"👤 Nome: {nome}") print(f"🔧 Tecnologias: {', '.join(techs)}") print(f"🐙 GitHub: {github_user}") # Sigma 3: Busca robusta de projetos print("\n📡 Buscando repositórios do GitHub...") projetos = buscar_projetos_github(github_user) if not projetos: return f"❌ Erro: Nenhum repositório encontrado para o usuário '{github_user}' ou erro na API do GitHub.", "" print(f"✅ {len(projetos)} repositórios encontrados!") # Inicializar agente agent = IntelligentCVAgent() # Sigma 4: Geração inteligente de experiências print("\n🤖 Analisando projetos e gerando experiências...") experiencias = gerar_experiencias_inteligentes(projetos, techs, agent) # Gerar CV Markdown print("\n📝 Gerando CV em Markdown...") cv_markdown = criar_cv_markdown( nome=nome, contato=contato, linkedin=linkedin, github=f"https://github.com/{github_user}", portfolio=portfolio, educacao=educacao, experiencias=experiencias, techs=techs, agent=agent ) print("✅ Markdown gerado!") # Estatísticas para o relatório total_projetos = len(projetos) projetos_utilizados = sum(len(exp) for exp in experiencias.values()) relatorio = f""" ## 📊 Relatório de Geração ✅ **CV gerado com sucesso!** ### Estatísticas: - 📁 Repositórios encontrados: {total_projetos} - 🎯 Projetos utilizados no CV: {projetos_utilizados} - 🤖 Tecnologias mapeadas: {len(techs)} ### Projetos por tecnologia: """ for tech in techs: count = len(experiencias[tech]) if count > 0: relatorio += f"- **{tech}**: {count} projetos\n" relatorio += "\n### 📥 Formato Disponível:\n" relatorio += "- ✅ **Markdown**: Formato de texto completo para cópia e edição\n" relatorio += "- 💡 **Dica**: Copie o conteúdo Markdown e use em qualquer editor de texto\n" print("\n" + "="*60) print("✅ PROCESSO CONCLUÍDO COM SUCESSO!") print("="*60 + "\n") return cv_markdown, relatorio except Exception as e: import traceback error_msg = f"❌ Erro durante a geração do CV: {str(e)}\n\n{traceback.format_exc()}" print(error_msg) return error_msg, "" # Interface Gradio with gr.Blocks(title="CV Generator AI - Agente Inteligente de Currículo", theme=gr.themes.Soft()) as demo: gr.Markdown( """ # 🤖 CV Generator AI ### Agente Inteligente de Currículo Este sistema analisa automaticamente seus projetos do GitHub e gera um currículo personalizado para cada vaga! """ ) with gr.Row(): with gr.Column(scale=1): gr.Markdown("## 📝 Informações Pessoais") nome = gr.Textbox( label="Nome Completo *", placeholder="Ex: João Silva" ) contato = gr.Textbox( label="Informações de Contato *", placeholder="Ex: Porto Alegre - RS | (51) 99999-9999 (somente WhatsApp) | email@exemplo.com" ) linkedin = gr.Textbox( label="LinkedIn *", placeholder="https://linkedin.com/in/seu-perfil" ) github_user = gr.Textbox( label="Usuário do GitHub *", placeholder="seu-usuario" ) portfolio = gr.Textbox( label="Portfólio/Site (opcional)", placeholder="https://seu-portfolio.com" ) educacao = gr.Textbox( label="Formação Acadêmica *", placeholder="Ex: Licenciatura em Ciência da Computação - Universidade Federal (Concluído em: jul/2024)" ) tecnologias = gr.Textbox( label="Tecnologias da Vaga (separadas por vírgula) *", placeholder="Ex: React, Node.js, Python, JavaScript, SQL, Docker, AWS...", info="✨ Digite QUALQUER tecnologia que desejar! Não há limitações." ) gerar_btn = gr.Button("🚀 Gerar CV Personalizado", variant="primary", size="lg") with gr.Column(scale=1): gr.Markdown("## 📊 Relatório e Resultados") relatorio = gr.Markdown( """ ### Instruções: 1. Preencha todas as informações ao lado (* campos obrigatórios) 2. Digite as tecnologias que deseja destacar no CV (QUALQUER tecnologia!) 3. Clique em **'Gerar CV Personalizado'** 4. Aguarde o processamento dos seus projetos do GitHub 5. Copie o conteúdo Markdown gerado ⏳ O processamento pode levar alguns segundos dependendo do número de repositórios. """ ) gr.Markdown("## 📄 Pré-visualização do CV") cv_output = gr.Textbox( label="CV em Markdown (para visualização e cópia)", lines=15, max_lines=25, show_copy_button=True ) # Event handler def processar_e_gerar(nome, contato, linkedin, github_user, portfolio, educacao, tecnologias): print("="*60) print("🚀 Iniciando geração do CV...") cv_markdown, relatorio_texto = gerar_cv_completo( nome, contato, linkedin, github_user, portfolio, educacao, tecnologias ) print(f"📄 Markdown: {len(cv_markdown) if cv_markdown else 0} caracteres") print(f"📊 Relatório: {len(relatorio_texto) if relatorio_texto else 0} caracteres") print("="*60) return cv_markdown, relatorio_texto gerar_btn.click( fn=processar_e_gerar, inputs=[nome, contato, linkedin, github_user, portfolio, educacao, tecnologias], outputs=[cv_output, relatorio] ) gr.Markdown( """ --- ### 🎯 Como funciona: 1. **Busca Inteligente**: Varre todos os seus repositórios públicos do GitHub 2. **Análise Semântica**: Identifica tecnologias relevantes para a vaga 3. **Geração de Textos**: Cria descrições profissionais otimizadas 4. **Formatação Profissional**: Gera CV em formato Markdown ### 💡 Dicas: - Use tecnologias específicas da vaga para melhores resultados - **ACEITA QUALQUER TECNOLOGIA** - não há lista pré-definida! - Mantenha suas descrições no GitHub atualizadas - Revise o CV gerado antes de usar - O formato Markdown é universal e pode ser convertido facilmente para outros formatos ### 📥 Sobre o Formato: - **Markdown**: Formato de texto universal e editável - **Copiável**: Use o botão de cópia para salvar o conteúdo - **Conversível**: Pode ser convertido para PDF, DOCX usando ferramentas online - **Editável**: Pode ser editado em qualquer editor de texto ### 🔒 Privacidade: - Seus dados não são armazenados em servidores - Processamento ocorre em tempo real - Nenhum arquivo temporário é criado no servidor ### ⚙️ Requisitos Técnicos: ```bash pip install gradio requests ``` --- **Desenvolvido com ❤️ usando IA Generativa** """ ) # Para executar diretamente if __name__ == "__main__": print("🚀 Iniciando interface Gradio...") demo.launch(share=True)