ImadEze commited on
Commit
71e611b
·
1 Parent(s): eb81b34

added the docker server now

Browse files
Files changed (6) hide show
  1. .gitignore +1 -0
  2. Dockerfile +16 -0
  3. README.md +17 -8
  4. app.py +115 -0
  5. requirements.txt +3 -0
  6. script.js +43 -43
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ venv_front/
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Copy requirements and install dependencies
6
+ COPY requirements.txt .
7
+ RUN pip install --no-cache-dir -r requirements.txt
8
+
9
+ # Copy application files
10
+ COPY . .
11
+
12
+ # Expose port
13
+ EXPOSE 7860
14
+
15
+ # Run the application
16
+ CMD ["python", "app.py"]
README.md CHANGED
@@ -3,7 +3,8 @@ title: ImmoReserv - Apartment Viewing Assistant
3
  emoji: 🏠
4
  colorFrom: blue
5
  colorTo: purple
6
- sdk: static
 
7
  pinned: false
8
  license: mit
9
  ---
@@ -18,14 +19,22 @@ An elegant conversational UI for apartment viewing reservations. This AI assista
18
  - 💬 Natural conversation flow with realistic timing
19
  - 🏠 Specialized for apartment viewing reservations
20
  - 📱 Fully responsive mobile and desktop design
21
- - ⚡ Fast static deployment - no server required
 
22
 
23
- ## Usage
24
 
25
- The assistant initiates conversations by asking about apartment availability and helps coordinate viewing schedules. Perfect for real estate agents and property managers.
 
 
 
 
 
26
 
27
- ## Technology
 
 
28
 
29
- - Pure HTML5, CSS3, and JavaScript
30
- - No external dependencies
31
- - Optimized for Hugging Face Spaces static deployment
 
3
  emoji: 🏠
4
  colorFrom: blue
5
  colorTo: purple
6
+ sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  license: mit
10
  ---
 
19
  - 💬 Natural conversation flow with realistic timing
20
  - 🏠 Specialized for apartment viewing reservations
21
  - 📱 Fully responsive mobile and desktop design
22
+ - ⚡ FastAPI backend with conversation logic
23
+ - 🔄 Real-time API communication
24
 
25
+ ## Architecture
26
 
27
+ - **Frontend**: Pure HTML5, CSS3, and JavaScript
28
+ - **Backend**: FastAPI with async conversation engine
29
+ - **Communication**: RESTful API endpoints
30
+ - **Deployment**: Dockerized for Hugging Face Spaces
31
+
32
+ ## API Endpoints
33
 
34
+ - `GET /` - Serves the main chat interface
35
+ - `POST /chat` - Processes conversation messages
36
+ - `GET /health` - Health check endpoint
37
 
38
+ ## Usage
39
+
40
+ The assistant initiates conversations by asking about apartment availability and helps coordinate viewing schedules. Perfect for real estate agents and property managers.
app.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.responses import FileResponse
3
+ from fastapi.staticfiles import StaticFiles
4
+ from pydantic import BaseModel
5
+ import os
6
+ from typing import Optional, List, Dict
7
+ import asyncio
8
+ import random
9
+
10
+ app = FastAPI(title="ImmoReserv API", version="1.0.0")
11
+
12
+ # Serve static files
13
+ app.mount("/static", StaticFiles(directory="."), name="static")
14
+
15
+ class ChatMessage(BaseModel):
16
+ message: str
17
+ conversation_history: Optional[List[Dict[str, str]]] = []
18
+
19
+ class ChatResponse(BaseModel):
20
+ message: str
21
+ quick_replies: Optional[List[str]] = None
22
+
23
+ # In-memory conversation logic (this will be replaced with real AI later)
24
+ class ConversationEngine:
25
+ def __init__(self):
26
+ self.responses = {
27
+ "apartment a": {
28
+ "message": "Perfect! You're interested in Apartment A - the lovely 2-bedroom, 1-bathroom unit. What days work best for you this week? I can check availability for morning or afternoon appointments.",
29
+ "quick_replies": ["Monday morning", "Tuesday afternoon", "Wednesday anytime", "Weekend preferred"]
30
+ },
31
+ "apartment b": {
32
+ "message": "Excellent choice! Apartment B is our spacious 3-bedroom, 2-bathroom unit with a great view. When would be most convenient for you to schedule the viewing?",
33
+ "quick_replies": ["This week", "Next week", "Morning slots", "Evening slots"]
34
+ },
35
+ "apartment c": {
36
+ "message": "Great! Apartment C is our cozy 1-bedroom, 1-bathroom unit - perfect for singles or couples. What time slots work best for your schedule?",
37
+ "quick_replies": ["Weekday morning", "Weekday evening", "Weekend", "I'm flexible"]
38
+ },
39
+ "multiple units": {
40
+ "message": "Wonderful! Since you have multiple units available, would you prefer to schedule viewings for all of them, or should we start with the one you think would be the best fit for our client?",
41
+ "quick_replies": ["Schedule all units", "Start with best fit", "Tell me about the client", "Show availability calendar"]
42
+ },
43
+ "monday morning": {
44
+ "message": "Monday morning sounds perfect! Would 10:00 AM work for you? I'll need to confirm a few details - what's the address of the property, and should our client bring any specific documents?",
45
+ "quick_replies": ["10 AM works", "Prefer 9 AM", "11 AM better", "Need different day"]
46
+ },
47
+ "tuesday afternoon": {
48
+ "message": "Tuesday afternoon is great! How about 2:00 PM? I'll make sure our client arrives on time. Could you please provide the exact address and any parking instructions?",
49
+ "quick_replies": ["2 PM perfect", "3 PM better", "1 PM works", "Send me details"]
50
+ },
51
+ "this week": {
52
+ "message": "Perfect! This week works well. What days are you available? I can offer morning slots (9 AM - 12 PM) or afternoon slots (2 PM - 5 PM).",
53
+ "quick_replies": ["Monday this week", "Tuesday this week", "Wednesday this week", "Thursday this week"]
54
+ },
55
+ "next week": {
56
+ "message": "Next week sounds great! That gives us time to prepare properly. Which days work best for you next week?",
57
+ "quick_replies": ["Monday next week", "Tuesday next week", "Weekend next week", "Any day works"]
58
+ }
59
+ }
60
+
61
+ async def generate_response(self, message: str, history: List[Dict[str, str]]) -> ChatResponse:
62
+ # Simulate processing time
63
+ await asyncio.sleep(random.uniform(1.5, 2.5))
64
+
65
+ key = message.lower()
66
+
67
+ # Check for exact matches first
68
+ if key in self.responses:
69
+ response_data = self.responses[key]
70
+ return ChatResponse(
71
+ message=response_data["message"],
72
+ quick_replies=response_data.get("quick_replies")
73
+ )
74
+
75
+ # Check for partial matches
76
+ for response_key in self.responses:
77
+ if key in response_key or response_key in key:
78
+ response_data = self.responses[response_key]
79
+ return ChatResponse(
80
+ message=response_data["message"],
81
+ quick_replies=response_data.get("quick_replies")
82
+ )
83
+
84
+ # Default response for unmatched messages
85
+ return ChatResponse(
86
+ message="I understand. Let me make sure I have all the details correct. Could you please provide more information about your availability and the apartment details?",
87
+ quick_replies=["Share apartment details", "Check calendar", "Call instead", "Send email"]
88
+ )
89
+
90
+ # Initialize conversation engine
91
+ conversation_engine = ConversationEngine()
92
+
93
+ @app.get("/")
94
+ async def read_root():
95
+ return FileResponse("index.html")
96
+
97
+ @app.post("/chat", response_model=ChatResponse)
98
+ async def chat_endpoint(chat_request: ChatMessage):
99
+ try:
100
+ response = await conversation_engine.generate_response(
101
+ chat_request.message,
102
+ chat_request.conversation_history
103
+ )
104
+ return response
105
+ except Exception as e:
106
+ raise HTTPException(status_code=500, detail=f"Error processing message: {str(e)}")
107
+
108
+ @app.get("/health")
109
+ async def health_check():
110
+ return {"status": "healthy", "service": "ImmoReserv API"}
111
+
112
+ if __name__ == "__main__":
113
+ import uvicorn
114
+ port = int(os.environ.get("PORT", 7860))
115
+ uvicorn.run(app, host="0.0.0.0", port=port)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ fastapi>=0.104.0
2
+ uvicorn[standard]>=0.24.0
3
+ pydantic>=2.0.0
script.js CHANGED
@@ -104,55 +104,55 @@ class ChatInterface {
104
  }
105
 
106
  async generateResponse(userMessage) {
107
- // Mock AI responses - this will be replaced with real AI later
108
- await this.delay(2000 + Math.random() * 1000);
109
-
110
- const responses = {
111
- "apartment a": {
112
- message: "Perfect! You're interested in Apartment A - the lovely 2-bedroom, 1-bathroom unit. What days work best for you this week? I can check availability for morning or afternoon appointments.",
113
- quickReplies: ["Monday morning", "Tuesday afternoon", "Wednesday anytime", "Weekend preferred"]
114
- },
115
- "apartment b": {
116
- message: "Excellent choice! Apartment B is our spacious 3-bedroom, 2-bathroom unit with a great view. When would be most convenient for you to schedule the viewing?",
117
- quickReplies: ["This week", "Next week", "Morning slots", "Evening slots"]
118
- },
119
- "apartment c": {
120
- message: "Great! Apartment C is our cozy 1-bedroom, 1-bathroom unit - perfect for singles or couples. What time slots work best for your schedule?",
121
- quickReplies: ["Weekday morning", "Weekday evening", "Weekend", "I'm flexible"]
122
- },
123
- "multiple units": {
124
- message: "Wonderful! Since you have multiple units available, would you prefer to schedule viewings for all of them, or should we start with the one you think would be the best fit for our client?",
125
- quickReplies: ["Schedule all units", "Start with best fit", "Tell me about the client", "Show availability calendar"]
126
- },
127
- "monday morning": {
128
- message: "Monday morning sounds perfect! Would 10:00 AM work for you? I'll need to confirm a few details - what's the address of the property, and should our client bring any specific documents?",
129
- quickReplies: ["10 AM works", "Prefer 9 AM", "11 AM better", "Need different day"]
130
- },
131
- "tuesday afternoon": {
132
- message: "Tuesday afternoon is great! How about 2:00 PM? I'll make sure our client arrives on time. Could you please provide the exact address and any parking instructions?",
133
- quickReplies: ["2 PM perfect", "3 PM better", "1 PM works", "Send me details"]
134
  }
135
- };
136
 
137
- const key = userMessage.toLowerCase();
138
 
139
- // Check for exact matches first
140
- if (responses[key]) {
141
- return responses[key];
142
- }
143
 
144
- // Check for partial matches
145
- for (const responseKey in responses) {
146
- if (key.includes(responseKey) || responseKey.includes(key)) {
147
- return responses[responseKey];
148
- }
 
 
 
149
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
- // Default response for unmatched messages
152
- return {
153
- message: "I understand. Let me make sure I have all the details correct. Could you please provide more information about your availability and the apartment details?",
154
- quickReplies: ["Share apartment details", "Check calendar", "Call instead", "Send email"]
155
- };
156
  }
157
 
158
  addUserMessage(message) {
 
104
  }
105
 
106
  async generateResponse(userMessage) {
107
+ try {
108
+ const response = await fetch('/chat', {
109
+ method: 'POST',
110
+ headers: {
111
+ 'Content-Type': 'application/json',
112
+ },
113
+ body: JSON.stringify({
114
+ message: userMessage,
115
+ conversation_history: this.getConversationHistory()
116
+ })
117
+ });
118
+
119
+ if (!response.ok) {
120
+ throw new Error(`HTTP error! status: ${response.status}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  }
 
122
 
123
+ const data = await response.json();
124
 
125
+ return {
126
+ message: data.message,
127
+ quickReplies: data.quick_replies || []
128
+ };
129
 
130
+ } catch (error) {
131
+ console.error('Error calling chat API:', error);
132
+
133
+ // Fallback response if API fails
134
+ return {
135
+ message: "I apologize, but I'm having trouble connecting right now. Could you please try again in a moment?",
136
+ quickReplies: ["Try again", "Contact support"]
137
+ };
138
  }
139
+ }
140
+
141
+ getConversationHistory() {
142
+ const messages = this.messagesContainer.querySelectorAll('.message');
143
+ const history = [];
144
+
145
+ messages.forEach(messageEl => {
146
+ const isBot = messageEl.classList.contains('message-bot');
147
+ const content = messageEl.querySelector('.message-content').textContent;
148
+
149
+ history.push({
150
+ role: isBot ? 'assistant' : 'user',
151
+ content: content
152
+ });
153
+ });
154
 
155
+ return history;
 
 
 
 
156
  }
157
 
158
  addUserMessage(message) {