|
|
import React, { useState, useRef, useEffect } from 'react'; |
|
|
import ReactMarkdown from 'react-markdown'; |
|
|
import { InferenceClient } from "@huggingface/inference"; |
|
|
import Avatar from './Avatar.jsx'; |
|
|
import '../App.css'; |
|
|
|
|
|
const ChatInterface = ({ messages = [], setMessages = () => {}, onMessageSent = () => {}, toLogin }) => { |
|
|
const [inputMessage, setInputMessage] = useState(''); |
|
|
const [isLoading, setIsLoading] = useState(false); |
|
|
const messagesEndRef = useRef(null); |
|
|
const textareaRef = useRef(null); |
|
|
|
|
|
|
|
|
const hfClient = new InferenceClient(process.env.REACT_APP_HF_TOKEN || "votre_token_ici"); |
|
|
console.log(hfClient); |
|
|
const isMarkdown = (text) => /[#*_>`-]/.test(text); |
|
|
|
|
|
const scrollToBottom = () => { |
|
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); |
|
|
}; |
|
|
|
|
|
useEffect(() => { |
|
|
scrollToBottom(); |
|
|
}, [messages]); |
|
|
|
|
|
const sendMessage = async (message) => { |
|
|
try { |
|
|
setIsLoading(true); |
|
|
|
|
|
onMessageSent(message); |
|
|
|
|
|
|
|
|
const chatCompletion = await hfClient.chatCompletion({ |
|
|
provider: "novita", |
|
|
model: "mistralai/Mistral-7B-Instruct-v0.3", |
|
|
messages: [ |
|
|
{ |
|
|
role: "system", |
|
|
content: "Tu es un assistant médical expert spécialisé uniquement dans la schizophrénie. Réponds uniquement aux questions concernant la schizophrénie. Si la question concerne un autre sujet médical, refuse poliment de répondre." |
|
|
}, |
|
|
{ |
|
|
role: "user", |
|
|
content: message |
|
|
} |
|
|
], |
|
|
max_tokens: 512, |
|
|
temperature: 0.7, |
|
|
}); |
|
|
|
|
|
|
|
|
const botResponse = chatCompletion.choices[0].message.content; |
|
|
|
|
|
setMessages(prev => [ |
|
|
...prev, |
|
|
{ sender: 'user', text: message }, |
|
|
{ sender: 'bot', text: botResponse } |
|
|
]); |
|
|
setIsLoading(false); |
|
|
} catch (error) { |
|
|
console.error("Erreur:", error); |
|
|
setIsLoading(false); |
|
|
setMessages(prev => [ |
|
|
...prev, |
|
|
{ sender: 'user', text: message }, |
|
|
{ sender: 'bot', text: "Désolé, une erreur s'est produite. Veuillez réessayer. 👍" } |
|
|
]); |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleSubmit = (e) => { |
|
|
e.preventDefault(); |
|
|
if (inputMessage.trim() === '') return; |
|
|
sendMessage(inputMessage); |
|
|
if (textareaRef.current) { |
|
|
textareaRef.current.style.height = 'auto'; |
|
|
} |
|
|
setInputMessage(''); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
return ( |
|
|
<div className="chat-container"> |
|
|
{messages.length === 0 ? ( |
|
|
<> |
|
|
<div className="chat-header"> |
|
|
<h2 className="chat-title">Medic.ial</h2> |
|
|
<Avatar onClick={toLogin}/> |
|
|
</div> |
|
|
<div className="no-messages-view"> |
|
|
<div className="welcome-content"> |
|
|
<div className="welcome-message"> |
|
|
<p>Bonjour ! Comment puis-je vous aider aujourd'hui ? 🧑⚕️</p> |
|
|
</div> |
|
|
<div className="input-container centered"> |
|
|
<form onSubmit={handleSubmit} className="input-form"> |
|
|
<textarea |
|
|
value={inputMessage} |
|
|
onChange={(e) => setInputMessage(e.target.value)} |
|
|
placeholder="Posez une question..." |
|
|
disabled={isLoading} |
|
|
rows="1" |
|
|
className="input-textarea" |
|
|
onKeyDown={(e) => { |
|
|
if (e.key === "Enter" && !e.shiftKey) { |
|
|
e.preventDefault(); |
|
|
handleSubmit(e); |
|
|
} |
|
|
}} |
|
|
onInput={(e) => { |
|
|
e.target.style.height = "auto"; // Réinitialise la hauteur |
|
|
e.target.style.height = `${e.target.scrollHeight}px`; // Ajuste à la hauteur du contenu |
|
|
}} |
|
|
/> |
|
|
<button type="submit" style={{background:"none"}} disabled={isLoading || inputMessage.trim() === ''}> |
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"> |
|
|
<path d="M120-160v-240l320-80-320-80v-240l760 320-760 320Z"/> |
|
|
</svg> |
|
|
</button> |
|
|
</form> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</> |
|
|
|
|
|
) : ( |
|
|
<> |
|
|
<div className="chat-header"> |
|
|
<Avatar onClick={toLogin}/> |
|
|
<h2 className="chat-title">Medic.ial</h2> |
|
|
</div> |
|
|
<div className="messages-container"> |
|
|
{messages.map((msg, index) => ( |
|
|
<div key={index} className={`message ${msg.sender}`}> |
|
|
<div className="message-content"> |
|
|
{isMarkdown(msg.text) ? ( |
|
|
<ReactMarkdown>{msg.text}</ReactMarkdown> |
|
|
) : ( |
|
|
msg.text |
|
|
)} |
|
|
</div> |
|
|
</div> |
|
|
))} |
|
|
{isLoading && ( |
|
|
<div className="message bot"> |
|
|
<div className="message-content loading"> |
|
|
<span>.</span><span>.</span><span>.</span> |
|
|
</div> |
|
|
</div> |
|
|
)} |
|
|
<div ref={messagesEndRef} /> |
|
|
</div> |
|
|
<div className="input-container"> |
|
|
<form onSubmit={handleSubmit} className="input-form"> |
|
|
<textarea |
|
|
value={inputMessage} |
|
|
onChange={(e) => setInputMessage(e.target.value) |
|
|
} |
|
|
placeholder="Tapez votre message ici..." |
|
|
disabled={isLoading} |
|
|
rows="1" |
|
|
ref={textareaRef} |
|
|
className="input-textarea" |
|
|
onKeyDown={(e) => { |
|
|
if (e.key === "Enter" && !e.shiftKey) { |
|
|
e.preventDefault(); |
|
|
handleSubmit(e); |
|
|
} |
|
|
}} |
|
|
onInput={(e) => { |
|
|
e.target.style.height = "auto"; |
|
|
e.target.style.height = `${e.target.scrollHeight}px`; |
|
|
}} |
|
|
/> |
|
|
<button type="submit" disabled={isLoading || inputMessage.trim() === ''}> |
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"> |
|
|
<path d="M120-160v-240l320-80-320-80v-240l760 320-760 320Z"/> |
|
|
</svg> |
|
|
</button> |
|
|
</form> |
|
|
<figcaption className="disclaimer-text">Medic.ial est sujet à faire des erreurs. Vérifiez les informations fournies.</figcaption> |
|
|
</div> |
|
|
</> |
|
|
)} |
|
|
</div> |
|
|
); |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default ChatInterface; |
|
|
|