Exploração Inicial da Estrutura do Projeto StoryEcho: Refinamentos no Sistema de Criação de Personagens e Integração com IA

Após a montagem inicial da estrutura, a equipe FateWeaver avançou para a fase de detalhamento e validação de funcionalidades. O trabalho se concentrou em aprimorar as interações principais da interface do usuário e verificar a viabilidade da integração com a API de modelos de linguagem grandes (LLM), garantindo a correção da abordagem técnica.

  1. Aprimoramento e Otimização da Criação de Personagens

A interface de criação de personagens, inicialmente um simples pop-up, foi expandida com funcionalidades detalhadas e otimizações de interface para proporcionar uma experiência mais completa ao usuário.

1.1 Design Diferenciado por Temática

Para suportar diferentes gêneros narrativos (fantasia, ficção científica, etc.), foram projetados sistemas independentes de talentos e origens. Cada gênero possui seu próprio conjunto de opções:

Talentos para Temática de Fantasia (ex: "Lendas da Floresta Nebulosa"):

// Dados de talentos de fantasia
const fantasyTalents = ref([
   { id: 'talent_001', name: 'Gênio de Combate', description: 'Você tem um talento extraordinário para o combate', 
     effects: { strength: 5, agility: 3 }, rarity: 'rare', unlocked: true, storyId: 'fantasy_001' },
   { id: 'talent_002', name: 'Erudito', description: 'Você possui um vasto conhecimento', 
     effects: { intelligence: 8, mp: 20 }, rarity: 'rare', unlocked: true, storyId: 'fantasy_001' },
   { id: 'talent_003', name: 'Sortudo', description: 'O destino parece sempre favorecê-lo', 
     effects: { luck: 10 }, rarity: 'epic', unlocked: true, storyId: 'fantasy_001' },
   { id: 'talent_005', name: 'Sangue de Dragão', description: 'O poder dos dragões corre em suas veias', 
     effects: { hp: 50, strength: 10 }, rarity: 'legendary', unlocked: false, storyId: 'fantasy_001' },
   // ... mais talentos
]);

Talentos para Temática de Ficção Científica (ex: "Cyberpunk 2077: Despertar"):

// Dados de talentos de ficção científica
const scifiTalents = ref([
   { id: 'sci_talent_001', name: 'Mestre Hacker', description: 'Você domina diversas técnicas de hacking', 
     effects: { intelligence: 8, tech_skill: 10 }, rarity: 'rare', unlocked: true, storyId: 'scifi_001' },
   { id: 'sci_talent_002', name: 'Adaptação Cibernética', description: 'Seu corpo se adapta melhor a implantes cibernéticos', 
     effects: { hp: 20, strength: 5 }, rarity: 'rare', unlocked: true, storyId: 'scifi_001' },
   { id: 'sci_talent_004', name: 'Implante de Combate', description: 'Você está equipado com implantes de combate de nível militar', 
     effects: { strength: 15, hp: 10 }, rarity: 'legendary', unlocked: false, storyId: 'scifi_001' },
   // ... mais talentos
]);

O sistema filtra dinamicamente os talentos e origens disponíveis com base no ID da história selecionada pelo usuário através de propriedades computadas como availableTalents e backgrounds.

// Talentos disponíveis para a história atual
const availableTalents = computed(() => {
   const allTalents = [...fantasyTalents.value, ...scifiTalents.value];
   if (!selectedStory.value) return fantasyTalents.value; // Retorna talentos de fantasia como padrão se nenhuma história for selecionada
   return allTalents.filter(t => t.storyId === selectedStory.value.story_id);
});

1.2 Sistema de Limite de Atributos

Diferentes temáticas possuem sistemas de atributos distintos. Uma configuração de atributos por história foi projetada para gerenciar isso:

const storyConfigs = {
   fantasy_001: {
       baseAttributes: { hp: 100, mp: 50, strength: 15, agility: 12, intelligence: 10, luck: 8 },
       maxValues: { hp: 150, mp: 100, strength: 50, agility: 50, intelligence: 50, luck: 50 }
   },
   scifi_001: {
       baseAttributes: { hp: 80, energy: 100, strength: 18, intelligence: 20, tech_skill: 15, money: 500 },
       maxValues: { hp: 120, energy: 150, strength: 60, intelligence: 60, tech_skill: 50, money: 9999 }
   }
};

A pré-visualização dos atributos calcula o valor base mais os bônus de talentos e origens, garantindo que não ultrapassem os limites definidos:

const previewAttributes = computed(() => {
   const config = currentStoryConfig.value;
   const base = { ...config.baseAttributes };
   const maxValues = config.maxValues;
   
   if (selectedTalent.value) {
       Object.entries(selectedTalent.value.effects).forEach(([attr, value]) => {
           if (base[attr] !== undefined) {
               // Aplica bônus, respeitando o limite máximo definido
               base[attr] = Math.min(base[attr] + value, maxValues[attr] || 100); 
           }
       });
   }
   if (selectedBackground.value) {
       Object.entries(selectedBackground.value.attribute_modifiers).forEach(([attr, value]) => {
           if (base[attr] !== undefined) {
                // Aplica bônus de origem, respeitando o limite máximo
               base[attr] = Math.min(base[attr] + value, maxValues[attr] || 100);
           }
       });
   }
   return base;
});

Mensagens de aviso são exibidas quando os atributos se aproximam ou atingem o limite.

const hasExceededLimit = computed(() => {
   const config = currentStoryConfig.value;
   const maxValues = config.maxValues;
   return Object.entries(previewAttributes.value).some(([attr, value]) => {
       // Verifica se algum atributo atingiu ou excedeu seu limite máximo
       return value >= (maxValues[attr] || 100); 
   });
});

1.3 Otimização da Barra de Progresso de Atributos

Uma barra de progresso com indicação de valor máximo foi implementada na área de pré-visualização de atributos para uma representação visual clara da proporção do atributo em relação ao seu limite.

<div class="attr-item">
   <span class="attr-name">{{ getAttrName(attr) }}</span>
   <div class="attr-bar">
       <div class="attr-fill" :style="{width: (value / getAttrMaxValue(attr) * 100) + '%'}"></div>
       <span class="attr-value">{{ value }}/{{ getAttrMaxValue(attr) }}</span>
   </div>
</div>
.attr-bar {
   flex: 1;
   height: 20px;
   background: rgba(255, 255, 255, 0.1);
   border-radius: 10px;
   position: relative;
   overflow: hidden;
}

.attr-fill {
   height: 100%;
   background: linear-gradient(90deg, #667eea, #764ba2);
   border-radius: 10px;
   transition: width 0.3s;
}

.attr-value {
   position: absolute;
   right: 8px;
   top: 50%;
   transform: translateY(-50%);
   font-size: 11px;
   color: white;
   text-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
   z-index: 1;
}

1.4 Resolução de Problemas de Sobreposição de Interface

Um problema de sobreposição entre a caixa de exibição de atributos e o controle deslizante de personalidade foi corrigido. A solução envolveu a definição de max-height e overflow-y: auto para os contêineres relevantes, introduzindo barras de rolagem quando o conteúdo excede o espaço definido.

.creation-content {
   display: grid;
   grid-template-columns: 1fr 1.5fr;
   gap: 30px;
   max-height: 500px; /* Limita a altura máxima */
}

.creation-form {
   overflow-y: auto; /* Adiciona rolagem vertical se necessário */
   padding-right: 10px;
   max-height: 500px;
}

.step-content {
   max-height: 350px;
   overflow-y: auto;
   padding-right: 10px;
}

O estilo do controle deslizante de personalidade também foi aprimorado.

.personality-slider {
   padding: 15px 0;
}

.personality-slider input {
   width: 100%;
   height: 6px;
   -webkit-appearance: none;
   appearance: none;
   background: linear-gradient(90deg, #10b981, #f59e0b, #ef4444);
   border-radius: 3px;
   outline: none;
}

.personality-slider input::-webkit-slider-thumb {
   -webkit-appearance: none;
   appearance: none;
   width: 20px;
   height: 20px;
   background: white;
   border-radius: 50%;
   cursor: pointer;
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

1.5 Adição da Funcionalidade de Filtragem de Histórias

Um componente de alternância de abas foi adicionado à página inicial para permitir a filtragem de histórias por gênero.

<div class="story-tabs-container">
   <div class="story-tab-item" :class="{active: activeStoryFilter === 'all'}" @click="activeStoryFilter = 'all'">
       <span>📚 All</span>
   </div>
   <div class="story-tab-item" :class="{active: activeStoryFilter === 'fantasy'}" @click="activeStoryFilter = 'fantasy'">
       <span>🌲 Fantasy</span>
   </div>
   <div class="story-tab-item" :class="{active: activeStoryFilter === 'scifi'}" @click="activeStoryFilter = 'scifi'">
       <span>🤖 Sci-Fi</span>
   </div>
</div>

A lógica de filtragem correspondente é a seguinte:

const filteredStories = computed(() => {
   if (activeStoryFilter.value === 'all') return stories.value;
   if (activeStoryFilter.value === 'fantasy') {
       return stories.value.filter(s => s.genre === 'Fantasy');
   }
   if (activeStoryFilter.value === 'scifi') {
       return stories.value.filter(s => s.genre === 'Sci-Fi');
   }
   return stories.value;
});

Ícones foram adicionados aos cards de história para melhorar o apelo visual.

<div class="story-card-header">
   <span class="story-icon">{{ story.icon || '📖' }}</span>
   <h3>{{ story.title }}</h3>
</div>
  1. Colaboração em Equipe e Integração de Código

Após a conclusão dos módulos individuais, uma integração de código centralizada foi realizada. Os trabalhos realizados pelos outros membros incluíram:

  • Otimização da interface do lobby de histórias, com melhoria nos cards e adição de rótulos de dificuldade.
  • Aprimoramento da barra de ferramentas da interface principal do jogo, com atalhos para registro de missões, rede de destinos, galeria de finais e herança de múltiplas jogadas.
  • Otimização do painel de status lateral, incluindo a exibição de barras de atributos e funcionalidade de expansão/recolhimento para o painel de afinidade de NPCs.
  • Estrutura base para as interfaces de final de jogo e galeria.

A integração resultou em um framework frontend funcional. Embora a maioria dos dados ainda fosse simulada (Mock data), o fluxo de interação do usuário estava substancialmente completo.

  1. Verificação de Integração de API e Primeira Conversa com IA

Paralelamente ao desenvolvimento frontend, um membro da equipe trabalhou na integração da API do DeepSeek para validar a viabilidade da narrativa interativa impulsionada por LLM.

3.1 Implementação da Classe LLMClient

A classe LLMClient foi implementada em story\_engine.py para encapsular as chamadas à API do LLM:

import os
import requests
from typing import List, Dict

class LLMClient:
   def __init__(self, api_key: str = None, base_url: str = None, model: str = None):
       # Prioriza chave e URL de ambiente, com fallback para valores fixos
       self.api_key = api_key or os.getenv("DEEPSEEK_API_KEY", "sk-2666c4c1dcfc4b0990dedc7b021cf29c")
       self.base_url = base_url or os.getenv("LLM_BASE_URL", "https://api.deepseek.com/v1")
       self.model = model or os.getenv("LLM_MODEL", "deepseek-chat")
       self.headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}

   def generate(self, messages: List[Dict[str, str]], temperature: float = 0.8) -> str:
       url = f"{self.base_url}/chat/completions"
       payload = {"model": self.model, "messages": messages, "temperature": temperature, "max_tokens": 800}
       try:
           response = requests.post(url, headers=self.headers, json=payload, timeout=30)
           response.raise_for_status() # Lança exceção para respostas de erro HTTP
           return response.json()["choices"][0]["message"]["content"]
       except requests.exceptions.RequestException as e:
           print(f"Falha na chamada LLM: {e}")
           return "(O modelo de linguagem não pôde responder no momento. Por favor, tente novamente mais tarde.)"

3.2 Ajustes de Inicialização do Backend

Em app.py, a inicialização do motor foi modificada para incluir o cliente LLM real:

# Inicializa o motor da história (usando o modelo de linguagem grande)
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "sk-2666c4c1dcfc4b0990dedc7b021cf29c")
llm_client = LLMClient(api_key=DEEPSEEK_API_KEY)
engine = StoryEngine(llm_client=llm_client)

3.3 Primeira Conversa com IA Bem-scuedida

Após a depuração, o fluxo completo de conversação com a IA foi implementado com sucesso! Esta validação bem-sucedida fortaleceu a confiança da equipe na arquitetura técnica.

  1. Conquistas Atuais e Planejamento Futuro

4.1 Resumo das Conquistas Atuais

  • Sistema de criação de personagens robusto com design diferenciado por temática, gerenciamento de limites de atributos e visualização em tempo real.
  • Funcionalidade de filtragem de histórias por gênero.
  • Validação bem-sucedida da integração com API de IA, estabelecendo um ciclo completo de entrada do usuário a geração de narrativa pela IA.
  • Framework frontend unificado, servindo como um protótipo interativo funcional.

4.2 Planejamento de Trabalho Futuro

No backend, os próximos passos incluem:

  • Persistência de dados usando um banco de dados para salvar o progresso do jogador, registros de coleta de finais e status de desbloqueio de talentos.
  • Refinamento do rastreamento de estado com nós de lógica de arbitragem mais avançados.
  • Implementação de um algoritmo de convergência de múltiplos finais.
  • Otimização do gerenciamento de contexto para manter a coerência em interações prolongadas.

A definição do framework frontend e a validação da conversa com IA removeram obstáculos significativos para o desenvolvimento paralelo. A equipe agora avançará com as tarefas atribuídas, realizando fusões de código regulares e testes de integração em direção a uma plataforma de narativa interativa completa.

Tags: Vue.js Python API LLM Node.js

Publicado em 7-4 01:26