AiProjectChat: contexto de equipo + SP/sprint para que la IA asigne HUs
- buildContext() ahora incluye team members del proyecto (nombres, roles, célula) desde storage per-project - HUs incluyen story_points (sp) y sprint para que la IA pueda balancear cargas de trabajo - Épicas incluyen assigned_name y story_points - System prompt instruye a la IA a: · Usar el equipo para asignar HUs · Detectar sobrecarga por sprint · Sugerir recursos transversales cuando aplique · Alertar sobre riesgo de cronograma
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { chatWithAI } from '@/services/ai'
|
||||
import { storage } from '@/services/storage'
|
||||
import { useSettingsStore, AVAILABLE_MODELS, PROVIDER_CONFIG, hasProviderApiKey, type AIProvider } from '@/stores/settings'
|
||||
import { useWorkItemsStore } from '@/stores/workitems'
|
||||
import { useUsersStore } from '@/stores/users'
|
||||
import { getSessionsByProject, getProjectState } from '@/services/transcriptions-db'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -21,6 +23,7 @@ import { Send, Loader2, AlertCircle, Brain, Settings2, Check, ChevronDown } from
|
||||
const { t } = useI18n()
|
||||
const settings = useSettingsStore()
|
||||
const workItems = useWorkItemsStore()
|
||||
const usersStore = useUsersStore()
|
||||
|
||||
const props = defineProps({
|
||||
projectId: { type: Number, required: true },
|
||||
@@ -53,20 +56,55 @@ function switchModel(provider: AIProvider, modelId: string) {
|
||||
async function buildContext(): Promise<string> {
|
||||
const ctx: Record<string, unknown> = {}
|
||||
|
||||
// 1. HUs: todas, formato compacto (sin límite)
|
||||
// 1. Team members asignados a este proyecto
|
||||
const teamIds = storage.getJSON<number[]>(`project_team_${props.projectId}`)
|
||||
if (teamIds && teamIds.length > 0) {
|
||||
const members = teamIds
|
||||
.map(id => usersStore.users.find(u => u.id === id))
|
||||
.filter(Boolean)
|
||||
.map(u => ({
|
||||
n: u!.full_name || u!.email,
|
||||
r: u!.role || '—',
|
||||
c: u!.cell || '—',
|
||||
}))
|
||||
ctx.team = { count: members.length, members }
|
||||
}
|
||||
|
||||
// 2. HUs: todas, con story points, sprint y estado
|
||||
const hus = workItems.userStories
|
||||
if (hus.length > 0) {
|
||||
const pending = hus.filter(h => !['done','completed','closed','finalizado'].includes(String(h.status ?? '').toLowerCase()))
|
||||
ctx.hus = { total: hus.length, pending: pending.length, items: hus.map(h => ({ t: h._cleanTitle || h.title, s: h.status, p: h.priority })) }
|
||||
ctx.hus = {
|
||||
total: hus.length,
|
||||
pending: pending.length,
|
||||
items: hus.map(h => ({
|
||||
t: h._cleanTitle || h.title,
|
||||
s: h.status,
|
||||
p: h.priority,
|
||||
sp: h.story_points ?? null,
|
||||
sprint: h.sprint ?? null,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Sesiones: últimas 3
|
||||
// 3. Épicas con asignación
|
||||
const epics = workItems.epics
|
||||
if (epics.length > 0) {
|
||||
ctx.epics = epics.map(e => ({
|
||||
n: e._cleanName || e.name || e.title,
|
||||
s: e.status,
|
||||
assigned: e.assigned_name || null,
|
||||
sp: e.story_points ?? null,
|
||||
}))
|
||||
}
|
||||
|
||||
// 4. Sesiones: últimas 3
|
||||
const sessions = await getSessionsByProject(props.projectId)
|
||||
if (sessions.length > 0) {
|
||||
ctx.sessions = { total: sessions.length, recent: sessions.slice(-3).reverse().map(s => ({ d: s.date, t: s.title })) }
|
||||
}
|
||||
|
||||
// 3. Estado
|
||||
// 5. Estado
|
||||
const state = await getProjectState(props.projectId)
|
||||
if (state?.summary) ctx.summary = state.summary.slice(0, 300)
|
||||
|
||||
@@ -84,9 +122,22 @@ async function sendPrompt() {
|
||||
|
||||
try {
|
||||
const context = await buildContext()
|
||||
const systemPrompt = `Proyecto: ${props.projectName}. ${props.projectDescription || ''} Épicas: ${props.epicCount} HUs: ${props.huCount}.
|
||||
Datos del proyecto (JSON): ${context || '{}'}
|
||||
Respondé en el mismo idioma del usuario. Sé conciso. Si no sabés, decilo.`
|
||||
const systemPrompt = `Eres un asistente de gestión de proyectos ágiles para el equipo de desarrollo.
|
||||
|
||||
Proyecto: ${props.projectName}. ${props.projectDescription || ''} Épicas: ${props.epicCount} HUs: ${props.huCount}.
|
||||
|
||||
Tienes acceso a estos datos del proyecto (JSON):
|
||||
${context || '{}'}
|
||||
|
||||
El campo "team" contiene los miembros del equipo asignados a este proyecto con su rol. Úsalo para responder quién trabaja en qué, sugerir asignaciones de HUs, y alertar sobre capacidad.
|
||||
|
||||
Cada HU puede tener "sp" (story points) y "sprint". Usa esta información para:
|
||||
- Recomendar asignaciones equilibradas según capacidad del equipo
|
||||
- Detectar sobrecarga de trabajo en un sprint
|
||||
- Sugerir recursos adicionales si una HU requiere expertise que no está en el equipo (célula transversal)
|
||||
- Alertar cuando el cronograma está en riesgo por falta de capacidad
|
||||
|
||||
Respondé en el mismo idioma del usuario. Sé conciso y práctico. Si algo no está en los datos, decilo.`
|
||||
|
||||
const msgs = [{ role: 'user' as const, content: text }]
|
||||
const result = await chatWithAI(msgs, systemPrompt)
|
||||
|
||||
Reference in New Issue
Block a user