File size: 6,296 Bytes
4cab1f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import { useEffect } from "react";
import { useComic } from "../context/ComicContext";
import { useImageGeneration } from "../hooks/useImageGeneration";
import { groupSegmentsIntoLayouts } from "../layouts/utils";
import { LAYOUTS } from "../layouts/config";
import axios from "axios";

const API_URL = import.meta.env.VITE_API_URL || "http://localhost:8000";

// Create axios instance with default config
const api = axios.create({
  headers: {
    "x-client-id": `client_${Math.random().toString(36).substring(2)}`,
  },
});

// Function to convert text with ** to bold elements
const formatTextWithBold = (text) => {
  if (!text) return "";
  const parts = text.split(/(\*\*.*?\*\*)/g);
  return parts.map((part, index) => {
    if (part.startsWith("**") && part.endsWith("**")) {
      return <strong key={index}>{part.slice(2, -2)}</strong>;
    }
    return part;
  });
};

export function StoryManager() {
  const { state, updateSegments, updateSegment, setChoices, setLoading } =
    useComic();
  const { generateImagesForSegment } = useImageGeneration();

  const handleStoryAction = async (action, choiceId = null) => {
    setLoading(true);
    try {
      // 1. Obtenir l'histoire
      const response = await api.post(`${API_URL}/api/chat`, {
        message: action,
        choice_id: choiceId,
      });

      // 2. Créer le nouveau segment
      const newSegment = {
        text: formatTextWithBold(response.data.story_text),
        isChoice: false,
        isDeath: response.data.is_death,
        isVictory: response.data.is_victory,
        radiationLevel: response.data.radiation_level,
        is_first_step: response.data.is_first_step,
        is_last_step: response.data.is_last_step,
        images: response.data.image_prompts
          ? Array(response.data.image_prompts.length).fill(null)
          : [],
      };

      // 3. Mettre à jour les segments
      const segmentIndex = action === "restart" ? 0 : state.segments.length;
      const updatedSegments =
        action === "restart" ? [newSegment] : [...state.segments, newSegment];

      updateSegments(updatedSegments);

      // 4. Mettre à jour les choix
      setChoices(response.data.choices);
      setLoading(false);

      // 5. Générer les images si nécessaire
      if (response.data.image_prompts?.length > 0) {
        const prompts = response.data.image_prompts;
        let currentPromptIndex = 0;
        let currentSegmentIndex = segmentIndex;

        while (currentPromptIndex < prompts.length) {
          // Recalculer les layouts avec les segments actuels
          const layouts = groupSegmentsIntoLayouts(updatedSegments);
          let currentLayout = layouts[layouts.length - 1];

          // Pour un layout COVER, ne prendre que le premier prompt
          if (currentLayout.type === "COVER") {
            const promptsToUse = [prompts[0]];
            console.log("COVER layout: using only first prompt");

            const images = await generateImagesForSegment(
              promptsToUse,
              currentLayout
            );

            if (images && images.length > 0) {
              const currentSegment = updatedSegments[currentSegmentIndex];
              const updatedSegment = {
                ...currentSegment,
                images: [images[0]], // Ne garder que la première image
              };
              updatedSegments[currentSegmentIndex] = updatedSegment;
              updateSegments(updatedSegments);
            }
            break; // Sortir de la boucle car nous n'avons besoin que d'une image
          }

          // Pour les autres layouts, continuer normalement
          const remainingPanels =
            LAYOUTS[currentLayout.type].panels.length -
            (currentLayout.segments[currentLayout.segments.length - 1].images
              ?.length || 0);

          if (remainingPanels === 0) {
            // Créer un nouveau segment pour la nouvelle page
            const newPageSegment = {
              ...newSegment,
              images: Array(prompts.length - currentPromptIndex).fill(null),
            };
            updatedSegments.push(newPageSegment);
            currentSegmentIndex = updatedSegments.length - 1;
            updateSegments(updatedSegments);
            continue;
          }

          // Générer les images pour ce layout
          const promptsForCurrentLayout = prompts.slice(
            currentPromptIndex,
            currentPromptIndex + remainingPanels
          );

          console.log("Generating images for layout:", {
            segmentIndex: currentSegmentIndex,
            layoutType: currentLayout.type,
            prompts: promptsForCurrentLayout,
            remainingPanels,
          });

          // Générer les images
          const images = await generateImagesForSegment(
            promptsForCurrentLayout,
            currentLayout
          );

          // Mettre à jour le segment avec les nouvelles images
          if (images && images.length > 0) {
            const currentSegment = updatedSegments[currentSegmentIndex];
            const updatedSegment = {
              ...currentSegment,
              images: [...(currentSegment.images || []), ...images],
            };
            updatedSegments[currentSegmentIndex] = updatedSegment;
            updateSegments(updatedSegments);
          }

          currentPromptIndex += promptsForCurrentLayout.length;
        }
      }
    } catch (error) {
      console.error("Error:", error);
      const errorSegment = {
        text: "Le conteur d'histoires est temporairement indisponible. Veuillez réessayer dans quelques instants...",
        isChoice: false,
        isDeath: false,
        isVictory: false,
        radiationLevel:
          state.segments.length > 0
            ? state.segments[state.segments.length - 1].radiationLevel
            : 0,
        images: [],
      };

      updateSegments(
        action === "restart"
          ? [errorSegment]
          : [...state.segments, errorSegment]
      );
      setChoices([{ id: 1, text: "Réessayer" }]);
      setLoading(false);
    }
  };

  // Démarrer l'histoire au montage
  useEffect(() => {
    handleStoryAction("restart");
  }, []);

  return null; // Ce composant ne rend rien, il gère juste la logique
}