Copie depuis Unity VCS vers GitHub

This commit is contained in:
Denis L.
2025-12-10 18:51:40 +01:00
parent 5cfd9de581
commit 7383621db3
902 changed files with 588195 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/*
Collez ce script à un bouton pour qu'il s'agrandisse progressivement.
NOTE: Ceci fonctionne mieux avec les backgrounds de Meta (Materials). C'est plus joli UwU.
*/
public class AgrandissementBoutons : MonoBehaviour
{
public enum AnimationDir
{
DeuxCôtés = 0,
Gauche = 1,
Droite = 2
};
[Header("Animation : Ouverture des boutons")]
private RectTransform bouton;
public float largeur_init = 100f;
public float largeur_max = 500f;
public float duree_ouverture = 0.3f;
public AnimationDir AnimerA = AnimationDir.DeuxCôtés;
private Coroutine coroutine;
private ComportementBoutonsMenu cbm;
// Afficher le texte
private TextMeshProUGUI texte;
private bool est_visible = false;
private bool micro_actif = false;
private void Start()
{
cbm = FindAnyObjectByType<ComportementBoutonsMenu>();
bouton = GetComponent<RectTransform>();
texte = GetComponentInChildren<TextMeshProUGUI>();
texte.gameObject.SetActive(est_visible);
}
/* @brief, Agrandir() permet de grossir la largeur du bouton (il s'étend à l'horizontale).*/
public void AgrandirMenu()
{
if(!cbm.GetAnimEnCours() && !cbm.GetBoutonClique())
{
Debug.Log("AgrandirMenu() exécutée.");
if (Mathf.Abs(bouton.sizeDelta.x - largeur_max) < 0.01f)
return;
if (coroutine != null) StopCoroutine(coroutine);
coroutine = StartCoroutine(ChangerLargeur(largeur_max));
}
}
/* @brief, Agrandir() permet de grossir la largeur du bouton (il s'étend à l'horizontale).*/
public void Agrandir()
{
Debug.Log("Agrandir() exécutée.");
if (Mathf.Abs(bouton.sizeDelta.x - largeur_max) < 0.01f)
return;
if (coroutine != null) StopCoroutine(coroutine);
coroutine = StartCoroutine(ChangerLargeur(largeur_max));
}
/* @brief, Retrecir() permet de rétrécir un bouton vers sa valeur d'origine après un certain délai. Le délai permet d'éviter les clignotements des pointeurs, qui déclenchent des évènements.
*/
public void Retrecir()
{
Debug.Log("Retrécir() appelée.");
if (coroutine != null)
StopCoroutine(coroutine);
coroutine = StartCoroutine(ChangerLargeur(largeur_init));
}
public void RetrecirMicro()
{
Debug.Log($"Entrée dans RetrecirMicro() avec un booléen qui vaut : {micro_actif}");
if(!micro_actif)
{
Debug.Log("RetrécirMicro() appelée.");
EventSystem.current.SetSelectedGameObject(null);
GetComponent<Selectable>().OnDeselect(null);
if (coroutine != null)
StopCoroutine(coroutine);
coroutine = StartCoroutine(ChangerLargeur(largeur_init));
}
}
public void OnToggleMicroButton()
{
Debug.Log($"OnToggleMicroButton() appelée avec un booléen à {micro_actif}.");
micro_actif = !micro_actif;
}
/*@brief, ChangerLargeur() permet de passer la largeur d'un bouton de sa valeur de base à une valeur cible.
@param1 cible, un flottant qui indique la taille vers laquelle le bouton doit évoluer.
@return IEnumerator, c'est aussi une coroutine, on la lance avec StartCoroutine()*/
private IEnumerator ChangerLargeur(float cible)
{
float depart = bouton.sizeDelta.x;
Vector2 pos_depart = bouton.anchoredPosition;
float t = 0;
while (t < duree_ouverture)
{
t += Time.deltaTime;
float w = Mathf.Lerp(depart, cible, t / duree_ouverture);
bouton.sizeDelta = new Vector2(w, bouton.sizeDelta.y);
if(bouton.sizeDelta.x/largeur_max > 0.8) est_visible = true;
else est_visible = false;
switch (AnimerA)
{
case AnimationDir.Gauche:
{
bouton.anchoredPosition = pos_depart - new Vector2((w - depart) / 2, 0);;
break;
}
case AnimationDir.Droite:
{
Vector2 pos = bouton.anchoredPosition + new Vector2(w / 2, 0);
bouton.anchoredPosition = pos;
break;
}
default:
break;
}
yield return null;
}
}
private void Update()
{
texte.gameObject.SetActive(est_visible);
}
public float GetXDuBouton() => bouton.sizeDelta.x;
public bool GetEtatMicro() => micro_actif;
public void SetMicroActif(bool b)
{
micro_actif = b;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 98531106a8a35ea45884856f2b70abde

View File

@@ -0,0 +1,5 @@
public static class BuildConstants
{
public const string LocalIP = "10.42.133.242";
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b9f739c9cbd5f3e41a507f5981861508

View File

@@ -0,0 +1,31 @@
using UnityEngine;
using UnityEngine.EventSystems;
public class ComportementBoutonsEntree : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
private AgrandissementBoutons ab;
void Start()
{
ab = GetComponent<AgrandissementBoutons>();
}
// Update is called once per frame
void Update()
{
}
public void OnPointerEnter(PointerEventData EventData)
{
Debug.Log("Pointeur Entré (Bouton Entrée utilisateur)");
ab.Agrandir();
}
public void OnPointerExit (PointerEventData EventData)
{
Debug.Log("Pointeur Sorti (Bouton Entrée Utilisateur)");
ab.Retrecir();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7a734844cc61b904b8eed0764796572e

View File

@@ -0,0 +1,31 @@
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
/*Collez ce script sur un bouton dans une fenêtre type UI pour qu'il réagisse aux bons évènements. Si votre bouton se trouve dans une fenêtre, ce script est votre meilleure option.*/
public class ComportementBoutonsFenetreUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
private AgrandissementBoutons ab;
public UnityEvent onPointerClick;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
ab = GetComponent<AgrandissementBoutons>();
}
public void OnPointerEnter(PointerEventData eventData)
{
ab.Agrandir();
}
public void OnPointerExit(PointerEventData eventData)
{
ab.Retrecir();
}
public void OnPointerClick(PointerEventData eventData)
{
if(onPointerClick== null)
Debug.LogError("Aucune fonction n'a été définie pour le bouton.");
onPointerClick?.Invoke();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b7db4a332f7e98d4ca6f7558f3613db5

View File

@@ -0,0 +1,156 @@
using TMPro;
using UnityEngine;
using System.Collections;
/*Collez ce script dans sur un canvas pour le faire apparaître/disparaître quand le bouton des trois barres horizontales est cliqué (fonctionne aussi avec la main gauche).
* Les boutons sont affichés du plus à gauche au plus à droite
Recherche un composant avec un Tag Debug et un autre avec un Tag MenuBoutons*/
public class ComportementBoutonsMenu : MonoBehaviour
{
private Canvas canvas;
private bool est_visible = false, animation_en_cours = false;
private TextMeshProUGUI debugs;
private AgrandissementBoutons[] ab;
private bool bouton_clique = false;
[Header("Animation : Boutons")]
public RectTransform[] boutons;
public float rayon = 0.35f;
[Header("Animation : Durée de l'apparition & déplacement des boutons (en secondes)")]
public float duree_deplacement = 0.5f;
private Vector2[] pos_init;
private Vector2[] pos_cercle;
void Start()
{
canvas = GameObject.FindWithTag("MenuBoutons")?.GetComponent<Canvas>();
debugs = GameObject.FindWithTag("Debug")?.GetComponent<TextMeshProUGUI>();
pos_init = new Vector2[boutons.Length];
pos_cercle = new Vector2[boutons.Length];
ab = new AgrandissementBoutons[boutons.Length];
for(int i = 0; i < boutons.Length; i++)
{
pos_init[i] = new(0f, 0f);
ab[i] = boutons[i].GetComponent<AgrandissementBoutons>();
}
pos_cercle = CalculerPositionCercle(boutons.Length, rayon);
if (canvas != null )
canvas.gameObject.SetActive(est_visible);
}
void Update()
{
if (OVRInput.GetDown(OVRInput.Button.Start))
{
est_visible = !est_visible;
animation_en_cours = true;
bouton_clique = false;
debugs.text += $"Update() boutons, valeur de bool : {est_visible} \n";
if (est_visible)
{
canvas.gameObject.SetActive(est_visible);
StartCoroutine(DeplacerBoutons(pos_cercle));
}
else
{
StartCoroutine(DeplacerBoutons(pos_init, () => canvas.gameObject.SetActive(est_visible)
));
}
}
}
/*@brief BoutonClique() permet de définir un comportement pour les boutons quand l'un d'entre eux est pressé. Ici, on demande à fermer le menu des boutons.*/
public void BoutonClique()
{
bouton_clique = true;
for(int i = 0; i < boutons.Length;i++)
{
if (ab[i].GetXDuBouton() > ab[i].largeur_init)
{
if (ab[i].duree_ouverture > duree_deplacement)
{
float duree_tmp = ab[i].duree_ouverture;
ab[i].duree_ouverture = duree_deplacement / 2;
ab[i].Retrecir();
ab[i].duree_ouverture = duree_tmp;
}
else
ab[i].Retrecir();
}
}
est_visible = false;
StartCoroutine(DeplacerBoutons(pos_init,
() => canvas.gameObject.SetActive(est_visible)
));
}
/*@brief, DeplacerBoutons() permet de bouger les boutons d'une position 1 vers une position 2. On les fait glisser vers la position (animation, pas une téléportation).
@param1 pos_cibles, position finale des boutons à la fin de la fonction.
@param2 onFinish, fonction de "callback" qui permet d'appeler une fonction incompatible avec les coroutines dans une coroutine (ici gameObject.SetVisible() ).
@return IEnumerator, c'est une coroutine, on l'appelle avec StartCoroutine().*/
private IEnumerator DeplacerBoutons(Vector2[] pos_cibles, System.Action onFinish = null)
{
float t = 0f;
Vector2[] pos_depart = new Vector2[boutons.Length];
for(int i = 0; i < boutons.Length; i++)
{
pos_depart[i] = boutons[i].anchoredPosition;
}
while (t < duree_deplacement)
{
t += Time.deltaTime;
float p = Mathf.SmoothStep(0f, 1f, t / duree_deplacement);
for(int i = 0; i < boutons.Length; i++)
{
boutons[i].anchoredPosition = Vector2.Lerp(pos_depart[i], pos_cibles[i], p);
}
yield return null;
}
onFinish?.Invoke();
animation_en_cours = false;
}
/*@brief GetAnimEnCours() est un accesseur. Permet de savoir si l'animation d'apparition du menu est en cours ou non.
@return, un booléen.*/
public bool GetAnimEnCours()
{
return animation_en_cours;
}
/*@brief GetBoutonClique() est un accesseur. Permet de savoir si l'utilisateur a cliqué sur un bouton ou non.
@return, un booléen.*/
public bool GetBoutonClique()
{
return bouton_clique;
}
/* @brief, CalculerPositionCercle retourne nb positons selon les paramètres angle_min/angle_max autour d'un cercle de rayon r.
@param1 nb, un entier qui permet de connaitre le nombre de positions à calculer.
@param2 r, le rayon du cercle.
@return un tableau de Vector2 contenant les positions.*/
private Vector2[] CalculerPositionCercle(int nb, float r)
{
Vector2[] resultats = new Vector2[nb];
float angle_min = 0f;
float angle_max = 180f;
float pas_entre_boutons = (angle_min - angle_max) / (nb - 1);
for(int i = 0; i < nb; i++)
{
float angle_degre = angle_max + i*pas_entre_boutons;
float normaliser_en_rad = angle_degre * Mathf.Deg2Rad;
resultats[i] = new Vector2(Mathf.Cos(normaliser_en_rad)*r, Mathf.Sin(normaliser_en_rad)*r);
}
return resultats;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a7d13754c638b8b438c04ad0cef34e84

View File

@@ -0,0 +1,25 @@
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/*Script à coller sur un bouton de la fenêtre des préférences pour activer la focntion (à coller dans l'inspecteur).*/
public class ComportementBoutonsPreferences : MonoBehaviour, IPointerClickHandler
{
private GameObject bouton;
[Header("Fonction à exécuter quand le bouton est pressé.")]
public UnityEvent fonction;
private void Start()
{
bouton = GameObject.FindWithTag("QDSUIToggleSwitch");
if (fonction == null)
Debug.LogError($"La fonction n'a pas été définie dans l'inspecteur ! Le bouton {bouton.name} est inutilisable.");
}
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log($"Bouton {bouton.name} cliqué");
fonction?.Invoke();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 426a9e0245cc0d041be77fb9f705fb86

View File

@@ -0,0 +1,21 @@
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
using TMPro;
/* Ce script est à coller sur une bulle texte.*/
public class ComportementBulleTexte3D : MonoBehaviour
{
private GameObject bulle;
private const string tag1 = "Bulle3D";
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
foreach (Transform t in transform)
{
if(t.gameObject.CompareTag(tag1))
bulle = t.gameObject;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 81607e97867670043b0f88a7850a3b78

View File

@@ -0,0 +1,72 @@
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
/*
Ce script permet de gérer l'envoi au serveur au niveau du TMP_InputField.
*/
public class ComportementEntreeUtilisateur : MonoBehaviour
{
private TMP_InputField Entree;
private TouchScreenKeyboard clavier;
private EnvoyerRecevoirDonnees envoyer_recevoir;
private RunWhisper ia;
private EnumFonctionsPreferences efp;
private void Start()
{
Entree = GetComponentInChildren<TMP_InputField>();
if (clavier == null)
Debug.LogError("Aucun clavier trouvé ! ALERTE AU GOGOLE LES ENFANTS !!!");
envoyer_recevoir = FindAnyObjectByType<EnvoyerRecevoirDonnees>();
ia = FindAnyObjectByType<RunWhisper>();
ia.OnTranscriptionComplete += HandleTranscriptionResult;
efp = FindAnyObjectByType<EnumFonctionsPreferences>();
}
public void TraitementEntree()
{
Debug.Log("Entrée dans TraitementEntrée()");
if (!string.IsNullOrWhiteSpace(Entree.text))
StartCoroutine(envoyer_recevoir.EnvoyerAction(Entree.text));
Entree.text = string.Empty;
Entree.DeactivateInputField();
}
public void TraitementEntreeAudio(string s)
{
Debug.Log("On est censé pouvoir parler là.");
if(ia != null)
{
ia.StartMicrophoneInference();
}
}
private void HandleTranscriptionResult(string texteTranscrit)
{
Debug.Log("HandleTranscriptionResult() Transcription terminée reçue : " + texteTranscrit);
if (!string.IsNullOrWhiteSpace(texteTranscrit))
{
Entree.text = texteTranscrit;
Entree.caretPosition = Entree.text.Length;
Entree.ForceLabelUpdate();
Entree.MoveTextEnd(false);
}
}
public TMP_InputField GetEntree() => Entree;
void OnDestroy()
{
if (ia != null)
{
ia.OnTranscriptionComplete -= HandleTranscriptionResult;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4f9a237365031784e9a1c139ac1991cb

View File

@@ -0,0 +1,40 @@
using Oculus.Interaction;
using UnityEngine;
/*Ce script est à coller sur un objet vide (pour éviter de désactiver ses évènements quand la fenêtre des préférences est désactivée). */
public class ComportementFenetrePreferences : MonoBehaviour
{
private GameObject prefab;
private bool est_visible = false;
private CanvasGroup canvas;
private void Start()
{
prefab = GameObject.FindWithTag("FenetrePrefs");
canvas = prefab.GetComponent<CanvasGroup>();
canvas.alpha = 0f;
canvas.interactable = false;
canvas.blocksRaycasts = false;
prefab.GetComponent<RayInteractable>().enabled = false;
}
public void ChangerEtat()
{
est_visible = !est_visible;
if (est_visible)
{
prefab.GetComponent<RayInteractable>().enabled = true;
canvas.alpha = 1.0f;
canvas.interactable = true;
canvas.blocksRaycasts = true;
}
else
{
canvas.alpha = 0f;
canvas.interactable = false;
canvas.blocksRaycasts = false;
prefab.GetComponent<RayInteractable>().enabled = false;
}
Debug.Log($"État de la fenêtre des préférences : {prefab.activeSelf}.");
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 40032d926c1a4a84aa451aaa2a114b53

View File

@@ -0,0 +1,17 @@
using UnityEngine;
/*Ce script permet de placer l'historique des messages devant l'utilisateur.*/
public class ComportementHistoriqueMessages : MonoBehaviour
{
private RectTransform historique;
void Start()
{
historique = GameObject.FindWithTag("HistoriqueMsg").GetComponent<RectTransform>();
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9665f1a818d81784aacb24ea78042758

View File

@@ -0,0 +1,37 @@
using UnityEngine;
using UnityEngine.UI;
/*Donné par ChatGPT pour débuguer les problèmes liés aux canvas en les affichant en rouge pâle. À mettre dans un objet vide avec Add component. S'active tout seul.*/
[ExecuteAlways]
public class DebugVisualEffects : MonoBehaviour
{
void Start()
{
foreach (Canvas canvas in FindObjectsByType<Canvas>(FindObjectsSortMode.None))
{
var existingOutline = canvas.transform.Find("CanvasDebugBordure");
GameObject outline;
if (existingOutline != null)
{
// Il existe déjà, on le réutilise
outline = existingOutline.gameObject;
}
else
{
// Sinon, on le crée
outline = new GameObject("CanvasDebugBordure");
outline.transform.SetParent(canvas.transform, false);
}
var img = outline.AddComponent<Image>();
img.color = new Color(1f, 0f, 0f, 0.1f); // rouge transparent
var rect = img.GetComponent<RectTransform>();
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
rect.offsetMin = rect.offsetMax = Vector2.zero;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 359753addc189e24bbbc5355eb782ba3

View File

@@ -0,0 +1,50 @@
using System.Collections;
using UnityEngine;
/*
Permet d'énumérer les différents cas/fonctions pour les boutons du menu.
*/
public class EnumFonctionsBouton : MonoBehaviour
{
private EnvoyerRecevoirDonnees e_r_d;
private ComportementFenetrePreferences c_f_p;
public void Start()
{
e_r_d = FindAnyObjectByType<EnvoyerRecevoirDonnees>();
c_f_p = FindAnyObjectByType<ComportementFenetrePreferences>();
}
/*@brief, LancerRecherche() permet de démarrer la coroutine EnvoyerRecherche() sans être elle-même une coroutine.*/
public void LancerRecherche()
{
StartCoroutine(EnvoyerRecherche());
}
/*@brief, EnvoyerRecherche() permet d'interrompre l'action en cours pour lancer une recherche côté serveur.
@return IEnumerator, c'est une coroutine donc on la démarre avec StartCoroutine().*/
public IEnumerator EnvoyerRecherche()
{
yield return StartCoroutine(e_r_d.EnvoyerRaccourci("2"));
}
/*@brief, LancerQuitter() permet de démarrer la coroutine EnvoyerQuitter() sans être elle-même une coroutine.*/
public void LancerQuitter()
{
StartCoroutine(EnvoyerQuitter());
}
/*@brief, EnvoyerQuitter() permet d'interrompre l'action en cours pour quitter côté serveur.
@return IEnumerator, c'est une coroutine donc on la démarre avec StartCoroutine().*/
public IEnumerator EnvoyerQuitter()
{
yield return StartCoroutine(e_r_d.EnvoyerRaccourci("3"));
Application.Quit();
}
/*@brief, LancerPrefs() permet d'ouvrir la fenêtre des préférences.*/
public void LancerPrefs()
{
c_f_p.ChangerEtat();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fdd9ec74efce24c4ebf3d3b203c97f0a

View File

@@ -0,0 +1,242 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
/*Ce script permet aux boutons de la fenętre de préférences de fonctionner. */
public class EnumFonctionsPreferences : MonoBehaviour
{
bool utiliser_microphone = false;
private TextMeshProUGUI[] tab_texte;
private AgrandissementBoutons[] tab_boutons;
private GameObject[] fenetres;
private Color[] tab_couleurs = new Color[3];
private GameObject entree;
private Image entree_img;
private TextMeshProUGUI[] tab_entree_tmp;
// Définition des couleurs
private readonly Color c_bleu_j = new(65 / 255f, 105 / 255f, 225 / 255f);
private readonly Color c_rouge_j = new(178 / 255f, 34 / 255f, 34 / 255f);
private readonly Color c_vert_j = new(108 / 255f, 186 / 255f, 104 / 255f);
private readonly Color c_bleu_n = new(100 / 255f, 149 / 255f, 237 / 255f);
private readonly Color c_rouge_n = new(220 / 255f, 20 / 255f, 60 / 255f);
private readonly Color c_vert_n = new(46 / 255f, 111 / 255f, 64 / 255f);
private readonly Color c_jour = new(0.95f, 0.95f, 0.95f);
private readonly Color c_nuit = new(0.35f, 0.35f, 0.35f);
private bool jour = false;
private TextMeshProUGUI debugs;
private GameObject scrollview;
private Image[] historique_image;
private Scrollbar[] scrollbars;
private Material rounded_box_bulles;
private const string rounded_box_bulle_chemin = "Materials/RoundedBoxUIBulles";
private Material triangle_bulles;
private const string triangle_bulle_chemin = "Materials/TriangleMask";
private readonly float alpha_bulles = 1;
private List<TextMeshProUGUI> tab_historique = new();
private GameObject choix_langue;
private void Awake()
{
tab_texte = FindObjectsByType<TextMeshProUGUI>(FindObjectsInactive.Include, FindObjectsSortMode.None);
tab_boutons = FindObjectsByType<AgrandissementBoutons>(FindObjectsInactive.Include, FindObjectsSortMode.None);
fenetres = FonctionsUtilitaires.FindAllWithTag("QDSUIBackplateGradient");
Debug.Log($"Valeur de fenetre : {fenetres}");
entree = GameObject.FindWithTag("Entree");
entree_img = entree.GetComponent<Image>();
tab_entree_tmp = entree.GetComponentsInChildren<TextMeshProUGUI>();
debugs = GameObject.FindWithTag("Debug").GetComponent<TextMeshProUGUI>();
scrollview = GameObject.FindWithTag("Scrollview");
historique_image = scrollview.GetComponentsInChildren<Image>();
scrollbars = scrollview.GetComponentsInChildren<Scrollbar>(true);
rounded_box_bulles = Resources.Load<Material>(rounded_box_bulle_chemin);
triangle_bulles = Resources.Load<Material>(triangle_bulle_chemin);
if (rounded_box_bulles == null)
{
Debug.LogError($"[Mode Nuit] Le Material ŕ l'emplacement '{rounded_box_bulle_chemin}' est introuvable. Les couleurs des bulles ne changeront pas.");
}
choix_langue = GameObject.FindWithTag("ChoisirLangue");
choix_langue.SetActive(false);
}
private void Start()
{
ChangerMode();
}
public void ChangerMode()
{
jour = !jour;
debugs.text += $"Entrée dans ChangerMode() avec un booléen ŕ {jour}.\n";
if(jour)
{
Material m = Resources.Load<Material>("Materials/LinearGradientUILight");
foreach (AgrandissementBoutons b in tab_boutons)
{
Debug.Log($"Bouton : {b}");
b.GetComponentInChildren<Image>(true).color = c_jour;
}
foreach (TextMeshProUGUI t in tab_texte)
{
Debug.Log($"TMP : {t}");
t.color = new Color(0.5f, 0.5f, 0.5f);
}
foreach (GameObject go in fenetres)
{
Debug.Log($"Fenetre : {fenetres}");
go.GetComponentInChildren<Image>(true).material = m;
Debug.Log($"Valeur de material : {go.GetComponentInChildren<Image>(true).material}");
}
tab_couleurs[0] = c_bleu_j;
tab_couleurs[1] = c_rouge_j;
tab_couleurs[2] = c_vert_j;
scrollview.GetComponent<Image>().color = c_jour;
foreach (Image im in historique_image)
{
im.color = new Color(1, 1, 1);
}
foreach (Scrollbar sc in scrollbars)
{
ColorBlock cb = sc.colors;
cb.normalColor = c_jour;
cb.highlightedColor = c_jour * 1.1f;
cb.pressedColor = c_jour * 0.9f;
sc.colors = cb;
}
Color nouvelle = c_jour;
nouvelle.a = alpha_bulles;
rounded_box_bulles.color = nouvelle;
triangle_bulles.color = nouvelle;
foreach (TextMeshProUGUI t in tab_historique)
{
if (t == null) continue;
float alpha = t.color.a;
Color couleur_tmp = c_jour;
if (t.color.Equals(c_bleu_n))
{
couleur_tmp = c_bleu_j;
}
else if (t.color.Equals(c_rouge_n))
{
couleur_tmp = c_rouge_j;
}
else if (t.color.Equals(c_vert_n))
{
couleur_tmp = c_vert_j;
}
couleur_tmp.a = alpha;
t.color = couleur_tmp;
}
entree_img.color = c_jour;
foreach (TextMeshProUGUI tmp in tab_entree_tmp)
{
if (tmp == null) continue;
Color c = new(0.3f, 0.3f, 0.3f);
float alpha = tmp.color.a;
c.a = alpha;
tmp.color = c;
}
}
else
{
Material m = Resources.Load<Material>("Materials/LinearGradientUIDark");
foreach (AgrandissementBoutons b in tab_boutons)
b.GetComponentInChildren<Image>(true).color = c_nuit;
foreach (TextMeshProUGUI t in tab_texte)
t.color = new Color(0.8f, 0.8f, 0.8f);
foreach (GameObject go in fenetres)
go.GetComponentInChildren<Image>(true).material = m;
tab_couleurs[0] = c_bleu_n;
tab_couleurs[1] = c_rouge_n;
tab_couleurs[2] = c_vert_n;
scrollview.GetComponent<Image>().color = c_nuit;
foreach (Image im in historique_image)
{
im.color = c_nuit;
}
foreach (Scrollbar sc in scrollbars)
{
ColorBlock cb = sc.colors;
cb.normalColor = c_nuit;
cb.highlightedColor = c_nuit * 1.1f;
cb.pressedColor = c_nuit * 0.9f;
sc.colors = cb;
}
Color nouvelle = c_nuit;
nouvelle.a = alpha_bulles;
rounded_box_bulles.color = nouvelle;
triangle_bulles.color = nouvelle;
foreach (TextMeshProUGUI t in tab_historique)
{
if (t == null) continue;
float alpha = t.color.a;
Color couleur_tmp = c_nuit;
if (t.color.Equals(c_bleu_j))
{
couleur_tmp = c_bleu_n;
}
else if (t.color.Equals(c_rouge_j))
{
couleur_tmp = c_rouge_n;
}
else if (t.color.Equals(c_vert_j))
{
couleur_tmp = c_vert_n;
}
couleur_tmp.a = alpha;
t.color = couleur_tmp;
}
entree_img.color = c_nuit;
foreach (TextMeshProUGUI tmp in tab_entree_tmp)
{
if (tmp == null) continue;
Color c = new(0.8f, 0.8f, 0.8f);
float alpha = tmp.color.a;
c.a = alpha;
tmp.color = c;
}
}
}
/*Permet d'activer le mode Text2Speech*/
public void ChangerSaisie()
{
utiliser_microphone = !utiliser_microphone;
choix_langue.SetActive(utiliser_microphone);
}
public bool GetSaisieAudio() => utiliser_microphone;
public Color[] GetTabCouleurs() => tab_couleurs;
public void SetMessageDansListeHistorique(TextMeshProUGUI tmp)
{
tab_historique.Add(tmp);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ef2f097cac0359b478ae44e2512c8f4c

View File

@@ -0,0 +1,138 @@
using System;
using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
/* Appelé par GestionnaireApplication.
* Permet de faire des requêtes vers le serveur aussi bien pour envoyer que pour recevoir des chose.
On décrypte la requête connue du serveur et on l'adapte.
*/
public class EnvoyerRecevoirDonnees: MonoBehaviour
{
private string base_url;
public string Token { get; private set; } = "";
private bool est_pret = false;
private Action<ReponseServeur> OnServeurUpdate;
private GestionnaireApplication gestapp;
[Serializable]
public class ReponseServeur
{
public string[] messages;
public string[] debugs;
public bool attente_saisie;
public bool continuer;
}
/*@brief, Init() sert de constructeur ++ pour la classe EnvoyerRecevoirDonnees. Elle instancie les paramètres et lance la boucle principale.
@param1 token, une chaine de caractère qui contient le token du client.
@param2 URL, l'URL du serveur.
@param3 callback, une fonction. Ici, il s'agit de OnServeurUpdate du GestionnaireApplication, qui lui permet de décrypter les données brutes reçues par le serveur. */
public void Init(string token, string URL, Action<ReponseServeur> callback)
{
Token = token;
est_pret = true;
OnServeurUpdate = callback;
base_url = URL;
gestapp = FindAnyObjectByType<GestionnaireApplication>();
Debug.Log("Client initialisé avec le token : " + Token);
// On lance la boucle principale
StartCoroutine(MainLoop());
}
/*@brief, MainLoop() est la boucle centrale de ce script. Elle permet de vérifier les nouvelles données du serveur.
@return, c'est une coroutine, on l'appelle avec StartCoroutine().
NOTE: on pourra modifier ces fonctions pour qu'elles ne fassent des requêtes que lorsque c'est nécessaire (ici on en fait toutes les deux secondes, même si rien n'a changé).*/
IEnumerator MainLoop()
{
while (est_pret)
{
if(gestapp.GetEnvoyerRequete())
{
yield return GetServerUpdate();
yield return new WaitForSeconds(2);
}
yield return null;
}
}
/*@brief, GetServerUpdate() fait la requête au serveur et les transmet au GestionnaireApplication grâce à la fonction callback.
@return IEnumerator, c'est une coroutine on l'appelle avec StartCoroutine()*/
IEnumerator GetServerUpdate()
{
using (UnityWebRequest requete = UnityWebRequest.Get(base_url + "envoyer/" + Token))
{
yield return requete.SendWebRequest();
if (requete.result != UnityWebRequest.Result.Success)
Debug.LogWarning("Erreur update : " + requete.error);
else
{
string json = requete.downloadHandler.text;
ReponseServeur donnees_brutes = JsonUtility.FromJson<ReponseServeur>(json);
Debug.Log("Données du serveur : " + json);
// On va essayer de transmettre les données vers le gestionnaire du jeu
OnServeurUpdate?.Invoke(donnees_brutes);
}
}
}
/*@brief, EnvoyerAction() permet d'envoyer des éléments au serveur de du type : "{"entree": "<ma_valeur>"}".
* @param action, la chaine de caractères à envoyer au serveur.
@return IEnumerator, c'est une coroutine, on l'appelle avec StartCoroutine().*/
public IEnumerator EnvoyerAction(string action)
{
if (!est_pret) yield break;
string jsonBody = "{\"entree\":\"" + action + "\"}";
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);
using (UnityWebRequest request = new UnityWebRequest(base_url + "recevoir/" + Token, "POST"))
{
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
Debug.LogError("Erreur envoi : " + request.error);
else
Debug.Log("Action envoyée : " + action);
}
gestapp.SetEnvoyerRequete(true);
}
/*@brief, EnvoyerRaccourci() permet de transmettre une interruption au serveur de type : "{"raccourci": "<ma_valeur>"}".
@param interruption, une chaine de caractère contenant l'interruption. Les interruptions contiennent des valeur entières qui seront transformées par le serveur au besoin (par exemple "1", "2", ...).
@return IEnumerator, c'est une coroutine donc on la démarre avec StartCoroutine().*/
public IEnumerator EnvoyerRaccourci(string interruption)
{
if (!est_pret) yield break;
gestapp.SetEnvoyerRequete(true);
string jsonBody = "{\"raccourci\":\"" + interruption + "\"}";
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);
using (UnityWebRequest request = new UnityWebRequest(base_url + "recevoir/" + Token, "POST"))
{
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
Debug.LogError("Erreur envoi : " + request.error);
else
Debug.Log("Action envoyée : " + interruption);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b3a5933ccf77e5b4dac95a07f78b7914

16
Assets/Scripts/FPS.cs Normal file
View File

@@ -0,0 +1,16 @@
using UnityEngine;
using TMPro;
public class FPS : MonoBehaviour
{
public TextMeshProUGUI fpsText;
private float deltaTime = 0.0f;
void Update()
{
deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
float fps = 1.0f / deltaTime;
if (fpsText != null)
fpsText.text = Mathf.Ceil(fps).ToString() + " FPS";
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7dd158344ea9428489f283268329574b

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using UnityEngine;
/*Référence les fonctions génériques du jeu. On le colle sur un objet vide pour qu'il puisse être détecté par les autres scripts qui ont besoin de lui .
NOTE : Les fonctions de ce script doivent être en statique pour que ça soit plus facile à intégrer.*/
public class FonctionsUtilitaires : MonoBehaviour
{
/*@brief, FindAllWIthTag Retourne un tableau contenant tous les GameObject avec un tag passé en paramètre.
@param1 tag, la chaine de caractère qui contient le tag.
@return, une liste contenant chaque GameObject qui correspond au tag.*/
public static GameObject[] FindAllWithTag(string tag)
{
List<GameObject> results = new();
Transform[] tousLesTransforms = GameObject.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
foreach (Transform t in tousLesTransforms)
{
if (t.CompareTag(tag))
{
results.Add(t.gameObject);
}
}
return results.ToArray();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b9083175e4e8315468d61e23c23acb0e

View File

@@ -0,0 +1,45 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
/*Je ne sais pas si ce script sert mais il permet d'ouvrir le clavier système du Quest. ATTENTION: CES ENC*LÉS de leurs grands morts de F*P de Meta ne précisent pas que ça ne FONCTIONNERA JAMAIS DANS LINK, IL FAUT ABSOLUMENT LE BUILD SI ON VEUT FAIRE APPARAÎTRE CE CLAVIER DU DÉMON.*/
public class GestionClavier : MonoBehaviour, ISelectHandler, IDeselectHandler
{
public InputField entree;
public OVRVirtualKeyboard clavier;
private TouchScreenKeyboard overlayKeyboard;
private void Start()
{
if (entree == null)
entree = GetComponent<InputField>();
if (clavier == null)
{
clavier = FindAnyObjectByType<OVRVirtualKeyboard>(FindObjectsInactive.Include);
if (clavier == null)
{
Debug.LogError("Pas de clavier virtuel dans la scène !");
}
}
if (clavier != null)
clavier.gameObject.SetActive(false);
}
public void OnSelect(BaseEventData eventData)
{
Debug.Log("Entrée sélectionnée, clavier affiché.");
overlayKeyboard = TouchScreenKeyboard.Open("", TouchScreenKeyboardType.Default);
Debug.Log($"clavier = {clavier}, entree = {entree}, clavier système = {overlayKeyboard}");
}
public void OnDeselect(BaseEventData eventData)
{
Debug.Log("Entrée désélectionnée, clavier masqué.");
if (clavier != null)
{
clavier.gameObject.SetActive(false);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8dbbddf722056334bbd9addba995c89d

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
public class GestionTexte : MonoBehaviour
{
public static class CouleursMessage
{
public const int accueil = 0;
public const int contre = 1;
public const int pour = 2;
}
/* @brief MessageAccueil() prend le texte reçu par le serveur pour en extraire les messages liés à l'accueil du joueur.
@param texte_brut, une liste de chaine de caractères (qui contient donc les messages à filtrer.
@return , une structure FIFO pour assurer la suppression des éléments après leur lecture.*/
public static Queue<(string message, int index_couleur)> CreerQueueDepuisTexte(List<string> texte_brut, TextMeshProUGUI debug)
{
(string pref, int ind)? AnalyserLigne(string l)
{
int sep = l.IndexOf(';');
if (sep < 0)
return null;
string prefixe_complet = l.Substring(0, sep).Trim();
string prefixe = prefixe_complet.Trim('[', ']', ' ').ToLowerInvariant();
debug.text += $"Prefixe trouvé : {prefixe}. Il y a {prefixe.Length} caractères dans le préfixe.\n";
int index;
switch (prefixe)
{
case "accueil":
{
index = CouleursMessage.accueil;
break;
}
case "pour":
{
index = CouleursMessage.pour;
break;
}
case "contre":
{
index = CouleursMessage.contre;
break;
}
default:
return null;
}
return (prefixe, index);
}
IEnumerable<(string message, int index_couleur)> messages_filtres = texte_brut
.Select(l => (l, l_analysee: AnalyserLigne(l.Trim())))
.Where(m => m.l_analysee.HasValue)
.Select(mbox =>
{
var ligne = mbox.l.Trim();
var index_sep = ligne.IndexOf(';');
string finalMsg = ligne.Substring(index_sep + 1).Trim();
int finalIndex = mbox.l_analysee.Value.ind;
return (message: finalMsg, index_couleur: finalIndex);
});
Queue<(string message, int index_couleur)> resultats = new(messages_filtres);
return resultats;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e7b03c53c16497046bb06b986f119ab5

View File

@@ -0,0 +1,254 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Meta.WitAi.TTS.Utilities;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/*
* Le script au coeur de l'interface. Il crée un token, permet les échanges serveur et redirige les messages du serveur au bon endroit.
*/
public class GestionnaireApplication : MonoBehaviour
{
[SerializeField] private FastAPIClient init_token_client;
[SerializeField] private EnvoyerRecevoirDonnees envoyer_recevoir;
[SerializeField] private TextMeshProUGUI DebugsTMP;
[SerializeField] private TMP_InputField Entree;
[SerializeField] private float delai_entre_deux_frappes = 0.04f;
[SerializeField] private ManagerTTS managerTTS;
private bool afficher_entree = false, envoyer_requete = true, continuer = true;
private const string base_url = "http://" + BuildConstants.LocalIP + ":8000/";
private TextMeshProUGUI accueil;
private TextMeshProUGUI[] pour;
private TextMeshProUGUI[] contre;
private string[] messages;
private Queue<(string message, int index_couleur)> queue_msg;
private EnumFonctionsPreferences efp;
private GameObject texte_prefab, historique_prefab;
private ScrollRect scrollview_historique;
private const float seuil_descente_auto = 0.05f;
public Transform content_historique;
private GameObject bouton_micro;
private void Awake()
{
efp = FindAnyObjectByType<EnumFonctionsPreferences>();
accueil = GameObject.FindWithTag("Accueil").GetComponentInChildren<TextMeshProUGUI>();
historique_prefab = GameObject.FindWithTag("TextePrefab");
GameObject clone = Instantiate(historique_prefab);
clone.SetActive(false);
TextMeshProUGUI clone_tmp = clone.GetComponent<TextMeshProUGUI>();
ConfigurerPrefabModele(clone_tmp);
texte_prefab = clone;
texte_prefab.transform.SetParent(null);
pour = new TextMeshProUGUI[5];
contre = new TextMeshProUGUI[5];
pour[0] = GameObject.FindWithTag("Pour").GetComponentInChildren<TextMeshProUGUI>();
contre[0] = GameObject.FindWithTag("Contre").GetComponentInChildren<TextMeshProUGUI>();
scrollview_historique = GameObject.FindWithTag("Scrollview").GetComponent<ScrollRect>();
bouton_micro = GameObject.FindWithTag("Micro");
}
private IEnumerator Start()
{
// Unity appelle Start() tout seul
Debug.Log($"URL : {base_url}");
DebugsTMP.text = "URL" + base_url + "\n";
yield return StartCoroutine(init_token_client.GetTokenDuServeur(base_url));
envoyer_recevoir.Init(init_token_client.Token,base_url, OnServeurUpdate);
}
private void ConfigurerPrefabModele(TextMeshProUGUI t)
{
t.text = "";
t.fontStyle = FontStyles.Normal;
t.fontSize = 12;
t.alignment = TextAlignmentOptions.TopLeft;
RectTransform rect = t.GetComponent<RectTransform>();
rect.anchorMin = new(0,1);
rect.anchorMax = new(1,1);
rect.pivot = rect.anchorMin;
rect.sizeDelta = new(0,25f);
}
/*@brief OnServeurUpdate() est appelée pour décrypter les messages du serveur.
@param1 donnees, les données brutes de la réponse du serveur. On les défait en plusieurs morceaux(un par entrée dans le dictionnaire).*/
private void OnServeurUpdate (EnvoyerRecevoirDonnees.ReponseServeur donnees)
{
messages = donnees.messages;
DebugsTMP.text = string.Join("\n", donnees.messages);
afficher_entree = donnees.attente_saisie;
continuer = donnees.continuer;
DemarrerLectureMessages();
}
private void Update()
{
if (Entree.IsActive() != afficher_entree)
{
Entree.transform.parent.gameObject.SetActive(afficher_entree);
}
if (!efp.GetSaisieAudio() && Entree.IsActive())
{
bouton_micro.SetActive(false);
}
else
{
bouton_micro.SetActive(true);
}
if (scrollview_historique.verticalNormalizedPosition < seuil_descente_auto)
Descendre();
// Si la barre vient d'apparaître, on la force à aller en bas.
else if (scrollview_historique.verticalNormalizedPosition > 1)
Descendre();
}
public bool GetEnvoyerRequete() => envoyer_requete;
public bool SetEnvoyerRequete(bool value) => envoyer_requete = value;
private void DemarrerLectureMessages()
{
queue_msg = GestionTexte.CreerQueueDepuisTexte(messages.ToList(), DebugsTMP);
StartCoroutine(LireMessagesQueue());
}
private IEnumerator LireMessagesQueue()
{
envoyer_requete = false;
Color[] couleurs = efp.GetTabCouleurs();
while (queue_msg.Count > 0)
{
var message_en_cours = queue_msg.Dequeue();
string msg = message_en_cours.message;
int index_couleur = message_en_cours.index_couleur;
DebugsTMP.text += ($"J'ai lu le message {msg} avec la couleur {index_couleur}. Sa couleur sera (en RGB) : {couleurs[index_couleur]}. La scrollbar est à {scrollview_historique.verticalNormalizedPosition}\n");
TTSSpeaker speakerActuel = new();
switch (index_couleur)
{
case 0:
{
AfficherMessageAccueil(msg);
speakerActuel = managerTTS.bobSpeaker;
break;
}
case 1:
{
DebugsTMP.text += "cas contre";
AfficherMessageContre(msg);
speakerActuel = managerTTS.carlSpeaker;
break;
}
case 2:
{
DebugsTMP.text += "cas pour";
AfficherMessagePour(msg);
speakerActuel = managerTTS.caelSpeaker;
break;
}
}
yield return StartCoroutine(EcrireEtLireMessage(msg, couleurs[index_couleur], speakerActuel));
}
}
private void AfficherMessageAccueil(string msg)
{
accueil.text = "";
accueil.text = msg;
}
private void AfficherMessagePour(string msg)
{
pour[0].text = "";
pour[0].text = msg;
}
private void AfficherMessageContre(string msg)
{
contre[0].text = "";
contre[0].text = msg;
}
private IEnumerator EcrireEtLireMessage(string msg, Color couleur, TTSSpeaker ttss)
{
GameObject nouveau_texte = Instantiate(texte_prefab, content_historique);
nouveau_texte.transform.SetParent(content_historique);
nouveau_texte.SetActive(true);
TextMeshProUGUI tmp = nouveau_texte.GetComponent<TextMeshProUGUI>();
efp.SetMessageDansListeHistorique(tmp);
tmp.color = couleur;
tmp.text = "";
DebugsTMP.text += ($"EcrireMessage(): Ecriture d'un texte avec la couleur {tmp.color}");
// Paroles
if(ttss != null)
{
ttss.Speak(msg);
yield return null;
}
for (int i = 0; i < msg.Length; i++)
{
tmp.text += msg[i];
yield return new WaitForSeconds(delai_entre_deux_frappes);
}
tmp.text += "\n";
// Attente de la fin de la parole
if (ttss != null)
{
bool isSpeaking = true;
// Listener temporaire pour synchroniser le texte et l'audio. coroutine
UnityEngine.Events.UnityAction<AudioClip> listener = null;
listener = (t) =>
{
isSpeaking = false;
// IMPORTANT : Se désabonner immédiatement pour ne pas interférer avec d'autres lignes
ttss.Events.OnAudioClipPlaybackFinished.RemoveListener(listener);
};
// S'abonner à l'événement du speaker actuel
ttss.Events.OnAudioClipPlaybackFinished.AddListener(listener);
Debug.Log($"[TTS] Attente de la fin de parole de {ttss.name}...");
// Boucle de blocage de la coroutine : on attend que l'événement soit déclenché
while (ttss.IsSpeaking)
{
yield return null;
}
if (!isSpeaking)
{
ttss.Events.OnAudioClipPlaybackFinished.RemoveListener(listener);
Debug.LogWarning($"[TTS] Avertissement: L'événement de fin a été manqué pour {ttss.name}. Nettoyage forcé du listener.");
}
Debug.Log($"[TTS] Fin de parole de {ttss.name} atteinte.");
}
}
public void Descendre()
{
// On force le rafraîchissement immédiat du Layout Group
// pour que le Content Size Fitter recalcule la taille totale avant de scroller.
LayoutRebuilder.ForceRebuildLayoutImmediate(scrollview_historique.content);
// Ajuste la position verticale au maximum (le bas)
// La position verticale est 0.0 en haut et 1.0 en bas de la Scroll View.
scrollview_historique.verticalNormalizedPosition = 0f;
}
public bool GetAffcherEntree() => afficher_entree;
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: daf83f5790a1ebc4b85208e164bc7016

19
Assets/Scripts/HUDMain.cs Normal file
View File

@@ -0,0 +1,19 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public class HUDMain : MonoBehaviour
{
[SerializeField] private RectTransform m_window;
[SerializeField] private Transform controller;
void Update()
{
Quaternion rotation_offset = Quaternion.Euler(45, 0, 0);
m_window.position = controller.TransformPoint(new Vector3(0f, 0.1f, 0f));
m_window.rotation = controller.rotation * rotation_offset;
InputDevice mainGauche = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8dbbc65f98bedc9459b94a96e3eaf813

View File

@@ -0,0 +1,49 @@
using System.Collections;
using System.Net;
using System.Net.Sockets;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
// Utilisé une seule fois par EnvoyerRecevoirDonnees pour créer un token
public class FastAPIClient : MonoBehaviour
{
[System.Serializable]
public class TokenInit
{
public string token;
}
public string Token = "";
/*@brief, GetTokenDuServeur() récupère un token et le stocke dans une chaine de caractères Token.
@param1 API_URL, une chaine de caractère qui contient l'adresse du serveur web.
@return IEnumerator, c'est une coroutine, on la lance avec StartCoroutine().*/
public IEnumerator GetTokenDuServeur(string API_URL)
{
using (UnityWebRequest request = UnityWebRequest.Get(API_URL))
{
// Envoie la requête et attend la réponse
yield return request.SendWebRequest();
// Vérifie les erreurs réseau ou HTTP
if (request.result != UnityWebRequest.Result.Success)
{
Debug.LogError("Erreur : " + request.error);
}
else
{
// Récupère la réponse JSON brute
string json = request.downloadHandler.text;
Debug.Log("Réponse brute : " + json);
// Désérialise le JSON
TokenInit token = JsonUtility.FromJson<TokenInit>(json);
Token = token.token;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 883d2ea4411452145a4a4d88824cca26

View File

@@ -0,0 +1,42 @@
using UnityEngine;
using UnityEngine.XR;
public class InteractionJoueur : MonoBehaviour
{
[SerializeField] public GameObject hud;
private bool hud_displayed = true;
bool deja_presse = false;
// Update is called once per frame
private void Update()
{
InputDevice mainDroite = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
InputDevice mainGauche = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
if (mainDroite.TryGetFeatureValue(CommonUsages.triggerButton, out bool gachettePressee)
&& gachettePressee)
{
Debug.Log("Gachette pressée.");
float rayonInteraction = 2f;
Collider[] collisions = Physics.OverlapSphere(transform.position, rayonInteraction);
foreach (Collider col in collisions)
{
if (col.TryGetComponent(out PNJInteraction pnj_i))
{
pnj_i.Interaction();
}
}
}
if (mainGauche.TryGetFeatureValue(CommonUsages.menuButton, out bool menuPresse))
{
if (menuPresse && !deja_presse)
{
hud.SetActive(!hud_displayed);
hud_displayed = !hud_displayed;
}
deja_presse = menuPresse;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cd95f96693bec0a409fa0a398bd370f0

View File

@@ -0,0 +1,14 @@
using Meta.WitAi.TTS.Utilities;
using UnityEngine;
public class LigneTexteTTS
{
public TTSSpeaker speaker;
public string text;
public LigneTexteTTS(TTSSpeaker speaker, string text)
{
this.speaker = speaker;
this.text = text;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 01692cd72f1657242b5fd1d18df516b4

View File

@@ -0,0 +1,11 @@
using UnityEngine;
using Meta.WitAi.TTS.Utilities;
public class ManagerTTS : MonoBehaviour
{
// Références aux speakers (à glisser dans l'Inspector)
public TTSSpeaker bobSpeaker;
public TTSSpeaker caelSpeaker;
public TTSSpeaker carlSpeaker;
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a9515da81d9fdab4e83868e6cadec01a

View File

@@ -0,0 +1,17 @@
using UnityEngine;
using TMPro;
public class MiseAJourDebug : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI Debug_text;
void OnEnable()
{
Application.logMessageReceived += GererLog;
}
void GererLog(string logString, string stackTrace, LogType type)
{
Debug_text.text = $"{type}: {logString} at {stackTrace}";
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 86d52aaa5462ee345b998fd84b9a253b

19
Assets/Scripts/MonTest.cs Normal file
View File

@@ -0,0 +1,19 @@
using UnityEngine;
using TMPro;
using UnityEngine.EventSystems;
/*Faites vos tests avec ce fichier. À RETIRER DE LA VERSION FINALE.*/
public class TestInputsOVR : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public TextMeshProUGUI debugText;
public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("Pointeur entré sur bouton Fermer.");
}
public void OnPointerExit(PointerEventData eventData)
{
Debug.Log("Pointeur sorti du bouton Fermer.");
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3eec3a2367d536a488ee8560da75edbc

View File

@@ -0,0 +1,32 @@
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class PNJInteraction : MonoBehaviour
{
[SerializeField] private AudioSource audio;
public void Interaction()
{
Debug.Log("Bonjour, je suis un \"Nolant Peasant Blue\".");
audio.Play();
StartCoroutine(MajSource());
}
IEnumerator MajSource()
{
string url = "/audio/2160";
using (UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(BuildConstants.LocalIP + ":8000" + url, AudioType.WAV))
{
yield return req.SendWebRequest();
if (req.result == UnityWebRequest.Result.Success)
{
audio.clip = DownloadHandlerAudioClip.GetContent(req);
}
else
{
Debug.LogError(req.error);
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 56c95b785ef8e2447a5a57e4cfaaedf4

View File

@@ -0,0 +1,60 @@
using UnityEngine;
/* Collez ce script au canvas de la fenêtre des préférences pour la placer correctement dans l'espace.*/
public class PositionEtRotationFenetrePreferences : MonoBehaviour
{
private Canvas canvas;
private Transform camera_transform;
private CanvasGroup prefab;
private void Start()
{
prefab = GameObject.FindWithTag("FenetrePrefs").GetComponent<CanvasGroup>();
canvas = GetComponent<Canvas>();
OVRCameraRig rig = FindAnyObjectByType<OVRCameraRig>();
camera_transform = rig.transform;
PositionnerEtRotaterFenetre();
}
private void Update()
{
// Si c pas visible on repositionne
if (prefab.alpha == 0f)
{
PositionnerEtRotaterFenetre();
}
}
public void PositionnerEtRotaterFenetre()
{
Debug.Log("PositionnerEtRotaterFenetre() : Entrée.");
if (canvas == null || camera_transform == null)
{
Debug.LogError("CanvasParent ou CameraTransform non assigné !");
return;
}
// Positionner le canvas devant le joueur
Vector3 offset = camera_transform.forward * 0.40f + Vector3.up * 0.7f; // 40 cm devant, 70 cm plus haut
Vector3 targetPosition = camera_transform.position + offset;
Vector3 direction_joueur = camera_transform.forward;
direction_joueur.y = 0;
// Éviter des erreurs
if (direction_joueur == Vector3.zero)
direction_joueur = Vector3.forward;
else
direction_joueur.Normalize();
// Faire face à la caméra
Quaternion targetRotation = Quaternion.LookRotation(direction_joueur, Vector3.up);
targetRotation *= Quaternion.Euler(30, 0, 0);
// Appliquer la position et la rotation au canvas
canvas.transform.SetPositionAndRotation(targetPosition, targetRotation);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bc560ecd6936ee440ac2a92f970db479

View File

@@ -0,0 +1,36 @@
using System.Collections;
using UnityEngine;
public class PositionEtRotationHistorique : MonoBehaviour
{
private RectTransform historique;
private Transform camera_transform;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
historique = GameObject.FindWithTag("HistoriqueMsg").GetComponent<RectTransform>();
camera_transform = FindAnyObjectByType<OVRCameraRig>().centerEyeAnchor;
StartCoroutine(InitialiserHistorique());
}
private IEnumerator InitialiserHistorique()
{
// On attend la prochaine image (càd la première image du programme) pour être sûr d'avoir la bonne hauteur.
yield return null;
float taille_y_historique = historique.sizeDelta.y;
float taille_y_a_l_echelle = historique.lossyScale.y;
float decalage_vertical_centre = (taille_y_historique / 2.0f) * taille_y_a_l_echelle;
float distance = 0.50f;
float decalage_droit = 0.30f;
Vector3 offset = camera_transform.forward * distance +
camera_transform.up * (0.15f - decalage_vertical_centre) +
camera_transform.right * decalage_droit;
Vector3 targetPosition = camera_transform.position + offset;
Vector3 directionCamera = camera_transform.position - targetPosition;
directionCamera.y = 0;
Quaternion regarderCamera = Quaternion.LookRotation(-directionCamera);
historique.transform.SetPositionAndRotation(targetPosition, regarderCamera);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 43ee61caa71f0774695520d49a722b33

View File

@@ -0,0 +1,65 @@
using UnityEngine;
/*
Collez ceci sur un canvas pour le déplacer en face de la caméra du joueur, sur une certaine position et non incliné.
*/
public class PositionEtRotationMenu : MonoBehaviour
{
private Canvas canvas;
private Transform camera_transform;
private bool mettre_a_jour_affichage = true;
private void OnDisable()
{
mettre_a_jour_affichage = true;
}
private void Start()
{
canvas = GetComponent<Canvas>();
OVRCameraRig rig = FindAnyObjectByType<OVRCameraRig>();
camera_transform = rig.transform;
PositionnerEtRotaterMenu();
}
private void Update()
{
if(this.gameObject.activeInHierarchy && mettre_a_jour_affichage)
{
PositionnerEtRotaterMenu();
mettre_a_jour_affichage = false;
}
}
void PositionnerEtRotaterMenu()
{
if (canvas == null || camera_transform == null)
{
Debug.LogError("CanvasParent ou CameraTransform non assigné !");
return;
}
// Positionner le canvas devant le joueur
Vector3 offset = camera_transform.forward * 0.40f + Vector3.up * 0.7f; // 40 cm devant, 70 cm plus haut
Vector3 targetPosition = camera_transform.position + offset;
Vector3 direction_joueur = camera_transform.forward;
direction_joueur.y = 0;
// Éviter des erreurs
if (direction_joueur == Vector3.zero)
direction_joueur = Vector3.forward;
else
direction_joueur.Normalize();
// Faire face à la caméra
Quaternion targetRotation = Quaternion.LookRotation(direction_joueur, Vector3.up);
targetRotation *= Quaternion.Euler(30, 0, 0);
// Appliquer la position et la rotation au canvas
canvas.transform.SetPositionAndRotation(targetPosition, targetRotation);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b6d529719047c6546bdedb62226bed83

View File

@@ -0,0 +1,75 @@
/*
Collez ce script sur un TMP_InputField si vous voulez le placer devant la caméra du joueur.
NOTE: Il faut le placer en tant que composant du TMP_InputField.
REQUIS: un Canvas, un TMP_InputFIeld et un OVRCameraRig dans la scène.
*/
using TMPro;
using Unity.AppUI.UI;
using Unity.VisualScripting;
using UnityEngine;
public class PositionRotationEntreeUtilisateur : MonoBehaviour
{
private Transform conteneur_transform;
private Transform camera_transform;
private GestionnaireApplication ga;
private bool mettre_a_jour_affichage = true;
private void OnDisable()
{
mettre_a_jour_affichage = true;
}
void Start()
{
conteneur_transform = GetComponent<Transform>();
OVRCameraRig rig = FindAnyObjectByType<OVRCameraRig>();
camera_transform = rig.transform;
ga = FindAnyObjectByType<GestionnaireApplication>();
PositionnerEtRotaterEntree();
}
// Si l'entrée est cachée on met à jour sa position pour que quand l'utilisateur la rappelle elle se replace vers lui.
void Update()
{
if(ga.GetAffcherEntree() && mettre_a_jour_affichage)
{
PositionnerEtRotaterEntree();
mettre_a_jour_affichage = false;
}
}
public void PositionnerEtRotaterEntree()
{
Debug.Log("PositionnerEtRotaterEntree() : Entrée.");
if (transform == null || camera_transform == null)
{
Debug.LogError("CanvasParent ou CameraTransform non assigné !");
return;
}
// Positionner le canvas devant le joueur
Vector3 offset = camera_transform.forward * 0.40f + Vector3.up * 0.7f; // 40 cm devant, 70 cm plus haut
Vector3 targetPosition = camera_transform.position + offset;
Vector3 direction_joueur = camera_transform.forward;
direction_joueur.y = 0;
// Éviter des erreurs
if (direction_joueur == Vector3.zero)
direction_joueur = Vector3.forward;
else
direction_joueur.Normalize();
// Faire face à la caméra
Quaternion targetRotation = Quaternion.LookRotation(direction_joueur, Vector3.up);
targetRotation *= Quaternion.Euler(50, 0, 0);
// Appliquer la position et la rotation au canvas
conteneur_transform.transform.SetPositionAndRotation(targetPosition, targetRotation);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e050578356dd7b94b8690fdfb1d58605

View File

@@ -0,0 +1,12 @@
using UnityEngine;
public class ReplacerJoueur : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
Debug.LogWarning("Entrée dans la collision " + other.name);
if (other.CompareTag("Player"))
other.transform.position = new Vector3(0f, 1f, 4f);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b23de8671ae61064a8eea338dc895c83

View File

@@ -0,0 +1,392 @@
using System.Collections.Generic;
using UnityEngine;
using Unity.InferenceEngine;
using System.Text;
using Unity.Collections;
using Newtonsoft.Json;
using Unity.AppUI.UI;
using TMPro;
using System.Threading.Tasks;
/*
NOTE : Utiliser ce modèle reste le meilleur choix pour le Quest mais expose à une perte de FPS d'environ 50 (72 FPS -> 20 FPS) pendant l'inférence (entre 1 et 5 secondes).
*/
public class RunWhisper : MonoBehaviour
{
Worker decoder1, decoder2, encoder, spectrogram;
Worker argmax;
private AudioClip audioClip;
private string microphone_name;
private float duree_defaut = 30f;
public event System.Action<string> OnTranscriptionComplete;
// This is how many tokens you want. It can be adjusted.
const int maxTokens = 100;
// Special tokens see added tokens file for details
const int END_OF_TEXT = 50257;
const int START_OF_TRANSCRIPT = 50258;
const int ENGLISH = 50259;
const int GERMAN = 50261;
const int FRENCH = 50265;
const int TRANSCRIBE = 50359; //for speech-to-text in specified language
const int TRANSLATE = 50358; //for speech-to-text then translate to English
const int NO_TIME_STAMPS = 50363;
const int START_TIME = 50364;
int numSamples;
string[] tokens;
int tokenCount = 0;
NativeArray<int> outputTokens;
// Used for special character decoding
int[] whiteSpaceCharacters = new int[256];
Tensor<float> encodedAudio;
bool transcribe = false;
string outputString = "";
// Maximum size of audioClip (30s at 16kHz)
const int maxSamples = 30 * 16000;
public ModelAsset audioDecoder1, audioDecoder2;
public ModelAsset audioEncoder;
public ModelAsset logMelSpectro;
// Mes variables à moi
public TMP_Dropdown choix_langues;
private static readonly int[] CODE_LANGUES_WHISPER = new int[]
{ // FR,EN,IT,ES,DE -> je les ai trouvés sur Hugging Face -> OpenAI -> Whisper -> added_tokens.json, *tout en bas*.
50265,50259,50274,50262,50261
};
private int preferred_language = 50265;
private bool enregistrement_en_cours = false;
private GameObject bouton_menu;
/*On démarre le moteur d'inférence, on ne le fait qu'une fois parce que la complexité temporelle est grande (Worker). En plus, ces structures sont réutilisables. */
private void Awake()
{
SetupWhiteSpaceShifts();
GetTokens();
decoder1 = new Worker(ModelLoader.Load(audioDecoder1), BackendType.GPUCompute);
decoder2 = new Worker(ModelLoader.Load(audioDecoder2), BackendType.GPUCompute);
// Ce graphe permet de calculer la probabilité de tous les jetons et avec ArgMax on récupère le jeton avec la plus haute valeur.
FunctionalGraph graph = new();
var input = graph.AddInput(DataType.Float, new DynamicTensorShape(1, 1, 51865));
var amax = Functional.ArgMax(input, -1, false);
var selectTokenModel = graph.Compile(amax);
argmax = new Worker(selectTokenModel, BackendType.GPUCompute);
encoder = new Worker(ModelLoader.Load(audioEncoder), BackendType.GPUCompute);
spectrogram = new Worker(ModelLoader.Load(logMelSpectro), BackendType.GPUCompute);
if (choix_langues != null)
{
choix_langues.onValueChanged.AddListener(SetLangueUtilisee);
}
if (Microphone.devices.Length > 0)
{
microphone_name = Microphone.devices[0];
}
else
{
Debug.LogError("Aucun microphone trouvé. Veuillez vérifier votre matériel.");
return;
}
bouton_menu = GameObject.FindWithTag("Micro");
}
public void Start()
{
outputTokens = new NativeArray<int>(maxTokens, Allocator.Persistent);
tokensTensor = new Tensor<int>(new TensorShape(1, maxTokens));
ComputeTensorData.Pin(tokensTensor);
tokensTensor.Reshape(new TensorShape(1, tokenCount));
tokensTensor.dataOnBackend.Upload<int>(outputTokens, tokenCount);
lastToken = new NativeArray<int>(1, Allocator.Persistent); lastToken[0] = NO_TIME_STAMPS;
lastTokenTensor = new Tensor<int>(new TensorShape(1, 1), new[] { NO_TIME_STAMPS });
}
Awaitable m_Awaitable;
NativeArray<int> lastToken;
Tensor<int> lastTokenTensor;
Tensor<int> tokensTensor;
Tensor<float> audioInput;
void LoadAudio(int echantillons_reels)
{
var data = new float[maxSamples];
audioClip.GetData(data, 0);
audioInput = new Tensor<float>(new TensorShape(1, maxSamples), data);
}
async Task EncodeAudio()
{
Debug.Log("EncodeAudio() Entrée.");
if(encodedAudio != null)
{
encodedAudio.Dispose();
encodedAudio = null;
}
spectrogram.Schedule(audioInput);
await Task.Yield();
var logmel = spectrogram.PeekOutput() as Tensor<float>;
Debug.Log("EncodeAudio() : Création du spectrogramme.");
encoder.Schedule(logmel);
Debug.Log("EncodeAudio() : Encodage.");
encodedAudio = encoder.PeekOutput() as Tensor<float>;
}
async Awaitable InferenceStep()
{
decoder1.SetInput("input_ids", tokensTensor);
decoder1.SetInput("encoder_hidden_states", encodedAudio);
decoder1.Schedule();
var past_key_values_0_decoder_key = decoder1.PeekOutput("present.0.decoder.key") as Tensor<float>;
var past_key_values_0_decoder_value = decoder1.PeekOutput("present.0.decoder.value") as Tensor<float>;
var past_key_values_1_decoder_key = decoder1.PeekOutput("present.1.decoder.key") as Tensor<float>;
var past_key_values_1_decoder_value = decoder1.PeekOutput("present.1.decoder.value") as Tensor<float>;
var past_key_values_2_decoder_key = decoder1.PeekOutput("present.2.decoder.key") as Tensor<float>;
var past_key_values_2_decoder_value = decoder1.PeekOutput("present.2.decoder.value") as Tensor<float>;
var past_key_values_3_decoder_key = decoder1.PeekOutput("present.3.decoder.key") as Tensor<float>;
var past_key_values_3_decoder_value = decoder1.PeekOutput("present.3.decoder.value") as Tensor<float>;
var past_key_values_0_encoder_key = decoder1.PeekOutput("present.0.encoder.key") as Tensor<float>;
var past_key_values_0_encoder_value = decoder1.PeekOutput("present.0.encoder.value") as Tensor<float>;
var past_key_values_1_encoder_key = decoder1.PeekOutput("present.1.encoder.key") as Tensor<float>;
var past_key_values_1_encoder_value = decoder1.PeekOutput("present.1.encoder.value") as Tensor<float>;
var past_key_values_2_encoder_key = decoder1.PeekOutput("present.2.encoder.key") as Tensor<float>;
var past_key_values_2_encoder_value = decoder1.PeekOutput("present.2.encoder.value") as Tensor<float>;
var past_key_values_3_encoder_key = decoder1.PeekOutput("present.3.encoder.key") as Tensor<float>;
var past_key_values_3_encoder_value = decoder1.PeekOutput("present.3.encoder.value") as Tensor<float>;
decoder2.SetInput("input_ids", lastTokenTensor);
decoder2.SetInput("past_key_values.0.decoder.key", past_key_values_0_decoder_key);
decoder2.SetInput("past_key_values.0.decoder.value", past_key_values_0_decoder_value);
decoder2.SetInput("past_key_values.1.decoder.key", past_key_values_1_decoder_key);
decoder2.SetInput("past_key_values.1.decoder.value", past_key_values_1_decoder_value);
decoder2.SetInput("past_key_values.2.decoder.key", past_key_values_2_decoder_key);
decoder2.SetInput("past_key_values.2.decoder.value", past_key_values_2_decoder_value);
decoder2.SetInput("past_key_values.3.decoder.key", past_key_values_3_decoder_key);
decoder2.SetInput("past_key_values.3.decoder.value", past_key_values_3_decoder_value);
decoder2.SetInput("past_key_values.0.encoder.key", past_key_values_0_encoder_key);
decoder2.SetInput("past_key_values.0.encoder.value", past_key_values_0_encoder_value);
decoder2.SetInput("past_key_values.1.encoder.key", past_key_values_1_encoder_key);
decoder2.SetInput("past_key_values.1.encoder.value", past_key_values_1_encoder_value);
decoder2.SetInput("past_key_values.2.encoder.key", past_key_values_2_encoder_key);
decoder2.SetInput("past_key_values.2.encoder.value", past_key_values_2_encoder_value);
decoder2.SetInput("past_key_values.3.encoder.key", past_key_values_3_encoder_key);
decoder2.SetInput("past_key_values.3.encoder.value", past_key_values_3_encoder_value);
decoder2.Schedule();
var logits = decoder2.PeekOutput("logits") as Tensor<float>;
argmax.Schedule(logits);
using var t_Token = await argmax.PeekOutput().ReadbackAndCloneAsync() as Tensor<int>;
int index = t_Token[0];
outputTokens[tokenCount] = lastToken[0];
lastToken[0] = index;
tokenCount++;
tokensTensor.Reshape(new TensorShape(1, tokenCount));
tokensTensor.dataOnBackend.Upload<int>(outputTokens, tokenCount);
lastTokenTensor.dataOnBackend.Upload<int>(lastToken, 1);
if (index == END_OF_TEXT)
{
transcribe = false;
}
else if (index < tokens.Length)
{
outputString += GetUnicodeText(tokens[index]);
}
Debug.Log($"RunWhisper() : {outputString}");
}
// Tokenizer
public TextAsset vocabAsset;
/* Cette fonction récupère les tokens présents dans le fichier vocab.json*/
void GetTokens()
{
var vocab = JsonConvert.DeserializeObject<Dictionary<string, int>>(vocabAsset.text);
tokens = new string[vocab.Count];
foreach (var item in vocab)
{
tokens[item.Value] = item.Key;
}
}
string GetUnicodeText(string text)
{
var bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(ShiftCharacterDown(text));
return Encoding.UTF8.GetString(bytes);
}
string ShiftCharacterDown(string text)
{
string outText = "";
foreach (char letter in text)
{
outText += ((int)letter <= 256) ? letter : (char)whiteSpaceCharacters[(int)(letter - 256)];
}
return outText;
}
void SetupWhiteSpaceShifts()
{
for (int i = 0, n = 0; i < 256; i++)
{
if (IsWhiteSpace((char)i)) whiteSpaceCharacters[n++] = i;
}
}
bool IsWhiteSpace(char c)
{
return !(('!' <= c && c <= '~') || ('<27>' <= c && c <= '<27>') || ('<27>' <= c && c <= '<27>'));
}
public void StartMicrophoneInference()
{
if(audioInput != null)
{
audioInput.Dispose();
audioInput = null;
}
if (Microphone.IsRecording(microphone_name))
{
Microphone.End(microphone_name);
}
audioClip = Microphone.Start(microphone_name, false, (int)duree_defaut, 16000);
outputString = string.Empty;
for (int i = 0; i < maxTokens; i++)
{
outputTokens[i] = 0; // Vider l'historique des tokens
}
tokenCount = 0;
Debug.Log("Enregistrement démarré. Durée max: " + duree_defaut + "s.");
Invoke(nameof(StopMicrophoneAndStartInference), duree_defaut);
}
private async void StopMicrophoneAndStartInference()
{
if (!enregistrement_en_cours)
return;
CancelInvoke(nameof(StopMicrophoneAndStartInference));
int position_arret = Microphone.GetPosition(microphone_name);
Microphone.End(microphone_name);
if(bouton_menu != null)
{
bouton_menu.GetComponent<AgrandissementBoutons>().SetMicroActif(false);
bouton_menu.GetComponent<AgrandissementBoutons>().RetrecirMicro();
}
await Task.Delay(100);
Debug.Log($"Enregistrement terminé. Lancement de l'inférence... avec une position égale à : {position_arret}");
if (audioClip != null)
{
LoadAudio(position_arret);
await Task.Yield();
await EncodeAudio();
transcribe = true;
StartTranscriptionLoop();
}
else
{
Debug.LogError("Échec de l'enregistrement de l'AudioClip.");
}
}
public async void StartTranscriptionLoop()
{
outputTokens[0] = START_OF_TRANSCRIPT;
outputTokens[1] = preferred_language; //FRENCH; //ENGLISH; //...
outputTokens[2] = TRANSCRIBE; //TRANSLATE;//
//outputTokens[3] = NO_TIME_STAMPS;// START_TIME;//
tokenCount = 3;
tokensTensor.Reshape(new TensorShape(1, tokenCount));
tokensTensor.dataOnBackend.Upload<int>(outputTokens, tokenCount);
lastToken[0] = NO_TIME_STAMPS;
lastTokenTensor.dataOnBackend.Upload<int>(lastToken, 1);
while (true)
{
if (!transcribe || tokenCount >= (outputTokens.Length - 1))
{
OnTranscriptionComplete?.Invoke(outputString);
return;
}
m_Awaitable = InferenceStep();
await m_Awaitable;
}
}
public int GetPreferredLanguage(int indice)
{
return CODE_LANGUES_WHISPER[indice];
}
/*@brief La procédure SetLangueUtilisee() permet de mettre à jour le langage reconnu par le modèle Whisper. Lors d'un enregistrement audio, le modèle cherchera à déterminer des mots de la langue passée en paramètre.
@param index, un entier index qui est relié au tableau constant CODE_LANGUE_WHISPER.
La fonction met à jour preferred_language vers une nouvelle valeur (par défaut sur français.*/
public void SetLangueUtilisee(int index)
{
Debug.Log($"SetLangueUtilisee() Valeur du paramètre : {index}");
preferred_language = GetPreferredLanguage(index);
}
public void DemarrerEnregistrement()
{
// Si on est déjà en train de calculer, on ignore le clic pour éviter les bugs
//if (enregistrement_en_cours) return;
Debug.Log($"Clic Micro. Enregistrement en cours : {enregistrement_en_cours}");
if (enregistrement_en_cours)
{
// On lance la version asynchrone (sans 'await' ici car DemarrerEnregistrement est void)
StopMicrophoneAndStartInference();
enregistrement_en_cours = false;
}
else
{
StartMicrophoneInference();
enregistrement_en_cours = true;
}
}
private void OnDestroy()
{
decoder1.Dispose();
decoder2.Dispose();
encoder.Dispose();
spectrogram.Dispose();
argmax.Dispose();
audioInput.Dispose();
lastTokenTensor.Dispose();
tokensTensor.Dispose();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 05e8a61ac02f22f4780fa659cb41a54b