T-K-O-H commited on
Commit
e2239a8
·
1 Parent(s): d5c37af

Convert to ChatUI with FastAPI backend

Browse files
Files changed (4) hide show
  1. Dockerfile +6 -7
  2. app/main.py +80 -0
  3. frontend/index.html +95 -0
  4. requirements.txt +11 -6
Dockerfile CHANGED
@@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y \
8
  && rm -rf /var/lib/apt/lists/*
9
 
10
  # Create a non-root user
11
- RUN useradd -m -u 1000 chainlit_user
12
 
13
  # Copy requirements first to leverage Docker cache
14
  COPY requirements.txt .
@@ -18,20 +18,19 @@ RUN pip install --no-cache-dir -r requirements.txt
18
  COPY . .
19
 
20
  # Create necessary directories and set permissions
21
- RUN mkdir -p data/uploads .files .chainlit/translations && \
22
- chown -R chainlit_user:chainlit_user /app
23
 
24
  # Set environment variables
25
  ENV PYTHONPATH=/app
26
- ENV CHAINLIT_SERVER_PORT=8000
27
- ENV CHAINLIT_HOST=0.0.0.0
28
  ENV HOME=/app
29
 
30
  # Switch to non-root user
31
- USER chainlit_user
32
 
33
  # Expose the port
34
  EXPOSE 8000
35
 
36
  # Command to run the application
37
- CMD ["chainlit", "run", "app/chainlit/chainlit.py", "--port", "8000", "--host", "0.0.0.0"]
 
8
  && rm -rf /var/lib/apt/lists/*
9
 
10
  # Create a non-root user
11
+ RUN useradd -m -u 1000 app_user
12
 
13
  # Copy requirements first to leverage Docker cache
14
  COPY requirements.txt .
 
18
  COPY . .
19
 
20
  # Create necessary directories and set permissions
21
+ RUN mkdir -p data/uploads .files frontend && \
22
+ chown -R app_user:app_user /app
23
 
24
  # Set environment variables
25
  ENV PYTHONPATH=/app
26
+ ENV PORT=8000
 
27
  ENV HOME=/app
28
 
29
  # Switch to non-root user
30
+ USER app_user
31
 
32
  # Expose the port
33
  EXPOSE 8000
34
 
35
  # Command to run the application
36
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
app/main.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, File, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import JSONResponse
4
+ from pydantic import BaseModel
5
+ from typing import List, Optional
6
+ import os
7
+ import json
8
+ from app.agent.agent import ResearchAgent
9
+ from app.agent.tools.semantic_search import SemanticSearch
10
+ from app.agent.tools.citation_analyzer import CitationAnalyzer
11
+ from app.agent.tools.workout_planner import WorkoutPlanner
12
+
13
+ app = FastAPI()
14
+
15
+ # Add CORS middleware
16
+ app.add_middleware(
17
+ CORSMiddleware,
18
+ allow_origins=["*"],
19
+ allow_credentials=True,
20
+ allow_methods=["*"],
21
+ allow_headers=["*"],
22
+ )
23
+
24
+ # Initialize tools and agent
25
+ semantic_search = SemanticSearch()
26
+ citation_analyzer = CitationAnalyzer()
27
+ workout_planner = WorkoutPlanner()
28
+
29
+ tools = [semantic_search, citation_analyzer, workout_planner]
30
+ agent = ResearchAgent(tools)
31
+
32
+ class Message(BaseModel):
33
+ role: str
34
+ content: str
35
+
36
+ class ChatRequest(BaseModel):
37
+ messages: List[Message]
38
+ stream: Optional[bool] = False
39
+
40
+ @app.post("/chat")
41
+ async def chat(request: ChatRequest):
42
+ try:
43
+ # Get the last message from the user
44
+ last_message = request.messages[-1]
45
+ if last_message.role != "user":
46
+ raise HTTPException(status_code=400, detail="Last message must be from user")
47
+
48
+ # Process the message with the agent
49
+ response = agent.process_message(last_message.content)
50
+
51
+ return JSONResponse(content={
52
+ "choices": [{
53
+ "message": {
54
+ "role": "assistant",
55
+ "content": response
56
+ }
57
+ }]
58
+ })
59
+ except Exception as e:
60
+ raise HTTPException(status_code=500, detail=str(e))
61
+
62
+ @app.post("/upload")
63
+ async def upload_file(file: UploadFile = File(...)):
64
+ try:
65
+ # Save the file
66
+ file_path = os.path.join("data/uploads", file.filename)
67
+ with open(file_path, "wb") as buffer:
68
+ content = await file.read()
69
+ buffer.write(content)
70
+
71
+ return JSONResponse(content={
72
+ "message": "File uploaded successfully",
73
+ "filename": file.filename
74
+ })
75
+ except Exception as e:
76
+ raise HTTPException(status_code=500, detail=str(e))
77
+
78
+ if __name__ == "__main__":
79
+ import uvicorn
80
+ uvicorn.run(app, host="0.0.0.0", port=8000)
frontend/index.html ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>5/3/1 Workout Program Assistant</title>
7
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@huggingface/chat-ui/dist/chat-ui.css">
8
+ <style>
9
+ body {
10
+ margin: 0;
11
+ padding: 0;
12
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
13
+ }
14
+ #chat-container {
15
+ max-width: 800px;
16
+ margin: 0 auto;
17
+ height: 100vh;
18
+ display: flex;
19
+ flex-direction: column;
20
+ }
21
+ .header {
22
+ padding: 1rem;
23
+ background-color: #f5f5f5;
24
+ border-bottom: 1px solid #e0e0e0;
25
+ }
26
+ .header h1 {
27
+ margin: 0;
28
+ font-size: 1.5rem;
29
+ color: #333;
30
+ }
31
+ </style>
32
+ </head>
33
+ <body>
34
+ <div id="chat-container">
35
+ <div class="header">
36
+ <h1>5/3/1 Workout Program Assistant</h1>
37
+ </div>
38
+ <div id="chat"></div>
39
+ </div>
40
+
41
+ <script src="https://cdn.jsdelivr.net/npm/@huggingface/chat-ui/dist/chat-ui.js"></script>
42
+ <script>
43
+ const chat = new ChatUI({
44
+ container: document.getElementById('chat'),
45
+ apiEndpoint: '/chat',
46
+ uploadEndpoint: '/upload',
47
+ welcomeMessage: 'Welcome to the 5/3/1 Workout Program Assistant! How can I help you today?',
48
+ userMessageColor: '#4a90e2',
49
+ assistantMessageColor: '#f5f5f5',
50
+ inputPlaceholder: 'Type your message here...',
51
+ uploadButtonText: 'Upload PDF',
52
+ uploadAcceptedFileTypes: '.pdf',
53
+ onMessage: async (message) => {
54
+ try {
55
+ const response = await fetch('/chat', {
56
+ method: 'POST',
57
+ headers: {
58
+ 'Content-Type': 'application/json',
59
+ },
60
+ body: JSON.stringify({
61
+ messages: [{
62
+ role: 'user',
63
+ content: message
64
+ }]
65
+ })
66
+ });
67
+
68
+ const data = await response.json();
69
+ return data.choices[0].message.content;
70
+ } catch (error) {
71
+ console.error('Error:', error);
72
+ return 'Sorry, there was an error processing your request.';
73
+ }
74
+ },
75
+ onFileUpload: async (file) => {
76
+ try {
77
+ const formData = new FormData();
78
+ formData.append('file', file);
79
+
80
+ const response = await fetch('/upload', {
81
+ method: 'POST',
82
+ body: formData
83
+ });
84
+
85
+ const data = await response.json();
86
+ return `File "${data.filename}" uploaded successfully. How can I help you with this file?`;
87
+ } catch (error) {
88
+ console.error('Error:', error);
89
+ return 'Sorry, there was an error uploading your file.';
90
+ }
91
+ }
92
+ });
93
+ </script>
94
+ </body>
95
+ </html>
requirements.txt CHANGED
@@ -1,6 +1,11 @@
1
- langchain>=0.1.0
2
- langchain-openai>=0.0.5
3
- chainlit>=0.7.0
4
- PyPDF2>=3.0.0
5
- python-dotenv>=1.0.0
6
- huggingface-hub>=0.16.0
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn==0.24.0
3
+ python-multipart==0.0.6
4
+ pydantic==2.4.2
5
+ openai==1.3.0
6
+ python-dotenv==1.0.0
7
+ langchain==0.0.350
8
+ pypdf==3.17.1
9
+ numpy==1.24.3
10
+ pandas==2.0.3
11
+ scikit-learn==1.3.2