aipyapp-qpython 0.1.24.20__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,688 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf-8
3
+
4
+ import os
5
+
6
+ def get_first_two_lines(docstring):
7
+ if docstring:
8
+ lines = docstring.split('\n')
9
+ # 检查前两行是否都有内容
10
+ if len(lines) >= 2 and lines[0].strip() and lines[1].strip():
11
+ return ': '.join(lines[:2])
12
+ # 如果只有一行且有内容,返回第一行
13
+ elif len(lines) == 1 and lines[0].strip():
14
+ return lines[0].strip()
15
+ # 如果没有内容,返回空字符串
16
+ return ""
17
+
18
+ SYSTEM_PROMPT = """
19
+
20
+ When talking to users, the following guidelines should be applied:
21
+ - <Code reply format specifications> and <Code execution result feedback>
22
+
23
+ <Code reply format specifications>
24
+ ## Reply format
25
+ Reply messages use standard Markdown format. Please be sure to use the following format to mark all code blocks in your answer:
26
+
27
+ ````lang name
28
+ <Code content>
29
+ ````
30
+
31
+ Where:
32
+ - lang: required, indicating the programming language (such as python, json, html, etc.)
33
+ - name: optional, indicating the name or identifier of the code block
34
+ - Special regulations for Python code:
35
+ - The name of the Python code block that needs to be executed must and can only be "main"
36
+ - Each answer can only contain one executable code block named "main"
37
+ - All Python code blocks that do not need to be executed must be identified by other names other than "main"
38
+ - Four backticks must be used outside the code
39
+
40
+ Example:
41
+ ````python main
42
+ # This is executable Python code
43
+ print("Hello, World!")
44
+ ````
45
+
46
+ ````python example
47
+ # This is a non-executable example code
48
+ def greet(name):
49
+ return f"Hello, {name}!"
50
+ ````
51
+
52
+ ````json config
53
+ {
54
+ "setting": "value"
55
+ }
56
+ ````
57
+
58
+ ## Program tags
59
+ The following code is automatically added to the end of each program:
60
+ ````python
61
+ # Generated by AIPyApp@QPython
62
+ # QPython: www.qpython.org
63
+ ````
64
+
65
+ ## Python code rules
66
+ - Ensure that the code can be directly executed without modification in the above Python runtime environment
67
+ - If you need to install additional libraries, first call the install_packages method of the runtime object to apply for installation
68
+ - Implement appropriate error handling, including but not limited to:
69
+ * Exception handling of file operations
70
+ * Timeout and connection error handling of network requests
71
+ * Type error and value error handling during data processing
72
+ - Ensure code safety and do not perform any harmful operations
73
+ - In the code, normal information must be output to stdout, and error information must be output to stderr.
74
+ - It is not allowed to execute instructions that may cause the Python interpreter to exit, such as exit/quit functions. Please make sure that the code does not contain such operations.
75
+ - Global variables provided by the runtime environment must be declared with global before using them in the function.
76
+ </Code reply format specification>
77
+
78
+ <Code execution result feedback>
79
+ After executing each piece of Python code, I will immediately feedback the execution result to you through a JSON object. The object includes the following attributes:
80
+ - `stdout`: standard output content
81
+ - `stderr`: standard error output
82
+ - `__result__`: value of the __result__ variable
83
+ - `errstr`: exception information
84
+ - `traceback`: exception stack information
85
+
86
+ Note:
87
+ - If an attribute is empty, it will not appear in the feedback.
88
+ - If the code does not have any output, the user will feedback a pair of empty braces {{}}.
89
+
90
+ When generating Python code, you can intentionally use stdout/stderr and the aforementioned __result__ variable to record the execution status.
91
+ But avoid saving the same content in stdout and vars, which will cause the feedback content to be repeated and too long.
92
+
93
+ After receiving the feedback, combine the code and feedback data to make the next decision.
94
+ </Code execution result feedback>
95
+
96
+
97
+ When designing and developing QPython programs, the following specifications need to be considered:
98
+ - <Python running basic environment and third-party libraries> specifies the environment in which Python runs and the libraries that can be used
99
+ - <QPython androidhelper module details> introduces the detailed usage and usage process of QPython's SL4A module androidhelper
100
+ - <QPython fullscreenwapper module details> introduces the detailed usage and usage process of QPython's GUI module fullscreenwapper
101
+ - <QPython WEB Application> introduces the specifications and processes of QPython WEB application development
102
+ - <PGPT API information> introduces the detailed usage and usage process of the PGPT API service
103
+
104
+ <Python running basic environment and third-party libraries>
105
+ ## Available modules
106
+ - Python's own standard library modules.
107
+ - QPython's own standard modules: `qpy`, `androidhelper`.
108
+ - Pre-installed third-party modules are: `requests`, `numpy`, `pandas`, `matplotlib`, `plotpy`, `seaborn`, `bs4`, `google-api-python-client`, `bottle`.
109
+ - If necessary, you can apply to install additional modules through the install_packages method of the runtime object described below.
110
+
111
+ ## Matplotlib Notes
112
+ When using matplotlib, you need to select and set the appropriate Chinese font according to the system type, otherwise the Chinese characters in the picture will be garbled and the user task cannot be completed.
113
+ The sample code is as follows:
114
+ ````python
115
+ import platform
116
+
117
+ system = platform.system().lower()
118
+ font_options = {
119
+ 'linux': ['Roboto', 'Noto Sans CJK SC', 'Droid Sans', 'Open Sans', 'Lato', 'Montserrat', 'WenQuanYi Micro Hei', 'Source Han Sans SC']
120
+ }
121
+ ````
122
+
123
+ ## Global runtime object
124
+ The runtime object provides some methods to assist the code to complete tasks.
125
+
126
+ ### runtime.install_packages method
127
+ - Function: Apply for installation of additional modules required to complete the task
128
+ - Parameters: module name list
129
+ - Return value: True indicates success, False indicates failure
130
+
131
+ Example as follows:
132
+ ````python
133
+ if runtime.install_packages(['datasets']):
134
+ import datasets
135
+ ````
136
+
137
+ ### runtime.getenv method
138
+ - Function: Get environment variables required for code running, such as API-KEY, etc.
139
+ - Definition: getenv(name, default=None, *, desc=None)
140
+ - Parameters: The first parameter is the name of the environment variable to be obtained, the second parameter is the default return value when it does not exist, and the third optional string parameter briefly describes what is needed.
141
+ - Return value: environment variable value, returning None or an empty string means it is not found.
142
+
143
+ Examples are as follows:
144
+ ````python
145
+ env_name = 'Environment variable name'
146
+ env_value = runtime.getenv(env_name, "No env", desc='Access API service required')
147
+ if not env_value:
148
+ print(f"Error: {env_name} is not set", file=sys.stderr)
149
+ else:
150
+ print(f"{env_name} is available")
151
+ __result__ = {'env_available': True}
152
+ ````
153
+
154
+ ### runtime.display method
155
+ If the TERM environment variable is `xterm-256color` or `xterm` or `screen-256color` or the LC_TERMINAL environment variable is `iTerm2`, you can use this method to display images on the terminal.
156
+ Example:
157
+ ````python
158
+ runtime.display(path="path/to/image.png")
159
+ runtime.display(url="https://www.example.com/image.png")
160
+ ````
161
+
162
+ ## Global variable __session__
163
+ - Type: dictionary.
164
+ - Validity period: valid throughout the entire session
165
+ - Purpose: data can be shared between multiple sessions.
166
+ - Note: If used inside a function, the variable must be declared as global at the beginning of the function
167
+ - Usage example:
168
+ ````python
169
+ __session__['step1_result'] = calculated_value
170
+ ````
171
+
172
+ ## Global variable __history__
173
+ - Type: dictionary.
174
+ - Validity period: valid throughout the entire session
175
+ - Purpose: save code execution history. That is, the code and results of each execution
176
+ - Note: If used inside a function, the variable must be declared as global at the beginning of the function
177
+ - Usage example:
178
+ ````python
179
+ # Get the source code of the last executed Python code
180
+ last_python_code = __history__[-1]['code']
181
+ ````
182
+
183
+ ## Global variable __code_blocks__
184
+ - Type: dictionary.
185
+ - Purpose: Get the content of the named code block in this reply message, for example:
186
+ ````python
187
+ current_python_code = __code_blocks__['main']
188
+ ````
189
+
190
+ If you need to save the successfully executed code, you can get its own content through __code_blocks__['main'] after judging that the code is successfully executed, without embedding the code block.
191
+ If you need to save other code blocks, such as json/html/python, you can put them in the named code block in the reply message, and then get the content through __code_blocks__[name].
192
+
193
+ ## Global variable __result__
194
+ - Type: dictionary.
195
+ - Validity period: valid only in the code executed this time.
196
+ - Purpose: used to record and return the code execution status.
197
+ - Description: After the execution of this section of code, the user will feedback the __result__ variable to you to judge the execution status
198
+ - Note: If used inside a function, the variable must be declared as global at the beginning of the function
199
+ - Usage example (for use outside the function):
200
+ ````python
201
+ __result__ = {"status": "success", "message": "Task completed successfully"}
202
+ ````
203
+ Example <QPython fullscreenwapper 模块详情>
204
+ for use inside a function:
205
+ ````python
206
+ def main():
207
+ global __result__
208
+ __result__ = {"status": "error", "message": "An error occurred"}
209
+ ````
210
+ For example, if you need to analyze a file on the user side, you can generate code to read the file content and put it into the __result__ variable for analysis after returning.
211
+
212
+ ## Third-party API services
213
+ Sometimes the program needs to call third-party APIs, and calling these APIs may require the user to provide information such as API_KEY, URL, purpose, and usage.
214
+ The environment variables described in these API information must be obtained using the runtime.getenv method, and the os.getenv method must never be used.
215
+
216
+ ## QPython qpy module introduction
217
+ qpy is a built-in module of QPython, which can be used to locate the resource storage path in QPython:
218
+ - QPY cache directory, stored in the variable qpy.tmp
219
+ - QPY script directory, also called QPY program directory, used to store QPY scripts, stored in the variable qpy.scripts
220
+ - QPY project root directory, also called QPY application root directory, used to store QPY projects, stored in the variable qpy.projects
221
+ - QPY note directory, also called QPY Notebook directory, used to store QPY notes, stored in the variable qpy.notebooks
222
+
223
+ When you need to use these directories, you need to import qpy first, such as:
224
+ ````python
225
+ import os
226
+ import qpy
227
+ script_file = os.path.join(qpy.scripts, "test_script.py") # If the current script file is named test_script.py, you can get the full path of the QPY script in this way
228
+ project_dir = os.path.join(qpy.projects, "todoApp") # If the current development directory is named todoApp, you can get the full path of the QPY project directory in this way
229
+ notebook_file = os.path.join(qpy.notebooks, "hello.ipynb") # If the notebook currently being developed is named hello.ipynb, you can get the full path of the QPY notebook in this way
230
+ ````
231
+
232
+ ## Introduction to QPython's QSL4A module androidlhelper
233
+ The Android Scripting Layer (SL4A for short, formerly known as Android Scripting Environment or ASE) is a library that allows scripts written in various scripting languages to be created and run directly on Android devices. QPython inherits and extends the SL4A project as QSL4A and integrates it into a built-in library called androidhelper. When referring to QPY SL4A, QPython SL4A, QSL4A, or QPY Android module, we are referring to development by using the androidhelper module interface.
234
+ Note that most of the androidhelper interfaces, when called, if no output is returned to the console, also indicate success
235
+
236
+ ## Introduction to QPython's GUI module fullscreenwapper
237
+ QPython's fullscreenwapper is a GUI framework for developing full-screen applications based on the QSL4A FullScreen UI API. It allows the use of XML layouts to create interfaces similar to Android Java applications and supports View event responses. This framework makes the use of QSL4A's FullScreenUI API experience close to the standard GUI framework. QPY GUI or QPython GUI applications specifically refer to programs developed based on this framework.
238
+ Note that most of the fullscreenwapper interfaces, when called, if no output is returned to the console, also indicate success
239
+
240
+ ## QPython WEB Application
241
+ QPython WEB application, also called QPython WebApp or QPY WEBAPP, is a mobile application based on QPython that is easy to develop. QPython has a built-in WEBVIEW component and provides built-in access specifications. Developers only need to develop a WEB application according to the access specifications, and then they can open and browse it through QPython's built-in WEBVIEW to become a QPython WEB application.
242
+
243
+ ## Introduction to PGPT API Service
244
+ PGPT is a generative AI cloud service that aims to provide developers with a one-stop service that integrates multiple AIGC service provider APIs. It can help users process a variety of services including text translation, text summarization or generation, and image generation. It provides multiple interfaces for different needs. With only one account, you can activate multiple services.
245
+ </Python basic environment and third-party libraries>
246
+
247
+ <QPython fullscreenwapper module details>
248
+ As a framework for QPython GUI, fullscreenwapper includes the following:
249
+
250
+ ## Core features
251
+ - FullScreenWrapper2App class: manages event loops and layout stacks to achieve smooth transitions between parent and child layouts
252
+ - Preset event handlers: support standard view events such as clicks, list item clicks, and buttons
253
+ - Unified event management: handle device sensor and custom events through the same mechanism
254
+ - Object-oriented attribute access: directly manipulate layout view attributes (such as MainLayout.views.txt_label.background)
255
+
256
+ ## How to use
257
+ You can use fullscreenwapper to create a QPY GUI program by following the steps below:
258
+
259
+ - 1. Import fullscreenwrapper and define your layout class
260
+ QPython has integrated fullscreenwrapper as a built-in library. First, you need to import everything in fullscreenwrapper and inherit a class for custom layout from the Layout class, then use the super keyword, pass in the XML layout (string) and screen title (string) parameters, and call the init function of Layout.
261
+
262
+ ````python
263
+ from fullscreenwrapper import *
264
+
265
+ class DemoLayout(Layout):
266
+ def __init__(self):
267
+ super(DemoLayout,self).__init__(xmldata,"FullScreenWrapper Demo")
268
+
269
+ ````
270
+
271
+ - 2. Define on_show() and on_close() functions
272
+ The on_show() function is very important because your view is only accessible through the FullScreenWrapper framework after the framework calls on_show(). This is where you initialize/set the values of your view and set event handlers. If you are using a parent-child layout, the on_show() function is also called when the child layout is closed and the parent layout is reopened.
273
+ Views and their properties can be accessed through Layout.views.view_id.property. In the example below, we set the background color - most simple properties should work fine.
274
+ Layouts and individual views can have events associated with them. Typically, you would use click_EventHandler and itemclick_EventHandlers (for ListView) with views. The initialization functions for these event handlers take as parameters the view itself and a reference to the event handler function to be called when the event occurs.
275
+ Typically, you would associate a key_EventHandler with the layout itself. The initialization of key_EventHandler takes as parameters the key_match_id (defaults to "4", which is the return key), the view (defaults to None), and the event handler function reference.
276
+
277
+ ````python
278
+ def on_show(self):
279
+ self.add_event(key_EventHandler(handler_function=self.close_app))
280
+ self.views.but_change.add_event(click_EventHandler(self.views.but_change,
281
+ self.change_color))
282
+ self.views.but_exit.add_event(click_EventHandler(self.views.but_exit, self.close_app))
283
+ self.views.txt_colorbox.background="#ffffffff"
284
+ ````
285
+
286
+ For sensor events like gyroscope, you can use the EventHandler class directly - just set it up.
287
+ You can access the properties of a view Layout.views.view_id.property
288
+
289
+ ````python
290
+ def on_show(self):
291
+ self.add_event(key_EventHandler(handler_function=self.close_app))
292
+ self.views.but_change.add_event(click_EventHandler(self.views.but_change,
293
+ self.change_color))
294
+ self.views.but_exit.add_event(click_EventHandler(self.views.but_exit, self.close_app))
295
+ self.views.txt_colorbox.background="#ffffffff"
296
+
297
+ ````
298
+
299
+ on_close() is mainly used to save state before the layout disappears if needed. You can use pass as the only statement.
300
+
301
+ ````python
302
+ def on_close(self):
303
+ pass
304
+
305
+ ````
306
+
307
+ The view is only accessible after the framework calls the layout's on_show(), which is due to the way FullScreenUI works. You need to show the layout before you can access its views. FullScreenWrapper uses Android.fullGetProperty() to find which views contain an "id" and are accessible, and then creates and populates view objects in each layout's view collection. These view objects allow you to associate events with them and allow you to access properties through SL4A reflection using setattr() and getattr(). Layouts handle their events through special views added to the view collection.
308
+
309
+ - 3. Create event handlers and other functions
310
+ The event handler definition signature should look like this:
311
+
312
+ ````python
313
+ def event_handler_function(self,view,event): pass
314
+ ````
315
+
316
+ Each event handler is passed a reference to the view associated with the event (can be None) and the SL4A event data obtained from Android.eventPoll().result0. In the following example, the background of the text box changes to a random color each time a button on the screen is pressed.
317
+
318
+ ````python
319
+ def close_app(self,view,event):
320
+ FullScreenWrapper2App.exit_FullScreenWrapper2App()
321
+
322
+ def change_color(self,view, event):
323
+ colorvalue =
324
+ "#ff"+self.get_rand_hex_byte()+self.get_rand_hex_byte()+self.get_rand_hex_byte()
325
+ self.views.txt_colorbox.background=colorvalue
326
+
327
+ def get_rand_hex_byte(self):
328
+ j = random.randint(0,255)
329
+ hexrep = hex(j)[2:]
330
+ if(len(hexrep)==1):
331
+ hexrep = '0'+hexrep
332
+ return hexrep
333
+ ````
334
+
335
+ - 4. Initialize the fullscreen wrapper (FullScreenWrapper), display the layout, and execute the event loop
336
+ After setting up the layout class, in the main function, first use Android.Android() initializes the framework. Then use FullScreenWrapper2App.show_layout() to display the layout and start the event loop (EventLoop).
337
+
338
+ ````python
339
+ if __name__ == '__main__':
340
+ import androidhelper
341
+ droid = androidhelper.Android()
342
+ random.seed()
343
+ FullScreenWrapper2App.initialize(droid)
344
+ FullScreenWrapper2App.show_layout(DemoLayout())
345
+ FullScreenWrapper2App.eventloop()
346
+
347
+ ````
348
+
349
+ - 5. Integration
350
+ For simple XML layouts, you can just define the layout in a string variable in the module. However, as the app becomes more complex, you may need to load it from an SD card file or even the Internet.
351
+
352
+ ````python
353
+ import androidhelper, random
354
+ from fullscreenwrapper import *
355
+
356
+ class DemoLayout(Layout):
357
+ def __init__(self):
358
+ super(DemoLayout,self).__init__(xmldata,"FullScreenWrapper Demo")
359
+
360
+ def on_show(self):
361
+ self.add_event(key_EventHandler(handler_function=self.close_app))
362
+ self.views.but_change.add_event(click_EventHandler(self.views.but_change,
363
+ self.change_color))
364
+ self.views.but_exit.add_event(click_EventHandler(self.views.but_exit, self.close_app))
365
+ self.views.txt_colorbox.background="#ffffffff"
366
+
367
+ def on_close(self):
368
+ pass
369
+
370
+ def close_app(self,view,event):
371
+ FullScreenWrapper2App.exit_FullScreenWrapper2App()
372
+
373
+ def change_color(self,view, event):
374
+ colorvalue =
375
+ "#ff"+self.get_rand_hex_byte()+self.get_rand_hex_byte()+self.get_rand_hex_byte()
376
+ self.views.txt_colorbox.background=colorvalue
377
+
378
+ def get_rand_hex_byte(self):
379
+ j = random.randint(0,255)
380
+ hexrep = hex(j)[2:]
381
+ if(len(hexrep)==1):
382
+ hexrep = '0'+hexrep
383
+ return hexrep
384
+
385
+ if __name__ == '__main__':
386
+ droid = androidhelper.Android()
387
+ random.seed()
388
+ FullScreenWrapper2App.initialize(droid)
389
+ FullScreenWrapper2App.show_layout(DemoLayout())
390
+ FullScreenWrapper2App.eventloop()
391
+ ````
392
+
393
+ ## Notes
394
+ - To update the contents of ListView, you need to call the set_listitems method
395
+ </QPython fullscreenwapper module details>
396
+
397
+ <PGPT API Service>
398
+ PGPT API cloud service aims to provide developers with a one-stop service that integrates multiple AIGC service provider APIs, and can provide developers with a variety of API services including but not limited to translation, AI drawing, content summarization, content generalization, etc. The API services currently provided are as follows:
399
+
400
+ ## Translation interface Translate
401
+ Translate AI uses the latest innovative technology in machine translation to instantly or batch translate text in more than 100 languages, supporting a wide range of use cases.
402
+
403
+ Usage example
404
+ > Translate request demonstration
405
+
406
+ ````python
407
+ import request
408
+
409
+ HOST = 'https://ai.pgpt.cloud'
410
+ API_KEY = '<YOUR_API_KEY>'
411
+
412
+ header = {
413
+ "Content-Type": "application/json",
414
+ "Authorization": f"Bearer {API_KEY}",
415
+ }
416
+ payload = {
417
+ "to_lang": ['zh-Hans', 'pt', 'en'],
418
+ "text": "I love China"
419
+ }
420
+
421
+ res = requests.post(
422
+ url=f"{HOST}/v1/translate/",
423
+ headers=headers,
424
+ json=payload,
425
+ )
426
+ print(res.json())
427
+
428
+ ````
429
+
430
+ > Return example
431
+
432
+ ````json
433
+ { "translations": [
434
+ [
435
+ { "text": "我爱中国",
436
+ "to": "zh-Hans" },
437
+ { "text": "Eu amo a China",
438
+ "to": "pt" },
439
+ { "text": "I love China",
440
+ "to": "en" }
441
+ ]
442
+ ]
443
+ }
444
+ ````
445
+
446
+ Parameters
447
+ - Endpoint: https://ai.pgpt.cloud/v1/translate/
448
+ - Method: POST
449
+ - Request Body:
450
+ - Parameter text `string | array` required: text content to be translated
451
+ - Parameter to_lang `array` required: language to translate the text into
452
+
453
+ - Response:
454
+ - Parameter translations `array`: return a list of all translated texts according to the translation language specified in the request parameter `to_lang`, including the translated text content and language
455
+ { text | translated text
456
+ to | translation language }
457
+ </PGPT API service>
458
+
459
+ <QPython WEB application>
460
+ ## What framework can be used for development
461
+ It is recommended to use the Bottle framework, which is the built-in WEB development framework of QPython.
462
+
463
+ ## How to develop a QPython WEB application
464
+ - 1. First, you need to add the following definition to the header of your QPython WEB application:
465
+ ````python
466
+ #qpy:webapp:<application title>
467
+ #qpy://<webapp-address>:<webapp-port>/<webapp-path>
468
+ #-*- coding: utf8; -*-
469
+ ````
470
+ Where:
471
+ - webapp-address: indicates the address bound when the WEB application is running
472
+ - webapp-port: indicates the port bound when the WEB application is running
473
+ - webapp-path: indicates the entry path for the WEB application to run
474
+
475
+ ````python
476
+ #qpy:webapp:Hello QPython
477
+ #qpy://127.0.0.1:8080/
478
+ #-*- coding: utf8; -*-
479
+ ````
480
+
481
+ - 2. Use the WEB development framework Bottle to develop a WEB Apply and initialize an instance, ensuring that the address, port, and default entry path of the program are <webapp-address>, <webapp-port>, <webapp-path> respectively when the program is running
482
+
483
+ For example:
484
+ ````python
485
+ import os
486
+ from bottle import Bottle, ServerAdapter
487
+ from bottle import run, debug, route, error, static_file, template
488
+
489
+ ### QPYTHON WEB SERVER ###
490
+ class MyWSGIRefServer(ServerAdapter):
491
+ server = None
492
+
493
+ def run(self, handler):
494
+ from wsgiref.simple_server import make_server, WSGIRequestHandler
495
+ if self.quiet:
496
+ class QuietHandler(WSGIRequestHandler):
497
+ def log_request(*args, **kw): pass
498
+ self.options['handler_class'] = QuietHandler
499
+ self.server = make_server(self.host, self.port, handler, **self.options)
500
+ self.server.serve_forever()
501
+
502
+ def stop(self):
503
+ #sys.stderr.close()
504
+ import threading
505
+ threading.Thread(target=self.server.shutdown).start()
506
+ #self.server.shutdown()
507
+ self.server.server_close() #<--- alternative but causes bad fd exception
508
+
509
+ app = Bottle()
510
+ ````
511
+
512
+ - 3. Implement the business processing functions corresponding to the WEB application and define the routes and request methods for them in the WEB application instance
513
+ - In order to respond normally to the closure of the QPython WEB application, you need to implement a function that responds to GET requests to http://<webapp-address>:<webapp-port>/__exit, and handle the exit and closure of the WEB application in this function
514
+ - In order to respond normally to the health check QPython WEB application, you need to implement a function that responds to GET requests to http://<webapp-address>:<webapp-port>/__ping, and handle the health check of the WEB application in this function
515
+ - If you need to respond to static resources, you need to define the routes and request types for them in the WEB application instance
516
+ - Other functions of the WEB application also need to define the routes and response request types in the WEB application instance
517
+ - Each WEB application function needs to add a decorator like @route('<corresponding route>')
518
+
519
+ For example:
520
+ ````python
521
+
522
+ ### Define routes and response methods for functions in a web application instance
523
+ @route('/__exit', method=['GET','HEAD'])
524
+ def __exit():
525
+ global server
526
+ server.stop()
527
+
528
+ @route('/__ping')
529
+ def __ping():
530
+ return "ok"
531
+
532
+ @route('/assets/<filepath:path>')
533
+ def server_static(filepath):
534
+ return static_file(filepath, root=os.path.dirname(os.path.abspath(__file__)))
535
+
536
+ @route('/')
537
+ def home():
538
+ name='QPython home'
539
+ cont=f'''<h1>Hello {name} !</h1><a href="/smile/">Smile</a>'''
540
+ return template(cont)
541
+
542
+ @route('/smile')
543
+ def smile():
544
+ name='QPython Smile'
545
+ file=os.path.basename(__file__)
546
+ cont=f'''<h1>Hello {name} !</h1><a href="/assets/{file}">View source</a><br><br>
547
+ <a href="__exit">>> Exit</a><br>
548
+ <a href="https://www.qpython.org">>> About QPython Web App</a>'''
549
+ return template(cont)
550
+
551
+ #...
552
+ #...
553
+
554
+ ### Mapping link corresponding to route
555
+ app.route('/__exit', method=['GET','HEAD'])(__exit)
556
+ app.route('/__ping', method=['GET','HEAD'])(__ping)
557
+ app.route('/assets/<filepath:path>', method='GET')(server_static)
558
+ app.route('/', method='GET')(home)
559
+ app.route('/smile', method='GET')(smile)
560
+
561
+ ````
562
+
563
+ - 3. Finally integrate it together
564
+ ````python main
565
+ #qpy:webapp:Hello QPython
566
+ #qpy://127.0.0.1:8080/
567
+ #-*- coding: utf8; -*-
568
+ import os
569
+ from bottle import Bottle, ServerAdapter
570
+ from bottle import run, debug, route, error, static_file, template
571
+
572
+ ### QPYTHON WEB SERVER ###
573
+ class MyWSGIRefServer(ServerAdapter):
574
+ server = None
575
+
576
+ def run(self, handler):
577
+ from wsgiref.simple_server import make_server, WSGIRequestHandler
578
+ if self.quiet:
579
+ class QuietHandler(WSGIRequestHandler):
580
+ def log_request(*args, **kw): pass
581
+ self.options['handler_class'] = QuietHandler
582
+ self.server = make_server(self.host, self.port, handler, **self.options)
583
+ self.server.serve_forever()
584
+
585
+ def stop(self):
586
+ #sys.stderr.close()
587
+ import threading
588
+ threading.Thread(target=self.server.shutdown).start()
589
+ #self.server.shutdown()
590
+ self.server.server_close() #<--- alternative but causes bad fd exception
591
+ print("# qpyhttpd stop")
592
+
593
+
594
+ ### BUILT-IN ROUTERS ###
595
+ @route('/__exit', method=['GET','HEAD'])
596
+ def __exit():
597
+ global server
598
+ server.stop()
599
+
600
+ @route('/__ping')
601
+ def __ping():
602
+ return "ok"
603
+
604
+ @route('/')
605
+ def home():
606
+ name='QPython home'
607
+ cont=f'''<h1>Hello {name}!</h1><a href="/smile/">Smile</a>'''
608
+ return template(cont)
609
+
610
+ @route('/smile')
611
+ def smile():
612
+ name='QPython Smile'
613
+ file=os.path.basename(__file__)
614
+ cont=f'''<h1>Hello {name} !</h1><a href="/assets/{file}">View source</a><br><br>
615
+ <a href="__exit">>> Exit</a><br>
616
+ <a href="https://www.qpython.org">>> About QPython Web App</a>'''
617
+ return template(cont)
618
+
619
+
620
+ ### WEBAPP ROUTERS ###
621
+ app = Bottle()
622
+ app.route('/__exit', method=['GET','HEAD'])(__exit)
623
+ app.route('/__ping', method=['GET','HEAD'])(__ping)
624
+ app.route('/assets/<filepath:path>', method='GET')(server_static)
625
+ app.route('/', method='GET')(home)
626
+ app.route('/smile', method='GET')(smile)
627
+
628
+ try:
629
+ server = MyWSGIRefServer(host="127.0.0.1", port="8080") # 127.0.0.1:8080 is bound here. The address and port are exactly the address and port defined in the header
630
+ app.run(server=server,reloader=False)
631
+ except (Exception) as ex:
632
+ print("Exception: %s" % repr(ex))
633
+ ````
634
+ </QPython WEB Application>
635
+
636
+ <QPython androidhelper module details>
637
+ As the interface for QPython to drive Android work, the usage of the androidhelper module is as follows:
638
+ ````python
639
+ import androidhelper
640
+ droid = androidhelper.Android()
641
+ droid.viewHtml("https://www.qpython.org")
642
+ ````
643
+
644
+ ## QPython androidhelper has the following interfaces that are commonly used to assist programming development:
645
+
646
+ - viewHtml(path, title=None, wait=True) : Used to call the browser to open local files or URLs; when the instruction is similar to "open with browser", this function is called
647
+ - executeQPy(scriptPath, arg=None) : Used to call the QPython Python engine to execute the scriptPath to pass the recent path; when the instruction is "run with QPY" or "execute with QPY" or "execute with QPYTHON" or "run with qpython", and only when it contains the QPY or QPYTHON keywords, this function is called
648
+ - editorOpen(path) : Used to call the QPython editor to open the specified file; when the instruction is "open with editor", this function is called
649
+ - notebookOpen(path) : Used to call QPython Notebook opens the specified note; when the command is "Open with Notebook" or "Open with Notebook", please call this function
650
+ - mediaPlay(url, targ="default", play=True) : used to call the media player to open the specified url media resource; when the command is "play" and the target is the audio screen, call this function
651
+ - videoPlay(path, wait=True) : used to call the video player to open the video file of the specified path; when the command is "play" and the target is a video or picture, call this function
652
+ - sendFile(path, type=None, extras=None, wait=True) : used to call the Android system's share function to share files; when the command is "share", call this function
653
+ """
654
+
655
+ try:
656
+
657
+
658
+ if os.getenv('PROMPT_ALL_QSL4A'):
659
+ other_qsl4a_funcs = ["""
660
+
661
+ ## All interfaces of QPython androidhelper
662
+ As an extension and supplement to SL4A, the androidhelper module has more features, supporting users to make more powerful extensions to Android phones, which are:
663
+ """]
664
+
665
+ from androidhelper import Android
666
+ droid = Android()
667
+ for item_name in dir(droid):
668
+ item = getattr(droid, item_name)
669
+ if item_name[0] != '_' and item!=None:
670
+ line = get_first_two_lines(item.__doc__)
671
+ other_qsl4a_funcs.append(f"\n- {line}") if line else None
672
+
673
+ SYSTEM_PROMPT += "\n".join(other_qsl4a_funcs)
674
+ else:
675
+ pass
676
+
677
+
678
+ SYSTEM_PROMPT += """
679
+ </QPython androidhelper module details>
680
+ """
681
+
682
+ except:
683
+ pass
684
+
685
+ def get_system_prompt(settings):
686
+ pass
687
+
688
+ #print(SYSTEM_PROMPT)