Plusieurs gros ajouts :
All checks were successful
All checks were successful
- 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
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
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; }
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user