| import requests |
| from datetime import datetime |
| import gradio as gr |
| import os |
| import tempfile |
| import sys |
|
|
| class IntelligentCVAgent: |
| def __init__(self): |
| |
| 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() |
| |
| |
| if tech_lower in text: |
| relevant.append(tech) |
| continue |
| |
| |
| 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 |
| |
| |
| 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) |
| |
| |
| 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.", "" |
| |
| |
| 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}") |
| |
| |
| 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!") |
| |
| |
| agent = IntelligentCVAgent() |
| |
| |
| print("\n🤖 Analisando projetos e gerando experiências...") |
| experiencias = gerar_experiencias_inteligentes(projetos, techs, agent) |
| |
| |
| 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!") |
| |
| |
| 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, "" |
|
|
| |
| 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 |
| ) |
| |
| |
| 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** |
| """ |
| ) |
|
|
| |
| if __name__ == "__main__": |
| print("🚀 Iniciando interface Gradio...") |
| demo.launch(share=True) |