August 14, 2026 · 20 min read
AI chatbots are the most common production application of large language models. This guide walks you through building a production-ready chatbot using Chinese AI models via TokenEase — from basic conversation handling to advanced features like memory, personas, and multi-turn context management.
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌─────────────┐
│ User │────▶│ Web/App │────▶│ Chatbot │────▶│ TokenEase │
│ Interface │◀────│ Frontend │◀────│ Backend │◀────│ API │
└─────────────┘ └──────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ Database │
│ (Memory) │
└─────────────┘
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import requests
import uuid
from datetime import datetime
app = FastAPI()
TOKEN = "your_tokenease_api_key"
BASE_URL = "https://tokenease.io/v1"
class Message(BaseModel):
role: str # "user" or "assistant"
content: str
timestamp: Optional[str] = None
class ChatRequest(BaseModel):
message: str
session_id: Optional[str] = None
model: str = "deepseek-v4"
class ChatResponse(BaseModel):
response: str
session_id: str
tokens_used: int
# In-memory session store (use Redis in production)
sessions = {}
def get_session_history(session_id: str) -> List[dict]:
"""Retrieve conversation history for a session"""
return sessions.get(session_id, [])
def add_to_session(session_id: str, message: dict):
"""Add message to session history"""
if session_id not in sessions:
sessions[session_id] = []
sessions[session_id].append(message)
# Keep last 20 messages to manage context window
if len(sessions[session_id]) > 20:
sessions[session_id] = sessions[session_id][-20:]
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
"""Main chat endpoint"""
# Generate session ID if new
session_id = request.session_id or str(uuid.uuid4())
# Get conversation history
history = get_session_history(session_id)
# Build messages array
messages = history + [{"role": "user", "content": request.message}]
# Call TokenEase API
try:
response = requests.post(
f"{BASE_URL}/chat/completions",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"model": request.model,
"messages": messages,
"temperature": 0.7,
"max_tokens": 1024
}
)
data = response.json()
assistant_message = data["choices"][0]["message"]["content"]
tokens_used = data.get("usage", {}).get("total_tokens", 0)
# Update session
add_to_session(session_id, {"role": "user", "content": request.message})
add_to_session(session_id, {"role": "assistant", "content": assistant_message})
return ChatResponse(
response=assistant_message,
session_id=session_id,
tokens_used=tokens_used
)
except Exception as e:
raise HTTPException(500, f"Chat error: {str(e)}")
@app.get("/chat/{session_id}/history")
async def get_history(session_id: str):
"""Get conversation history"""
return {"session_id": session_id, "messages": get_session_history(session_id)}
@app.delete("/chat/{session_id}")
async def clear_session(session_id: str):
"""Clear conversation history"""
if session_id in sessions:
del sessions[session_id]
return {"status": "cleared"}
PERSONAS = {
"helpful_assistant": {
"name": "Helpful Assistant",
"system_prompt": "You are a helpful, friendly assistant. Answer questions accurately and concisely."
},
"code_expert": {
"name": "Code Expert",
"system_prompt": "You are an expert programmer. Provide clean, well-commented code with explanations. Prefer Python and modern best practices."
},
"creative_writer": {
"name": "Creative Writer",
"system_prompt": "You are a creative writing assistant. Help with storytelling, character development, and editing. Be imaginative and encouraging."
},
"customer_support": {
"name": "Customer Support",
"system_prompt": "You are a professional customer support agent. Be polite, empathetic, and solution-oriented. If you cannot help, escalate appropriately."
},
"math_tutor": {
"name": "Math Tutor",
"system_prompt": "You are a patient math tutor. Explain concepts step by step. Use analogies and examples. Never give the answer directly — guide the student."
}
}
@app.post("/chat")
async def chat_with_persona(request: ChatRequest):
"""Chat with persona support"""
session_id = request.session_id or str(uuid.uuid4())
persona = request.persona or "helpful_assistant"
# Get persona system prompt
system_prompt = PERSONAS.get(persona, PERSONAS["helpful_assistant"])["system_prompt"]
# Build messages with system prompt
history = get_session_history(session_id)
messages = [{"role": "system", "content": system_prompt}] + history
messages.append({"role": "user", "content": request.message})
# Call API
response = requests.post(
f"{BASE_URL}/chat/completions",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"model": request.model,
"messages": messages,
"temperature": 0.7
}
)
# ... process and store response
from fastapi.responses import StreamingResponse
@app.post("/chat/stream")
async def chat_stream(request: ChatRequest):
"""Streaming chat endpoint for real-time responses"""
session_id = request.session_id or str(uuid.uuid4())
history = get_session_history(session_id)
messages = history + [{"role": "user", "content": request.message}]
def generate():
full_response = ""
response = requests.post(
f"{BASE_URL}/chat/completions",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"model": request.model,
"messages": messages,
"stream": True,
"temperature": 0.7
},
stream=True
)
for line in response.iter_lines():
if line:
line = line.decode("utf-8")
if line.startswith("data: "):
data = line[6:]
if data == "[DONE]":
# Store complete response
add_to_session(session_id, {"role": "user", "content": request.message})
add_to_session(session_id, {"role": "assistant", "content": full_response})
break
try:
chunk = json.loads(data)
token = chunk["choices"][0]["delta"].get("content", "")
if token:
full_response += token
yield f"data: {json.dumps({'token': token})}\n\n"
except:
pass
return StreamingResponse(
generate(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"}
)
def summarize_conversation(messages: List[dict], model: str = "kimi-k2") -> str:
"""Summarize long conversations to manage context window"""
conversation_text = "\n".join([
f"{m['role']}: {m['content']}" for m in messages
])
summary_prompt = f"""Summarize the following conversation, preserving key facts, decisions, and context:
{conversation_text}
Summary:"""
response = requests.post(
f"{BASE_URL}/chat/completions",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"model": model,
"messages": [{"role": "user", "content": summary_prompt}],
"max_tokens": 500
}
)
return response.json()["choices"][0]["message"]["content"]
def manage_context(session_id: str, max_messages: int = 10):
"""Keep conversation within context limits by summarizing"""
history = get_session_history(session_id)
if len(history) > max_messages * 2: # Each turn = user + assistant
# Keep most recent messages
recent = history[-max_messages * 2:]
# Summarize older messages
older = history[:-max_messages * 2]
summary = summarize_conversation(older)
# Replace with summary + recent
sessions[session_id] = [
{"role": "system", "content": f"Previous conversation summary: {summary}"}
] + recent
return True
return False
class ChatbotUI {
constructor(apiUrl, containerId) {
this.apiUrl = apiUrl;
this.container = document.getElementById(containerId);
this.sessionId = localStorage.getItem("chat_session_id") || null;
this.messages = [];
this.init();
}
init() {
this.container.innerHTML = `
`;
this.input = this.container.querySelector("input");
this.button = this.container.querySelector("button");
this.messagesDiv = this.container.querySelector(".chat-messages");
this.button.addEventListener("click", () => this.sendMessage());
this.input.addEventListener("keypress", (e) => {
if (e.key === "Enter") this.sendMessage();
});
}
async sendMessage() {
const text = this.input.value.trim();
if (!text) return;
this.input.value = "";
this.addMessage("user", text);
// Show typing indicator
const typingId = this.showTyping();
try {
const response = await fetch(this.apiUrl, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
message: text,
session_id: this.sessionId,
model: "deepseek-v4"
})
});
const data = await response.json();
this.sessionId = data.session_id;
localStorage.setItem("chat_session_id", this.sessionId);
this.hideTyping(typingId);
this.addMessage("assistant", data.response);
} catch (error) {
this.hideTyping(typingId);
this.addMessage("assistant", "Sorry, I encountered an error. Please try again.");
}
}
addMessage(role, text) {
const msgDiv = document.createElement("div");
msgDiv.className = `message ${role}`;
msgDiv.textContent = text;
this.messagesDiv.appendChild(msgDiv);
this.messagesDiv.scrollTop = this.messagesDiv.scrollHeight;
}
showTyping() {
const id = "typing-" + Date.now();
const div = document.createElement("div");
div.id = id;
div.className = "message assistant typing";
div.textContent = "...";
this.messagesDiv.appendChild(div);
return id;
}
hideTyping(id) {
const el = document.getElementById(id);
if (el) el.remove();
}
}
// Initialize
const chatbot = new ChatbotUI("/chat", "chat-container");
def detect_language(text: str) -> str:
"""Simple language detection"""
chinese_chars = sum(1 for c in text if '\u4e00' <= c <= '\u9fff')
if chinese_chars / len(text) > 0.3:
return "zh"
return "en"
def get_model_for_language(lang: str) -> str:
"""Select optimal model for language"""
if lang == "zh":
return "glm-4" # Excellent Chinese understanding
return "deepseek-v4" # Strong multilingual performance
@app.post("/chat")
async def multilingual_chat(request: ChatRequest):
"""Auto-detect language and select appropriate model"""
lang = detect_language(request.message)
model = get_model_for_language(lang)
# Continue with chat using selected model
# ...
| Use Case | Recommended Model | Why |
|---|---|---|
| General Q&A | DeepSeek-V4 | Balanced quality and cost |
| Chinese conversations | GLM-4 | Superior Chinese nuance |
| Fast responses | Kimi-K2 | Lowest latency |
| Technical support | Qwen-Max | Strong reasoning |
| Budget-conscious | Doubao-Pro | Cheapest per token |
Running a chatbot serving 10,000 conversations/day (avg 10 turns each):
For advanced features, see our guides on AI agent development and real-time streaming APIs.
Last updated: August 2026. Model recommendations may change with new releases.