Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
math_tutor_dev
public_math_tutor
Commits
55ea7dcf
Commit
55ea7dcf
authored
Jan 19, 2026
by
Kantz
Browse files
adden GWDG API
parent
9c04fca1
Changes
3
Hide whitespace changes
Inline
Side-by-side
math-tutor/backend/app/api/chat.py
View file @
55ea7dcf
...
...
@@ -2,11 +2,20 @@ from __future__ import annotations
from
typing
import
List
,
Optional
import
os
from
fastapi
import
APIRouter
,
HTTPException
from
dotenv
import
load_dotenv
import
httpx
from
pydantic
import
BaseModel
,
Field
router
=
APIRouter
()
load_dotenv
()
OPENAI_BASE_URL
=
os
.
getenv
(
"OPENAI_BASE_URL"
)
OPENAI_API_KEY
=
os
.
getenv
(
"OPENAI_API_KEY"
)
OPENAI_MODEL
=
os
.
getenv
(
"OPENAI_MODEL"
,
"gpt-4o-mini"
)
class
ChatMessage
(
BaseModel
):
role
:
str
=
Field
(...,
pattern
=
"^(user|assistant)$"
)
...
...
@@ -28,6 +37,31 @@ def chat(request: ChatRequest) -> ChatResponse:
if
not
request
.
messages
:
raise
HTTPException
(
status_code
=
400
,
detail
=
"messages required"
)
last
=
request
.
messages
[
-
1
]
reply
=
f
"Mock reply to:
{
last
.
text
}
"
return
ChatResponse
(
reply
=
reply
,
sources
=
[
"doc:example"
])
if
not
OPENAI_BASE_URL
or
not
OPENAI_API_KEY
:
last
=
request
.
messages
[
-
1
]
reply
=
f
"Mock reply to:
{
last
.
text
}
"
return
ChatResponse
(
reply
=
reply
,
sources
=
[
"doc:example"
])
messages_payload
=
[
{
"role"
:
message
.
role
,
"content"
:
message
.
text
}
for
message
in
request
.
messages
]
payload
=
{
"model"
:
OPENAI_MODEL
,
"messages"
:
messages_payload
,
}
headers
=
{
"Authorization"
:
f
"Bearer
{
OPENAI_API_KEY
}
"
}
url
=
f
"
{
OPENAI_BASE_URL
.
rstrip
(
'/'
)
}
/v1/chat/completions"
try
:
with
httpx
.
Client
(
timeout
=
60.0
)
as
client
:
response
=
client
.
post
(
url
,
headers
=
headers
,
json
=
payload
)
response
.
raise_for_status
()
except
httpx
.
HTTPError
as
exc
:
raise
HTTPException
(
status_code
=
502
,
detail
=
"chat provider failed"
)
from
exc
data
=
response
.
json
()
reply
=
data
[
"choices"
][
0
][
"message"
][
"content"
]
return
ChatResponse
(
reply
=
reply
,
sources
=
[
"openai-compatible"
])
math-tutor/backend/requirements.txt
View file @
55ea7dcf
...
...
@@ -2,4 +2,5 @@ fastapi
uvicorn
python-dotenv
mpxpy
pillow
\ No newline at end of file
pillow
httpx
math-tutor/frontend/src/pages/App.tsx
View file @
55ea7dcf
...
...
@@ -33,7 +33,7 @@ export default function App() {
const
[
draft
,
setDraft
]
=
useState
(
""
);
const
[
isCanvasVisible
,
setIsCanvasVisible
]
=
useState
(
true
);
const
handleSend
=
()
=>
{
const
handleSend
=
async
()
=>
{
const
trimmed
=
draft
.
trim
();
if
(
!
trimmed
)
{
return
;
...
...
@@ -45,14 +45,47 @@ export default function App() {
text
:
trimmed
,
};
const
assistantMessage
:
ChatMessage
=
{
id
:
`m-
${
Date
.
now
()}
-assistant`
,
role
:
"
assistant
"
,
text
:
"
Got it. I will solve that step by step.
"
,
};
setMessages
((
prev
)
=>
[...
prev
,
userMessage
,
assistantMessage
]);
setMessages
((
prev
)
=>
[...
prev
,
userMessage
]);
setDraft
(
""
);
try
{
const
response
=
await
fetch
(
"
http://localhost:8000/api/chat
"
,
{
method
:
"
POST
"
,
headers
:
{
"
Content-Type
"
:
"
application/json
"
},
body
:
JSON
.
stringify
({
messages
:
[...
messages
,
userMessage
].
map
((
message
)
=>
({
role
:
message
.
role
,
text
:
message
.
text
,
})),
}),
});
if
(
!
response
.
ok
)
{
throw
new
Error
(
`Chat failed:
${
response
.
status
}
`
);
}
const
payload
:
{
reply
?:
string
}
=
await
response
.
json
();
if
(
payload
.
reply
)
{
setMessages
((
prev
)
=>
[
...
prev
,
{
id
:
`m-
${
Date
.
now
()}
-assistant`
,
role
:
"
assistant
"
,
text
:
payload
.
reply
,
},
]);
}
}
catch
(
error
)
{
setMessages
((
prev
)
=>
[
...
prev
,
{
id
:
`m-
${
Date
.
now
()}
-assistant`
,
role
:
"
assistant
"
,
text
:
"
Chat request failed. Check the API logs.
"
,
},
]);
void
error
;
}
};
const
handleToggleCanvas
=
()
=>
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment