Daniel251's picture
Update app.py
ab0adf9 verified
Raw
History Blame Contribute Delete
22.3 kB
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)