-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrecord_complete_demo.py
More file actions
288 lines (231 loc) · 10.2 KB
/
record_complete_demo.py
File metadata and controls
288 lines (231 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#!/usr/bin/env python3
"""
Record COMPLETE Demo - Upload Document + Chat with AI
"""
import asyncio
import os
import shutil
from pathlib import Path
from playwright.async_api import async_playwright
OUTPUT_DIR = Path("docs/images")
GIF_PATH = OUTPUT_DIR / "demo.gif"
FRONTEND_URL = "http://localhost:3002"
SAMPLE_DOC = Path("sample_docs/product_guide.txt")
async def record_complete_demo():
"""Record complete demo: Create KB -> Upload Doc -> Chat with AI"""
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
frames_dir = OUTPUT_DIR / "frames"
if frames_dir.exists():
shutil.rmtree(frames_dir)
frames_dir.mkdir()
print("=" * 70)
print("COMPLETE DEMO: Upload Document + Real AI Chat")
print("=" * 70)
print()
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False, slow_mo=50)
context = await browser.new_context(viewport={"width": 1280, "height": 720})
page = await context.new_page()
frame_count = 0
async def snap(desc="", count=1):
nonlocal frame_count
for i in range(count):
frame_count += 1
await page.screenshot(path=str(frames_dir / f"frame_{frame_count:03d}.png"))
if i == 0 and desc:
print(f" [{frame_count:2d}] {desc}")
await asyncio.sleep(0.1)
# ===== 1. LANDING =====
print("[1] Landing Page")
await page.goto(FRONTEND_URL, timeout=30000)
await asyncio.sleep(1.5)
await snap("Welcome to Info Naut", 3)
# ===== 2. DASHBOARD =====
print("[2] Dashboard")
await page.goto(f"{FRONTEND_URL}/dashboard", timeout=30000)
await asyncio.sleep(1.5)
await snap("Dashboard", 3)
# ===== 3. CREATE KNOWLEDGE BASE =====
print("[3] Create Knowledge Base")
await page.goto(f"{FRONTEND_URL}/dashboard/knowledge/new", timeout=30000)
await asyncio.sleep(1.5)
await snap("New KB Form", 2)
# Fill name
name_input = page.locator('input').first
if await name_input.count() > 0:
await name_input.fill("Product Docs")
await asyncio.sleep(0.3)
await snap("KB Name Filled", 2)
# Fill description
desc_input = page.locator('textarea').first
if await desc_input.count() > 0:
await desc_input.fill("Product documentation and guides")
await asyncio.sleep(0.3)
await snap("KB Description Filled", 2)
# Click Create
create_btn = page.locator('button:has-text("Create")').first
if await create_btn.count() > 0:
await create_btn.click()
await asyncio.sleep(2)
await snap("KB Created!", 3)
# ===== 4. UPLOAD DOCUMENT =====
print("[4] Upload Document")
# Go to KB list and click on the new KB
await page.goto(f"{FRONTEND_URL}/dashboard/knowledge", timeout=30000)
await asyncio.sleep(2)
await snap("KB List", 2)
# Click on the KB we just created
kb_link = page.locator('a[href*="/knowledge/"]').first
if await kb_link.count() > 0:
await kb_link.click()
await asyncio.sleep(2)
await snap("Inside KB", 2)
# Look for upload button or drop zone
upload_btn = page.locator('button:has-text("Upload"), input[type="file"], [data-testid="upload"]')
# Try file input approach
file_input = page.locator('input[type="file"]')
if await file_input.count() > 0:
# Upload the sample document
await file_input.set_input_files(str(SAMPLE_DOC.absolute()))
await asyncio.sleep(1)
await snap("Document Selected", 2)
# Wait for upload to process
print(" Waiting for document to process...")
await asyncio.sleep(5)
await snap("Document Uploaded!", 3)
else:
# Try clicking upload button first
upload_trigger = page.locator('button:has-text("Upload"), button:has-text("Add Document")')
if await upload_trigger.count() > 0:
await upload_trigger.first.click()
await asyncio.sleep(1)
await snap("Upload Dialog", 2)
# Now look for file input
file_input = page.locator('input[type="file"]')
if await file_input.count() > 0:
await file_input.set_input_files(str(SAMPLE_DOC.absolute()))
await asyncio.sleep(5)
await snap("Document Uploaded!", 3)
# ===== 5. VIEW UPLOADED DOCUMENT =====
print("[5] View Documents")
await asyncio.sleep(2)
await snap("KB with Document", 3)
# ===== 6. START CHAT =====
print("[6] Start Chat with Knowledge Base")
await page.goto(f"{FRONTEND_URL}/dashboard/chat/new", timeout=30000)
await asyncio.sleep(2)
await snap("New Chat - Select KB", 2)
# Select the knowledge base
kb_checkbox = page.locator('input[type="checkbox"]').first
if await kb_checkbox.count() > 0:
await kb_checkbox.check()
await asyncio.sleep(0.5)
await snap("KB Selected", 2)
# Type question about the document content
question_input = page.locator('textarea').last
if await question_input.count() == 0:
question_input = page.locator('input[type="text"]').last
if await question_input.count() > 0:
await question_input.click()
# Ask about document content
question = "What are the key features of Info Naut?"
print(f" Asking: {question}")
for char in question:
await question_input.type(char, delay=25)
await asyncio.sleep(0.5)
await snap("Question Typed", 3)
# Submit
submit_btn = page.locator('button[type="submit"]:not([disabled]), button:has-text("Send"):not([disabled]), button:has-text("Start"):not([disabled])')
if await submit_btn.count() > 0:
await submit_btn.first.click()
await snap("Sending...", 2)
# Wait for AI to respond
print(" Waiting for AI response (this uses real OpenAI)...")
await asyncio.sleep(12)
await snap("AI Response from Document!", 5)
# Scroll to see full response
await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
await asyncio.sleep(1)
await snap("Full AI Response", 4)
# Follow-up question
print(" Follow-up question...")
follow_input = page.locator('textarea, input[type="text"]').last
if await follow_input.count() > 0:
await follow_input.fill("")
await follow_input.type("How does document processing work?", delay=25)
await asyncio.sleep(0.5)
await snap("Follow-up Question", 2)
send_btn = page.locator('button[type="submit"]:not([disabled]), button:has-text("Send"):not([disabled])')
if await send_btn.count() > 0:
await send_btn.first.click()
await asyncio.sleep(10)
await snap("Follow-up AI Response!", 5)
else:
print(" Button disabled, showing current state")
await snap("Chat Interface", 3)
# ===== 7. API KEYS =====
print("[7] API Keys")
await page.goto(f"{FRONTEND_URL}/dashboard/api-keys", timeout=30000)
await asyncio.sleep(1.5)
await snap("API Keys", 3)
# ===== 8. FINAL =====
print("[8] Final Dashboard")
await page.goto(f"{FRONTEND_URL}/dashboard", timeout=30000)
await asyncio.sleep(1)
await snap("Complete!", 3)
await browser.close()
print()
print(f"Total frames: {frame_count}")
return frames_dir, frame_count
def create_gif(frames_dir, output_path, duration=300):
"""Create optimized GIF"""
print()
print("Creating GIF...")
try:
from PIL import Image
files = sorted(frames_dir.glob("frame_*.png"))
if not files:
print(" No frames!")
return False
print(f" {len(files)} frames...")
frames = []
for f in files:
img = Image.open(f)
img = img.resize((800, 450), Image.LANCZOS)
img = img.convert('P', palette=Image.ADAPTIVE, colors=256)
frames.append(img)
frames[0].save(
output_path,
save_all=True,
append_images=frames[1:],
duration=duration,
loop=0,
optimize=True
)
size = os.path.getsize(output_path) / (1024 * 1024)
print(f" Done: {size:.2f} MB")
if size > 5:
print(" Optimizing...")
opt = [frames[i] for i in range(0, len(frames), 2)]
opt[0].save(output_path, save_all=True, append_images=opt[1:],
duration=duration*2, loop=0, optimize=True)
print(f" Optimized: {os.path.getsize(output_path)/(1024*1024):.2f} MB")
shutil.rmtree(frames_dir)
return True
except Exception as e:
print(f" Error: {e}")
return False
async def main():
print()
print("Recording COMPLETE demo with document upload + AI chat")
print()
frames_dir, count = await record_complete_demo()
if count > 0:
if create_gif(frames_dir, GIF_PATH):
print()
print("=" * 70)
print("SUCCESS! Complete demo with document + AI chat!")
print("=" * 70)
print(f"GIF: {GIF_PATH}")
if __name__ == "__main__":
asyncio.run(main())