SalwaM commited on
Commit
ecd11e4
·
verified ·
1 Parent(s): fb8ed1a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +540 -0
app.py ADDED
@@ -0,0 +1,540 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from datetime import datetime
3
+ from groq import Groq
4
+ import traceback
5
+ import json
6
+ import os
7
+
8
+ # --- 1. API KEY ---
9
+ api_key_coder= os.environ.get('Chat_with_Your_Context')
10
+ if not api_key_coder:
11
+ raise ValueError("Groq API key not found. Set fristapi environment variable.")
12
+
13
+ # --- 2. LLM CLIENT ---
14
+ class GroqLLM:
15
+ def __init__(self, api_key, model="meta-llama/llama-4-scout-17b-16e-instruct", temperature=0.1):
16
+ self.client = Groq(api_key=api_key)
17
+ self.model = model
18
+ self.temperature = temperature
19
+
20
+ def invoke(self, prompt):
21
+ try:
22
+ response = self.client.chat.completions.create(
23
+ model=self.model,
24
+ messages=[{"role": "user", "content": prompt}],
25
+ temperature=self.temperature,
26
+ max_tokens=2000
27
+ )
28
+ return response.choices[0].message.content
29
+ except Exception as e:
30
+ return f"LLM Error: {str(e)}"
31
+
32
+ llm = GroqLLM(api_key=api_key_coder)
33
+
34
+ # ============================================
35
+ # PART 1: SmartQA System (Multi-Source Test Generation)
36
+ # ============================================
37
+
38
+ # --- Dummy Runner and DOM Matcher for SmartQA ---
39
+ class DummyRunner:
40
+ def run(self, test_script):
41
+ if "fail" in test_script.lower() or "assert false" in test_script.lower():
42
+ return {
43
+ "status": "failed",
44
+ "error": "AssertionError: Expected True but got False",
45
+ "logs": "Stack trace: line 10 in test_function",
46
+ "dom": "<button id='submit-btn' class='btn'>Submit</button>"
47
+ }
48
+ return {"status": "passed", "message": "All tests passed successfully"}
49
+
50
+ class DOMMatcher:
51
+ def find_similar(self, dom, failed_locator):
52
+ return "button#submit-btn", 0.92
53
+
54
+ runner = DummyRunner()
55
+ dom_matcher = DOMMatcher()
56
+
57
+ # --- SmartQA Functions ---
58
+ def detect_failure(test_script):
59
+ return runner.run(test_script)
60
+
61
+ def analyze_root_cause(failure_data):
62
+ error = failure_data.get("error", "Unknown")
63
+ logs = failure_data.get("logs", "")
64
+ prompt = f"""
65
+ Analyze this test failure:
66
+ Error: {error}
67
+ Logs: {logs}
68
+ Provide:
69
+ 1. Root cause analysis
70
+ 2. Suggested fix
71
+ """
72
+ analysis = llm.invoke(prompt)
73
+ return {"root_cause": analysis, "confidence": "high"}
74
+
75
+ def heal_locator(failure_data):
76
+ dom = failure_data.get("dom", "")
77
+ error = failure_data.get("error", "")
78
+ new_locator, score = dom_matcher.find_similar(dom, error)
79
+ return {"suggested_locator": new_locator, "confidence": score}
80
+
81
+ def update_script(script_content, old_locator, new_locator):
82
+ return script_content.replace(old_locator, new_locator)
83
+
84
+ def reexecute_test(test_script):
85
+ return runner.run(test_script)
86
+
87
+ def generate_report(data):
88
+ prompt = f"""
89
+ Generate a comprehensive QA report based on this data:
90
+ {json.dumps(data, indent=2, ensure_ascii=False)}
91
+ Include:
92
+ - Test Execution Summary
93
+ - Failures Detected
94
+ - Root Cause Analysis
95
+ - Healing Actions
96
+ - Final Results
97
+ - Recommendations
98
+ """
99
+ return llm.invoke(prompt)
100
+
101
+ # --- SmartQA Knowledge Classes ---
102
+ class KnowledgeInput:
103
+ def __init__(self, requirements=None, dom=None, api_spec=None, user_flows=None, source_code=None, recording=None):
104
+ self.requirements = requirements
105
+ self.dom = dom
106
+ self.api_spec = api_spec
107
+ self.user_flows = user_flows
108
+ self.source_code = source_code
109
+ self.recording = recording
110
+
111
+ class KnowledgeProcessor:
112
+ def parse_requirements(self, text): return text.strip()
113
+ def parse_dom(self, dom_text): return dom_text[:4000]
114
+ def parse_api(self, api_text): return api_text[:4000]
115
+ def parse_flows(self, flows_text): return flows_text.strip()
116
+ def analyze_code(self, code_text): return code_text[:4000]
117
+ def parse_recording(self, rec_text): return rec_text.strip()
118
+
119
+ def process(self, knowledge):
120
+ data = {}
121
+ if knowledge.requirements: data["req"] = self.parse_requirements(knowledge.requirements)
122
+ if knowledge.dom: data["ui"] = self.parse_dom(knowledge.dom)
123
+ if knowledge.api_spec: data["api"] = self.parse_api(knowledge.api_spec)
124
+ if knowledge.user_flows: data["flows"] = self.parse_flows(knowledge.user_flows)
125
+ if knowledge.source_code: data["code"] = self.analyze_code(knowledge.source_code)
126
+ if knowledge.recording: data["record"] = self.parse_recording(knowledge.recording)
127
+ return data
128
+
129
+ class TestGenerator:
130
+ def __init__(self, llm): self.llm = llm
131
+ def generate_req_tests(self, data): return self.llm.invoke(f"Generate Python Selenium tests from requirements:\n{data['req']}")
132
+ def generate_ui_tests(self, data): return self.llm.invoke(f"Generate Selenium UI tests from DOM:\n{data['ui']}")
133
+ def generate_api_tests(self, data): return self.llm.invoke(f"Generate API tests from spec:\n{data['api']}")
134
+ def generate_flow_tests(self, data): return self.llm.invoke(f"Generate E2E tests from flows:\n{data['flows']}")
135
+ def generate_code_tests(self, data): return self.llm.invoke(f"Generate tests from code:\n{data['code']}")
136
+ def generate_record_tests(self, data): return self.llm.invoke(f"Convert recording to test:\n{data['record']}")
137
+
138
+ def generate(self, processed_data):
139
+ if "api" in processed_data: return self.generate_api_tests(processed_data)
140
+ if "ui" in processed_data: return self.generate_ui_tests(processed_data)
141
+ if "flows" in processed_data: return self.generate_flow_tests(processed_data)
142
+ if "req" in processed_data: return self.generate_req_tests(processed_data)
143
+ if "code" in processed_data: return self.generate_code_tests(processed_data)
144
+ if "record" in processed_data: return self.generate_record_tests(processed_data)
145
+ return "No valid input provided"
146
+
147
+ def run_complete_analysis(test_script):
148
+ report_data = {"original_script": test_script, "steps": [], "final_result": {}, "healing_applied": False}
149
+ result = detect_failure(test_script)
150
+ report_data["steps"].append({"step": "initial_execution", "result": result})
151
+
152
+ if result["status"] == "failed":
153
+ report_data["healing_applied"] = True
154
+ analysis = analyze_root_cause(result)
155
+ report_data["steps"].append({"step": "root_cause_analysis", "analysis": analysis})
156
+ healing = heal_locator(result)
157
+ report_data["steps"].append({"step": "healing_attempt", "healing": healing})
158
+
159
+ if "suggested_locator" in healing:
160
+ old = "button"
161
+ new = healing["suggested_locator"]
162
+ updated_script = update_script(test_script, old, new)
163
+ report_data["steps"].append({"step": "script_updated", "new_script": updated_script})
164
+ final_result = reexecute_test(updated_script)
165
+ report_data["final_result"] = final_result
166
+ report_data["steps"].append({"step": "re_execution", "result": final_result})
167
+ else:
168
+ report_data["final_result"] = result
169
+
170
+ report = generate_report(report_data)
171
+ report_data["full_report"] = report
172
+ return report_data
173
+
174
+ class SmartQASystem:
175
+ def __init__(self, llm):
176
+ self.processor = KnowledgeProcessor()
177
+ self.generator = TestGenerator(llm)
178
+
179
+ def run(self, knowledge):
180
+ processed = self.processor.process(knowledge)
181
+ generated_tests = self.generator.generate(processed)
182
+ results = run_complete_analysis(generated_tests)
183
+ return {
184
+ "generated_test": generated_tests,
185
+ "updated_test": results.get("steps", [{}])[-1].get("new_script", generated_tests) if results.get("healing_applied") else generated_tests,
186
+ "initial_result": str(results["steps"][0]["result"]),
187
+ "final_result": str(results["final_result"]),
188
+ "report": results["full_report"]
189
+ }
190
+
191
+ smartqa = SmartQASystem(llm)
192
+
193
+ # ============================================
194
+ # PART 2: HealTest AI System (Simple Test Healing)
195
+ # ============================================
196
+
197
+ def process_test_inputs(script_text, testcase_text):
198
+ try:
199
+ if not script_text.strip():
200
+ return "⛔ Please paste a test script."
201
+
202
+ result = run_complete_analysis(script_text)
203
+
204
+ preview = script_text[:500]
205
+ if len(script_text) > 500:
206
+ preview += "..."
207
+
208
+ display = (
209
+ "# 📊 HealTest AI Analysis Result\n\n"
210
+ "## 🧾 Test Script:\n"
211
+ "```python\n"
212
+ + preview +
213
+ "\n```\n\n"
214
+ "## 📋 Test Case:\n"
215
+ + testcase_text +
216
+ "\n\n## 🔍 Analysis Steps:\n"
217
+ )
218
+
219
+ for step in result["steps"]:
220
+ display += f"\n### ➡️ {step['step']}\n"
221
+ display += f"```\n{json.dumps(step, indent=2, ensure_ascii=False)}\n```\n"
222
+
223
+ display += "\n## 📈 Final Result: " + json.dumps(result["final_result"], ensure_ascii=False) + "\n"
224
+ display += "\n## 📝 Full Report:\n" + str(result["full_report"]) + "\n"
225
+
226
+ return display
227
+
228
+ except Exception as e:
229
+ return f"❌ Error: {str(e)}\n\n{traceback.format_exc()}"
230
+
231
+ # ============================================
232
+ # PART 3: SmartQA Interface Functions
233
+ # ============================================
234
+
235
+ def run_smartqa(requirements, dom, api_spec, flows, code, recording):
236
+ try:
237
+ knowledge = KnowledgeInput(
238
+ requirements=requirements,
239
+ dom=dom,
240
+ api_spec=api_spec,
241
+ user_flows=flows,
242
+ source_code=code,
243
+ recording=recording
244
+ )
245
+
246
+ result = smartqa.run(knowledge)
247
+
248
+ return (
249
+ result["generated_test"],
250
+ result["updated_test"],
251
+ result["initial_result"],
252
+ result["final_result"],
253
+ result["report"]
254
+ )
255
+ except Exception as e:
256
+ error_msg = f"Error: {str(e)}\n{traceback.format_exc()}"
257
+ return error_msg, error_msg, error_msg, error_msg, error_msg
258
+
259
+ def load_smartqa_examples():
260
+ example_requirements = """
261
+ User can login with email and password
262
+ User can search for a product
263
+ User can add product to cart
264
+ """
265
+ example_dom = """
266
+ <html>
267
+ <body>
268
+ <input id=\"email\" />
269
+ <input id=\"password\" />
270
+ <button id=\"login-btn\">Login</button>
271
+ <input id=\"search\" />
272
+ <button id=\"search-btn\">Search</button>
273
+ <button id=\"add-cart\">Add to Cart</button>
274
+ </body>
275
+ </html>
276
+ """
277
+ example_api = """
278
+ POST /login
279
+ Body: { email, password }
280
+ GET /products
281
+ POST /cart
282
+ Body: { product_id }
283
+ """
284
+ example_flows = """
285
+ Open login page
286
+ Enter email and password
287
+ Click login
288
+ Search product
289
+ Add to cart
290
+ """
291
+ example_code = """
292
+ @app.route('/login', methods=['POST'])
293
+ def login():
294
+ email = request.json['email']
295
+ password = request.json['password']
296
+ if authenticate(email, password):
297
+ return {'status': 'ok'}
298
+ return {'status': 'fail'}, 401
299
+ """
300
+ example_recording = """
301
+ User navigates to /login
302
+ Types email test@mail.com
303
+ Types password 123456
304
+ Clicks Login button
305
+ Navigates to /products
306
+ Clicks Add to Cart
307
+ """
308
+ return (example_requirements, example_dom, example_api, example_flows, example_code, example_recording)
309
+
310
+ # ============================================
311
+ # PART 4: HealTest Examples
312
+ # ============================================
313
+
314
+ heal_example_scripts = {
315
+ "example1": """def test_login_ui():
316
+ driver.get("https://example.com/login")
317
+ driver.find_element(By.ID, "submit-btn").click()
318
+ assert False""",
319
+ "example2": """def test_add_to_cart():
320
+ driver.get("https://shop.com/product/1")
321
+ driver.find_element(By.ID, "add-to-cart").click()
322
+ assert False""",
323
+ "example3": """def test_submit_button():
324
+ driver.get("https://example.com/form")
325
+ driver.find_element(By.TAG_NAME, "button").click()
326
+ assert False"""
327
+ }
328
+
329
+ heal_example_testcases = {
330
+ "example1": """Test: Login via UI
331
+ Steps:
332
+ - Open login page
333
+ - Click Login button
334
+ Expected:
335
+ - User redirected to dashboard""",
336
+ "example2": """Test: Add product to cart
337
+ Steps:
338
+ - Open product page
339
+ - Click Add to Cart
340
+ Expected:
341
+ - Product appears in cart""",
342
+ "example3": """Test: Submit form
343
+ Steps:
344
+ - Open form page
345
+ - Click Submit
346
+ Expected:
347
+ - Form submitted successfully"""
348
+ }
349
+
350
+ def load_heal_example1():
351
+ return heal_example_scripts["example1"], heal_example_testcases["example1"]
352
+
353
+ def load_heal_example2():
354
+ return heal_example_scripts["example2"], heal_example_testcases["example2"]
355
+
356
+ def load_heal_example3():
357
+ return heal_example_scripts["example3"], heal_example_testcases["example3"]
358
+
359
+ # ============================================
360
+ # PART 5: Unified Gradio Interface
361
+ # ============================================
362
+
363
+ with gr.Blocks(title="SmartQA + HealTest AI", theme=gr.themes.Soft()) as demo:
364
+ gr.Markdown("""
365
+ # 🧠 SmartQA + HealTest AI - Unified Testing Platform
366
+ ### Multi-Source Test Generation + Self-Healing Test Automation
367
+ """)
368
+
369
+ with gr.Tab("🏠 Home"):
370
+ gr.Markdown("""
371
+ ## Welcome to the Unified Testing Platform!
372
+
373
+ This platform combines two powerful AI-powered testing tools:
374
+
375
+ ### 1. 🎯 **SmartQA - Multi-Source Test Generation**
376
+ - Generate tests from multiple sources:
377
+ - Requirements
378
+ - UI/DOM
379
+ - API Specifications
380
+ - User Flows
381
+ - Source Code
382
+ - User Recordings
383
+ - AI-powered test generation
384
+ - Comprehensive test coverage
385
+
386
+ ### 2. 🔧 **HealTest AI - Self-Healing Test Automation**
387
+ - Paste your test script
388
+ - Add test case description
389
+ - AI detects failures
390
+ - Automatically heals broken locators
391
+ - Generates detailed reports
392
+
393
+ ### 🚀 How to Use:
394
+ 1. Navigate to the desired tool using the tabs above
395
+ 2. Input your data or load examples
396
+ 3. Click the analyze button
397
+ 4. View comprehensive results
398
+
399
+ ### 💡 Benefits:
400
+ - Save hours of manual test writing
401
+ - Automatic test maintenance
402
+ - Reduced flaky tests
403
+ - Better test coverage
404
+ - AI-powered insights
405
+ """)
406
+
407
+ with gr.Tab("🎯 SmartQA - Multi-Source Generator"):
408
+ gr.Markdown("### Generate tests from multiple sources")
409
+
410
+ with gr.Row():
411
+ with gr.Column(scale=1):
412
+ gr.Markdown("#### Input Sources")
413
+ with gr.Tab("Requirements"):
414
+ req_input = gr.Textbox(lines=4, label="Requirements", placeholder="Enter functional requirements...")
415
+ with gr.Tab("UI / DOM"):
416
+ dom_input = gr.Textbox(lines=4, label="HTML DOM", placeholder="Paste HTML DOM structure...")
417
+ with gr.Tab("API Spec"):
418
+ api_input = gr.Textbox(lines=4, label="API Specification", placeholder="Enter API endpoints and specs...")
419
+ with gr.Tab("User Flows"):
420
+ flow_input = gr.Textbox(lines=4, label="User Flows", placeholder="Describe user interaction flows...")
421
+ with gr.Tab("Source Code"):
422
+ code_input = gr.Textbox(lines=4, label="Source Code", placeholder="Paste source code to analyze...")
423
+ with gr.Tab("Recording"):
424
+ rec_input = gr.Textbox(lines=4, label="Recording", placeholder="Paste user interaction recording...")
425
+
426
+ with gr.Column(scale=1):
427
+ gr.Markdown("#### Actions & Results")
428
+ with gr.Row():
429
+ smartqa_run_btn = gr.Button("🚀 Generate Tests", variant="primary", size="lg")
430
+ smartqa_example_btn = gr.Button("📂 Load Examples", size="lg")
431
+
432
+ gr.Markdown("---")
433
+
434
+ with gr.Row():
435
+ with gr.Column():
436
+ gr.Markdown("#### Generated Test")
437
+ smartqa_gen_out = gr.Code(label="Generated Test", language="python")
438
+ with gr.Column():
439
+ gr.Markdown("#### Healed Test")
440
+ smartqa_upd_out = gr.Code(label="Healed Test", language="python")
441
+
442
+ with gr.Row():
443
+ with gr.Column():
444
+ smartqa_init_out = gr.Textbox(label="Initial Result", lines=3)
445
+ with gr.Column():
446
+ smartqa_final_out = gr.Textbox(label="Final Result", lines=3)
447
+
448
+ smartqa_report_out = gr.Textbox(label="QA Report", lines=10)
449
+
450
+ # SmartQA event handlers
451
+ smartqa_example_btn.click(
452
+ fn=load_smartqa_examples,
453
+ inputs=[],
454
+ outputs=[req_input, dom_input, api_input, flow_input, code_input, rec_input]
455
+ )
456
+
457
+ smartqa_run_btn.click(
458
+ fn=run_smartqa,
459
+ inputs=[req_input, dom_input, api_input, flow_input, code_input, rec_input],
460
+ outputs=[smartqa_gen_out, smartqa_upd_out, smartqa_init_out, smartqa_final_out, smartqa_report_out]
461
+ )
462
+
463
+ with gr.Tab("🔧 HealTest AI - Self-Healing"):
464
+ gr.Markdown("### Self-Healing Test Automation")
465
+
466
+ with gr.Row():
467
+ with gr.Column():
468
+ gr.Markdown("#### Input")
469
+ heal_script_input = gr.Textbox(
470
+ label="📝 Paste Test Script",
471
+ lines=10,
472
+ placeholder="# Paste your Python test script here...\ndef test_example():\n driver.find_element(By.ID, 'submit-btn').click()\n assert True"
473
+ )
474
+
475
+ heal_testcase_input = gr.Textbox(
476
+ label="📋 Test Case Description",
477
+ lines=6,
478
+ placeholder="Describe what the test should do...\n\nSteps:\n1. Open page\n2. Click button\n3. Verify result"
479
+ )
480
+
481
+ with gr.Row():
482
+ heal_analyze_btn = gr.Button("🚀 Start Analysis", variant="primary", size="lg")
483
+
484
+ with gr.Row():
485
+ heal_example1_btn = gr.Button("📂 Example 1 - Login", size="sm")
486
+ heal_example2_btn = gr.Button("📂 Example 2 - Add to Cart", size="sm")
487
+ heal_example3_btn = gr.Button("📂 Example 3 - Submit", size="sm")
488
+
489
+ with gr.Column():
490
+ gr.Markdown("#### Results")
491
+ heal_output = gr.Markdown(label="Analysis Result", value="Click 'Start Analysis' to begin...")
492
+
493
+ # HealTest event handlers
494
+ heal_example1_btn.click(load_heal_example1, [], [heal_script_input, heal_testcase_input])
495
+ heal_example2_btn.click(load_heal_example2, [], [heal_script_input, heal_testcase_input])
496
+ heal_example3_btn.click(load_heal_example3, [], [heal_script_input, heal_testcase_input])
497
+
498
+ heal_analyze_btn.click(
499
+ fn=process_test_inputs,
500
+ inputs=[heal_script_input, heal_testcase_input],
501
+ outputs=heal_output
502
+ )
503
+
504
+ with gr.Tab("📊 About"):
505
+ gr.Markdown("""
506
+ ## About This Platform
507
+
508
+ ### SmartQA System
509
+ An AI-powered test generation system that creates automated tests from various input sources:
510
+ - **Requirements**: Converts functional requirements to test scripts
511
+ - **UI/DOM**: Generates Selenium tests from HTML structure
512
+ - **API Specs**: Creates API tests from OpenAPI/Swagger
513
+ - **User Flows**: Builds E2E tests from user scenarios
514
+ - **Source Code**: Analyzes code to generate relevant tests
515
+ - **Recordings**: Transforms user interactions into test scripts
516
+
517
+ ### HealTest AI
518
+ A self-healing test automation system that:
519
+ 1. **Detects** test failures automatically
520
+ 2. **Analyzes** root causes using AI
521
+ 3. **Heals** broken locators by finding alternatives
522
+ 4. **Updates** test scripts automatically
523
+ 5. **Re-executes** to verify the fix
524
+ 6. **Generates** comprehensive reports
525
+
526
+ ### Technology Stack
527
+ - **Frontend**: Gradio
528
+ - **AI Model**: Meta Llama-4 (via Groq API)
529
+ - **Backend**: Python
530
+
531
+ ### Created by
532
+ A unified testing solution for modern QA teams
533
+ """)
534
+
535
+ # ============================================
536
+ # LAUNCH THE APPLICATION
537
+ # ============================================
538
+
539
+ if __name__ == "__main__":
540
+ demo.launch(share=True, debug=False, server_name="0.0.0.0")