Skip to content
Extraits de code Groupes Projets

Comparer les révisions

Les modifications sont affichées comme si la révision source était fusionnée avec la révision cible. En savoir plus sur la comparaison des révisions.

Source

Sélectionner le projet cible
No results found

Cible

Sélectionner le projet cible
  • sbibauw/languagelab
1 résultat
Afficher les modifications
Validations sur la source (8)
...@@ -28,6 +28,7 @@ import config ...@@ -28,6 +28,7 @@ import config
from security import jwt_cookie, get_jwt_user from security import jwt_cookie, get_jwt_user
from routes.tests import testRouter from routes.tests import testRouter
from routes.studies import studiesRouter from routes.studies import studiesRouter
from routes.chat import chatRouter
websocket_users = defaultdict(lambda: defaultdict(set)) websocket_users = defaultdict(lambda: defaultdict(set))
websocket_users_global = defaultdict(set) websocket_users_global = defaultdict(set)
...@@ -1057,5 +1058,6 @@ v1Router.include_router(studyRouter) ...@@ -1057,5 +1058,6 @@ v1Router.include_router(studyRouter)
v1Router.include_router(websocketRouter) v1Router.include_router(websocketRouter)
v1Router.include_router(testRouter) v1Router.include_router(testRouter)
v1Router.include_router(studiesRouter) v1Router.include_router(studiesRouter)
v1Router.include_router(chatRouter)
apiRouter.include_router(v1Router) apiRouter.include_router(v1Router)
app.include_router(apiRouter) app.include_router(apiRouter)
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
import requests
import os
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("OPENROUTER_API_KEY")
MODEL_NAME = "mistralai/mistral-small-24b-instruct-2501:free"
API_URL = "https://openrouter.ai/api/v1/chat/completions"
chatRouter = APIRouter(prefix="/chat", tags=["chat"])
class ChatMessage(BaseModel):
session_id: str
role: str
content: str
chat_sessions = {}
@chatRouter.post("/")
async def chat_with_ai(message: ChatMessage):
session_id = message.session_id
user_message = {"role": message.role, "content": message.content}
if session_id not in chat_sessions:
chat_sessions[session_id] = []
chat_sessions[session_id].append(user_message)
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
data = {"model": MODEL_NAME, "messages": chat_sessions[session_id]}
response = requests.post(API_URL, headers=headers, json=data)
if response.status_code == 200:
bot_response = response.json()["choices"][0]["message"]["content"]
chat_sessions[session_id].append({"role": "assistant", "content": bot_response})
return {"response": bot_response}
else:
raise HTTPException(status_code=response.status_code, detail=response.text)
uvicorn[standard]>=0.27.0,<0.28.0 alembic==1.14.1
fastapi>=0.110.0,<0.111.0 annotated-types==0.7.0
fastapi_jwt>=0.2.0,<0.3.0 anyio==4.7.0
sqlalchemy>=2.0.0,<2.1.0 bcrypt==3.2.0
passlib>=1.7.0,<1.8.0 black==24.10.0
python-jose>=3.3.0,<3.4.0 certifi==2025.1.31
python-multipart>=0.0.0,<0.1.0 cffi==1.17.1
charset-normalizer==3.4.1
click==8.1.7
cryptography==44.0.0
ecdsa==0.19.0
fastapi==0.110.3
fastapi-jwt==0.2.0
h11==0.14.0
httptools==0.6.4
idna==3.10
Mako==1.3.9
MarkupSafe==3.0.2
mypy-extensions==1.0.0
packaging==24.2
passlib==1.7.4
pathspec==0.12.1
platformdirs==4.3.6
pyasn1==0.6.1
pycparser==2.22
pydantic==2.10.3
pydantic_core==2.27.1
python-dotenv==1.0.1
python-jose==3.3.0
python-multipart==0.0.19
PyYAML==6.0.2
requests==2.32.3
rsa==4.9
six==1.17.0
sniffio==1.3.1
SQLAlchemy==2.0.36
starlette==0.37.2
typing_extensions==4.12.2
urllib3==2.3.0
uvicorn==0.27.1
uvloop==0.21.0
watchfiles==1.0.3
websockets==14.1
Ce diff est replié.
...@@ -53,6 +53,26 @@ export async function createMessageAPI( ...@@ -53,6 +53,26 @@ export async function createMessageAPI(
return await response.json(); return await response.json();
} }
export async function createAIMessageAPI(
fetch: fetchType,
sessionId: string,
content: string
): Promise<any | null> {
const response = await fetch(`/api/chat/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
session_id: sessionId,
role: 'user',
content: content
})
});
if (!response.ok) return null;
return await response.json();
}
export async function updateMessageAPI( export async function updateMessageAPI(
fetch: fetchType, fetch: fetchType,
id: number, id: number,
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
rid, rid,
user?.id || null, user?.id || null,
typingTest.id, typingTest.id,
user?.study_id ?? 0,
position, position,
downtime, downtime,
uptime, uptime,
......
...@@ -12,7 +12,8 @@ import { ...@@ -12,7 +12,8 @@ import {
patchSessionAPI, patchSessionAPI,
removeUserFromSessionAPI, removeUserFromSessionAPI,
sendPresenceAPI, sendPresenceAPI,
sendTypingAPI sendTypingAPI,
createAIMessageAPI
} from '$lib/api/sessions'; } from '$lib/api/sessions';
import Message from './message'; import Message from './message';
import config from '$lib/config'; import config from '$lib/config';
...@@ -204,6 +205,8 @@ export default class Session { ...@@ -204,6 +205,8 @@ export default class Session {
replyTo: string | null replyTo: string | null
): Promise<Message | null> { ): Promise<Message | null> {
const json = await createMessageAPI(fetch, this.id, content, metadata, replyTo); const json = await createMessageAPI(fetch, this.id, content, metadata, replyTo);
const ai_message = await createAIMessageAPI(fetch, this.id.toString(), content);
console.log('AI Message: ', ai_message);
if (json == null || json.id == null || json.message_id == null) { if (json == null || json.id == null || json.message_id == null) {
toastAlert('Failed to parse message'); toastAlert('Failed to parse message');
return null; return null;
......
...@@ -162,8 +162,16 @@ export default class User { ...@@ -162,8 +162,16 @@ export default class User {
return this._tutor_list; return this._tutor_list;
} }
get availabilities(): { day: string; start: string; end: string }[] { get availabilities(): {
return this._availabilities; avaibility: number;
day: string;
start: string;
end: string;
}[] {
return this._availabilities.map((availability, index) => ({
avaibility: index,
...availability
}));
} }
set availabilities(value: { day: string; start: string; end: string }[]) { set availabilities(value: { day: string; start: string; end: string }[]) {
......
...@@ -129,6 +129,18 @@ ...@@ -129,6 +129,18 @@
); );
} }
async function createSoloSession() {
let session = await Session.create();
if (!session) {
console.warn('Failed to create solo session.');
return;
}
contactSessions = [...contactSessions, session].sort(
(a, b) => b.start_time.getTime() - a.start_time.getTime()
);
}
async function searchNickname() { async function searchNickname() {
if (!user || !nickname || !nickname.includes('@')) { if (!user || !nickname || !nickname.includes('@')) {
toastWarning('Please enter a valid email address'); toastWarning('Please enter a valid email address');
...@@ -190,6 +202,16 @@ ...@@ -190,6 +202,16 @@
> >
{$t('home.createSession')} {$t('home.createSession')}
</button> </button>
<button
onclick={(e) => {
e.preventDefault();
createSoloSession();
}}
class="button float-start mr-2"
>
Solo session
</button>
<button <button
class="button float-start" class="button float-start"
class:btn-disabled={!contact || !contact.calcom_link} class:btn-disabled={!contact || !contact.calcom_link}
......
...@@ -615,7 +615,7 @@ ...@@ -615,7 +615,7 @@
<p class="text-center"> <p class="text-center">
{@html $t('register.continue')} {@html $t('register.continue')}
</p> </p>
<button class="button mt-4 w-full" onclick={() => (current_step = 6)}> <button class="button mt-4 w-full" onclick={() => (current_step = 8)}>
{$t('register.continueButton')} {$t('register.continueButton')}
</button> </button>
<button class="button mt-4 w-full" onclick={() => (document.location.href = '/')}> <button class="button mt-4 w-full" onclick={() => (document.location.href = '/')}>
......