mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-05 18:54:14 +02:00
Merge pull request #1315 from ispyisail/feature/assistant-house-style
Add a house style that every AI assistant reads
This commit is contained in:
+16
-1
@@ -42,7 +42,7 @@ here read the model.
|
||||
| `qet_check` | **design-rule checks** — duplicate labels, unlabelled masters, unnumbered conductors, empty folios, terminals with more than four wires, folio reports with several wires |
|
||||
| `qet_layout_check` | **does the drawing read well?** — a 0–100 score; wires that jog because two symbols are a few pixels out of line, symbols off the grid, wires through symbols, overlaps, crossings, labels over wires, 4-way junction dots, side branches out of line; and the moves that fix them, ready for `qet_edit` |
|
||||
| `qet_query` | **ask the project database** — read-only SQL over the views and tables |
|
||||
| `qet_about` | **start here** — where QElectroTech keeps things, what is switched on, the stored scripts, the calls a script can make (from `qet-assistant.json`), and the installation's standard symbols if it has any |
|
||||
| `qet_about` | **start here** — where QElectroTech keeps things, what is switched on, the stored scripts, the calls a script can make (from `qet-assistant.json`), the installation's standard symbols if it has any, and your house style |
|
||||
| `qet_script_api` | **what a script can call** — every `qet.*` call of this build, and the header that makes a script a button |
|
||||
| `qet_script_test` | **try a script** on a copy of a project: what it would change, what it logged, its errors |
|
||||
| `qet_script_install` | **make a button** — store a script (and an SVG icon) where QElectroTech shows it in Project > Scripts and the Scripts toolbar |
|
||||
@@ -323,6 +323,21 @@ The usual round: read the recording, write a script that does the same in
|
||||
general (on the selected elements, say, not on these exact ones),
|
||||
`qet_recording_check` it until it matches, then `qet_script_install` it.
|
||||
|
||||
## Your house style
|
||||
|
||||
Drawing conventions you want every assistant to follow -- grid, flow
|
||||
direction, wire routing, tags, grouping -- written once, in your own words,
|
||||
and kept by QElectroTech itself rather than by any one assistant:
|
||||
|
||||
```js
|
||||
qet.setHouseStyle("Never place a symbol off the 10 px grid.\n...");
|
||||
```
|
||||
|
||||
It is stored in QElectroTech's settings (needs `QET_ENABLE_SCRIPTING=1`, as
|
||||
for any change), written to `qet-assistant.json` as `house_style`, and shown
|
||||
by `qet_about`, whose description tells the assistant to follow it. Every
|
||||
assistant that connects, of any make, reads the same text.
|
||||
|
||||
## Live mode: working in the QElectroTech you have open
|
||||
|
||||
Every tool above works on files, with no QElectroTech window involved. The
|
||||
|
||||
+15
-3
@@ -3829,7 +3829,9 @@ SERVER_INSTRUCTIONS = (
|
||||
"diagrams. A project (.qet) holds folios (sheets) of symbols "
|
||||
"(elements) joined by wires (conductors). Folio indexes count from 0.\n"
|
||||
"Start with qet_about: where QElectroTech keeps things, what is "
|
||||
"switched on, and the stored scripts.\n"
|
||||
"switched on, the stored scripts, and house_style -- this "
|
||||
"installation's own drawing conventions if the user set any. Follow "
|
||||
"house_style when placing or wiring anything.\n"
|
||||
"Two ways of working. HEADLESS (qet_* and qet_script_*): read, check "
|
||||
"and edit .qet files and store script buttons; nothing the user has "
|
||||
"open is touched. To make a button: qet_script_api for the calls, "
|
||||
@@ -3910,6 +3912,12 @@ def tool_about() -> dict:
|
||||
"script_api": info.get("script_api"),
|
||||
# Never the token: it is for the live tools, not the conversation.
|
||||
"live": {"open": bool(live), "pid": (live or {}).get("pid")},
|
||||
# This installation's drawing conventions, set once via
|
||||
# qet.setHouseStyle() (scripting consent required, same as any
|
||||
# other write) and read here so every assistant that connects sees
|
||||
# them without being told by the user each time. No GUI field yet
|
||||
# -- QetSettings::setHouseStyle() is there for one if it is wanted.
|
||||
"house_style": info.get("house_style"),
|
||||
# One symbol per device role, the user's own choice: use these
|
||||
# paths with add_element / qet.addElement before searching.
|
||||
"standard_symbols": standard_symbols(info),
|
||||
@@ -5663,8 +5671,12 @@ TOOLS = [
|
||||
"scripts, element and title block collections), which "
|
||||
"features are on (scripting, live mode), every call a script "
|
||||
"can make, the stored scripts and the ones refused with why, "
|
||||
"and whether a live session is open; plus this server's own "
|
||||
"setup. Reads one file; changes nothing.",
|
||||
"whether a live session is open, and house_style -- this "
|
||||
"installation's own drawing conventions, in the user's words, "
|
||||
"if they set any (qet.setHouseStyle()); null if not. Read "
|
||||
"house_style and follow it, the same as any explicit "
|
||||
"instruction, before placing or wiring anything. "
|
||||
"Reads one file; changes nothing.",
|
||||
"inputSchema": {"type": "object", "properties": {}},
|
||||
"handler": lambda a: tool_about(),
|
||||
},
|
||||
|
||||
@@ -3784,6 +3784,15 @@ class AssistantInfoFile(unittest.TestCase):
|
||||
self.assertNotIn("SECRET", json.dumps(about))
|
||||
self.assertEqual(about["script_api"], ["int currentFolio()"])
|
||||
|
||||
def test_house_style_passes_through(self):
|
||||
self.write(house_style="Grid: never off. Inputs left, outputs right.")
|
||||
about = m.tool_about()
|
||||
self.assertEqual(about["house_style"], "Grid: never off. Inputs left, outputs right.")
|
||||
|
||||
def test_house_style_null_when_unset(self):
|
||||
self.write(house_style=None)
|
||||
self.assertIsNone(m.tool_about()["house_style"])
|
||||
|
||||
def test_first_contact_carries_the_instructions(self):
|
||||
reply = m.handle({"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}})
|
||||
self.assertIn("qet_about", reply["result"]["instructions"])
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
namespace {
|
||||
QJsonObject s_live; ///< empty while live mode is closed
|
||||
bool s_running = true;
|
||||
bool s_watching = false; ///< this QElectroTech writes the file (an editor opened)
|
||||
}
|
||||
|
||||
namespace AssistantInfo {
|
||||
@@ -54,14 +55,25 @@ QString path()
|
||||
*/
|
||||
void watch()
|
||||
{
|
||||
static bool watching = false;
|
||||
if (watching) return;
|
||||
watching = true;
|
||||
if (s_watching) return;
|
||||
s_watching = true;
|
||||
QObject::connect(&ScriptLibrary::instance(), &ScriptLibrary::changed, &write);
|
||||
QObject::connect(qApp, &QCoreApplication::aboutToQuit, &markStopped);
|
||||
write();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief refresh
|
||||
Write the file again after a setting it carries changed, but only in a
|
||||
QElectroTech that writes it at all: a headless --run never opened an
|
||||
editor, and writing from it would replace the open QElectroTech's live
|
||||
channel with its own empty one.
|
||||
*/
|
||||
void refresh()
|
||||
{
|
||||
if (s_watching) write();
|
||||
}
|
||||
|
||||
void write()
|
||||
{
|
||||
QJsonArray scripts, refused;
|
||||
@@ -111,7 +123,14 @@ void write()
|
||||
{QStringLiteral("stored_scripts"), scripts},
|
||||
{QStringLiteral("refused_scripts"), refused},
|
||||
{QStringLiteral("recordings"), MacroRecorder::recordings()},
|
||||
{QStringLiteral("live"), s_live.isEmpty() ? QJsonValue() : QJsonValue(s_live)}};
|
||||
{QStringLiteral("live"), s_live.isEmpty() ? QJsonValue() : QJsonValue(s_live)},
|
||||
// Free-text drawing conventions, set once by the user
|
||||
// (QetSettings::setHouseStyle(), qet.setHouseStyle()) and read
|
||||
// by any assistant that connects, live or headless, without it
|
||||
// having to ask the user or guess. Null, not "", when unset --
|
||||
// the two mean different things to a reader.
|
||||
{QStringLiteral("house_style"), QetSettings::houseStyle().isEmpty()
|
||||
? QJsonValue() : QJsonValue(QetSettings::houseStyle())}};
|
||||
|
||||
const QString file_path = path();
|
||||
QDir().mkpath(QFileInfo(file_path).path());
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace AssistantInfo
|
||||
QString path();
|
||||
void watch();
|
||||
void write();
|
||||
void refresh();
|
||||
void setLive(const QJsonObject &live);
|
||||
void markStopped();
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#include "../conductorsegment.h"
|
||||
#include "../conductorrouter.h"
|
||||
#include "../qetgraphicsitem/diagramimageitem.h"
|
||||
#include "../utils/qetsettings.h"
|
||||
#include "assistantinfo.h"
|
||||
|
||||
// See diagrameventaddpdf.h: a missing QtPdf module (or Qt < 6.4) is not
|
||||
// fatal at build time, so addPdfPage() is always declared -- a script
|
||||
@@ -4219,6 +4221,35 @@ QStringList QetScriptApi::folioPresets() const
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::houseStyle
|
||||
This installation's drawing conventions (grid, flow direction, routing,
|
||||
tagging, grouping, ...), as free text the user wrote once. Empty when
|
||||
nobody has set any. Not project-scoped: the same text for every
|
||||
project this QElectroTech opens, same as liveAssistantEnabled().
|
||||
@return the text
|
||||
*/
|
||||
QString QetScriptApi::houseStyle() const
|
||||
{
|
||||
return QetSettings::houseStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::setHouseStyle
|
||||
Write the installation's drawing conventions. Always succeeds (a plain
|
||||
setting, not project data, so there is nothing here to refuse); @return
|
||||
is for a consistent call shape with the rest of the API.
|
||||
@param text
|
||||
*/
|
||||
bool QetScriptApi::setHouseStyle(const QString &text)
|
||||
{
|
||||
QetSettings::setHouseStyle(text);
|
||||
//qet-assistant.json carries it: an assistant reading the file
|
||||
//now must see the new text, not the one from the last start
|
||||
AssistantInfo::refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::setFolioBorder
|
||||
Change one field of a folio's frame through ChangeBorderCommand, as the
|
||||
|
||||
@@ -569,6 +569,11 @@ class QetScriptApi : public QObject
|
||||
Q_INVOKABLE bool setFolioBorder(int folioIndex, const QString &property, const QString &value);
|
||||
Q_INVOKABLE QStringList folioPresets() const;
|
||||
|
||||
// -- this installation's drawing conventions (grid, flow, routing, tagging, --
|
||||
// -- grouping, ...), free text, for every assistant that connects to read --
|
||||
Q_INVOKABLE QString houseStyle() const;
|
||||
Q_INVOKABLE bool setHouseStyle(const QString &text);
|
||||
|
||||
// -- the conductor defaults of a folio (Folio properties > Conductors),
|
||||
// or with folioIndex -1, the project's defaults for new folios --
|
||||
Q_INVOKABLE QString conductorDefault(int folioIndex, const QString &property) const;
|
||||
|
||||
@@ -173,6 +173,23 @@ namespace QetSettings
|
||||
settings.setValue("scripting/live_assistant", enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief houseStyle
|
||||
* @return this installation's drawing conventions, in the user's own
|
||||
* words -- empty when nobody has set any.
|
||||
*/
|
||||
QString houseStyle()
|
||||
{
|
||||
QSettings settings;
|
||||
return settings.value("assistant/house_style", QString()).toString();
|
||||
}
|
||||
|
||||
void setHouseStyle(const QString &text)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue("assistant/house_style", text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief setSheetBackground
|
||||
* Store the sheet background last picked in the diagram editor, so the
|
||||
|
||||
@@ -41,6 +41,16 @@ namespace QetSettings
|
||||
bool liveAssistantEnabled();
|
||||
void setLiveAssistantEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
@brief Free-text drawing conventions for this installation (grid,
|
||||
flow direction, routing, tagging, grouping, ...), written once by
|
||||
the user and read by every AI assistant that connects -- live or
|
||||
headless -- through qet-assistant.json and qet.houseStyle().
|
||||
Empty when never set.
|
||||
*/
|
||||
QString houseStyle();
|
||||
void setHouseStyle(const QString &text);
|
||||
|
||||
/**
|
||||
@brief The sheet (folio) background the diagram editors draw.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user