Felix Zieger commited on
Commit
ac04e03
·
1 Parent(s): 831f7e7

fine tuning

Browse files
index.html CHANGED
@@ -7,6 +7,7 @@
7
  <meta name="description" content="A word puzzle game." />
8
  <meta name="author" content="Team M1X" />
9
  <meta property="og:image" content="/og-image.png" />
 
10
  </head>
11
 
12
  <body>
 
7
  <meta name="description" content="A word puzzle game." />
8
  <meta name="author" content="Team M1X" />
9
  <meta property="og:image" content="/og-image.png" />
10
+ <script defer data-domain="think-in-sync.com" src="https://plausible.sonnenhof-zieger.de/js/script.js"></script>
11
  </head>
12
 
13
  <body>
src/components/GameContainer.tsx CHANGED
@@ -53,6 +53,10 @@ export const GameContainer = () => {
53
  setGameState("theme-selection");
54
  };
55
 
 
 
 
 
56
  const handleThemeSelect = async (theme: string) => {
57
  setCurrentTheme(theme);
58
  try {
@@ -87,7 +91,7 @@ export const GameContainer = () => {
87
 
88
  setIsAiThinking(true);
89
  try {
90
- const aiWord = await generateAIResponse(currentWord, newSentence);
91
  const newSentenceWithAi = [...newSentence, aiWord];
92
  setSentence(newSentenceWithAi);
93
  setTotalWords(prev => prev + 1);
@@ -118,7 +122,7 @@ export const GameContainer = () => {
118
  if (finalSentence.length === 0) return;
119
 
120
  const sentenceString = finalSentence.join(' ');
121
- const guess = await guessWord(sentenceString);
122
  setAiGuess(guess);
123
  setGameState("showing-guess");
124
  } catch (error) {
@@ -139,7 +143,7 @@ export const GameContainer = () => {
139
  try {
140
  const word = currentTheme === "standard" ?
141
  getRandomWord() :
142
- await getThemedWord(currentTheme, usedWords);
143
  setCurrentWord(word);
144
  setGameState("building-sentence");
145
  setSentence([]);
@@ -199,7 +203,7 @@ export const GameContainer = () => {
199
  {gameState === "welcome" ? (
200
  <WelcomeScreen onStart={handleStart} />
201
  ) : gameState === "theme-selection" ? (
202
- <ThemeSelector onThemeSelect={handleThemeSelect} />
203
  ) : gameState === "building-sentence" ? (
204
  <SentenceBuilder
205
  currentWord={currentWord}
 
53
  setGameState("theme-selection");
54
  };
55
 
56
+ const handleBack = () => {
57
+ setGameState("welcome");
58
+ };
59
+
60
  const handleThemeSelect = async (theme: string) => {
61
  setCurrentTheme(theme);
62
  try {
 
91
 
92
  setIsAiThinking(true);
93
  try {
94
+ const aiWord = await generateAIResponse(currentWord, newSentence, language);
95
  const newSentenceWithAi = [...newSentence, aiWord];
96
  setSentence(newSentenceWithAi);
97
  setTotalWords(prev => prev + 1);
 
122
  if (finalSentence.length === 0) return;
123
 
124
  const sentenceString = finalSentence.join(' ');
125
+ const guess = await guessWord(sentenceString, language);
126
  setAiGuess(guess);
127
  setGameState("showing-guess");
128
  } catch (error) {
 
143
  try {
144
  const word = currentTheme === "standard" ?
145
  getRandomWord() :
146
+ await getThemedWord(currentTheme, usedWords, language);
147
  setCurrentWord(word);
148
  setGameState("building-sentence");
149
  setSentence([]);
 
203
  {gameState === "welcome" ? (
204
  <WelcomeScreen onStart={handleStart} />
205
  ) : gameState === "theme-selection" ? (
206
+ <ThemeSelector onThemeSelect={handleThemeSelect} onBack={handleBack} />
207
  ) : gameState === "building-sentence" ? (
208
  <SentenceBuilder
209
  currentWord={currentWord}
src/components/HighScoreBoard.tsx CHANGED
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
2
  import { Button } from "@/components/ui/button";
3
  import { Input } from "@/components/ui/input";
4
  import { supabase } from "@/integrations/supabase/client";
5
- import { useQuery } from "@tanstack/react-query";
6
  import {
7
  Table,
8
  TableBody,
@@ -64,23 +64,30 @@ export const HighScoreBoard = ({
64
  const [currentPage, setCurrentPage] = useState(1);
65
  const { toast } = useToast();
66
  const t = useTranslation();
 
67
 
68
  const { data: highScores, refetch } = useQuery({
69
  queryKey: ["highScores"],
70
  queryFn: async () => {
 
71
  const { data, error } = await supabase
72
  .from("high_scores")
73
  .select("*")
74
  .order("score", { ascending: false })
75
  .order("avg_words_per_round", { ascending: true });
76
 
77
- if (error) throw error;
 
 
 
 
78
  return data as HighScore[];
79
  },
80
  });
81
 
82
  const handleSubmitScore = async () => {
83
- if (!playerName.trim() || !/^[a-zA-Z0-9]+$/.test(playerName.trim())) {
 
84
  toast({
85
  title: t.leaderboard.error.invalidName,
86
  description: t.leaderboard.error.invalidName,
@@ -109,16 +116,24 @@ export const HighScoreBoard = ({
109
 
110
  setIsSubmitting(true);
111
  try {
112
- const { data: existingScores } = await supabase
 
113
  .from("high_scores")
114
  .select("*")
115
  .eq("player_name", playerName.trim());
116
 
 
 
 
 
 
117
  const existingScore = existingScores?.[0];
 
118
 
119
  if (existingScore) {
120
  if (currentScore > existingScore.score) {
121
- const { error } = await supabase
 
122
  .from("high_scores")
123
  .update({
124
  score: currentScore,
@@ -126,12 +141,21 @@ export const HighScoreBoard = ({
126
  })
127
  .eq("id", existingScore.id);
128
 
129
- if (error) throw error;
 
 
 
130
 
131
  toast({
132
  title: t.leaderboard.error.newHighScore,
133
- description: t.leaderboard.error.beatRecord.replace("{score}", String(existingScore.score)),
 
 
 
134
  });
 
 
 
135
  } else {
136
  toast({
137
  title: t.leaderboard.error.notHigher
@@ -143,17 +167,23 @@ export const HighScoreBoard = ({
143
  return;
144
  }
145
  } else {
146
- const { error } = await supabase.from("high_scores").insert({
 
147
  player_name: playerName.trim(),
148
  score: currentScore,
149
  avg_words_per_round: avgWordsPerRound,
150
  });
151
 
152
- if (error) throw error;
 
 
 
 
 
 
153
  }
154
-
155
  setHasSubmitted(true);
156
- await refetch();
157
  setPlayerName("");
158
  } catch (error) {
159
  console.error("Error submitting score:", error);
@@ -209,7 +239,8 @@ export const HighScoreBoard = ({
209
  <h2 className="text-2xl font-bold mb-2">{t.leaderboard.title}</h2>
210
  <p className="text-gray-600">
211
  {t.leaderboard.yourScore}: {currentScore} {t.leaderboard.roundCount}
212
- {currentScore > 0 && ` (${avgWordsPerRound.toFixed(1)} ${t.leaderboard.wordsPerRound})`}
 
213
  </p>
214
  </div>
215
 
@@ -219,7 +250,8 @@ export const HighScoreBoard = ({
219
  placeholder={t.leaderboard.enterName}
220
  value={playerName}
221
  onChange={(e) => {
222
- const value = e.target.value.replace(/[^a-zA-Z0-9]/g, '');
 
223
  setPlayerName(value);
224
  }}
225
  onKeyDown={handleKeyDown}
@@ -276,7 +308,7 @@ export const HighScoreBoard = ({
276
  <Pagination>
277
  <PaginationContent>
278
  <PaginationItem>
279
- <PaginationPrevious
280
  onClick={handlePreviousPage}
281
  className={currentPage === 1 ? "pointer-events-none opacity-50" : ""}
282
  >
@@ -297,7 +329,9 @@ export const HighScoreBoard = ({
297
  <PaginationItem>
298
  <PaginationNext
299
  onClick={handleNextPage}
300
- className={currentPage === totalPages ? "pointer-events-none opacity-50" : ""}
 
 
301
  >
302
  <span className="hidden sm:inline">{t.leaderboard.next}</span>
303
  <span className="text-xs text-muted-foreground ml-1">→</span>
@@ -308,4 +342,4 @@ export const HighScoreBoard = ({
308
  )}
309
  </div>
310
  );
311
- };
 
2
  import { Button } from "@/components/ui/button";
3
  import { Input } from "@/components/ui/input";
4
  import { supabase } from "@/integrations/supabase/client";
5
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
6
  import {
7
  Table,
8
  TableBody,
 
64
  const [currentPage, setCurrentPage] = useState(1);
65
  const { toast } = useToast();
66
  const t = useTranslation();
67
+ const queryClient = useQueryClient();
68
 
69
  const { data: highScores, refetch } = useQuery({
70
  queryKey: ["highScores"],
71
  queryFn: async () => {
72
+ console.log("Fetching high scores...");
73
  const { data, error } = await supabase
74
  .from("high_scores")
75
  .select("*")
76
  .order("score", { ascending: false })
77
  .order("avg_words_per_round", { ascending: true });
78
 
79
+ if (error) {
80
+ console.error("Error fetching high scores:", error);
81
+ throw error;
82
+ }
83
+ console.log("Fetched high scores:", data);
84
  return data as HighScore[];
85
  },
86
  });
87
 
88
  const handleSubmitScore = async () => {
89
+ // Updated regex to allow letters with diacritics and special characters
90
+ if (!playerName.trim() || !/^[\p{L}0-9]+$/u.test(playerName.trim())) {
91
  toast({
92
  title: t.leaderboard.error.invalidName,
93
  description: t.leaderboard.error.invalidName,
 
116
 
117
  setIsSubmitting(true);
118
  try {
119
+ console.log("Checking existing score for player:", playerName.trim());
120
+ const { data: existingScores, error: fetchError } = await supabase
121
  .from("high_scores")
122
  .select("*")
123
  .eq("player_name", playerName.trim());
124
 
125
+ if (fetchError) {
126
+ console.error("Error fetching existing scores:", fetchError);
127
+ throw fetchError;
128
+ }
129
+
130
  const existingScore = existingScores?.[0];
131
+ console.log("Existing score found:", existingScore);
132
 
133
  if (existingScore) {
134
  if (currentScore > existingScore.score) {
135
+ console.log("Updating existing score...");
136
+ const { error: updateError } = await supabase
137
  .from("high_scores")
138
  .update({
139
  score: currentScore,
 
141
  })
142
  .eq("id", existingScore.id);
143
 
144
+ if (updateError) {
145
+ console.error("Error updating score:", updateError);
146
+ throw updateError;
147
+ }
148
 
149
  toast({
150
  title: t.leaderboard.error.newHighScore,
151
+ description: t.leaderboard.error.beatRecord.replace(
152
+ "{score}",
153
+ String(existingScore.score)
154
+ ),
155
  });
156
+
157
+ console.log("Score updated successfully");
158
+ await queryClient.invalidateQueries({ queryKey: ["highScores"] });
159
  } else {
160
  toast({
161
  title: t.leaderboard.error.notHigher
 
167
  return;
168
  }
169
  } else {
170
+ console.log("Inserting new score...");
171
+ const { error: insertError } = await supabase.from("high_scores").insert({
172
  player_name: playerName.trim(),
173
  score: currentScore,
174
  avg_words_per_round: avgWordsPerRound,
175
  });
176
 
177
+ if (insertError) {
178
+ console.error("Error inserting score:", insertError);
179
+ throw insertError;
180
+ }
181
+
182
+ console.log("New score inserted successfully");
183
+ await queryClient.invalidateQueries({ queryKey: ["highScores"] });
184
  }
185
+
186
  setHasSubmitted(true);
 
187
  setPlayerName("");
188
  } catch (error) {
189
  console.error("Error submitting score:", error);
 
239
  <h2 className="text-2xl font-bold mb-2">{t.leaderboard.title}</h2>
240
  <p className="text-gray-600">
241
  {t.leaderboard.yourScore}: {currentScore} {t.leaderboard.roundCount}
242
+ {currentScore > 0 &&
243
+ ` (${avgWordsPerRound.toFixed(1)} ${t.leaderboard.wordsPerRound})`}
244
  </p>
245
  </div>
246
 
 
250
  placeholder={t.leaderboard.enterName}
251
  value={playerName}
252
  onChange={(e) => {
253
+ // Allow letters with diacritics and numbers
254
+ const value = e.target.value.replace(/[^a-zA-ZÀ-ÿ0-9]/g, "");
255
  setPlayerName(value);
256
  }}
257
  onKeyDown={handleKeyDown}
 
308
  <Pagination>
309
  <PaginationContent>
310
  <PaginationItem>
311
+ <PaginationPrevious
312
  onClick={handlePreviousPage}
313
  className={currentPage === 1 ? "pointer-events-none opacity-50" : ""}
314
  >
 
329
  <PaginationItem>
330
  <PaginationNext
331
  onClick={handleNextPage}
332
+ className={
333
+ currentPage === totalPages ? "pointer-events-none opacity-50" : ""
334
+ }
335
  >
336
  <span className="hidden sm:inline">{t.leaderboard.next}</span>
337
  <span className="text-xs text-muted-foreground ml-1">→</span>
 
342
  )}
343
  </div>
344
  );
345
+ };
src/components/game/SentenceBuilder.tsx CHANGED
@@ -68,7 +68,8 @@ export const SentenceBuilder = ({
68
  const input = playerInput.trim().toLowerCase();
69
  const target = currentWord.toLowerCase();
70
 
71
- if (!/^[a-zA-Z]+$/.test(input)) {
 
72
  toast({
73
  title: t.game.invalidWord,
74
  description: t.game.lettersOnly,
@@ -124,7 +125,8 @@ export const SentenceBuilder = ({
124
  type="text"
125
  value={playerInput}
126
  onChange={(e) => {
127
- const value = e.target.value.replace(/[^a-zA-Z]/g, '');
 
128
  onInputChange(value);
129
  }}
130
  onKeyDown={handleKeyDown}
 
68
  const input = playerInput.trim().toLowerCase();
69
  const target = currentWord.toLowerCase();
70
 
71
+ // Updated regex to allow letters with diacritics and special characters
72
+ if (!/^[\p{L}]+$/u.test(input)) {
73
  toast({
74
  title: t.game.invalidWord,
75
  description: t.game.lettersOnly,
 
125
  type="text"
126
  value={playerInput}
127
  onChange={(e) => {
128
+ // Allow all letters including those with diacritics
129
+ const value = e.target.value.replace(/[^a-zA-ZÀ-ÿ]/g, '');
130
  onInputChange(value);
131
  }}
132
  onKeyDown={handleKeyDown}
src/components/game/ThemeSelector.tsx CHANGED
@@ -5,14 +5,16 @@ import { motion } from "framer-motion";
5
  import { useTranslation } from "@/hooks/useTranslation";
6
  import { useContext } from "react";
7
  import { LanguageContext } from "@/contexts/LanguageContext";
 
8
 
9
  type Theme = "standard" | "technology" | "sports" | "food" | "custom";
10
 
11
  interface ThemeSelectorProps {
12
  onThemeSelect: (theme: string) => void;
 
13
  }
14
 
15
- export const ThemeSelector = ({ onThemeSelect }: ThemeSelectorProps) => {
16
  const [selectedTheme, setSelectedTheme] = useState<Theme>("standard");
17
  const [customTheme, setCustomTheme] = useState("");
18
  const [isGenerating, setIsGenerating] = useState(false);
@@ -53,12 +55,16 @@ export const ThemeSelector = ({ onThemeSelect }: ThemeSelectorProps) => {
53
  handleSubmit();
54
  }
55
  break;
 
 
 
 
56
  }
57
  };
58
 
59
  window.addEventListener('keydown', handleKeyPress);
60
  return () => window.removeEventListener('keydown', handleKeyPress);
61
- }, [selectedTheme, customTheme, language]);
62
 
63
  useEffect(() => {
64
  if (selectedTheme === "custom") {
@@ -91,11 +97,21 @@ export const ThemeSelector = ({ onThemeSelect }: ThemeSelectorProps) => {
91
  animate={{ opacity: 1 }}
92
  className="space-y-6"
93
  >
94
- <div className="text-center space-y-2">
 
 
 
 
 
 
 
 
95
  <h2 className="text-2xl font-bold text-gray-900">{t.themes.title}</h2>
96
- <p className="text-gray-600">{t.themes.subtitle}</p>
97
  </div>
98
 
 
 
99
  <div className="space-y-4">
100
  {language === 'en' ? (
101
  <Button
 
5
  import { useTranslation } from "@/hooks/useTranslation";
6
  import { useContext } from "react";
7
  import { LanguageContext } from "@/contexts/LanguageContext";
8
+ import { ArrowLeft } from "lucide-react";
9
 
10
  type Theme = "standard" | "technology" | "sports" | "food" | "custom";
11
 
12
  interface ThemeSelectorProps {
13
  onThemeSelect: (theme: string) => void;
14
+ onBack: () => void;
15
  }
16
 
17
+ export const ThemeSelector = ({ onThemeSelect, onBack }: ThemeSelectorProps) => {
18
  const [selectedTheme, setSelectedTheme] = useState<Theme>("standard");
19
  const [customTheme, setCustomTheme] = useState("");
20
  const [isGenerating, setIsGenerating] = useState(false);
 
55
  handleSubmit();
56
  }
57
  break;
58
+ case 'backspace':
59
+ e.preventDefault();
60
+ onBack();
61
+ break;
62
  }
63
  };
64
 
65
  window.addEventListener('keydown', handleKeyPress);
66
  return () => window.removeEventListener('keydown', handleKeyPress);
67
+ }, [selectedTheme, customTheme, language, onBack]);
68
 
69
  useEffect(() => {
70
  if (selectedTheme === "custom") {
 
97
  animate={{ opacity: 1 }}
98
  className="space-y-6"
99
  >
100
+ <div className="flex items-center justify-between mb-4">
101
+ <Button
102
+ variant="ghost"
103
+ size="icon"
104
+ onClick={onBack}
105
+ className="hover:bg-gray-100"
106
+ >
107
+ <ArrowLeft className="h-4 w-4" />
108
+ </Button>
109
  <h2 className="text-2xl font-bold text-gray-900">{t.themes.title}</h2>
110
+ <div className="w-8" /> {/* Spacer for centering */}
111
  </div>
112
 
113
+ <p className="text-gray-600 text-center">{t.themes.subtitle}</p>
114
+
115
  <div className="space-y-4">
116
  {language === 'en' ? (
117
  <Button
src/components/game/WelcomeScreen.tsx CHANGED
@@ -7,6 +7,7 @@ import { LanguageSelector } from "./LanguageSelector";
7
  import { useTranslation } from "@/hooks/useTranslation";
8
  import { useContext } from "react";
9
  import { LanguageContext } from "@/contexts/LanguageContext";
 
10
 
11
  interface WelcomeScreenProps {
12
  onStart: () => void;
@@ -60,6 +61,38 @@ export const WelcomeScreen = ({ onStart }: WelcomeScreenProps) => {
60
  </div>
61
  </motion.div>
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  <Dialog open={showHighScores} onOpenChange={setShowHighScores}>
64
  <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-[600px]">
65
  <HighScoreBoard
 
7
  import { useTranslation } from "@/hooks/useTranslation";
8
  import { useContext } from "react";
9
  import { LanguageContext } from "@/contexts/LanguageContext";
10
+ import { Heart } from "lucide-react";
11
 
12
  interface WelcomeScreenProps {
13
  onStart: () => void;
 
61
  </div>
62
  </motion.div>
63
 
64
+ <motion.div
65
+ initial={{ opacity: 0 }}
66
+ animate={{ opacity: 1 }}
67
+ transition={{ delay: 0.2 }}
68
+ className="max-w-2xl mx-auto text-center mt-12 space-y-4"
69
+ >
70
+ <p className="text-sm text-gray-500">
71
+ {t.welcome.credits}{" "}
72
+ <a
73
+ href="https://blog.felixzieger.de/gaming-hackathon-paris/"
74
+ target="_blank"
75
+ rel="noopener noreferrer"
76
+ className="text-primary hover:underline"
77
+ >
78
+ AI Gaming Hackathon
79
+ </a>.
80
+ </p>
81
+ <div className="flex flex-col items-center gap-2">
82
+ <p className="text-sm text-gray-600">{t.welcome.helpWin}</p>
83
+ <a
84
+ href="https://huggingface.co/spaces/Mistral-AI-Game-Jam/description-improv/tree/main"
85
+ target="_blank"
86
+ rel="noopener noreferrer"
87
+ className="inline-flex flex-col items-center gap-2 px-4 py-2 text-sm font-bold text-primary hover:text-primary/90 transition-colors border border-primary/20 rounded-md hover:border-primary/40"
88
+ >
89
+ <span className="inline-flex items-center gap-2">
90
+ <Heart className="w-4 h-4" /> {t.welcome.onHuggingface}
91
+ </span>
92
+ </a>
93
+ </div>
94
+ </motion.div>
95
+
96
  <Dialog open={showHighScores} onOpenChange={setShowHighScores}>
97
  <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-[600px]">
98
  <HighScoreBoard
src/i18n/translations/de.ts CHANGED
@@ -4,7 +4,10 @@ export const de = {
4
  subtitle: "In diesem Spiel arbeiten Sie mit KI zusammen, um geheime Wörter zu erraten!",
5
  startButton: "Spiel Starten",
6
  howToPlay: "Spielanleitung",
7
- leaderboard: "Bestenliste"
 
 
 
8
  },
9
  howToPlay: {
10
  setup: {
@@ -91,4 +94,4 @@ export const de = {
91
  submitError: "Fehler beim Einreichen der Punktzahl. Bitte versuchen Sie es erneut."
92
  }
93
  }
94
- };
 
4
  subtitle: "In diesem Spiel arbeiten Sie mit KI zusammen, um geheime Wörter zu erraten!",
5
  startButton: "Spiel Starten",
6
  howToPlay: "Spielanleitung",
7
+ leaderboard: "Bestenliste",
8
+ credits: "Erstellt von Sandro, Alessandro, Mattia, Michael, Emiliano und Felix beim",
9
+ helpWin: "Helfen Sie uns einen Preis zu gewinnen",
10
+ onHuggingface: "unser Projekt auf huggingface"
11
  },
12
  howToPlay: {
13
  setup: {
 
94
  submitError: "Fehler beim Einreichen der Punktzahl. Bitte versuchen Sie es erneut."
95
  }
96
  }
97
+ };
src/i18n/translations/en.ts CHANGED
@@ -4,7 +4,10 @@ export const en = {
4
  subtitle: "In this game you team up with AI to guess secret words!",
5
  startButton: "Start Game",
6
  howToPlay: "How to Play",
7
- leaderboard: "Leaderboard"
 
 
 
8
  },
9
  howToPlay: {
10
  setup: {
@@ -91,4 +94,4 @@ export const en = {
91
  submitError: "Failed to submit score. Please try again."
92
  }
93
  }
94
- };
 
4
  subtitle: "In this game you team up with AI to guess secret words!",
5
  startButton: "Start Game",
6
  howToPlay: "How to Play",
7
+ leaderboard: "Leaderboard",
8
+ credits: "Made by Sandro, Alessandro, Mattia, Michael, Emiliano, and Felix at",
9
+ helpWin: "Help us win a price by",
10
+ onHuggingface: "our project on huggingface"
11
  },
12
  howToPlay: {
13
  setup: {
 
94
  submitError: "Failed to submit score. Please try again."
95
  }
96
  }
97
+ };
src/i18n/translations/es.ts CHANGED
@@ -4,7 +4,10 @@ export const es = {
4
  subtitle: "¡En este juego te unes a la IA para adivinar palabras secretas!",
5
  startButton: "Comenzar Juego",
6
  howToPlay: "Cómo Jugar",
7
- leaderboard: "Tabla de Posiciones"
 
 
 
8
  },
9
  howToPlay: {
10
  setup: {
@@ -46,7 +49,7 @@ export const es = {
46
  incorrect: "¡Juego terminado! Presiona Enter para jugar de nuevo",
47
  nextRound: "Siguiente Ronda",
48
  playAgain: "Jugar de Nuevo",
49
- viewLeaderboard: "Ver Tabla de Posiciones"
50
  },
51
  gameOver: {
52
  title: "¡Juego Terminado!",
@@ -67,7 +70,7 @@ export const es = {
67
  pressKey: "Presiona"
68
  },
69
  leaderboard: {
70
- title: "Tabla de Posiciones",
71
  yourScore: "Tu puntaje",
72
  roundCount: "rondas",
73
  wordsPerRound: "palabras/ronda",
@@ -91,4 +94,4 @@ export const es = {
91
  submitError: "Error al enviar el puntaje. Por favor intenta de nuevo."
92
  }
93
  }
94
- };
 
4
  subtitle: "¡En este juego te unes a la IA para adivinar palabras secretas!",
5
  startButton: "Comenzar Juego",
6
  howToPlay: "Cómo Jugar",
7
+ leaderboard: "Clasificación",
8
+ credits: "Creado por Sandro, Alessandro, Mattia, Michael, Emiliano y Felix en el",
9
+ helpWin: "Ayúdanos a ganar un premio",
10
+ onHuggingface: "nuestro proyecto en huggingface"
11
  },
12
  howToPlay: {
13
  setup: {
 
49
  incorrect: "¡Juego terminado! Presiona Enter para jugar de nuevo",
50
  nextRound: "Siguiente Ronda",
51
  playAgain: "Jugar de Nuevo",
52
+ viewLeaderboard: "Ver Clasificación"
53
  },
54
  gameOver: {
55
  title: "¡Juego Terminado!",
 
70
  pressKey: "Presiona"
71
  },
72
  leaderboard: {
73
+ title: "Clasificación",
74
  yourScore: "Tu puntaje",
75
  roundCount: "rondas",
76
  wordsPerRound: "palabras/ronda",
 
94
  submitError: "Error al enviar el puntaje. Por favor intenta de nuevo."
95
  }
96
  }
97
+ };
src/i18n/translations/fr.ts CHANGED
@@ -4,7 +4,10 @@ export const fr = {
4
  subtitle: "Dans ce jeu, vous faites équipe avec l'IA pour deviner des mots secrets !",
5
  startButton: "Commencer",
6
  howToPlay: "Comment Jouer",
7
- leaderboard: "Classement"
 
 
 
8
  },
9
  howToPlay: {
10
  setup: {
@@ -91,4 +94,4 @@ export const fr = {
91
  submitError: "Échec de la soumission du score. Veuillez réessayer."
92
  }
93
  }
94
- };
 
4
  subtitle: "Dans ce jeu, vous faites équipe avec l'IA pour deviner des mots secrets !",
5
  startButton: "Commencer",
6
  howToPlay: "Comment Jouer",
7
+ leaderboard: "Classement",
8
+ credits: "Créé par Sandro, Alessandro, Mattia, Michael, Emiliano et Felix lors du",
9
+ helpWin: "Aidez-nous à gagner un prix en",
10
+ onHuggingface: "notre projet sur huggingface"
11
  },
12
  howToPlay: {
13
  setup: {
 
94
  submitError: "Échec de la soumission du score. Veuillez réessayer."
95
  }
96
  }
97
+ };
src/i18n/translations/it.ts CHANGED
@@ -4,7 +4,10 @@ export const it = {
4
  subtitle: "In questo gioco fai squadra con l'IA per indovinare parole segrete!",
5
  startButton: "Inizia Gioco",
6
  howToPlay: "Come Giocare",
7
- leaderboard: "Classifica"
 
 
 
8
  },
9
  howToPlay: {
10
  setup: {
@@ -87,8 +90,8 @@ export const it = {
87
  alreadySubmitted: "Hai già inviato il tuo punteggio per questa partita",
88
  newHighScore: "Nuovo Record!",
89
  beatRecord: "Hai battuto il tuo record precedente di {score} round!",
90
- notHigher: "Il tuo punteggio attuale ({current}) non è superiore al tuo miglior punteggio ({best})",
91
  submitError: "Errore nell'invio del punteggio. Riprova."
92
  }
93
  }
94
- };
 
4
  subtitle: "In questo gioco fai squadra con l'IA per indovinare parole segrete!",
5
  startButton: "Inizia Gioco",
6
  howToPlay: "Come Giocare",
7
+ leaderboard: "Classifica",
8
+ credits: "Creato da Sandro, Alessandro, Mattia, Michael, Emiliano e Felix all'",
9
+ helpWin: "Aiutaci a vincere un premio",
10
+ onHuggingface: "il nostro progetto su huggingface"
11
  },
12
  howToPlay: {
13
  setup: {
 
90
  alreadySubmitted: "Hai già inviato il tuo punteggio per questa partita",
91
  newHighScore: "Nuovo Record!",
92
  beatRecord: "Hai battuto il tuo record precedente di {score} round!",
93
+ notHigher: "Il tuo punteggio attuale ({current}) non è superiore al miglior punteggio ({best})",
94
  submitError: "Errore nell'invio del punteggio. Riprova."
95
  }
96
  }
97
+ };
src/services/mistralService.ts CHANGED
@@ -1,12 +1,13 @@
1
  import { supabase } from "@/integrations/supabase/client";
2
 
3
- export const generateAIResponse = async (currentWord: string, currentSentence: string[]): Promise<string> => {
4
- console.log('Calling generate-word function with:', { currentWord, currentSentence });
5
 
6
  const { data, error } = await supabase.functions.invoke('generate-word', {
7
  body: {
8
  currentWord,
9
- currentSentence: currentSentence.join(' ')
 
10
  }
11
  });
12
 
@@ -27,11 +28,11 @@ export const generateAIResponse = async (currentWord: string, currentSentence: s
27
  return data.word;
28
  };
29
 
30
- export const guessWord = async (sentence: string): Promise<string> => {
31
- console.log('Calling guess-word function with sentence:', sentence);
32
 
33
  const { data, error } = await supabase.functions.invoke('guess-word', {
34
- body: { sentence }
35
  });
36
 
37
  if (error) {
 
1
  import { supabase } from "@/integrations/supabase/client";
2
 
3
+ export const generateAIResponse = async (currentWord: string, currentSentence: string[], language: string = 'en'): Promise<string> => {
4
+ console.log('Calling generate-word function with:', { currentWord, currentSentence, language });
5
 
6
  const { data, error } = await supabase.functions.invoke('generate-word', {
7
  body: {
8
  currentWord,
9
+ currentSentence: currentSentence.join(' '),
10
+ language
11
  }
12
  });
13
 
 
28
  return data.word;
29
  };
30
 
31
+ export const guessWord = async (sentence: string, language: string): Promise<string> => {
32
+ console.log('Calling guess-word function with sentence:', sentence, 'language:', language);
33
 
34
  const { data, error } = await supabase.functions.invoke('guess-word', {
35
+ body: { sentence, language }
36
  });
37
 
38
  if (error) {
supabase/functions/generate-themed-word/index.ts CHANGED
@@ -53,7 +53,7 @@ serve(async (req) => {
53
  content: `${prompts.systemPrompt} "${theme}".\n${prompts.requirements} ${usedWords.join(', ')}\n\nRespond with just the word in UPPERCASE, nothing else.`
54
  }
55
  ],
56
- maxTokens: 15,
57
  temperature: 0.99
58
  });
59
 
 
53
  content: `${prompts.systemPrompt} "${theme}".\n${prompts.requirements} ${usedWords.join(', ')}\n\nRespond with just the word in UPPERCASE, nothing else.`
54
  }
55
  ],
56
+ maxTokens: 300,
57
  temperature: 0.99
58
  });
59
 
supabase/functions/generate-word/index.ts CHANGED
@@ -64,7 +64,7 @@ serve(async (req) => {
64
  content: `${prompts.systemPrompt} "${currentWord}". ${prompts.task} ${prompts.instruction} "${existingSentence}". Do not add quotes or backticks. Just answer with the sentence.`
65
  }
66
  ],
67
- maxTokens: 200,
68
  temperature: 0.5
69
  });
70
 
 
64
  content: `${prompts.systemPrompt} "${currentWord}". ${prompts.task} ${prompts.instruction} "${existingSentence}". Do not add quotes or backticks. Just answer with the sentence.`
65
  }
66
  ],
67
+ maxTokens: 300,
68
  temperature: 0.5
69
  });
70
 
supabase/functions/guess-word/index.ts CHANGED
@@ -62,7 +62,7 @@ serve(async (req) => {
62
  content: `${prompts.instruction} "${sentence}"`
63
  }
64
  ],
65
- maxTokens: 10,
66
  temperature: 0.1
67
  });
68
 
 
62
  content: `${prompts.instruction} "${sentence}"`
63
  }
64
  ],
65
+ maxTokens: 50,
66
  temperature: 0.1
67
  });
68