Skip to content

Commit 664797d

Browse files
committed
Enhance chat interface and functionality
- Updated `web.py` to include timestamps for user and assistant messages and handle async calls for chat and completions. - Improved `chat.html` with a new layout, auto-scroll feature, and error/loading states. - Refined CSS in `style.css` for better styling and responsiveness of chat elements.
1 parent 026776b commit 664797d

3 files changed

Lines changed: 91 additions & 40 deletions

File tree

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1-
body { font-family: Arial, sans-serif; background: #f7f7f7; margin: 0; padding: 2em; }
2-
h1 { color: #2b3a67; }
3-
form { margin-bottom: 0.5em; }
4-
input[type=text] { padding: 0.5em; border-radius: 4px; border: 1px solid #ccc; }
5-
button { padding: 0.5em 1em; border-radius: 4px; border: none; background: #2b3a67; color: #fff; cursor: pointer; }
6-
div { margin-bottom: 0.5em; }
7-
.chat-history { background: #fff; border-radius: 8px; padding: 1em; box-shadow: 0 2px 8px #0001; min-height: 120px; }
8-
.user-msg { background: #e3eaff; border-radius: 6px; margin: 0.5em 0; padding: 0.5em 1em; text-align: right; }
9-
.assistant-msg { background: #f0f0f0; border-radius: 6px; margin: 0.5em 0; padding: 0.5em 1em; text-align: left; }
1+
body { font-family: Arial, sans-serif; background: #f7f7f7; margin: 0; padding: 0; }
2+
.container { max-width: 700px; margin: 2em auto; background: #fff; border-radius: 12px; box-shadow: 0 2px 16px #0002; padding: 2em; }
3+
h1 { color: #2b3a67; margin-top: 0; }
4+
form { margin-bottom: 0.5em; display: flex; gap: 0.5em; }
5+
#user_message { flex: 1; padding: 0.7em; border-radius: 6px; border: 1px solid #ccc; font-size: 1em; resize: vertical; }
6+
button { padding: 0.7em 1.2em; border-radius: 6px; border: none; background: #2b3a67; color: #fff; cursor: pointer; font-size: 1em; }
7+
button.reset-btn { background: #aaa; color: #fff; }
8+
.chat-history { background: #f4f6fa; border-radius: 8px; padding: 1em; box-shadow: 0 1px 4px #0001; min-height: 180px; max-height: 350px; overflow-y: auto; margin-top: 1.5em; }
9+
.msg-row { display: flex; align-items: flex-end; margin-bottom: 1em; }
10+
.avatar { font-size: 1.7em; margin: 0 0.7em 0 0; align-self: flex-end; }
11+
.user .avatar { order: 2; margin: 0 0 0 0.7em; }
12+
.user .bubble { margin-left: auto; background: #e3eaff; color: #1a237e; text-align: right; }
13+
.assistant .bubble { margin-right: auto; background: #f0f0f0; color: #222; text-align: left; }
14+
.bubble { padding: 0.7em 1.1em; border-radius: 16px; max-width: 80%; box-shadow: 0 1px 4px #0001; position: relative; }
15+
.role { font-weight: bold; margin-right: 0.5em; }
16+
.timestamp { font-size: 0.85em; color: #888; margin-left: 0.5em; }
17+
.error-banner { background: #ffdddd; color: #a00; padding: 0.7em 1em; border-radius: 6px; margin-top: 1em; text-align: center; }
18+
.loading { text-align: center; color: #2b3a67; margin-top: 1em; font-style: italic; }
19+
.loading-bubble { font-style: italic; color: #888; background: #e0e0e0; }

src/deepseek_wrapper/templates/chat.html

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,52 @@
44
<meta charset="UTF-8">
55
<title>DeepSeek Chat</title>
66
<link rel="stylesheet" href="/static/style.css">
7+
<script>
8+
// Auto-scroll chat to bottom
9+
window.onload = function() {
10+
var chat = document.getElementById('chat-history');
11+
if (chat) chat.scrollTop = chat.scrollHeight;
12+
document.getElementById('user_message').focus();
13+
};
14+
// Enter to send, Shift+Enter for newline
15+
function handleKey(e) {
16+
if (e.key === 'Enter' && !e.shiftKey) {
17+
e.preventDefault();
18+
document.getElementById('chat-form').submit();
19+
}
20+
}
21+
</script>
722
</head>
823
<body>
9-
<h1>DeepSeek Chat</h1>
10-
<form method="post" action="/chat">
11-
<input type="text" name="user_message" placeholder="Type your message..." required style="width: 60%;">
12-
<button type="submit">Send</button>
13-
</form>
14-
<form method="post" action="/completions" style="margin-top: 1em;">
15-
<input type="text" name="prompt" placeholder="Prompt for completions endpoint..." style="width: 60%;">
16-
<button type="submit">Completions</button>
17-
</form>
18-
<form method="post" action="/reset" style="margin-top: 1em;">
19-
<button type="submit">Reset Conversation</button>
20-
</form>
21-
<div class="chat-history" style="margin-top:2em; max-width: 800px;">
22-
{% for msg in messages %}
23-
<div class="{{ msg.role }}-msg"><b>{{ msg.role.title() }}:</b> {{ msg.content }}</div>
24-
{% endfor %}
24+
<div class="container">
25+
<h1>DeepSeek Chat</h1>
26+
<form id="chat-form" method="post" action="/chat" autocomplete="off">
27+
<textarea id="user_message" name="user_message" placeholder="Type your message..." required rows="2" onkeydown="handleKey(event)"></textarea>
28+
<button type="submit">Send</button>
29+
<button type="button" onclick="document.getElementById('reset-form').submit();" class="reset-btn">Reset</button>
30+
</form>
31+
<form id="reset-form" method="post" action="/reset" style="display:none;"></form>
32+
<div id="chat-history" class="chat-history">
33+
{% for msg in messages %}
34+
<div class="msg-row {{ msg.role }}">
35+
<div class="avatar">{% if msg.role == 'user' %}🧑{% else %}🤖{% endif %}</div>
36+
<div class="bubble {{ msg.role }}-msg">
37+
<span class="role">{{ msg.role.title() }}</span>
38+
<span class="timestamp">{{ msg.timestamp }}</span><br>
39+
<span class="content">{{ msg.content }}</span>
40+
</div>
41+
</div>
42+
{% endfor %}
43+
{% if loading %}
44+
<div class="msg-row assistant">
45+
<div class="avatar">🤖</div>
46+
<div class="bubble assistant-msg loading-bubble">Assistant is typing...</div>
47+
</div>
48+
{% endif %}
49+
</div>
50+
{% if error %}
51+
<div class="error-banner">{{ error }}</div>
52+
{% endif %}
2553
</div>
2654
</body>
2755
</html>

src/deepseek_wrapper/web.py

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
from fastapi import FastAPI, Request, Form, Response
1+
from fastapi import FastAPI, Request, Form
22
from fastapi.responses import HTMLResponse, RedirectResponse
33
from fastapi.templating import Jinja2Templates
44
from fastapi.staticfiles import StaticFiles
55
from starlette.middleware.sessions import SessionMiddleware
66
from deepseek_wrapper import DeepSeekClient, DeepSeekConfig
7-
import asyncio
87
import os
8+
from datetime import datetime
99

1010
app = FastAPI()
1111
app.add_middleware(SessionMiddleware, secret_key=os.getenv("SESSION_SECRET_KEY", "supersecret"))
@@ -14,36 +14,49 @@
1414

1515
client = DeepSeekClient()
1616

17+
def now_str():
18+
return datetime.now().strftime("%H:%M:%S")
19+
1720
@app.get("/", response_class=HTMLResponse)
18-
def home(request: Request):
21+
async def home(request: Request):
1922
history = request.session.get("history", [])
20-
return templates.TemplateResponse("chat.html", {"request": request, "messages": history})
23+
return templates.TemplateResponse("chat.html", {"request": request, "messages": history, "error": None, "loading": False})
2124

2225
@app.post("/chat", response_class=HTMLResponse)
23-
def chat(request: Request, user_message: str = Form(...)):
26+
async def chat(request: Request, user_message: str = Form(...)):
2427
history = request.session.get("history", [])
25-
history.append({"role": "user", "content": user_message})
28+
history.append({"role": "user", "content": user_message, "timestamp": now_str()})
29+
error = None
30+
loading = True
2631
try:
27-
response = client.chat_completion(history)
32+
response = await client.async_chat_completion(history)
33+
loading = False
2834
except Exception as e:
2935
response = f"Error: {e}"
30-
history.append({"role": "assistant", "content": response})
36+
error = str(e)
37+
loading = False
38+
history.append({"role": "assistant", "content": response, "timestamp": now_str()})
3139
request.session["history"] = history
32-
return templates.TemplateResponse("chat.html", {"request": request, "messages": history})
40+
return templates.TemplateResponse("chat.html", {"request": request, "messages": history, "error": error, "loading": loading})
3341

3442
@app.post("/completions", response_class=HTMLResponse)
35-
def completions(request: Request, prompt: str = Form(...)):
43+
async def completions(request: Request, prompt: str = Form(...)):
3644
history = request.session.get("history", [])
45+
error = None
46+
loading = True
3747
try:
38-
response = client.generate_text(prompt)
48+
response = await client.async_generate_text(prompt)
49+
loading = False
3950
except Exception as e:
4051
response = f"Error: {e}"
41-
history.append({"role": "user", "content": prompt})
42-
history.append({"role": "assistant", "content": response})
52+
error = str(e)
53+
loading = False
54+
history.append({"role": "user", "content": prompt, "timestamp": now_str()})
55+
history.append({"role": "assistant", "content": response, "timestamp": now_str()})
4356
request.session["history"] = history
44-
return templates.TemplateResponse("chat.html", {"request": request, "messages": history})
57+
return templates.TemplateResponse("chat.html", {"request": request, "messages": history, "error": error, "loading": loading})
4558

4659
@app.post("/reset", response_class=HTMLResponse)
47-
def reset(request: Request):
60+
async def reset(request: Request):
4861
request.session["history"] = []
4962
return RedirectResponse("/", status_code=303)

0 commit comments

Comments
 (0)