mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-02-10 17:20:19 -05:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e3a2b5a64c | |||
| 0ae12e0fc6 | |||
| 793b855819 | |||
| 8e052ff45c | |||
| 2fb876ff00 | |||
| cd1a9e16e0 | |||
| f07610df5c | |||
| 7cd35082b2 | |||
| c1dd59e65c | |||
| faaf59f163 | |||
| 539a220771 |
@ -54,4 +54,5 @@ add_qtc_plugin(QodeAssist
|
||||
settings/CustomPromptSettings.hpp settings/CustomPromptSettings.cpp
|
||||
settings/PresetPromptsSettings.hpp settings/PresetPromptsSettings.cpp
|
||||
settings/SettingsUtils.hpp
|
||||
core/ChangesManager.h core/ChangesManager.cpp
|
||||
)
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "LLMProvidersManager.hpp"
|
||||
#include "PromptTemplateManager.hpp"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "core/ChangesManager.h"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
|
||||
@ -277,14 +278,19 @@ ContextData LLMClientInterface::prepareContext(const QJsonObject &request,
|
||||
|
||||
DocumentContextReader reader(widget->textDocument());
|
||||
|
||||
QString recentChanges = ChangesManager::instance().getRecentChangesContext(textDocument);
|
||||
|
||||
QString contextBefore = сontextBefore(widget, lineNumber, cursorPosition);
|
||||
QString contextAfter = сontextAfter(widget, lineNumber, cursorPosition);
|
||||
QString instructions = QString("%1%2").arg(Settings::contextSettings().useSpecificInstructions()
|
||||
? reader.getSpecificInstructions()
|
||||
: QString(),
|
||||
Settings::contextSettings().useFilePathInContext()
|
||||
? reader.getLanguageAndFileInfo()
|
||||
: QString());
|
||||
QString instructions
|
||||
= QString("%1%2%3").arg(Settings::contextSettings().useSpecificInstructions()
|
||||
? reader.getSpecificInstructions()
|
||||
: QString(),
|
||||
Settings::contextSettings().useFilePathInContext()
|
||||
? reader.getLanguageAndFileInfo()
|
||||
: QString(),
|
||||
Settings::contextSettings().useProjectChangesCache() ? recentChanges
|
||||
: QString());
|
||||
|
||||
return {QString("%1%2").arg(contextBefore, accumulatedCompletion), contextAfter, instructions};
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"Name" : "QodeAssist",
|
||||
"Version" : "0.1.0",
|
||||
"Version" : "0.1.2",
|
||||
"CompatVersion" : "${IDE_VERSION_COMPAT}",
|
||||
"Vendor" : "Petr Mironychev",
|
||||
"Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} Petr Mironychev, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd",
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
|
||||
#include "LLMClientInterface.hpp"
|
||||
#include "LLMSuggestion.hpp"
|
||||
#include "core/ChangesManager.h"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
|
||||
using namespace LanguageServerProtocol;
|
||||
@ -83,6 +85,13 @@ void QodeAssistClient::openDocument(TextEditor::TextDocument *document)
|
||||
auto textEditor = BaseTextEditor::currentTextEditor();
|
||||
if (!textEditor || textEditor->document() != document)
|
||||
return;
|
||||
|
||||
if (Settings::contextSettings().useProjectChangesCache())
|
||||
ChangesManager::instance().addChange(document,
|
||||
position,
|
||||
charsRemoved,
|
||||
charsAdded);
|
||||
|
||||
TextEditorWidget *widget = textEditor->editorWidget();
|
||||
if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors())
|
||||
return;
|
||||
|
||||
@ -59,6 +59,8 @@ const char API_KEY[] = "QodeAssist.apiKey";
|
||||
const char USE_SPECIFIC_INSTRUCTIONS[] = "QodeAssist.useSpecificInstructions";
|
||||
const char USE_FILE_PATH_IN_CONTEXT[] = "QodeAssist.useFilePathInContext";
|
||||
const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate";
|
||||
const char USE_PROJECT_CHANGES_CACHE[] = "QodeAssist.useProjectChangesCache";
|
||||
const char MAX_CHANGES_CACHE_SIZE[] = "QodeAssist.maxChangesCacheSize";
|
||||
|
||||
const char QODE_ASSIST_GENERAL_OPTIONS_ID[] = "QodeAssist.GeneralOptions";
|
||||
const char QODE_ASSIST_GENERAL_SETTINGS_PAGE_ID[] = "QodeAssist.1GeneralSettingsPageId";
|
||||
|
||||
60
README.md
60
README.md
@ -1,8 +1,10 @@
|
||||
# QodeAssist
|
||||
[](https://github.com/Palm1r/QodeAssist/actions/workflows/build_cmake.yml) [](https://ko-fi.com/petrmdev)
|
||||
[](https://github.com/Palm1r/QodeAssist/actions/workflows/build_cmake.yml)
|
||||
|
||||
QodeAssist is an AI-powered coding assistant plugin for Qt Creator. It provides intelligent code completion and suggestions for C++ and QML, leveraging large language models through local providers like Ollama. Enhance your coding productivity with context-aware AI assistance directly in your Qt development environment.
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/255a52f1-5cc0-4ca3-b05c-c4cf9cdbe25a" width="600" alt="QodeAssistPreview">
|
||||
|
||||
## Supported LLM Providers
|
||||
QodeAssist currently supports the following LLM (Large Language Model) providers:
|
||||
- [Ollama](https://ollama.com)
|
||||
@ -10,25 +12,53 @@ QodeAssist currently supports the following LLM (Large Language Model) providers
|
||||
- OpenAI compatible providers
|
||||
|
||||
## Supported Models
|
||||
QodeAssist has been tested with the following language models, all trained for Fill-in-theMiddle:
|
||||
|
||||
Ollama:
|
||||
- [starcoder2](https://ollama.com/library/starcoder2)
|
||||
- [codellama](https://ollama.com/library/codellama)
|
||||
QodeAssist has been thoroughly tested and optimized for use with the following language models, all of which are specifically trained for Fill-in-the-Middle (FIM) tasks:
|
||||
|
||||
- CodeLlama
|
||||
- StarCoder2
|
||||
- DeepSeek-Coder-V2-Lite-Base
|
||||
|
||||
LM studio:
|
||||
These models have demonstrated excellent performance in code completion and assistance tasks within the QodeAssist environment.
|
||||
|
||||
### Custom Prompts
|
||||
|
||||
For advanced users or those with specific requirements, QodeAssist offers the flexibility to create, save, and load custom prompts using JSON templates. This feature allows you to tailor the AI's behavior to your exact needs.
|
||||
|
||||
To get started with custom prompts:
|
||||
|
||||
1. Navigate to the "Custom Template" option in the FIM Prompt Settings.
|
||||
2. Create your custom JSON prompt template.
|
||||
3. Use the "Save Custom Template to JSON" button to store your template for future use.
|
||||
4. To use a previously saved template, click "Load Custom Template from JSON".
|
||||
5. Make sure to select "Custom Template" from the dropdown menu in the FIM Prompt Settings on the General page to activate your custom template.
|
||||
|
||||
For inspiration and examples of effective custom prompts, please refer to the `rawPromptExamples` folder in our repository.
|
||||
|
||||
<img width="600" alt="Custom template" src="https://github.com/user-attachments/assets/4a14c552-baba-4531-ab4f-cb1f9ac6620b">
|
||||
<img width="600" alt="Select custom template" src="https://github.com/user-attachments/assets/3651dafd-83f9-4df9-943f-69c28cd3d8a3">
|
||||
|
||||
### Tested Models
|
||||
|
||||
#### Ollama:
|
||||
- [starcoder2](https://ollama.com/library/starcoder2)
|
||||
- [codellama](https://ollama.com/library/codellama)
|
||||
|
||||
#### LM Studio:
|
||||
- [second-state/StarCoder2-7B-GGUF](https://huggingface.co/second-state/StarCoder2-7B-GGUF)
|
||||
- [TheBloke/CodeLlama-7B-GGUF](https://huggingface.co/TheBloke/CodeLlama-7B-GGUF)
|
||||
|
||||
Please note that while these models have been specifically tested and confirmed to work well with QodeAssist, other models compatible with the supported providers may also work. We encourage users to experiment with different models and report their experiences.
|
||||
|
||||
If you've successfully used a model that's not listed here, please let us know by opening an issue or submitting a pull request to update this list.
|
||||
|
||||
## Development Progress
|
||||
|
||||
- [x] Basic plugin with code autocomplete functionality
|
||||
- [ ] Improve and automate settings
|
||||
- [x] Improve and automate settings
|
||||
- [ ] Add chat functionality
|
||||
- [x] Sharing diff with model
|
||||
- [ ] Sharing project source with model
|
||||
- [ ] Support for more providers and models
|
||||
|
||||
## Plugin installation using Ollama as an example
|
||||
@ -48,13 +78,16 @@ ollama run starcoder2:7b
|
||||
|
||||
## Configure Plugin
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/0743d09e-1f02-44ed-9a1a-85e2a0a0c01a" width="800" alt="QodeAssist в действии">
|
||||
|
||||
1. Open Qt Creator settings
|
||||
2. Navigate to the "Qode Assist" tab
|
||||
3. Choose your LLM provider (e.g., Ollama)
|
||||
4. Select the installed model by the "Select Model" button
|
||||
3. Select "General" page
|
||||
4. Choose your LLM provider (e.g., Ollama)
|
||||
5. Select the installed model by the "Select Model" button
|
||||
- For LM Studio you will see current load model
|
||||
5. Choose the prompt template that corresponds to your model
|
||||
6. Apply the settings
|
||||
6. Choose the prompt template that corresponds to your model
|
||||
7. Apply the settings
|
||||
|
||||
You're all set! QodeAssist is now ready to use in Qt Creator.
|
||||
|
||||
@ -91,7 +124,8 @@ Verify that the selected prompt template matches the model you're using
|
||||
If you're still experiencing issues with QodeAssist, you can try resetting the settings to their default values:
|
||||
1. Open Qt Creator settings
|
||||
2. Navigate to the "Qode Assist" tab
|
||||
3. Click on the "Reset to Defaults" button
|
||||
3. Pick settings page for reset
|
||||
4. Click on the "Reset Page to Defaults" button
|
||||
- The API key will not reset
|
||||
- Select model after reset
|
||||
|
||||
@ -105,7 +139,7 @@ If you find QodeAssist helpful, there are several ways you can support the proje
|
||||
3. **Spread the Word**: Star our GitHub repository and share QodeAssist with your fellow developers.
|
||||
|
||||
4. **Financial Support**: If you'd like to support the development financially, you can make a donation using one of the following:
|
||||
- Buy me a coffee [](https://ko-fi.com/petrmdev)
|
||||
- [](https://ko-fi.com/P5P412V96G)
|
||||
- Bitcoin (BTC): `bc1qndq7f0mpnlya48vk7kugvyqj5w89xrg4wzg68t`
|
||||
- Ethereum (ETH): `0xA5e8c37c94b24e25F9f1f292a01AF55F03099D8D`
|
||||
- Litecoin (LTC): `ltc1qlrxnk30s2pcjchzx4qrxvdjt5gzuervy5mv0vy`
|
||||
|
||||
89
core/ChangesManager.cpp
Normal file
89
core/ChangesManager.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
*
|
||||
* QodeAssist is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QodeAssist is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ChangesManager.h"
|
||||
#include "QodeAssistUtils.hpp"
|
||||
#include "settings/ContextSettings.hpp"
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
ChangesManager &ChangesManager::instance()
|
||||
{
|
||||
static ChangesManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
ChangesManager::ChangesManager()
|
||||
: QObject(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ChangesManager::~ChangesManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ChangesManager::addChange(TextEditor::TextDocument *document,
|
||||
int position,
|
||||
int charsRemoved,
|
||||
int charsAdded)
|
||||
{
|
||||
auto &documentQueue = m_documentChanges[document];
|
||||
|
||||
QTextBlock block = document->document()->findBlock(position);
|
||||
int lineNumber = block.blockNumber();
|
||||
QString lineContent = block.text();
|
||||
QString fileName = document->filePath().fileName();
|
||||
|
||||
ChangeInfo change{fileName, lineNumber, lineContent};
|
||||
|
||||
auto it = std::find_if(documentQueue.begin(),
|
||||
documentQueue.end(),
|
||||
[lineNumber](const ChangeInfo &c) { return c.lineNumber == lineNumber; });
|
||||
|
||||
if (it != documentQueue.end()) {
|
||||
it->lineContent = lineContent;
|
||||
} else {
|
||||
documentQueue.enqueue(change);
|
||||
|
||||
if (documentQueue.size() > Settings::contextSettings().maxChangesCacheSize()) {
|
||||
documentQueue.dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
logMessage(QString("ChangesManager: Updated %1 line %2: '%3'")
|
||||
.arg(fileName)
|
||||
.arg(lineNumber)
|
||||
.arg(lineContent));
|
||||
logMessage(QString("ChangesManager: Document queue size %1").arg(documentQueue.size()));
|
||||
}
|
||||
|
||||
QString ChangesManager::getRecentChangesContext(const TextEditor::TextDocument *currentDocument) const
|
||||
{
|
||||
QString context;
|
||||
for (auto it = m_documentChanges.constBegin(); it != m_documentChanges.constEnd(); ++it) {
|
||||
if (it.key() != currentDocument) {
|
||||
for (const auto &change : it.value()) {
|
||||
context += change.lineContent + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist
|
||||
61
core/ChangesManager.h
Normal file
61
core/ChangesManager.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Petr Mironychev
|
||||
*
|
||||
* This file is part of QodeAssist.
|
||||
*
|
||||
* QodeAssist is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QodeAssist is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QQueue>
|
||||
#include <QTimer>
|
||||
#include <texteditor/textdocument.h>
|
||||
|
||||
namespace QodeAssist {
|
||||
|
||||
class ChangesManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct ChangeInfo
|
||||
{
|
||||
QString fileName;
|
||||
int lineNumber;
|
||||
QString lineContent;
|
||||
};
|
||||
|
||||
static ChangesManager &instance();
|
||||
|
||||
void addChange(TextEditor::TextDocument *document,
|
||||
int position,
|
||||
int charsRemoved,
|
||||
int charsAdded);
|
||||
QString getRecentChangesContext(const TextEditor::TextDocument *currentDocument) const;
|
||||
|
||||
private:
|
||||
ChangesManager();
|
||||
~ChangesManager();
|
||||
ChangesManager(const ChangesManager &) = delete;
|
||||
ChangesManager &operator=(const ChangesManager &) = delete;
|
||||
|
||||
void cleanupOldChanges();
|
||||
|
||||
QHash<TextEditor::TextDocument *, QQueue<ChangeInfo>> m_documentChanges;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist
|
||||
@ -74,6 +74,15 @@ ContextSettings::ContextSettings()
|
||||
|
||||
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
||||
|
||||
useProjectChangesCache.setSettingsKey(Constants::USE_PROJECT_CHANGES_CACHE);
|
||||
useProjectChangesCache.setDefaultValue(true);
|
||||
useProjectChangesCache.setLabelText(Tr::tr("Use Project Changes Cache"));
|
||||
|
||||
maxChangesCacheSize.setSettingsKey(Constants::MAX_CHANGES_CACHE_SIZE);
|
||||
maxChangesCacheSize.setLabelText(Tr::tr("Max Changes Cache Size"));
|
||||
maxChangesCacheSize.setRange(2, 1000);
|
||||
maxChangesCacheSize.setDefaultValue(20);
|
||||
|
||||
readSettings();
|
||||
|
||||
readStringsAfterCursor.setEnabled(!readFullFile());
|
||||
@ -85,11 +94,13 @@ ContextSettings::ContextSettings()
|
||||
setLayouter([this]() {
|
||||
using namespace Layouting;
|
||||
return Column{Row{readFullFile, Stretch{1}, resetToDefaults},
|
||||
readStringsBeforeCursor,
|
||||
readStringsAfterCursor,
|
||||
Row{readStringsBeforeCursor, Stretch{1}},
|
||||
Row{readStringsAfterCursor, Stretch{1}},
|
||||
useFilePathInContext,
|
||||
useSpecificInstructions,
|
||||
specificInstractions,
|
||||
useProjectChangesCache,
|
||||
Row{maxChangesCacheSize, Stretch{1}},
|
||||
Stretch{1}};
|
||||
});
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ public:
|
||||
Utils::StringAspect specificInstractions{this};
|
||||
Utils::BoolAspect useSpecificInstructions{this};
|
||||
Utils::BoolAspect useFilePathInContext{this};
|
||||
Utils::BoolAspect useProjectChangesCache{this};
|
||||
Utils::IntegerAspect maxChangesCacheSize{this};
|
||||
|
||||
ButtonAspect resetToDefaults{this};
|
||||
|
||||
|
||||
@ -62,22 +62,20 @@ GeneralSettings::GeneralSettings()
|
||||
multiLineCompletion.setLabelText(Tr::tr("Enable Multiline Completion"));
|
||||
|
||||
startSuggestionTimer.setSettingsKey(Constants::START_SUGGESTION_TIMER);
|
||||
startSuggestionTimer.setLabelText(Tr::tr("Start Suggestion Timer:"));
|
||||
startSuggestionTimer.setLabelText(Tr::tr("with delay(ms)"));
|
||||
startSuggestionTimer.setRange(10, 10000);
|
||||
startSuggestionTimer.setDefaultValue(500);
|
||||
|
||||
autoCompletionCharThreshold.setSettingsKey(Constants::AUTO_COMPLETION_CHAR_THRESHOLD);
|
||||
autoCompletionCharThreshold.setLabelText(
|
||||
Tr::tr("Character threshold for AI suggestion start:"));
|
||||
autoCompletionCharThreshold.setLabelText(Tr::tr("AI suggestion triggers after typing"));
|
||||
autoCompletionCharThreshold.setToolTip(
|
||||
Tr::tr("The number of characters that need to be typed within the typing interval "
|
||||
"before an AI suggestion request is sent."));
|
||||
autoCompletionCharThreshold.setRange(1, 10);
|
||||
autoCompletionCharThreshold.setDefaultValue(2);
|
||||
autoCompletionCharThreshold.setRange(0, 10);
|
||||
autoCompletionCharThreshold.setDefaultValue(0);
|
||||
|
||||
autoCompletionTypingInterval.setSettingsKey(Constants::AUTO_COMPLETION_TYPING_INTERVAL);
|
||||
autoCompletionTypingInterval.setLabelText(
|
||||
Tr::tr("Typing interval for AI suggestion start(ms):"));
|
||||
autoCompletionTypingInterval.setLabelText(Tr::tr("character(s) within(ms)"));
|
||||
autoCompletionTypingInterval.setToolTip(
|
||||
Tr::tr("The time window (in milliseconds) during which the character threshold "
|
||||
"must be met to trigger an AI suggestion request."));
|
||||
@ -138,10 +136,11 @@ GeneralSettings::GeneralSettings()
|
||||
|
||||
auto rootLayout = Column{Row{enableQodeAssist, Stretch{1}, resetToDefaults},
|
||||
enableAutoComplete,
|
||||
startSuggestionTimer,
|
||||
autoCompletionCharThreshold,
|
||||
autoCompletionTypingInterval,
|
||||
multiLineCompletion,
|
||||
Row{autoCompletionCharThreshold,
|
||||
autoCompletionTypingInterval,
|
||||
startSuggestionTimer,
|
||||
Stretch{1}},
|
||||
Space{8},
|
||||
enableLogging,
|
||||
Space{8},
|
||||
|
||||
Reference in New Issue
Block a user