Files
LoreMind/web/src/app/sessions/session-random-tables-panel/session-random-tables-panel.component.ts
IETM_FIXE\ietm6 75357983a1
All checks were successful
Build & Push Images / build (brain) (push) Successful in 1m29s
Build & Push Images / build (core) (push) Successful in 1m51s
Build & Push Images / build-switcher (push) Successful in 16s
Build & Push Images / build (web) (push) Successful in 1m43s
Plusieurs gros ajouts :
- Possibilité de discuter avec un PDF ; RAG ou analyse approfondie. Enlèvement de l'autre outil PDF de discussion qui analysait d'abord un PDF en proposant directement une intégration sans attendre qu'on pose de question
- Mise en place de l'import directement dans les outils dans la sidebar
- Mise en place d'un outil pour créer des tables aléatoires avec possibilité d'utiliser pendant la partie
- Mise en place d'un outil pour mettre en place des PNJ, scènes, chapitre.... directement à partir de la discussion avec le PDF
- Mise en place RAG avec mistal-embeding ou nomic si on utilise ollama
- Mise en place mistral, google en fournisseurs alternatifs pour l'IA dans le cloud
- version 0.11.0-bêta
2026-06-07 09:52:15 +02:00

111 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LucideAngularModule, Dices, BookmarkPlus, Sparkles, ChevronLeft } from 'lucide-angular';
import { catchError, of } from 'rxjs';
import { RandomTableService } from '../../services/random-table.service';
import { RandomTable, RandomTableEntry } from '../../services/random-table.model';
import { DiceUtils, DiceRoll } from '../../shared/dice.utils';
import { DiceRollResult } from '../session-dice-panel/session-dice-panel.component';
/**
* Panneau "Tables aléatoires" du mode jeu : choisir une table de la campagne,
* la JETER, consigner le résultat au journal, et (option) demander à l'IA
* d'improviser un court récit sur le tirage.
*
* Réutilise les sorties existantes du panneau de référence :
* - `rolled` (DiceRollResult) → entrée DICE_ROLL dans le journal ;
* - `aiReplyToJournal` (string) → entrée NOTE (récit IA).
*/
@Component({
selector: 'app-session-random-tables-panel',
standalone: true,
imports: [CommonModule, LucideAngularModule],
templateUrl: './session-random-tables-panel.component.html',
styleUrls: ['./session-random-tables-panel.component.scss']
})
export class SessionRandomTablesPanelComponent implements OnInit {
readonly Dices = Dices;
readonly BookmarkPlus = BookmarkPlus;
readonly Sparkles = Sparkles;
readonly ChevronLeft = ChevronLeft;
@Input() campaignId!: string;
@Input() canAddToJournal = true;
@Output() rolled = new EventEmitter<DiceRollResult>();
@Output() aiReplyToJournal = new EventEmitter<string>();
tables: RandomTable[] = [];
loading = false;
selected: RandomTable | null = null;
lastRoll: DiceRoll | null = null;
matched: RandomTableEntry | null = null;
improvising = false;
constructor(private service: RandomTableService) {}
ngOnInit(): void {
if (!this.campaignId) return;
this.loading = true;
this.service.getByCampaign(this.campaignId).pipe(catchError(() => of([] as RandomTable[])))
.subscribe(list => { this.tables = list; this.loading = false; });
}
select(table: RandomTable): void {
this.selected = table;
this.lastRoll = null;
this.matched = null;
}
backToList(): void {
this.selected = null;
this.lastRoll = null;
this.matched = null;
}
roll(): void {
if (!this.selected) return;
const result = DiceUtils.roll(this.selected.diceFormula);
if (!result) { this.lastRoll = null; this.matched = null; return; }
this.lastRoll = result;
this.matched = this.selected.entries.find(
e => result.total >= e.minRoll && result.total <= e.maxRoll
) ?? null;
}
rangeLabel(entry: RandomTableEntry): string {
return entry.minRoll === entry.maxRoll ? String(entry.minRoll) : `${entry.minRoll}${entry.maxRoll}`;
}
/** Consigne le tirage au journal (entrée DICE_ROLL via la sortie `rolled`). */
addToJournal(): void {
if (!this.canAddToJournal || !this.selected || !this.lastRoll) return;
const label = this.matched?.label ?? 'aucun résultat';
const result: DiceRollResult = {
notation: this.selected.diceFormula,
rolls: this.lastRoll.rolls,
modifier: 0,
total: this.lastRoll.total,
summary: `🎲 ${this.selected.name} : ${this.lastRoll.total}${label}`
};
this.rolled.emit(result);
}
/** Demande à l'IA un court récit sur le résultat, puis l'envoie au journal (NOTE). */
improvise(): void {
if (!this.selected || !this.matched || this.improvising) return;
this.improvising = true;
this.service.improvise(
this.campaignId, this.selected.name, this.matched.label, this.matched.detail ?? ''
).subscribe({
next: (r) => {
this.improvising = false;
if (r.narration?.trim() && this.canAddToJournal) {
this.aiReplyToJournal.emit(r.narration.trim());
}
},
error: () => { this.improvising = false; }
});
}
}