Tuesday, June 13, 2023

Unleash Your Voice: Empowering Self-Expression through Voice Cloning

Unlock the power of your unique voice with cutting-edge voice cloning technology. Now you can effortlessly clone your own voice, capturing every nuance and tone, without relying on any specific brand or product. Dive into the realm of personalized audio expression and bring your ideas to life like never before. With our innovative voice cloning solution, your voice becomes your ultimate tool for creativity and self-expression. Discover the freedom to mold your voice in exciting ways, opening up a world of endless possibilities. Embrace the future of voice cloning and unleash your voice's true potential.

In this article, I will show how to clone your own voice. It requires knowledge of Python though but I think some websites already offer  a paid subscription that will enable you to clone your own voice.

To create a Python voice cloner program using Real-Time-Voice-Cloning (RTVC), you'll need to install the necessary libraries and follow a step-by-step process. Here's a general outline of the steps involved:

Install dependencies:

  • Install Python 3.x (if not already installed)
  • Install the required libraries by running the following commands:

pip install tensorflow==1.15
pip install numba==0.48
pip install SoundFile
pip install unidecode
pip install librosa

Clone the Real-Time-Voice-Cloning repository:

git clone https://github.com/CorentinJ/Real-Time-Voice-Cloning.git

Download the pretrained models:

  • Download the "pretrained.zip" file from the following link: https://github.com/CorentinJ/Real-Time-Voice-Cloning/releases/tag/v1.1-pretrained
  • Extract the contents of the zip file into the cloned repository folder.

Create a Python script for the voice cloner:

Import the necessary modules
import sys
import os
import numpy as np
import librosa
import argparse
from synthesizer.inference import Synthesizer
from encoder import inference as encoder
from vocoder import inference as vocoder
from pathlib import Path

Set up paths to the model files:

encoder_weights = Path("pretrained/encoder/saved_models/pretrained.pt")
vocoder_weights = Path("pretrained/vocoder/saved_models/pretrained/pretrained.pt")
syn_dir = Path("pretrained/synthesizer/saved_models/logs-pretrained/taco_pretrained")

Initialize the models:

encoder.load_model(encoder_weights)
synthesizer = Synthesizer(syn_dir)
vocoder.load_model(vocoder_weights)

Define a function for cloning the voice:

def clone_voice(input_file, output_file):

    # Load input audio
    audio, sr = librosa.load(input_file, 22050)
    # Preprocess audio
    wav = encoder.preprocess_wav(audio, sr)
    # Extract speaker embeddings
    speaker_embed = encoder.embed_utterance(wav)
    # Synthesize cloned voice
    specs = synthesizer.synthesize_spectrograms([input_text], [speaker_embed])
    generated_wav = vocoder.infer_waveform(specs[0])
    # Save synthesized audio
    librosa.output.write_wav(output_file, generated_wav, synthesize_sample_rate)

Parse command-line arguments:

parser = argparse.ArgumentParser(description="Python Voice Cloner")
parser.add_argument("--input_file", help="Path to input audio file")
parser.add_argument("--output_file", help="Path to output cloned audio file")
args = parser.parse_args()

Clone the voice:

clone_voice(args.input_file, args.output_file)

Run the Python script:

Open a terminal or command prompt and navigate to the cloned repository folder.
Execute the Python script with the appropriate command-line arguments:
python voice_cloner.py --input_file path/to/input.wav --output_file path/to/output.wav

Ensure that you have a suitable input audio file and specify the paths to the input and output files accordingly. The script will generate a cloned version of the input voice in the specified output file.

Please note that Real-Time 


Reference:



Tuesday, May 30, 2023

Building a Product Information Retrieval System with ChatGPT, Flask, and PyQt6

 Introduction:

In this article, we will explore how to train ChatGPT, a powerful language model, to retrieve specific product information. We will build a web API using Flask and create a user interface using PyQt6. Users will be able to enter questions about a product, and ChatGPT will generate responses with relevant product information.

Section 1: Setting up the Flask API

  1. Install Flask and set up a new Flask project.
  2. Define the necessary routes for handling API requests, such as /retrieve_info for retrieving product information.
  3. Implement the logic for processing user questions and generating responses using ChatGPT.
  4. Integrate the ChatGPT model into the Flask API by calling the model and generating responses based on user input.

Section 2: Creating the PyQt6 User Interface

  1. Install PyQt6 and set up a new PyQt6 project.
  2. Design the user interface using the appropriate PyQt6 widgets, including a QLineEdit for entering questions, a QPushButton to execute the question, and a QTextEdit to display the conversation history.
  3. Connect the button's click event to a function that sends the user's question to the Flask API and updates the QTextEdit with the response from ChatGPT.
  4. Implement error handling and display appropriate messages to the user in case of API failures or other issues.

Section 3: Running the Application

  1. Launch the Flask API using a development server.
  2. Start the PyQt6 application and display the user interface to the user.
  3. Allow the user to enter questions and interact with ChatGPT to retrieve product information.
  4. Continuously update the QTextEdit widget with the conversation history, including the user's questions and ChatGPT's responses.

Conclusion:

By combining the power of ChatGPT, Flask, and PyQt6, we have built a robust system for retrieving specific product information. Users can now enter questions through the PyQt6 user interface, and ChatGPT will generate informative responses based on the product data. This system can be further enhanced with more training data and improved user experience features.

Additional Considerations:

  • It's important to handle security and authentication measures when deploying the Flask API to protect sensitive product information.
  • Training the ChatGPT model specifically for product information retrieval may require a dataset containing relevant product details and associated questions.
  • Implementing data caching or other optimization techniques can improve the response time of the API and enhance the user experience.

By following the steps outlined in this article, you'll be able to develop a product information retrieval system using ChatGPT, Flask, and PyQt6. Users can interact with the system through the PyQt6 user interface, and ChatGPT will provide accurate and helpful product information based on their queries.

Here is an example of a Python-Flask Program:

 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
from flask import Flask, jsonify, request

app = Flask(__name__)

# Sample product data
products = [
    {
        'id': 1,
        'name': 'Product 1',
        'description': 'Description of Product 1',
        'price': 10.99
    },
    {
        'id': 2,
        'name': 'Product 2',
        'description': 'Description of Product 2',
        'price': 19.99
    }
]

# Endpoint to retrieve all products
@app.route('/products', methods=['GET'])
def get_all_products():
    return jsonify(products)

# Endpoint to retrieve a specific product by ID
@app.route('/products/<int:product_id>', methods=['GET'])
def get_product_by_id(product_id):
    product = next((product for product in products if product['id'] == product_id), None)
    if product:
        return jsonify(product)
    else:
        return jsonify({'message': 'Product not found'}), 404

if __name__ == '__main__':
    app.run(debug=True)

In this example, we define two endpoints: /products to retrieve all products and /products/{id} to retrieve a specific product by ID. We use a simple list of dictionaries to store the product data.


To run the example, save the code in a file (e.g., app.py) and execute it using Python. The API will be available at http://localhost:5000. You can access the endpoints using tools like curl or Postman.


Here are a few example requests you can make:


  • GET http://localhost:5000/products: Retrieves all products.
  • GET http://localhost:5000/products/1: Retrieves the product with ID 1.
  • GET http://localhost:5000/products/3: Returns a "Product not found" message as there is no product with ID 3.

Feel free to modify the code according to your specific requirements and integrate it with your trading platform's existing infrastructure.

And Lastly, here is the Python-Pyqt6 program:

 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
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QLineEdit, QTextEdit, QPushButton
from PyQt6.QtGui import QTextCursor
import requests

class ChatGPTApp(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('ChatGPT Product Information')
        self.setGeometry(100, 100, 400, 400)

        self.question_label = QLabel('Enter your question:')
        self.question_input = QLineEdit()
        self.chatlog_label = QLabel('Chat Log:')
        self.chatlog_output = QTextEdit()
        self.chatlog_output.setReadOnly(True)
        self.ask_button = QPushButton('Ask')
        self.ask_button.clicked.connect(self.process_question)

        layout = QVBoxLayout()
        layout.addWidget(self.question_label)
        layout.addWidget(self.question_input)
        layout.addWidget(self.ask_button)
        layout.addWidget(self.chatlog_label)
        layout.addWidget(self.chatlog_output)

        self.setLayout(layout)

        self.base_url = 'http://127.0.0.1:5000/products'

    def process_question(self):
        question = self.question_input.text()
        if question:
            product_id = self.extract_product_code(question)
            if product_id:
                response = self.get_product_info(product_id)
                if 'message' in response:
                    answer = response['message']
                else:
                    print(response)
                    answer = response['description']
            else:
                answer = 'Invalid question format. Please enter a valid product code.'
            self.update_chatlog(question, answer)
            self.question_input.clear()

    def extract_product_code(self, question):
        # Extract numeric product code from the question
        product_code = ''.join(filter(str.isdigit, question))
        if product_code:
            return product_code
        return None

    def get_product_info(self, product_id):
        url = f'{self.base_url}/{product_id}'
        response = requests.get(url)
        if response.status_code == 200:
            return response.json()
        elif response.status_code == 404:
            return {'message': 'Product not found'}
        else:
            return {'message': 'Error occurred'}

    def update_chatlog(self, question, answer):
        log = f'User: {question}\nChatGPT: {answer}\n\n'
        self.chatlog_output.insertPlainText(log)
        self.chatlog_output.moveCursor(QTextCursor.MoveOperation.End)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    chatgpt_app = ChatGPTApp()
    chatgpt_app.show()
    sys.exit(app.exec())

To run this program, make sure you replace 'YOUR_OPENAI_API_KEY' with your actual OpenAI API key. Save the program in a Python file, for example, chatgpt_product_info.py, and execute it. You will see a PyQt6 window with an input field to enter questions, a "Ask" button to send the question to ChatGPT, and a chat log area to display the conversation history between the user and ChatGPT.

The program only answers the question "What is the description or product 1?", Feel free to modify the program to return the price, etc. Also it only detects numeric numbers in the question, so it is not really that intelligent, you need to create a Machine Learning Model to identify intelligently the product id in the question. But in this example, users are like having conversation with a human.



Note: The Python Codes in this article is generated by ChatGPT and I have yet to verify if the program is working. But do note that it is very useful already and it is meant to give an idea on how to create the program

Thursday, April 6, 2023

Hover over a word to select it then click it to print it

 Another good feature of an integrated development environment (IDE) is its ability to go to the definition of that function/variable/method/class when clicked or double clicked. It saves a lot of time especially when the project involves several thousands of lines of codes spread out over several files. To implement this function, a word must be able to be identified as the mouse hovers it and when selected, it should be clickable, In todays post, I have prepared a simple code snippet to do just that. What the program basically do is in the title itself, select a word by hovering the mouse pointer over it then click it to print it. To take this further, the program must be able to identify the word as a defined variable in the program or a class/method/function. I have already prepared a code snippet to identify if a word is a defined variable as stated on the planner in my chat application project, you may visit the logs here. The portion where I specifically mentioned this can be found at 'Plans for 03/08/2023'

Here is the code:

 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
from PyQt6.QtWidgets import QApplication, QTextEdit
from PyQt6.QtGui import QTextCursor
class HoverTextEdit(QTextEdit):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setMouseTracking(True)
        self.mousePressEvent = self.onMouseClick
        
        
    def mouseMoveEvent(self, event):
        super().mouseMoveEvent(event)
        cursor = self.cursorForPosition(event.pos())
        cursor.select(QTextCursor.SelectionType.WordUnderCursor)
        self.setTextCursor(cursor)
        
    def onMouseClick(self, event):
        super().mousePressEvent(event)
        cursor = self.textCursor()
        if cursor.hasSelection():
            selected_word = cursor.selectedText()
            print(selected_word)
if __name__ == '__main__':
    app = QApplication([])
    widget = HoverTextEdit()
    widget.show()
    app.exec()

Monday, April 3, 2023

Simple Find Function for my IDE Project

One of the key functions of a good IDE is the find function. This function is very important because based on my experience, I am having  such a hard time searching for a particular word in a 1000+ lines of codes. There are many ways to implement this like highlight all found words with the syntax hilighter so that all found words can be immediately be seen or create a small pane that enumerates the location of each found word and when clicked, the cursor will be positioned to that found word, or a combination of both, and many others. In this post I just implemented a simple way of searching a word in a QTextEdit widget by pressing contrl+f to enter the searchstring and the program will position the cursor to the first found word and select it. It is a very simple implementation and can be further modified with tons of features. 

Here is the screenshot:



Here is the code:

 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
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QDialog, QVBoxLayout, QLabel, QLineEdit, QPushButton, QShortcut, QInputDialog, QMessageBox
from PyQt5.QtGui import QKeySequence, QTextCursor, QTextCharFormat, QTextDocument
from PyQt5.QtCore import Qt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
    
    def initUI(self):
        # Create a QTextEdit widget
        self.textEdit = QTextEdit(self)
        self.setCentralWidget(self.textEdit)
        
        # Create a shortcut for the "Find" action
        findShortcut = QShortcut(QKeySequence("Ctrl+F"), self)
        findShortcut.activated.connect(self.findText)
        
        # Show the main window
        self.show() 
    def findText(self):
        # Show the find dialog box
        searchString, ok = QInputDialog.getText(self, "Find", "Find:")

        if not ok:
            return

        # Get the QTextCursor and QTextDocument
        cursor = self.textEdit.textCursor()
        document = self.textEdit.document()

        # Set the search options
        options = QTextDocument.FindFlags()
        options |= QTextDocument.FindCaseSensitively
        options |= QTextDocument.FindWholeWords  # Add this line

        # Search for the text
        count = 0
        #while True:
        cursor = document.find(searchString, cursor, options)
        #if cursor is None:
        #   break

        count += 1

        # Move the cursor to the beginning of the match and select the text
        cursor.movePosition(QTextCursor.StartOfWord)
        char_after_word = document.characterAt(cursor.position())
        print(char_after_word)
        if searchString[0] != char_after_word:
           cursor.movePosition(QTextCursor.Left, QTextCursor.MoveAnchor, len(searchString))
        cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor)
        
        self.textEdit.setTextCursor(cursor)
        self.textEdit.setFocus()

        if count == 0:
            QMessageBox.information(self, "Find", "No match found.")
        #else:
        #    QMessageBox.information(self, "Find", f"{count} matches found.")
# Create the QApplication
app = QApplication([])
# Create the MainWindow
mainWindow = MainWindow()
# Run the event loop
app.exec_()

In case where you just pressed the contro+v to paste a block of codes and you want the cursor to go back to the start(0,0) of the QTextEdit widget, you may add a keypress event. Here is the method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    def onTextChanged(self):
        # Do something when the text changes
        global paste
        #print(paste)
        #pass
    
        if paste == 1:
            self.textEdit.moveCursor(QTextCursor.Start)
            paste = 0
    def keyPressEvent(self, event):
        global paste
        # If Ctrl+V is pressed, move the cursor to the beginning of the QTextEdit widget        
        if event.modifiers() == Qt.ControlModifier and event.key() == 16777249:
            self.textEdit.moveCursor(QTextCursor.Start)
            paste = 1
        # Call the parent class's keyPressEvent to handle other key events
        super().keyPressEvent(event)  

The keypress event will not be able to move the cursor to the start position so I added another method ontextchanged to handle the cursor position and I used global variable paste to store the result in keypressevent.


Saturday, March 25, 2023

A simple Python Code for Un/Commenting multiple lines with PyQt

For everyone's benefits I am sharing my code snippet. As part of my on going personal Python IDE project, I need to find a way to somehow automate certain repetetive tasks that a python developer encounters when using an ordinary text editor like me. I encounter this scenario a lot wherein I have to comment out/uncomment several lines of codes. Or as a bonus, indenting/unindenting several lines of codes. I have prepared a simple python program to address this issue by using the following python program. I will update my actual project using this code :

  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
from PyQt5.QtWidgets import QTextEdit, QPushButton, QVBoxLayout, QApplication, QWidget, QShortcut, QMenu, QAction
from PyQt5.QtGui import QTextCursor, QKeySequence
from PyQt5.QtCore import Qt

app = QApplication([])

# Create a QTextEdit widget
text_edit = QTextEdit()

# Set the text of the widget
text_edit.setPlainText("This is a test text")

# Create a context menu for the text edit
context_menu = QMenu(text_edit)
add_hash_action = QAction("Add '#' to selected lines", context_menu)
remove_hash_action = QAction("Remove '#' from selected lines", context_menu)
add_spaces_action = QAction("Add 4 leading spaces to selected lines", context_menu)
remove_spaces_action = QAction("Remove 4 leading spaces from selected lines", context_menu)

# Define the function to be called when F3 is pressed
def insert_spaces():
    # Get the current cursor position
    cursor_position = text_edit.textCursor().position()
    cursor = text_edit.textCursor()
    selected_text = cursor.selectedText()
    # Get the text before the cursor position
    text_before_cursor = text_edit.toPlainText()[:cursor_position]
    
    # Split the text into lines
    lines = selected_text.split("\u2029")
    print(lines)
    # Add 4 spaces at the beginning of each line

    lines = ["    " + line if not line.startswith("#") else line for line in lines]
    # Join the lines and set the new text
    cursor.insertText("\n".join(lines))


# Define the function to be called when Shift+F3 is pressed
def remove_spaces():
    # Get the current cursor position and selected text
    cursor = text_edit.textCursor()
    selected_text = cursor.selectedText()

    # Split the selected text into lines
    lines = selected_text.split("\u2029")

    # Remove a 4 SPACES from the beginning of each line
    lines = [line[4:] if line.startswith("    ") else line for line in lines]

    # Replace the selected text with the modified text
    cursor.insertText("\n".join(lines))

# Define the function to add hash at the beginning of each selected line
def add_hash():
    # Get the current cursor position and selected text
    cursor = text_edit.textCursor()
    selected_text = cursor.selectedText()

    # Split the selected text into lines
    lines = selected_text.split("\u2029")
    print(lines)
    # Add a hash at the beginning of each line
    lines = ["#" + line if not line.startswith("#") else line for line in lines]

    # Replace the selected text with the modified text
    cursor.insertText("\n".join(lines))

# Define the function to remove hash from the beginning of each selected line
def remove_hash():
    # Get the current cursor position and selected text
    cursor = text_edit.textCursor()
    selected_text = cursor.selectedText()

    # Split the selected text into lines
    lines = selected_text.split("\u2029")

    # Remove a hash from the beginning of each line
    lines = [line[1:] if line.startswith("#") else line for line in lines]

    # Replace the selected text with the modified text
    cursor.insertText("\n".join(lines))
# Create a shortcut for the F3 key
shortcut_insert = QShortcut(QKeySequence("F3"), text_edit)
shortcut_insert.activated.connect(insert_spaces)

# Create a shortcut for the Shift+F3 key
shortcut_remove = QShortcut(QKeySequence("Shift+F3"), text_edit)
shortcut_remove.activated.connect(remove_spaces)

# Connect the add_spaces_action to the insert_spaces function
add_spaces_action.triggered.connect(insert_spaces)

# Connect the remove_spaces_action to the remove_spaces function
remove_spaces_action.triggered.connect(remove_spaces)

# Add the add_spaces_action and remove_spaces_action to the context menu
context_menu.addAction(add_spaces_action)
context_menu.addAction(remove_spaces_action)

# Set the context menu policy of the text edit
text_edit.setContextMenuPolicy(Qt.CustomContextMenu)
text_edit.customContextMenuRequested.connect(lambda event: context_menu.exec_(text_edit.mapToGlobal(event)))

# Create a shortcut for the F2 key to add hash
shortcut_add_hash = QShortcut(QKeySequence("F2"), text_edit)
shortcut_add_hash.activated.connect(add_hash)

# Create a shortcut for the Shift+F2 key to remove hash
shortcut_remove_hash = QShortcut(QKeySequence("Shift+F2"), text_edit)
shortcut_remove_hash.activated.connect(remove_hash)

# Connect the add_hash_action to the add_hash function
add_hash_action.triggered.connect(add_hash)

# Connect the remove_hash_action to the remove_hash function
remove_hash_action.triggered.connect(remove_hash)

# Add the add_hash_action and remove_hash_action to the context menu
context_menu.addAction(add_hash_action)
context_menu.addAction(remove_hash_action)

# Set the context menu policy of the text edit
text_edit.setContextMenuPolicy(Qt.CustomContextMenu)
text_edit.customContextMenuRequested.connect(lambda event: context_menu.exec_(text_edit.mapToGlobal(event)))

# Create a QPushButton widget
button = QPushButton("Print Selected Text")

# Define the function to be called when the button is clicked
def print_selected_text():
    selected_text = text_edit.textCursor().selectedText()
    print(f"Selected text: {selected_text}")

# Connect the button's clicked signal to the print_selected_text function
button.clicked.connect(print_selected_text)

# Create a QVBoxLayout to organize the widgets vertically
layout = QVBoxLayout()

# Add the widgets to the layout
layout.addWidget(text_edit)
layout.addWidget(button)

# Create a QWidget to hold the layout
widget = QWidget()

# Set the layout of the QWidget
widget.setLayout(layout)

# Show the QWidget
widget.show()

app.exec_()

I am also thinking of adding a feature wherein if I double-click a method, the cursor will go to the definition of that method and invent a way to make the cursor go back to its original position.

Wednesday, March 15, 2023

My Chat Application Project : 3rd Upgrade

 I uploaded the latest upgrade of my Chat Application Project to my github repository. Here is the link. To furhter check my struggles and bumps during the development you may check my logs. The latest upgrade is not so huge and the project is still a work in progress because I work 1 to 2 hours per day sometime I would work on it whenever I am in a mood. 

Here is the screenshot of the new IDE:



Here some of the upgrades:

    Chat App:

    • User can now register
    • User can now login with a password
    • Messages are now being saved in local database(SQlite3) and in the server(MySql)
    • Previous messages are now getting displayed at the chat window
    • The friend's name turns into red when that friend sends a message
    • The screen for adding a friend has been implemented but not yet working
    • The synhronization of messages(DELIVERED) between chat window and server has been implemented

    IDE:

    • Syntax Highlighting has been implemented
    • Auto Indentaion has been implemented
    • A new 'Read' pane has been added to help in proofreading a text file
    • Cursor tracking is now working(shows the row and column in realtime)
    What I am up to:
    • Currently working on the debugging window
    • Working hard to enable newly registered users add friends
   I am also planning to add the following features:
    • Planning to add comment shortcut by selecting the lines to be commented and then right click on it a context menu will appear then choose comment out selected text. It should insert the pound sign at the beginning of each line. It is also possible to insert pre formatted commenting functions such as adding comment like date and time and the project number with version number and username, etc. This will involve adding a user management system in order to identify the user editing the program and a link to the specification documents in order to identify the project number, the version, etc.
    • Planning to add a search feature wherein if it found the word, it will go to it and highlight it and there should be a status that will tell it is one out of several words it found and by pressing F7 key, it will go to the next word. 

You may test the chat app by first make sure that mysql on WAMP server is already active and by running the server first by entering python server.py and enter any letter at the textbox then click the 'Connect' button beside it. On another CMD Terminal, enter the following python popchat.py then use the following login credentials:

User: john   Password: F@c3B00p.0123

User: josh   Password: F@c3B00p.0123 

Tuesday, March 14, 2023

Detecting External Scripts in a Python Program

 Python is a popular programming language due to its simplicity, ease of use, and versatility. One of the useful tools in Python for debugging is the Python Debugger (PDB), which allows developers to interactively debug their Python code. PDB enables developers to set breakpoints, inspect variables, and step through code to help identify and resolve issues.

However, when debugging a program that imports external Python scripts, it can be challenging to detect these external scripts in PDB. The lack of visibility into external scripts can make debugging more complicated and time-consuming. In this article, we will discuss the importance of detecting external scripts in a Python program when designing a debugging window using PDB.

Figure 1: Using yesterday's post (A Better MVC Example), the sample program 
was able to detect the external python scripts



The Challenge of Debugging External Scripts
Python programs are often composed of multiple files, with each file containing classes, functions, and variables that are used across the program. These files may be located in different directories, which can make it challenging to keep track of their dependencies. External scripts are often imported into a Python program using the import statement or from statement. These external scripts may contain critical functions, classes, and variables that are essential to the program's operation.

When using PDB, the challenge arises when trying to debug a program that imports external scripts. By default, PDB only displays the current frame and does not provide visibility into external scripts. This makes it difficult to see the code in external scripts, set breakpoints, and interact with variables. This limitation can make debugging more challenging, especially if the issue is in an external script.

The Importance of Detecting External Scripts
Detecting external scripts in a Python program when designing a debugging window using PDB is crucial for efficient debugging. By detecting external scripts, developers can ensure that they have visibility into all parts of the program and can effectively debug issues.

One of the ways to detect external scripts in a Python program is to use the Abstract Syntax Tree (AST) module in Python. The AST module is part of the Python standard library and provides a way to parse Python code into an abstract syntax tree. By analyzing the AST of a Python program, developers can identify all the external scripts that the program imports. Once the external scripts are detected, they can be displayed in the debugging window, providing developers with visibility into all parts of the program.

Conclusion
In conclusion, detecting external scripts in a Python program when designing a debugging window using PDB is essential for effective debugging. By detecting external scripts, developers can ensure that they have visibility into all parts of the program and can efficiently debug issues. Python's AST module provides a way to parse Python code into an abstract syntax tree, which can be used to detect external scripts. By displaying external scripts in the debugging window, developers can have visibility into all parts of the program and effectively debug any issues.

I have prepared a simple program for this post and here is the code:


 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
import ast
import os
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QApplication, QFileDialog, QHBoxLayout, QLabel, QLineEdit, \
    QMainWindow, QPushButton, QListWidget, QVBoxLayout, QWidget, QListWidgetItem


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # Set up the main window layout
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # Add a label and QLineEdit to enter the path of the Python script
        input_layout = QHBoxLayout()
        input_label = QLabel('Python script path:')
        input_label.setFixedWidth(120)
        input_layout.addWidget(input_label)
        self.input_edit = QLineEdit()
        input_layout.addWidget(self.input_edit)
        main_layout.addLayout(input_layout)

        # Add a button to open a file dialog to select the Python script
        self.select_button = QPushButton('Select script')
        self.select_button.clicked.connect(self.select_script)
        main_layout.addWidget(self.select_button)

        # Add a label and QListWidget to display the detected Python scripts
        output_label = QLabel('Detected scripts:')
        main_layout.addWidget(output_label)
        self.output_list = QListWidget()
        main_layout.addWidget(self.output_list)

        # Set up the font for the output list
        font = QFont('Courier New', 10)
        self.output_list.setFont(font)

    def select_script(self):
        # Open a file dialog to select the Python script
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filepath, _ = QFileDialog.getOpenFileName(self, 'Select Python script', '', 'Python Files (*.py)', options=options)

        # If a filepath was selected, analyze the script and display the detected scripts
        if filepath:
            self.input_edit.setText(filepath)
            detected_scripts = self.analyze_script(filepath)
            self.display_scripts(detected_scripts)

    def analyze_script(self, filepath):
        # Parse the Python script with AST and extract the imported scripts
        with open(filepath, 'r') as f:
            source = f.read()

        tree = ast.parse(source)
        imported_scripts = set()

        for node in ast.walk(tree):
            if isinstance(node, ast.Import):
                for alias in node.names:
                    if not alias.name.startswith('_'):
                        imported_scripts.add(alias.name)
            elif isinstance(node, ast.ImportFrom):
                if not node.module.startswith('_'):
                    imported_scripts.add(node.module)

        # Find the full path of the imported scripts
        script_dir = os.path.dirname(filepath)
        detected_scripts = set()

        for script in imported_scripts:
            script_path = os.path.join(script_dir, script.replace('.', '/') + '.py')
            if os.path.exists(script_path):
                detected_scripts.add(script_path)

        return detected_scripts

    def display_scripts(self, scripts):
        # Clear the output list and add the detected scripts
        self.output_list.clear()
        for script in scripts:
            item = QListWidgetItem(script)
            item.setTextAlignment(Qt.AlignCenter)
            self.output_list.addItem(item)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setWindowTitle('Python Script Analyzer')
    window.show()
    sys.exit(app.exec_())