10000 Merge pull request #61 from yjg30737/Dev · ag-python-qt/pyqt-openai@c11ed57 · GitHub
[go: up one dir, main page]

Skip to content

Commit c11ed57

Browse files
authored
Merge pull request yjg30737#61 from yjg30737/Dev
1. support multiple languages 2. remove sd api feature 3. add feature (upload files)
2 parents 6aa4556 + b83f7ca commit c11ed57

37 files changed

+1039
-977
lines changed

README.md

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,17 @@
88

99
</div>
1010

11-
Example of using OpenAI with PyQt (Python cross-platform GUI toolkit)
11+
PyQt/PySide(Python cross-platform GUI toolkit) OpenAI Chatbot which supports more than 8 languages (you can see the list below)
1212

13-
This shows an example of using OpenAI with PyQt as a chatbot and using DALL-E or Stable Diffusion as a image generation tool.
14-
15-
Even though this project has become too huge to be called an 'example'.
13+
You can use OpenAI models(GPT4, DALL-E, etc.) with PyQt as a chatbot.
1614

1715
The major advantage of this package is that you don't need to know other language aside from Python.
1816

1917
If you want to study openai with Python-only good old desktop software, this is for you.
2018

21-
The OpenAI model this package uses is the <a href="https://platform.openai.com/docs/models/gpt-3-5">gpt-3.5-turbo</a> model(which is nearly as functional as <b>ChatGPT</b>) by default. You can use gpt-4 as well.
22-
23-
Image generation feature(DALL-E and Stable Diffusion) is also available.
19+
The OpenAI model this package uses is the <a href="https://platform.openai.com/docs/models/gpt-3-5">gpt-3.5-turbo</a> model by default. You can use gpt-4 as well.
2420

25-
<b>Stable Diffusion</b> used [DreamStudio API](https://dreamstudio.ai/). This is not entirely free like stable-diffusion-webgui.
26-
27-
But this is very lightweight and more accessible. don't need CUDA, torch, expansive PC, anything.
21+
Image generation feature(DALL-E) is also available.
2822

2923
This is using <b>sqlite</b> as a database.
3024

@@ -38,6 +32,7 @@ If you have any questions or you want to make AI related software with PyQt or P
3832

3933
## Table of Contents
4034
* [Feature](#feature)
35+
* [Supported Languages](#supported-languages)
4136
* [Requirements](#requirements)
4237
* [Preview and Usage](#preview-and-usage)
4338
* [How to Install](#how-to-install)
@@ -64,17 +59,31 @@ If you have any questions or you want to make AI related software with PyQt or P
6459
* you can <b>run this in background</b> application
6560
* notification will pop up when response is generated
6661
* you can make window stack on top or control its transparency
67-
* image generation (DALL-E, Stable Diffusion with DreamStudio API)
62+
* image generation (DALL-E)
6863
* you can copy and download the image if you want. just hover the mouse cursor over the image.
6964
* you can <b>fine-tune</b> openai with llama-index.
65+
* support text-based file uploading
66+
67+
## Supported Languages
68+
* English
69+
* Spanish
70+
* Chinese
71+
* Russian
72+
* Korean
73+
* French
74+
* German
75+
* Italian
76+
* Hindi
77+
* Arabic
78+
79+
If you have any additional languages you would like to add, please feel free to make a request by mail, issue, discord, etc at any time.
7080

7181
## Requirements
7282
* qtpy - the package allowing you to write code that works with both PyQt and PySide
7383
* PyQt5 >= 5.14 or PySide6
7484
* openai
7585
* aiohttp - for openai dependency
7686
* pyperclip - to copy prompt text from prompt generator
77-
* stability_sdk - for Stable Diffusion
7887
* jinja2 - for saving the conversation with html file
7988
* llama-index - to fine-tune
8089

@@ -160,9 +169,6 @@ In this preview, i pressed the keyboard shortcut of each actions(show beginning,
160169

161170
I made the command suggestion GUI resemble the Discord command autocomplete popup, with which a lot of people have become accustomed.
162171

163-
### Image Generation
164-
![image](https://github.com/yjg30737/pyqt-openai/assets/55078043/d0903a76-bf4f-4900-bfea-89da6f072c9d)
165-
166172
## How to Install
167173
1. git clone ~
168174
2. cd pyqt-openai
@@ -224,14 +230,10 @@ You can join pyqt-openai's <a href="https://discord.gg/cHekprskVE">Discord Serve
224230
I recommend to install sqlite management software. It's not necessary to run this app (obviously), but it's good practice to manage database about conversation history with AI and to know how this works.
225231

226232
## TODO list
227-
* DB for images (to further experiement of both DALL-E and Stable Diffusion or other image generation engine)
228233
* show the explanation of every model and terms related to AI (e.g. temperature, topp..)
229234
* tokenizer
230235
* highlight the source (optional, eventually)
231-
* support multiple language
232-
* use SQLAlchemy (maybe not)
233236
* show reason when the chat input is disabled for some reasons
234-
* add the basic example sources of making deep learning model with PyTorch (eventually)
235237

236238
## See Also
237239
* <a href="https://learn.microsoft.com/en-us/azure/cognitive-services/openai/overview">Azure OpenAI service</a>

pyqt_openai/aboutDialog.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from qtpy.QtGui import QPixmap, QDesktopServices
33
from qtpy.QtWidgets import QDialog, QPushButton, QHBoxLayout, QWidget, QVBoxLayout, QLabel
44

5+
from pyqt_openai.res.language_dict import LangClass
56
from pyqt_openai.svgLabel import SvgLabel
67

78

@@ -24,20 +25,20 @@ def __init__(self):
2425
self.__initUi()
2526

2627
def __initUi(self):
27-
self.setWindowTitle('About')
28+
self.setWindowTitle(LangClass.TRANSLATIONS['About'])
2829
self.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint)
2930

30-
self.__okBtn = QPushButton('OK')
31+
self.__okBtn = QPushButton(LangClass.TRANSLATIONS['OK'])
3132
self.__okBtn.clicked.connect(self.accept)
3233

3334
p = QPixmap('pyqtopenai.png')
3435
logoLbl = QLabel()
3536
logoLbl.setPixmap(p)
3637

3738
expWidget = QLabel()
38-
expWidget.setText('''
39+
expWidget.setText(f'''
3940
<h1>pyqt-openai</h1>
40-
<p>Powered by qtpy</p>
41+
<p>{LangClass.TRANSLATIONS['Powered by qtpy']}</p>
4142
''')
4243
expWidget.setAlignment(Qt.AlignTop)
4344

@@ -75,7 +76,7 @@ def __initUi(self):
7576
topWidget = QWidget()
7677
topWidget.setLayout(lay)
7778

78-
cancelBtn = QPushButton('Cancel')
79+
cancelBtn = QPushButton(LangClass.TRANSLATIONS['Cancel'])
7980
cancelBtn.clicked.connect(self.close)
8081

8182
lay = QHBoxLayout()

pyqt_openai/chat_widget/chatBrowser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from pyqt_openai.chat_widget.aiChatUnit import AIChatUnit
77
from pyqt_openai.chat_widget.userChatUnit import UserChatUnit
8+
from pyqt_openai.res.language_dict import LangClass
89

910

1011
class ChatBrowser(QScrollArea):
@@ -19,7 +20,7 @@ def __initVal(self):
1920
self.__cur_id = 0
2021

2122
def __initUi(self):
22-
self.__homeWidget = QLabel('Home')
23+
self.__homeWidget = QLabel(LangClass.TRANSLATIONS['Home'])
2324
self.__homeWidget.setAlignment(Qt.AlignCenter)
2425
self.__homeWidget.setFont(QFont('Arial', 32))
2526

pyqt_openai/chat_widget/prompt.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import os
2+
13
from qtpy.QtCore import Qt
2-
from qtpy.QtWidgets import QVBoxLayout, QToolButton, QMenu, QAction, QWidget, QHBoxLayout
4+
from qtpy.QtWidgets import QVBoxLayout, QFileDialog, QToolButton, QMenu, QAction, QWidget, QHBoxLayout
35

46
from pyqt_openai.chat_widget.textEditPropmtGroup import TextEditPropmtGroup
57
from pyqt_openai.propmt_command_completer.commandSuggestionWidget import CommandSuggestionWidget
8+
from pyqt_openai.res.language_dict import LangClass
69
from pyqt_openai.sqlite import SqliteDatabase
710
from pyqt_openai.svgToolButton import SvgToolButton
811

@@ -47,31 +50,35 @@ def __initUi(self):
4750

4851
settingsBtn = SvgToolButton()
4952
settingsBtn.setIcon('ico/vertical_three_dots.svg')
50-
settingsBtn.setToolTip('Prompt Settings')
53+
settingsBtn.setToolTip(LangClass.TRANSLATIONS['Prompt Settings'])
5154

5255
# Create the menu
5356
menu = QMenu(self)
5457

5558
# Create the actions
56-
beginningAction = QAction("Show Beginning", self)
59+
beginningAction = QAction(LangClass.TRANSLATIONS['Show Beginning'], self)
5760
beginningAction.setShortcut('Ctrl+B')
5861
beginningAction.setCheckable(True)
5962
beginningAction.toggled.connect(self.__showBeginning)
6063

61-
endingAction = QAction("Show Ending", self)
64+
endingAction = QAction(LangClass.TRANSLATIONS['Show Ending'], self)
6265
endingAction.setShortcut('Ctrl+E')
6366
endingAction.setCheckable(True)
6467
endingAction.toggled.connect(self.__showEnding)
6568

66-
supportPromptCommandAction = QAction('Support Prompt Command', self)
69+
supportPromptCommandAction = QAction(LangClass.TRANSLATIONS['Support Prompt Command'], self)
6770
supportPromptCommandAction.setShortcut('Ctrl+Shift+P')
6871
supportPromptCommandAction.setCheckable(True)
6972
supportPromptCommandAction.toggled.connect(self.__supportPromptCommand)
7073

74+
readingFilesAction = QAction(LangClass.TRANSLATIONS['Upload Files...'], self)
75+
readingFilesAction.triggered.connect(self.__readingFiles)
76+
7177
# Add the actions to the menu
7278
menu.addAction(beginningAction)
7379
menu.addAction(endingAction)
7480
menu.addAction(supportPromptCommandAction)
81+
menu.addAction(readingFilesAction)
7582

7683
# Connect the button to the menu
7784
settingsBtn.setMenu(menu)
@@ -183,4 +190,22 @@ def __showEnding(self, f):
183190

184191
def __supportPromptCommand(self, f):
185192
self.__commandEnabled = f
186-
self.__textEditGroup.setCommandEnabled(f)
193+
self.__textEditGroup.setCommandEnabled(f)
194+
195+
def __readingFiles(self):
196+
filenames = QFileDialog.getOpenFileNames(self, 'Find', '', 'All Files (*.*)')
197+
if filenames[0]:
198+
filenames = filenames[0]
199+
source_context = ''
200+
for filename in filenames:
201+
base_filename = os.path.basename(filename)
202+
source_context += f'=== {base_filename} start ==='
203+
source_context += '\n'*2
204+
with open(filename, 'r', encoding='utf-8') as f:
205+
source_context += f.read()
206+
source_context += '\n'*2
207+
source_context += f'=== {base_filename} end ==='
208+
source_context += '\n'*2
209+
prompt_context = f'== Source Start ==\n{source_context}== Source End =='
210+
211+
self.__textEditGroup.getGroup()[1].setText(prompt_context)

pyqt_openai/chat_widget/textEditPropmtGroup.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from qtpy.QtWidgets import QVBoxLayout, QWidget
44

55
from pyqt_openai.chat_widget.textEditPrompt import TextEditPrompt
6+
from pyqt_openai.res.language_dict import LangClass
67
from pyqt_openai.sqlite import SqliteDatabase
78

89

@@ -21,18 +22,18 @@ def __initVal(self, db):
2122

2223
def __initUi(self):
2324
self.__beginningTextEdit = TextEditPrompt()
24-
self.__beginningTextEdit.setPlaceholderText('Beginning')
25+
self.__beginningTextEdit.setPlaceholderText(LangClass.TRANSLATIONS['Beginning'])
2526

2627
self.__textEdit = TextEditPrompt()
27-
self.__textEdit.setPlaceholderText('Write some text...')
28+
self.__textEdit.setPlaceholderText(LangClass.TRANSLATIONS['Write some text...'])
2829

2930
# old code
3031
# self.__textEdit.textChanged.connect(self.textChanged)
3132
# self.__textEdit.sendSuggestionWidget.connect(self.__initPromptCommandAutocomplete)
32-
# self.__textEdit.setPlaceholderText('Write some text...')
33+
# self.__textEdit.setPlaceholderText(LangClass.TRANSLATIONS['Write some text...'])
3334

3435
self.__endingTextEdit = TextEditPrompt()
35-
self.__endingTextEdit.setPlaceholderText('Ending')
36+
self.__endingTextEdit.setPlaceholderText(LangClass.TRANSLATIONS['Ending'])
3637

3738
# all false by default
3839
self.__beginningTextEdit.setVisible(False)

pyqt_openai/chat_widget/userChatUnit.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ def __initUi(self):
3131
menuWidget.setStyleSheet('QWidget { background-color: #BBB }')
3232

3333
self.__lbl = QLabel()
34-
self.__lbl.setStyleSheet('QLabel { padding: 1em }')
34+
self.__lbl.setStyleSheet('QLabel { padding: 6px }')
3535

36-
self.__lbl.setAlignment(Qt.AlignRight)
36+
self.__lbl.setAlignment(Qt.AlignLeft)
3737
self.__lbl.setWordWrap(True)
3838
self.__lbl.setTextInteractionFlags(Qt.TextSelectableByMouse)
3939
self.__lbl.setOpenExternalLinks(True)

pyqt_openai/customizeDialog.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from qtpy.QtWidgets import QGraphicsScene, QGraphicsView
1111

1212
from pyqt_openai.circleProfileImage import RoundedImage
13+
from pyqt_openai.res.language_dict import LangClass
1314

1415

1516
class SingleImageGraphicsView(QGraphicsView):
@@ -72,7 +73,7 @@ def __showToolTip(self):
7273

7374
def __prepareMenu(self, pos):
7475
menu = QMenu(self)
75-
openDirAction = QAction('Open Path')
76+
openDirAction = QAction(LangClass.TRANSLATIONS['Open Path'])
7677
openDirAction.setEnabled(self.text().strip() != '')
7778
openDirAction.triggered.connect(self.__openPath)
7879
menu.addAction(openDirAction)
@@ -102,7 +103,7 @@ def __initUi(self, default_filename: str = ''):
102103
if default_filename:
103104
self.__pathLineEdit.setText(default_filename)
104105

105-
self.__pathFindBtn = QPushButton('Find...')
106+
self.__pathFindBtn = QPushButton(LangClass.TRANSLATIONS['Find...'])
106107

107108
self.__pathFindBtn.clicked.connect(self.__find)
108109

@@ -172,7 +173,7 @@ def __initVal(self):
172173
pass
173174

174175
def __initUi(self):
175-
self.setWindowTitle('Customize (working)')
176+
self.setWindowTitle(LangClass.TRANSLATIONS['Customize (working)'])
176177
self.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint)
177178

178179
homePageGraphicsView = SingleImageGraphicsView()
@@ -213,9 +214,9 @@ def __initUi(self):
213214
aiWidget.setLayout(lay3)
214215

215216
lay = QFormLayout()
216-
lay.addRow('Home Image', homePageWidget)
217-
lay.addRow('User Image', userWidget)
218-
lay.addRow('AI Image', aiWidget)
217+
lay.addRow(LangClass.TRANSLATIONS['Home Image'], homePageWidget)
218+
lay.addRow(LangClass.TRANSLATIONS['User Image'], userWidget)
219+
lay.addRow(LangClass.TRANSLATIONS['AI Image'], aiWidget)
219220

220221
self.__topWidget = QWidget()
221222
self.__topWidget.setLayout(lay)
@@ -224,10 +225,10 @@ def __initUi(self):
224225
sep.setFrameShape(QFrame.HLine)
225226
sep.setFrameShadow(QFrame.Sunken)
226227

227-
self.__okBtn = QPushButton('OK')
228+
self.__okBtn = QPushButton(LangClass.TRANSLATIONS['OK'])
228229
self.__okBtn.clicked.connect(self.accept)
229230

230-
cancelBtn = QPushButton('Cancel')
231+
cancelBtn = QPushButton(LangClass.TRANSLATIONS['Cancel'])
231232
cancelBtn.clicked.connect(self.close)
232233

233234
lay = QHBoxLayout()

pyqt_openai/image_gen_widget/currentImageView.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ def __initVal(self):
1717
self._item = ''
1818

1919
def __initUi(self):
20-
# Create a button
21-
self.button = QPushButton("Click me", self)
22-
self.button.hide()
2320
self.setMouseTracking(True)
2421

2522
def setFilename(self, filename: str):
@@ -33,17 +30,6 @@ def setFilename(self, filename: str):
3330
def setAspectRatioMode(self, mode):
3431
self.__aspectRatioMode = mode
3532

36-
def enterEvent(self, e):
37-
# Show the button when the mouse enters the view
38-
self.button.move(self.rect().x(), self.rect().y())
39-
self.button.show()
40-
return super().enterEvent(e)
41-
42-
def leaveEvent(self, e):
43-
# Hide the button when the mouse leaves the view
44-
self.button.hide()
45-
return super().leaveEvent(e)
46-
4733
def resizeEvent(self, e):
4834
if self._item:
4935
self.fitInView(self.sceneRect(), self.__aspectRatioMode)

pyqt_openai/image_gen_widget/imageDallEPage.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from qtpy.QtCore import Signal, QThread
55

66
from pyqt_openai.notifier import NotifierWidget
7+
from pyqt_openai.res.language_dict import LangClass
78
from pyqt_openai.toast import Toast
89

910

@@ -50,13 +51,13 @@ def __initUi(self):
5051
self.__sizeCmbBox.currentTextChanged.connect(self.__sizeChanged)
5152

5253
self.__promptWidget = QPlainTextEdit()
53-
self.__submitBtn = QPushButton('Submit')
54+
self.__submitBtn = QPushButton(LangClass.TRANSLATIONS['Submit'])
5455
self.__submitBtn.clicked.connect(self.__submit)
5556

5657
lay = QFormLayout()
57-
lay.addRow('Total', self.__nSpinBox)
58-
lay.addRow('Size', self.__sizeCmbBox)
59-
lay.addRow(QLabel('Prompt'))
58+
lay.addRow(LangClass.TRANSLATIONS['Total'], self.__nSpinBox)
59+
lay.addRow(LangClass.TRANSLATIONS['Size'], self.__sizeCmbBox)
60+
lay.addRow(QLabel(LangClass.TRANSLATIONS['Prompt']))
6061
lay.addRow(self.__promptWidget)
6162
lay.addRow(self.__submitBtn)
6263

@@ -96,7 +97,7 @@ def __failToGenerate(self, e):
9697
def __afterGenerated(self, image_url):
9798
self.submitDallE.emit(image_url)
9899
if not self.isVisible():
99-
self.__notifierWidget = NotifierWidget(informative_text='Response 👌', detailed_text='Click this!')
100+
self.__notifierWidget = NotifierWidget(informative_text=LangClass.TRANSLATIONS['Response 👌'], detailed_text=LangClass.TRANSLATIONS['Click this!'])
100101
self.__notifierWidget.show()
101102
self.__notifierWidget.doubleClicked.connect(self.notifierWidgetActivated)
102103
self.__submitBtn.setEnabled(True)

0 commit comments

Comments
 (0)
0