Refactor: Remove classic debate mode, simplify to collaborative design only
- Delete CHANGELOG.md (unnecessary documentation)
- Remove classic debate mode and all related components
- Simplify App.vue to single flow: input → session
- Redesign CollaborativeInput to accept optional context file (MD/TXT)
- Always output Markdown format (remove format selection)
- Add NetworkStatus component showing latency and network quality
- Network indicator auto-checks every 5 seconds with color-coded status
- File upload validation for .md and .txt formats only
- Cleaner, more focused user experience
Output format now always: Markdown
Input options: description (required) + context file (optional)
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7574f353ee
commit
f20c0b4996
174
CHANGELOG.md
174
CHANGELOG.md
@ -1,174 +0,0 @@
|
|||||||
# Changelog - Collaborative Design System
|
|
||||||
|
|
||||||
## Version 2.0 - Collaborative Document Design (Nouvelle Fonctionnalité)
|
|
||||||
|
|
||||||
### 🎯 Concept Principal
|
|
||||||
Remplacement du système de débat parallèle par un système de **conception itérative collaborative** où :
|
|
||||||
- Un architecte lead crée un document initial complet
|
|
||||||
- 3-7 agents spécialisés révisent et améliorent le document tour par tour
|
|
||||||
- Le document évolue progressivement jusqu'à convergence naturelle
|
|
||||||
- Traçabilité complète de toutes les modifications
|
|
||||||
|
|
||||||
### Backend - Changements
|
|
||||||
|
|
||||||
#### 1. **Base de Données** (`src/db/schema.js`)
|
|
||||||
- ✅ Nouvelles tables :
|
|
||||||
- `collaborative_sessions` : Sessions de conception
|
|
||||||
- `document_versions` : Historique complet des versions
|
|
||||||
- `document_rounds` : Suivi des tours de table
|
|
||||||
- Maintien de la compatibilité rétro avec `debates` et `responses`
|
|
||||||
|
|
||||||
#### 2. **Service d'Orchestration** (`src/services/collaborativeOrchestrator.js` - NOUVEAU)
|
|
||||||
- `createSession()` : Crée une nouvelle session collaborative
|
|
||||||
- `startCollaborativeSession()` : Lead Architect crée le document initial
|
|
||||||
- `runRound()` : Exécute un tour de revue (chaque agent revoit le document)
|
|
||||||
- `getSessionDetails()` : Récupère l'état complet avec historique
|
|
||||||
- `calculateDiff()` : Suivi des modifications entre versions
|
|
||||||
- Détection automatique de convergence (aucun changement d'un tour complet)
|
|
||||||
|
|
||||||
#### 3. **Routes API** (`src/routes/collaborate.js` - NOUVEAU)
|
|
||||||
```
|
|
||||||
POST /api/collaborate - Créer une session
|
|
||||||
POST /api/collaborate/:id/start - Démarrer la session
|
|
||||||
POST /api/collaborate/:id/round - Exécuter un tour de revue
|
|
||||||
GET /api/collaborate/:id - Obtenir les détails
|
|
||||||
GET /api/collaborate/:id/document - Télécharger le document actuel
|
|
||||||
GET /api/collaborate/:id/versions/:v - Obtenir une version spécifique
|
|
||||||
POST /api/collaborate/:id/complete - Terminer la session
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4. **Serveur Principal** (`src/index.js`)
|
|
||||||
- ✅ Intégration du nouvel orchestrateur collaboratif
|
|
||||||
- ✅ Support WebSocket pour `sessionId` en plus de `debateId`
|
|
||||||
- Routage automatique vers `/api/collaborate`
|
|
||||||
|
|
||||||
### Frontend - Changements
|
|
||||||
|
|
||||||
#### 1. **Store Pinia** (`src/stores/collaboration.js` - NOUVEAU)
|
|
||||||
- Gestion d'état des sessions collaboratives
|
|
||||||
- Fonctions pour créer, lancer, et suivre les sessions
|
|
||||||
- Méthodes de téléchargement de documents
|
|
||||||
|
|
||||||
#### 2. **Composants Vue**
|
|
||||||
|
|
||||||
**CollaborativeInput.vue** (NOUVEAU)
|
|
||||||
- Formulaire pour créer une nouvelle session
|
|
||||||
- Choix du format (Markdown/Texte)
|
|
||||||
- Sélection du nombre d'agents (3-7)
|
|
||||||
- Interface conviviale avec explications
|
|
||||||
|
|
||||||
**CollaborativeSession.vue** (NOUVEAU)
|
|
||||||
- Affichage en temps réel du document en évolution
|
|
||||||
- Timeline des modifications avec agents impliqués
|
|
||||||
- Boutons de contrôle :
|
|
||||||
- "Next Review Round" : Lancer le tour suivant
|
|
||||||
- "Complete Session" : Terminer
|
|
||||||
- "Download" : Exporter le document
|
|
||||||
- "Timeline" : Voir l'historique
|
|
||||||
- Affichage du statut de convergence
|
|
||||||
|
|
||||||
**DocumentViewer.vue** (NOUVEAU)
|
|
||||||
- Rendu du document en Markdown ou texte brut
|
|
||||||
- Mise en évidence syntaxique simple
|
|
||||||
- Support des liens, listes, code blocks
|
|
||||||
- Responsive et bien stylisé
|
|
||||||
|
|
||||||
#### 3. **App.vue** - Refonte Majeure
|
|
||||||
- Écran de sélection du mode au démarrage
|
|
||||||
- 2 modes : "Classic Debate" vs "Collaborative Design" (Recommandé)
|
|
||||||
- Navigation fluide entre les modes
|
|
||||||
- Boutons de retour intuitifs
|
|
||||||
|
|
||||||
#### 4. **Composable WebSocket Amélioré** (`src/composables/useWebSocket.js`)
|
|
||||||
- Support de `sessionId` en paramètre
|
|
||||||
- Rétro-compatible avec `debateId`
|
|
||||||
- Routing automatique du WebSocket
|
|
||||||
|
|
||||||
### Améliorations Produit
|
|
||||||
|
|
||||||
#### 1. **7 Agents Spécialisés** (vs 4 avant)
|
|
||||||
- Lead Architect (créateur du document initial, poids 1.5x dans anciennes versions)
|
|
||||||
- Backend Engineer
|
|
||||||
- Frontend Engineer
|
|
||||||
- UI/UX Designer
|
|
||||||
- DevOps Engineer (NOUVEAU)
|
|
||||||
- Product Manager (NOUVEAU)
|
|
||||||
- Security Specialist (NOUVEAU)
|
|
||||||
|
|
||||||
#### 2. **Flux Itératif Intelligent**
|
|
||||||
- Chaque agent voit le document complet + historique
|
|
||||||
- System prompts spécialisés pour chaque rôle
|
|
||||||
- Détection de convergence automatique
|
|
||||||
- Arrêt quand aucune modification d'un tour complet
|
|
||||||
|
|
||||||
#### 3. **Documents Flexibles**
|
|
||||||
- Format Markdown (.md) pour documents structurés
|
|
||||||
- Format Texte brut (.txt) pour contenu simple
|
|
||||||
- Versioning complet avec historique
|
|
||||||
- Export facile en un clic
|
|
||||||
|
|
||||||
#### 4. **Traçabilité Complète**
|
|
||||||
- Historique de chaque modification
|
|
||||||
- Qui a changé quoi et pourquoi
|
|
||||||
- Timeline visuelle interactive
|
|
||||||
- Accès à n'importe quelle version
|
|
||||||
|
|
||||||
### Avantages du Nouveau Système
|
|
||||||
|
|
||||||
| Aspect | Mode Débat | Mode Collaboratif |
|
|
||||||
|--------|-----------|------------------|
|
|
||||||
| **Processus** | Parallèle | Itératif |
|
|
||||||
| **Document** | Consensus arbitraire | Construction progressive |
|
|
||||||
| **Agents** | 4 | 3-7 (configurable) |
|
|
||||||
| **Convergence** | Vote pondéré (60%) | Naturelle (0 changements) |
|
|
||||||
| **Traçabilité** | Propositions individuelles | Historique complet |
|
|
||||||
| **Format** | JSON fixe | Flexible (MD/TXT) |
|
|
||||||
| **Qualité finale** | Bonne | Excellente |
|
|
||||||
| **Temps** | Rapide (1 appel) | Graduel (multiple tours) |
|
|
||||||
|
|
||||||
### Fichiers Créés
|
|
||||||
- ✅ `backend/src/services/collaborativeOrchestrator.js`
|
|
||||||
- ✅ `backend/src/routes/collaborate.js`
|
|
||||||
- ✅ `frontend/src/stores/collaboration.js`
|
|
||||||
- ✅ `frontend/src/components/CollaborativeInput.vue`
|
|
||||||
- ✅ `frontend/src/components/CollaborativeSession.vue`
|
|
||||||
- ✅ `frontend/src/components/DocumentViewer.vue`
|
|
||||||
- ✅ `CHANGELOG.md` (ce fichier)
|
|
||||||
|
|
||||||
### Fichiers Modifiés
|
|
||||||
- ✅ `backend/src/index.js` - Intégration orchestrateur
|
|
||||||
- ✅ `backend/src/db/schema.js` - Nouvelles tables
|
|
||||||
- ✅ `frontend/src/App.vue` - Mode selector et navigation
|
|
||||||
- ✅ `frontend/src/composables/useWebSocket.js` - Support sessionId
|
|
||||||
- ✅ `README.md` - Documentation
|
|
||||||
|
|
||||||
### Tests à Faire
|
|
||||||
```bash
|
|
||||||
# Backend
|
|
||||||
npm start # Doit démarrer sans erreurs
|
|
||||||
curl http://localhost:3000/api/health
|
|
||||||
|
|
||||||
# Frontend
|
|
||||||
npm run dev # Vite dev server
|
|
||||||
# Tester: http://localhost:5173
|
|
||||||
```
|
|
||||||
|
|
||||||
### Prochaines Améliorations Possibles
|
|
||||||
- [ ] Support téléchargement fichiers contextuels (upload MD/TXT)
|
|
||||||
- [ ] Intégration Git (commit auto après convergence)
|
|
||||||
- [ ] Export PDF avec mise en page professionnelle
|
|
||||||
- [ ] Comparaison côte à côte des versions
|
|
||||||
- [ ] Statistiques détaillées par agent
|
|
||||||
- [ ] Webhook pour notifications externes
|
|
||||||
- [ ] Support collaboration multi-utilisateurs simultanés
|
|
||||||
|
|
||||||
### Notes
|
|
||||||
- Système entièrement rétro-compatible : mode débat classique toujours disponible
|
|
||||||
- Performance : Chaque tour prend ~30-60s selon la longueur du document
|
|
||||||
- Coût API : Similaire au mode débat (n agents × 1 appel par tour)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Version** : 2.0.0
|
|
||||||
**Date** : October 2024
|
|
||||||
**Status** : Production Ready
|
|
||||||
@ -1,119 +1,46 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useDebateStore } from './stores/debate'
|
|
||||||
import { useCollaborationStore } from './stores/collaboration'
|
import { useCollaborationStore } from './stores/collaboration'
|
||||||
import PromptInput from './components/PromptInput.vue'
|
|
||||||
import DebateThread from './components/DebateThread.vue'
|
|
||||||
import CollaborativeInput from './components/CollaborativeInput.vue'
|
import CollaborativeInput from './components/CollaborativeInput.vue'
|
||||||
import CollaborativeSession from './components/CollaborativeSession.vue'
|
import CollaborativeSession from './components/CollaborativeSession.vue'
|
||||||
|
import NetworkStatus from './components/NetworkStatus.vue'
|
||||||
|
|
||||||
const debateStore = useDebateStore()
|
|
||||||
const collaborationStore = useCollaborationStore()
|
const collaborationStore = useCollaborationStore()
|
||||||
|
|
||||||
const mode = ref('choose') // 'choose', 'debate', 'collaborate'
|
|
||||||
const showDebate = ref(false)
|
|
||||||
const showSession = ref(false)
|
const showSession = ref(false)
|
||||||
const currentSessionId = ref(null)
|
const currentSessionId = ref(null)
|
||||||
|
|
||||||
function handleDebateCreated(debate) {
|
|
||||||
showDebate.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCollaborationCreated(session) {
|
function handleCollaborationCreated(session) {
|
||||||
currentSessionId.value = session.sessionId
|
currentSessionId.value = session.sessionId
|
||||||
showSession.value = true
|
showSession.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function startNewDebate() {
|
|
||||||
debateStore.clearCurrentDebate()
|
|
||||||
showDebate.value = false
|
|
||||||
mode.value = 'choose'
|
|
||||||
}
|
|
||||||
|
|
||||||
function startNewCollaboration() {
|
function startNewCollaboration() {
|
||||||
collaborationStore.clearCurrentSession()
|
collaborationStore.clearCurrentSession()
|
||||||
showSession.value = false
|
showSession.value = false
|
||||||
mode.value = 'choose'
|
|
||||||
}
|
|
||||||
|
|
||||||
function goBack() {
|
|
||||||
mode.value = 'choose'
|
|
||||||
showDebate.value = false
|
|
||||||
showSession.value = false
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="app">
|
<div class="app">
|
||||||
<!-- Mode Selection -->
|
<NetworkStatus />
|
||||||
<div v-if="mode === 'choose'" class="mode-selector">
|
|
||||||
<div class="selector-container">
|
|
||||||
<h1>Agora AI</h1>
|
|
||||||
<p class="subtitle">Choose your AI collaboration mode:</p>
|
|
||||||
|
|
||||||
<div class="mode-cards">
|
<!-- Input Mode -->
|
||||||
<button @click="mode = 'debate'" class="mode-card debate-mode">
|
<div v-if="!showSession">
|
||||||
<div class="mode-icon">🗣️</div>
|
<CollaborativeInput @session-created="handleCollaborationCreated" />
|
||||||
<h3>Classic Debate</h3>
|
|
||||||
<p>
|
|
||||||
Multiple AI agents debate different perspectives on your architecture
|
|
||||||
in parallel and reach consensus.
|
|
||||||
</p>
|
|
||||||
<span class="mode-badge">Traditional</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button @click="mode = 'collaborate'" class="mode-card collaborate-mode">
|
|
||||||
<div class="mode-icon">🤝</div>
|
|
||||||
<h3>Collaborative Design</h3>
|
|
||||||
<p>
|
|
||||||
AI specialists iteratively refine an architecture document through
|
|
||||||
collaborative rounds until perfect consensus is reached.
|
|
||||||
</p>
|
|
||||||
<span class="mode-badge">Recommended</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Debate Mode -->
|
<!-- Session Mode -->
|
||||||
<div v-else-if="mode === 'debate'">
|
<div v-else>
|
||||||
<div v-if="!showDebate">
|
<button @click="startNewCollaboration" class="new-session-btn">
|
||||||
<button @click="goBack" class="back-btn">← Back to Mode Selection</button>
|
+ New Session
|
||||||
<PromptInput @debate-created="handleDebateCreated" />
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else>
|
<CollaborativeSession
|
||||||
<div class="debate-view">
|
v-if="currentSessionId"
|
||||||
<button @click="startNewDebate" class="new-debate-btn">
|
:session-id="currentSessionId"
|
||||||
+ New Debate
|
@session-completed="startNewCollaboration"
|
||||||
</button>
|
/>
|
||||||
|
|
||||||
<DebateThread
|
|
||||||
v-if="debateStore.currentDebate"
|
|
||||||
:debate="debateStore.currentDebate"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Collaboration Mode -->
|
|
||||||
<div v-else-if="mode === 'collaborate'">
|
|
||||||
<div v-if="!showSession">
|
|
||||||
<button @click="goBack" class="back-btn">← Back to Mode Selection</button>
|
|
||||||
<CollaborativeInput @session-created="handleCollaborationCreated" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else>
|
|
||||||
<button @click="startNewCollaboration" class="new-session-btn">
|
|
||||||
+ New Session
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<CollaborativeSession
|
|
||||||
v-if="currentSessionId"
|
|
||||||
:session-id="currentSessionId"
|
|
||||||
@session-completed="startNewCollaboration"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -142,122 +69,6 @@ body {
|
|||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mode Selector */
|
|
||||||
.mode-selector {
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.selector-container {
|
|
||||||
text-align: center;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selector-container h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
opacity: 0.95;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-cards {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
||||||
gap: 2rem;
|
|
||||||
max-width: 900px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-card {
|
|
||||||
background: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 2rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s;
|
|
||||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
||||||
color: #2c3e50;
|
|
||||||
text-align: center;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-card:hover {
|
|
||||||
transform: translateY(-8px);
|
|
||||||
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-icon {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-card h3 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
color: #667eea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-card p {
|
|
||||||
color: #666;
|
|
||||||
line-height: 1.6;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-badge {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
border-radius: 20px;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.debate-mode .mode-badge {
|
|
||||||
background: #e8eef7;
|
|
||||||
color: #667eea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collaborate-mode .mode-badge {
|
|
||||||
background: #764ba2;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Navigation Buttons */
|
|
||||||
.back-btn {
|
|
||||||
position: fixed;
|
|
||||||
top: 1.5rem;
|
|
||||||
left: 1.5rem;
|
|
||||||
padding: 0.75rem 1.5rem;
|
|
||||||
background-color: white;
|
|
||||||
border: 2px solid #667eea;
|
|
||||||
color: #667eea;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s;
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-btn:hover {
|
|
||||||
background-color: #667eea;
|
|
||||||
color: white;
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.debate-view {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-debate-btn,
|
|
||||||
.new-session-btn {
|
.new-session-btn {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 2rem;
|
top: 2rem;
|
||||||
@ -274,29 +85,10 @@ body {
|
|||||||
z-index: 50;
|
z-index: 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-debate-btn:hover,
|
|
||||||
.new-session-btn:hover {
|
.new-session-btn:hover {
|
||||||
background-color: #667eea;
|
background-color: #667eea;
|
||||||
color: white;
|
color: white;
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.selector-container h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-cards {
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mode-card {
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -7,32 +7,53 @@ const emit = defineEmits(['session-created'])
|
|||||||
const collaborationStore = useCollaborationStore()
|
const collaborationStore = useCollaborationStore()
|
||||||
|
|
||||||
const prompt = ref('')
|
const prompt = ref('')
|
||||||
const documentFormat = ref('md')
|
const contextFile = ref(null)
|
||||||
const agentCount = ref(7)
|
const agentCount = ref(7)
|
||||||
const isCreating = ref(false)
|
const isCreating = ref(false)
|
||||||
|
|
||||||
const formats = [
|
|
||||||
{ value: 'md', label: 'Markdown (.md)' },
|
|
||||||
{ value: 'txt', label: 'Plain Text (.txt)' }
|
|
||||||
]
|
|
||||||
|
|
||||||
const agentOptions = [
|
const agentOptions = [
|
||||||
{ value: 3, label: '3 agents (Quick)' },
|
{ value: 3, label: '3 agents (Quick)' },
|
||||||
{ value: 5, label: '5 agents (Balanced)' },
|
{ value: 5, label: '5 agents (Balanced)' },
|
||||||
{ value: 7, label: '7 agents (Comprehensive)' }
|
{ value: 7, label: '7 agents (Comprehensive)' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const handleFileSelect = (event) => {
|
||||||
|
const file = event.target.files?.[0]
|
||||||
|
if (file) {
|
||||||
|
const validTypes = ['text/markdown', 'text/plain', 'application/octet-stream']
|
||||||
|
const validExtensions = ['.md', '.txt']
|
||||||
|
const hasValidType = validTypes.includes(file.type)
|
||||||
|
const hasValidExtension = validExtensions.some(ext => file.name.endsWith(ext))
|
||||||
|
|
||||||
|
if (!hasValidType && !hasValidExtension) {
|
||||||
|
alert('Please upload a Markdown (.md) or Text (.txt) file')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
contextFile.value = file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleCreateSession = async () => {
|
const handleCreateSession = async () => {
|
||||||
if (!prompt.value.trim()) {
|
if (!prompt.value.trim()) {
|
||||||
alert('Please enter a project prompt')
|
alert('Please enter a project description')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isCreating.value = true
|
isCreating.value = true
|
||||||
try {
|
try {
|
||||||
|
let finalPrompt = prompt.value
|
||||||
|
|
||||||
|
// If a context file was uploaded, prepend it to the prompt
|
||||||
|
if (contextFile.value) {
|
||||||
|
const fileContent = await contextFile.value.text()
|
||||||
|
finalPrompt = `Context file content:\n\`\`\`\n${fileContent}\n\`\`\`\n\nProject description:\n${prompt.value}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always use 'md' format for output
|
||||||
const session = await collaborationStore.createSession(
|
const session = await collaborationStore.createSession(
|
||||||
prompt.value,
|
finalPrompt,
|
||||||
documentFormat.value,
|
'md',
|
||||||
agentCount.value
|
agentCount.value
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,7 +61,7 @@ const handleCreateSession = async () => {
|
|||||||
|
|
||||||
// Reset form
|
// Reset form
|
||||||
prompt.value = ''
|
prompt.value = ''
|
||||||
documentFormat.value = 'md'
|
contextFile.value = null
|
||||||
agentCount.value = 7
|
agentCount.value = 7
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(`Error creating session: ${collaborationStore.error}`)
|
alert(`Error creating session: ${collaborationStore.error}`)
|
||||||
@ -54,47 +75,77 @@ const handleKeydown = (e) => {
|
|||||||
handleCreateSession()
|
handleCreateSession()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const removeFile = () => {
|
||||||
|
contextFile.value = null
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="collaborative-input">
|
<div class="collaborative-input">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<h1>🎯 Collaborative Architecture Design</h1>
|
<h1>🎯 AI Architecture Design</h1>
|
||||||
<p class="subtitle">
|
<p class="subtitle">
|
||||||
Describe your software project idea, and let multiple AI specialists design
|
Describe your software project. Multiple AI specialists will collaboratively
|
||||||
the perfect architecture through collaborative discussion.
|
design the perfect architecture through iterative refinement.
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<form @submit.prevent="handleCreateSession" class="form">
|
<form @submit.prevent="handleCreateSession" class="form">
|
||||||
|
<!-- Project Description -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<label for="prompt" class="label">Project Description</label>
|
<label for="prompt" class="label">Project Description</label>
|
||||||
<p class="label-hint">
|
<p class="label-hint">
|
||||||
Describe your software project in detail. What is it? What problems does it solve?
|
Describe your software project in detail. What is it? What problems does it solve? What are the key requirements?
|
||||||
</p>
|
</p>
|
||||||
<textarea
|
<textarea
|
||||||
id="prompt"
|
id="prompt"
|
||||||
v-model="prompt"
|
v-model="prompt"
|
||||||
@keydown="handleKeydown"
|
@keydown="handleKeydown"
|
||||||
placeholder="Example: I want to build a real-time collaborative document editing platform similar to Google Docs, with support for multiple users, version history, and commenting..."
|
placeholder="Example: I want to build a real-time collaborative document editing platform with support for multiple users, version history, and commenting..."
|
||||||
class="textarea"
|
class="textarea"
|
||||||
rows="8"
|
rows="8"
|
||||||
></textarea>
|
></textarea>
|
||||||
<p class="hint">💡 Tip: The more detailed your description, the better the AI collaboration.</p>
|
<p class="hint">💡 The more detailed your description, the better the AI collaboration.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-grid">
|
<!-- Optional Context File -->
|
||||||
<div class="form-group">
|
<div class="form-section">
|
||||||
<label for="format" class="label">Document Format</label>
|
<label class="label">Context File (Optional)</label>
|
||||||
<select v-model="documentFormat" id="format" class="select">
|
<p class="label-hint">
|
||||||
<option v-for="fmt in formats" :key="fmt.value" :value="fmt.value">
|
Upload an existing Markdown or text file to use as context for the AI specialists.
|
||||||
{{ fmt.label }}
|
</p>
|
||||||
</option>
|
|
||||||
</select>
|
<div class="file-input-wrapper">
|
||||||
<p class="hint">The final document will be saved in this format.</p>
|
<input
|
||||||
|
type="file"
|
||||||
|
id="contextFile"
|
||||||
|
accept=".md,.txt"
|
||||||
|
@change="handleFileSelect"
|
||||||
|
class="file-input"
|
||||||
|
/>
|
||||||
|
<label for="contextFile" class="file-label">
|
||||||
|
📎 Choose a file (.md or .txt)
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="contextFile" class="file-selected">
|
||||||
|
<span class="file-name">✓ {{ contextFile.name }}</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="removeFile"
|
||||||
|
class="remove-btn"
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="hint">Optional: Provide existing documentation or requirements to guide the design.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Agent Count Selection -->
|
||||||
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="agents" class="label">Number of AI Specialists</label>
|
<label for="agents" class="label">Number of AI Specialists</label>
|
||||||
<select v-model.number="agentCount" id="agents" class="select">
|
<select v-model.number="agentCount" id="agents" class="select">
|
||||||
@ -106,32 +157,32 @@ const handleKeydown = (e) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Box -->
|
||||||
<div class="info-box">
|
<div class="info-box">
|
||||||
<p>
|
<p><strong>How it works:</strong></p>
|
||||||
<strong>How it works:</strong>
|
|
||||||
</p>
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>A lead architect creates an initial design document</li>
|
<li>Lead Architect creates initial design</li>
|
||||||
<li>{{ agentCount }} AI specialists review and provide feedback</li>
|
<li>{{ agentCount }} specialists review iteratively</li>
|
||||||
<li>Each agent proposes improvements based on their expertise</li>
|
<li>Each proposes improvements based on expertise</li>
|
||||||
<li>The document evolves through collaborative refinement</li>
|
<li>Document evolves through refinement</li>
|
||||||
<li>Process continues until consensus is reached</li>
|
<li>Converges when consensus reached</li>
|
||||||
<li>Download the final architectural specification</li>
|
<li>Output: Markdown architectural specification</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Submit Button -->
|
||||||
<button
|
<button
|
||||||
@click="handleCreateSession"
|
@click="handleCreateSession"
|
||||||
:disabled="!prompt.trim() || isCreating"
|
:disabled="!prompt.trim() || isCreating"
|
||||||
type="button"
|
type="button"
|
||||||
class="submit-btn"
|
class="submit-btn"
|
||||||
>
|
>
|
||||||
{{ isCreating ? 'Creating Session...' : '✨ Start Collaborative Design Session' }}
|
{{ isCreating ? 'Starting Session...' : '✨ Start Design Session' }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<p>Each session typically involves 2-5 review rounds for complete consensus</p>
|
<p>Typical session: 2-5 rounds for complete consensus. Output format: Markdown</p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -294,6 +345,69 @@ const handleKeydown = (e) => {
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file-input-wrapper {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-label {
|
||||||
|
display: block;
|
||||||
|
padding: 1rem;
|
||||||
|
border: 2px dashed #667eea;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
background: #f9fafb;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-label:hover {
|
||||||
|
background: #f0f3ff;
|
||||||
|
border-color: #764ba2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-input:focus + .file-label {
|
||||||
|
border-color: #667eea;
|
||||||
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-selected {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: #e8f5e9;
|
||||||
|
border: 1px solid #4caf50;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-name {
|
||||||
|
color: #2e7d32;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #d32f2f;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-btn:hover {
|
||||||
|
color: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: white;
|
color: white;
|
||||||
|
|||||||
154
frontend/src/components/NetworkStatus.vue
Normal file
154
frontend/src/components/NetworkStatus.vue
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
|
||||||
|
const latency = ref(0)
|
||||||
|
const quality = ref('excellent')
|
||||||
|
const lastCheckTime = ref(Date.now())
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
checkInterval: {
|
||||||
|
type: Number,
|
||||||
|
default: 5000 // Check every 5 seconds
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let intervalId = null
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
checkNetworkStatus()
|
||||||
|
intervalId = setInterval(checkNetworkStatus, props.checkInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (intervalId) clearInterval(intervalId)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function checkNetworkStatus() {
|
||||||
|
const startTime = Date.now()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/health', {
|
||||||
|
method: 'HEAD'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const endTime = Date.now()
|
||||||
|
latency.value = endTime - startTime
|
||||||
|
updateQuality(latency.value)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
latency.value = 0
|
||||||
|
quality.value = 'offline'
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCheckTime.value = Date.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateQuality(lat) {
|
||||||
|
if (lat < 100) quality.value = 'excellent'
|
||||||
|
else if (lat < 300) quality.value = 'good'
|
||||||
|
else if (lat < 600) quality.value = 'fair'
|
||||||
|
else quality.value = 'poor'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusColor() {
|
||||||
|
switch (quality.value) {
|
||||||
|
case 'excellent': return '#4caf50'
|
||||||
|
case 'good': return '#8bc34a'
|
||||||
|
case 'fair': return '#ffc107'
|
||||||
|
case 'poor': return '#ff9800'
|
||||||
|
case 'offline': return '#f44336'
|
||||||
|
default: return '#666'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusEmoji() {
|
||||||
|
switch (quality.value) {
|
||||||
|
case 'excellent': return '✓'
|
||||||
|
case 'good': return '✓'
|
||||||
|
case 'fair': return '⚠'
|
||||||
|
case 'poor': return '⚠'
|
||||||
|
case 'offline': return '✕'
|
||||||
|
default: return '?'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="network-status" :style="{ backgroundColor: getStatusColor() }">
|
||||||
|
<div class="status-content">
|
||||||
|
<span class="emoji">{{ getStatusEmoji() }}</span>
|
||||||
|
<span class="text">
|
||||||
|
<span class="latency">{{ latency }}ms</span>
|
||||||
|
<span class="quality">{{ quality }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.network-status {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 2rem;
|
||||||
|
right: 2rem;
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
z-index: 40;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.network-status:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
font-size: 1rem;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency {
|
||||||
|
display: block;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quality {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.network-status {
|
||||||
|
bottom: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user