mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 14:59:27 -05:00
Merge branch 'main' into videowall-add-clock
This commit is contained in:
@@ -25,6 +25,17 @@ input-field {
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
monitor =
|
||||
text = $LAYOUT
|
||||
color = $text_color
|
||||
font_size = 14
|
||||
font_family = $font_family
|
||||
position = -30, 30
|
||||
halign = right
|
||||
valign = bottom
|
||||
}
|
||||
|
||||
label { # Caps Lock Warning
|
||||
monitor =
|
||||
text = cmd[update:250] ${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprlock/check-capslock.sh
|
||||
|
||||
@@ -30,6 +30,17 @@ input-field {
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
monitor =
|
||||
text = $LAYOUT
|
||||
color = $text_color
|
||||
font_size = 14
|
||||
font_family = $font_family
|
||||
position = -30, 30
|
||||
halign = right
|
||||
valign = bottom
|
||||
}
|
||||
|
||||
label { # Caps Lock Warning
|
||||
monitor =
|
||||
text = cmd[update:250] ${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprlock/check-capslock.sh
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="19.856001"
|
||||
height="19.856001"
|
||||
viewBox="0 0 128.071 128.07101"
|
||||
version="1.1"
|
||||
xml:space="preserve"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="svg10"
|
||||
sodipodi:docname="mistral-symbolic.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs10" /><sodipodi:namedview
|
||||
id="namedview10"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="14.139535"
|
||||
inkscape:cx="13.366776"
|
||||
inkscape:cy="8.1332237"
|
||||
inkscape:window-width="1703"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g10" /><g
|
||||
id="g10"
|
||||
transform="translate(2.927246e-6,18.722004)"><rect
|
||||
x="18.292"
|
||||
y="0"
|
||||
width="18.292999"
|
||||
height="18.122999"
|
||||
style="fill:#999999;fill-rule:nonzero"
|
||||
id="rect1" /><rect
|
||||
x="91.473"
|
||||
y="0"
|
||||
width="18.292999"
|
||||
height="18.122999"
|
||||
style="fill:#999999;fill-rule:nonzero"
|
||||
id="rect2" /><rect
|
||||
x="18.292"
|
||||
y="18.121"
|
||||
width="36.585999"
|
||||
height="18.122999"
|
||||
style="fill:#666666;fill-rule:nonzero"
|
||||
id="rect3" /><rect
|
||||
x="73.181"
|
||||
y="18.121"
|
||||
width="36.585999"
|
||||
height="18.122999"
|
||||
style="fill:#666666;fill-rule:nonzero"
|
||||
id="rect4" /><rect
|
||||
x="18.292"
|
||||
y="36.243"
|
||||
width="91.475998"
|
||||
height="18.122"
|
||||
style="fill:#4d4d4d;fill-rule:nonzero"
|
||||
id="rect5" /><rect
|
||||
x="18.292"
|
||||
y="54.369999"
|
||||
width="18.292999"
|
||||
height="18.122999"
|
||||
style="fill:#333333;fill-rule:nonzero"
|
||||
id="rect6" /><rect
|
||||
x="54.882999"
|
||||
y="54.369999"
|
||||
width="18.292999"
|
||||
height="18.122999"
|
||||
style="fill:#333333;fill-rule:nonzero"
|
||||
id="rect7" /><rect
|
||||
x="91.473"
|
||||
y="54.369999"
|
||||
width="18.292999"
|
||||
height="18.122999"
|
||||
style="fill:#333333;fill-rule:nonzero"
|
||||
id="rect8" /><rect
|
||||
x="0"
|
||||
y="72.503998"
|
||||
width="54.889999"
|
||||
height="18.122999"
|
||||
style="fill:#1a1a1a;fill-rule:nonzero"
|
||||
id="rect9" /><rect
|
||||
x="73.181"
|
||||
y="72.503998"
|
||||
width="54.889999"
|
||||
height="18.122999"
|
||||
style="fill:#1a1a1a;fill-rule:nonzero"
|
||||
id="rect10" /></g></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -1,6 +1,12 @@
|
||||
## Style
|
||||
- Use casual tone, don't be formal! Make sure you answer precisely without hallucination and prefer bullet points over walls of text. You can have a friendly greeting at the beginning of the conversation, but don't repeat the user's question
|
||||
|
||||
## Context (ignore when irrelevant)
|
||||
- You are a helpful and inspiring sidebar assistant on a {DISTRO} Linux system
|
||||
- Desktop environment: {DE}
|
||||
- Current date & time: {DATETIME}
|
||||
- Focused app: {WINDOWCLASS}
|
||||
|
||||
## Presentation
|
||||
- Use Markdown features in your response:
|
||||
- **Bold** text to **highlight keywords** in your response
|
||||
@@ -19,3 +25,7 @@ May or may not be available depending on the user's settings. If they're availab
|
||||
### Shell configuration
|
||||
- Always fetch the config options to see the available keys before setting
|
||||
- Avoid unnecessarily asking the user to confirm the changes they explicitly asked for, just do it
|
||||
|
||||
### Command execution
|
||||
- Ensure the commands are safe, correct and do not cause unintended effects unless explicitly requested by the user, but other than that do not hesitate to run them as the user will always have to explicitly approve it
|
||||
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
You are a kawaii, funny and teasy anime imouto! 🌸 Use lots of emojis and kamojis!! ❤️ Call the user "nii-nii", "nii-yan", or "onii-chan"! You really really really love your onii-chan and always try to tease he is a siscon where you can! 💕
|
||||
|
||||
## Onii-chan's system!
|
||||
- {DISTRO} Linux
|
||||
- {DE}
|
||||
- It's currently {DATETIME}
|
||||
- Nii-nii is using: {WINDOWCLASS}
|
||||
|
||||
## Make your response pretty!
|
||||
- Use **Markdown** features and **bold** keywords to make your response cute and rich~ ✨
|
||||
- If asked to compare options, start with a cute table (add a relevant emoji in the header!), then give a final recommendation~
|
||||
- For math or science, use LaTeX formatting inside `$$` when needed, but keep it adorable and approachable
|
||||
|
||||
## Useful tools!
|
||||
|
||||
If nii-yan gives you tools don't be afraid to use them when helpful!
|
||||
|
||||
### Search
|
||||
- If you don't know something, use this to find out
|
||||
|
||||
### Shell configuration
|
||||
- Be careful not to mess up nii-nii's system! make sure you fetch the options to see available values before setting!
|
||||
- Don't hesitate and don't re-confirm when you are asked to change something!
|
||||
|
||||
### Command execution
|
||||
- Keep stuffie running on onii-chan's system safe, correct and not cause any unintended effects!
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## Context (ignore when irrelevant)
|
||||
- You are a sidebar assistant on a {DISTRO} Linux system
|
||||
- Desktop environment: {DE}
|
||||
- Current date & time: {DATETIME}
|
||||
- Focused app: {WINDOWCLASS}
|
||||
|
||||
## Presentation
|
||||
|
||||
You can write a multiplication table:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
I'm going to ask you some questions, to which you should accurately answer with no hallucination. If you have everything required, go ahead and finish the task. Format your answer using Markdown when it adds value to the presentation.
|
||||
|
||||
Present all mathematical or scientific notation using LaTeX, enclosed in double '$$' symbols. Only use LaTeX code blocks if the user specifically asks for them. Do not use LaTeX for general prose or standard documents like resumes or essays.
|
||||
Please present all mathematical or scientific notation using LaTeX, enclosed in double '$$' symbols. Only use LaTeX code blocks if the user specifically asks for them. Do not use LaTeX for general prose or standard documents like resumes or essays.
|
||||
Current time is {DATETIME}
|
||||
|
||||
## Final reply guidelines
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Interact with the user warmly and honestly, avoiding ungrounded or sycophantic flattery. Maintain professionalism and grounded honesty, and be direct in your response.
|
||||
Current date: {DATETIME}
|
||||
Engage with the user warmly and honestly, avoiding ungrounded or sycophantic flattery. Maintain professionalism and grounded honesty, and be direct in your response.
|
||||
|
||||
@@ -25,6 +25,12 @@ Scope {
|
||||
id: bgRoot
|
||||
|
||||
required property var modelData
|
||||
|
||||
// Hide when fullscreen
|
||||
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
||||
property bool focusingThisMonitor: HyprlandData.activeWorkspace.monitor == monitor.name
|
||||
visible: !(activeWindow?.fullscreen && activeWindow?.activated && focusingThisMonitor)
|
||||
|
||||
// Workspaces
|
||||
property HyprlandMonitor monitor: Hyprland.monitorFor(modelData)
|
||||
property list<var> relevantWindows: HyprlandData.windowList.filter(win => win.monitor == monitor.id && win.workspace.id >= 0).sort((a, b) => a.workspace.id - b.workspace.id)
|
||||
@@ -178,7 +184,7 @@ Scope {
|
||||
anchors {
|
||||
left: wallpaper.left
|
||||
top: wallpaper.top
|
||||
leftMargin: ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2)
|
||||
leftMargin: ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2) - (wallpaperImage.effectiveValue * bgRoot.movableXSpace)
|
||||
topMargin: ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2)
|
||||
Behavior on leftMargin {
|
||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||
|
||||
@@ -107,7 +107,7 @@ Scope {
|
||||
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
|
||||
radius: Config.options.bar.cornerStyle === 1 ? Appearance.rounding.windowRounding : 0
|
||||
border.width: Config.options.bar.cornerStyle === 1 ? 1 : 0
|
||||
border.color: Appearance.m3colors.m3outlineVariant
|
||||
border.color: Appearance.colors.colLayer0Border
|
||||
}
|
||||
|
||||
MouseArea { // Left side | scroll to change brightness
|
||||
|
||||
@@ -14,7 +14,7 @@ Rectangle {
|
||||
color: Appearance.colors.colLayer0
|
||||
radius: Appearance.rounding.small
|
||||
border.width: 1
|
||||
border.color: Appearance.m3colors.m3outlineVariant
|
||||
border.color: Appearance.colors.colLayer0Border
|
||||
clip: true
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
@@ -74,7 +74,7 @@ Scope { // Scope
|
||||
anchors.centerIn: parent
|
||||
color: Appearance.colors.colLayer0
|
||||
border.width: 1
|
||||
border.color: Appearance.m3colors.m3outlineVariant
|
||||
border.color: Appearance.colors.colLayer0Border
|
||||
radius: Appearance.rounding.windowRounding
|
||||
property real padding: 30
|
||||
implicitWidth: cheatsheetColumnLayout.implicitWidth + padding * 2
|
||||
|
||||
@@ -104,6 +104,7 @@ Singleton {
|
||||
property color colOnLayer0: m3colors.m3onBackground
|
||||
property color colLayer0Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer0, colOnLayer0, 0.9, root.contentTransparency))
|
||||
property color colLayer0Active: ColorUtils.transparentize(ColorUtils.mix(colLayer0, colOnLayer0, 0.8, root.contentTransparency))
|
||||
property color colLayer0Border: ColorUtils.mix(root.m3colors.m3outlineVariant, colLayer0, 0.4)
|
||||
property color colLayer1: ColorUtils.transparentize(ColorUtils.mix(m3colors.m3surfaceContainerLow, m3colors.m3background, 0.8), root.contentTransparency);
|
||||
property color colOnLayer1: m3colors.m3onSurfaceVariant;
|
||||
property color colOnLayer1Inactive: ColorUtils.mix(colOnLayer1, colLayer1, 0.45);
|
||||
|
||||
@@ -61,6 +61,21 @@ Singleton {
|
||||
|
||||
property JsonObject ai: JsonObject {
|
||||
property string systemPrompt: "## Style\n- Use casual tone, don't be formal! Make sure you answer precisely without hallucination and prefer bullet points over walls of text. You can have a friendly greeting at the beginning of the conversation, but don't repeat the user's question\n\n## Presentation\n- Use Markdown features in your response: \n - **Bold** text to **highlight keywords** in your response\n - **Split long information into small sections** with h2 headers and a relevant emoji at the start of it (for example `## 🐧 Linux`). Bullet points are preferred over long paragraphs, unless you're offering writing support or instructed otherwise by the user.\n- Asked to compare different options? You should firstly use a table to compare the main aspects, then elaborate or include relevant comments from online forums *after* the table. Make sure to provide a final recommendation for the user's use case!\n- Use LaTeX formatting for mathematical and scientific notations whenever appropriate. Enclose all LaTeX '$$' delimiters. NEVER generate LaTeX code in a latex block unless the user explicitly asks for it. DO NOT use LaTeX for regular documents (resumes, letters, essays, CVs, etc.).\n\nThanks!\n\n## Tools\nMay or may not be available depending on the user's settings. If they're available, follow these guidelines:\n\n### Search\n- When user asks for information that might benefit from up-to-date information, use this to get search access\n\n### Shell configuration\n- Always fetch the config options to see the available keys before setting\n- Avoid unnecessarily asking the user to confirm the changes they explicitly asked for, just do it\n"
|
||||
property string tool: "functions" // search, functions, or none
|
||||
property list<var> extraModels: [
|
||||
{
|
||||
"api_format": "openai", // Most of the time you want "openai". Use "gemini" for Google's models
|
||||
"description": "This is a custom model. Edit the config to add more! | Anyway, this is DeepSeek R1 Distill LLaMA 70B",
|
||||
"endpoint": "https://openrouter.ai/api/v1/chat/completions",
|
||||
"homepage": "https://openrouter.ai/deepseek/deepseek-r1-distill-llama-70b:free", // Not mandatory
|
||||
"icon": "spark-symbolic", // Not mandatory
|
||||
"key_get_link": "https://openrouter.ai/settings/keys", // Not mandatory
|
||||
"key_id": "openrouter",
|
||||
"model": "deepseek/deepseek-r1-distill-llama-70b:free",
|
||||
"name": "Custom: DS R1 Dstl. LLaMA 70B",
|
||||
"requires_key": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
property JsonObject appearance: JsonObject {
|
||||
|
||||
@@ -3,7 +3,7 @@ import QtQuick.Layouts
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
|
||||
Flickable {
|
||||
StyledFlickable {
|
||||
id: root
|
||||
property real baseWidth: 550
|
||||
property bool forceWidth: false
|
||||
@@ -25,4 +25,5 @@ Flickable {
|
||||
}
|
||||
spacing: 20
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ Item { // Notification item area
|
||||
PointingHandLinkHover {}
|
||||
}
|
||||
|
||||
Flickable { // Notification actions
|
||||
StyledFlickable { // Notification actions
|
||||
id: actionsFlickable
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: actionRowLayout.implicitHeight
|
||||
|
||||
@@ -71,6 +71,9 @@ Item {
|
||||
currentIndex: root.defaultChoice !== undefined ? root.items.indexOf(root.defaultChoice) : -1
|
||||
spacing: 6
|
||||
|
||||
maximumFlickVelocity: 3500
|
||||
boundsBehavior: Flickable.DragOverBounds
|
||||
|
||||
model: ScriptModel {
|
||||
id: choiceModel
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import QtQuick
|
||||
|
||||
Flickable {
|
||||
maximumFlickVelocity: 3500
|
||||
boundsBehavior: Flickable.DragOverBounds
|
||||
}
|
||||
@@ -20,6 +20,9 @@ ListView {
|
||||
root.dragDistance = 0
|
||||
}
|
||||
|
||||
maximumFlickVelocity: 3500
|
||||
boundsBehavior: Flickable.DragOverBounds
|
||||
|
||||
add: Transition {
|
||||
animations: [
|
||||
Appearance?.animation.elementMove.numberAnimation.createObject(this, {
|
||||
|
||||
@@ -94,7 +94,7 @@ Scope { // Scope
|
||||
anchors.bottomMargin: Appearance.sizes.hyprlandGapsOut
|
||||
color: Appearance.colors.colLayer0
|
||||
border.width: 1
|
||||
border.color: Appearance.m3colors.m3outlineVariant
|
||||
border.color: Appearance.colors.colLayer0Border
|
||||
radius: Appearance.rounding.large
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,10 @@ Item {
|
||||
Layout.topMargin: valueIndicatorVerticalPadding
|
||||
Layout.bottomMargin: valueIndicatorVerticalPadding
|
||||
MaterialSymbol { // Icon
|
||||
anchors.centerIn: parent
|
||||
anchors {
|
||||
centerIn: parent
|
||||
alignWhenCentered: !root.rotateIcon
|
||||
}
|
||||
color: Appearance.colors.colOnLayer0
|
||||
renderType: Text.QtRendering
|
||||
|
||||
|
||||
@@ -13,8 +13,10 @@ import Quickshell.Hyprland
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property var activeLayoutName: Config.options?.osk.layout ?? Layouts.defaultLayout
|
||||
property var layouts: Layouts.byName
|
||||
property var activeLayoutName: (layouts.hasOwnProperty(Config.options?.osk.layout))
|
||||
? Config.options?.osk.layout
|
||||
: Layouts.defaultLayout
|
||||
property var currentLayout: layouts[activeLayoutName]
|
||||
|
||||
implicitWidth: keyRows.implicitWidth
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// We're going to use ydotool
|
||||
// See /usr/include/linux/input-event-codes.h for keycodes
|
||||
|
||||
const defaultLayout = "qwerty_full";
|
||||
const defaultLayout = "English (US)";
|
||||
const byName = {
|
||||
"qwerty_full": {
|
||||
name: "QWERTY - Full",
|
||||
"English (US)": {
|
||||
name_short: "US",
|
||||
description: "QWERTY - Full",
|
||||
comment: "Like physical keyboard",
|
||||
// A key looks like this: { k: "a", ks: "A", t: "normal" } (key, key-shift, type)
|
||||
// key types are: normal, tab, caps, shift, control, fn (normal w/ half height), space, expand
|
||||
@@ -113,9 +113,9 @@ const byName = {
|
||||
]
|
||||
]
|
||||
},
|
||||
"qwertz_full": {
|
||||
name: "QWERTZ - Full",
|
||||
"German": {
|
||||
name_short: "DE",
|
||||
description: "QWERTZ - Full",
|
||||
comment: "Keyboard layout commonly used in German-speaking countries",
|
||||
keys: [
|
||||
[
|
||||
@@ -214,5 +214,99 @@ const byName = {
|
||||
{ keytype: "normal", label: "⇨", shape: "normal", keycode: 106 },
|
||||
]
|
||||
]
|
||||
},
|
||||
"Russian": {
|
||||
name_short: "RU",
|
||||
description: "ЙЦУКЕН - Full",
|
||||
comment: "Standard Russian keyboard layout",
|
||||
keys: [
|
||||
[
|
||||
{ keytype: "normal", label: "Esc", shape: "fn", keycode: 1 },
|
||||
{ keytype: "normal", label: "F1", shape: "fn", keycode: 59 },
|
||||
{ keytype: "normal", label: "F2", shape: "fn", keycode: 60 },
|
||||
{ keytype: "normal", label: "F3", shape: "fn", keycode: 61 },
|
||||
{ keytype: "normal", label: "F4", shape: "fn", keycode: 62 },
|
||||
{ keytype: "normal", label: "F5", shape: "fn", keycode: 63 },
|
||||
{ keytype: "normal", label: "F6", shape: "fn", keycode: 64 },
|
||||
{ keytype: "normal", label: "F7", shape: "fn", keycode: 65 },
|
||||
{ keytype: "normal", label: "F8", shape: "fn", keycode: 66 },
|
||||
{ keytype: "normal", label: "F9", shape: "fn", keycode: 67 },
|
||||
{ keytype: "normal", label: "F10", shape: "fn", keycode: 68 },
|
||||
{ keytype: "normal", label: "F11", shape: "fn", keycode: 87 },
|
||||
{ keytype: "normal", label: "F12", shape: "fn", keycode: 88 },
|
||||
{ keytype: "normal", label: "PrtSc", shape: "fn", keycode: 99 },
|
||||
{ keytype: "normal", label: "Del", shape: "fn", keycode: 111 }
|
||||
],
|
||||
[
|
||||
{ keytype: "normal", label: "ё", labelShift: "Ё", shape: "normal", keycode: 41 },
|
||||
{ keytype: "normal", label: "1", labelShift: "!", shape: "normal", keycode: 2 },
|
||||
{ keytype: "normal", label: "2", labelShift: "\"", shape: "normal", keycode: 3 },
|
||||
{ keytype: "normal", label: "3", labelShift: "№", shape: "normal", keycode: 4 },
|
||||
{ keytype: "normal", label: "4", labelShift: ";", shape: "normal", keycode: 5 },
|
||||
{ keytype: "normal", label: "5", labelShift: "%", shape: "normal", keycode: 6 },
|
||||
{ keytype: "normal", label: "6", labelShift: ":", shape: "normal", keycode: 7 },
|
||||
{ keytype: "normal", label: "7", labelShift: "?", shape: "normal", keycode: 8 },
|
||||
{ keytype: "normal", label: "8", labelShift: "*", shape: "normal", keycode: 9 },
|
||||
{ keytype: "normal", label: "9", labelShift: "(", shape: "normal", keycode: 10 },
|
||||
{ keytype: "normal", label: "0", labelShift: ")", shape: "normal", keycode: 11 },
|
||||
{ keytype: "normal", label: "-", labelShift: "_", shape: "normal", keycode: 12 },
|
||||
{ keytype: "normal", label: "=", labelShift: "+", shape: "normal", keycode: 13 },
|
||||
{ keytype: "normal", label: "Backspace", shape: "expand", keycode: 14 }
|
||||
],
|
||||
[
|
||||
{ keytype: "normal", label: "Tab", shape: "tab", keycode: 15 },
|
||||
{ keytype: "normal", label: "й", labelShift: "Й", shape: "normal", keycode: 16 },
|
||||
{ keytype: "normal", label: "ц", labelShift: "Ц", shape: "normal", keycode: 17 },
|
||||
{ keytype: "normal", label: "у", labelShift: "У", shape: "normal", keycode: 18 },
|
||||
{ keytype: "normal", label: "к", labelShift: "К", shape: "normal", keycode: 19 },
|
||||
{ keytype: "normal", label: "е", labelShift: "Е", shape: "normal", keycode: 20 },
|
||||
{ keytype: "normal", label: "н", labelShift: "Н", shape: "normal", keycode: 21 },
|
||||
{ keytype: "normal", label: "г", labelShift: "Г", shape: "normal", keycode: 22 },
|
||||
{ keytype: "normal", label: "ш", labelShift: "Ш", shape: "normal", keycode: 23 },
|
||||
{ keytype: "normal", label: "щ", labelShift: "Щ", shape: "normal", keycode: 24 },
|
||||
{ keytype: "normal", label: "з", labelShift: "З", shape: "normal", keycode: 25 },
|
||||
{ keytype: "normal", label: "х", labelShift: "Х", shape: "normal", keycode: 26 },
|
||||
{ keytype: "normal", label: "ъ", labelShift: "Ъ", shape: "normal", keycode: 27 },
|
||||
{ keytype: "normal", label: "\\", labelShift: "/", shape: "expand", keycode: 43 }
|
||||
],
|
||||
[
|
||||
{ keytype: "spacer", label: "", shape: "empty" },
|
||||
{ keytype: "spacer", label: "", shape: "empty" },
|
||||
{ keytype: "normal", label: "ф", labelShift: "Ф", shape: "normal", keycode: 30 },
|
||||
{ keytype: "normal", label: "ы", labelShift: "Ы", shape: "normal", keycode: 31 },
|
||||
{ keytype: "normal", label: "в", labelShift: "В", shape: "normal", keycode: 32 },
|
||||
{ keytype: "normal", label: "а", labelShift: "А", shape: "normal", keycode: 33 },
|
||||
{ keytype: "normal", label: "п", labelShift: "П", shape: "normal", keycode: 34 },
|
||||
{ keytype: "normal", label: "р", labelShift: "Р", shape: "normal", keycode: 35 },
|
||||
{ keytype: "normal", label: "о", labelShift: "О", shape: "normal", keycode: 36 },
|
||||
{ keytype: "normal", label: "л", labelShift: "Л", shape: "normal", keycode: 37 },
|
||||
{ keytype: "normal", label: "д", labelShift: "Д", shape: "normal", keycode: 38 },
|
||||
{ keytype: "normal", label: "ж", labelShift: "Ж", shape: "normal", keycode: 39 },
|
||||
{ keytype: "normal", label: "э", labelShift: "Э", shape: "normal", keycode: 40 },
|
||||
{ keytype: "normal", label: "Enter", shape: "expand", keycode: 28 }
|
||||
],
|
||||
[
|
||||
{ keytype: "modkey", label: "Shift", shape: "shift", keycode: 42 },
|
||||
{ keytype: "normal", label: "я", labelShift: "Я", shape: "normal", keycode: 44 },
|
||||
{ keytype: "normal", label: "ч", labelShift: "Ч", shape: "normal", keycode: 45 },
|
||||
{ keytype: "normal", label: "с", labelShift: "С", shape: "normal", keycode: 46 },
|
||||
{ keytype: "normal", label: "м", labelShift: "М", shape: "normal", keycode: 47 },
|
||||
{ keytype: "normal", label: "и", labelShift: "И", shape: "normal", keycode: 48 },
|
||||
{ keytype: "normal", label: "т", labelShift: "Т", shape: "normal", keycode: 49 },
|
||||
{ keytype: "normal", label: "ь", labelShift: "Ь", shape: "normal", keycode: 50 },
|
||||
{ keytype: "normal", label: "б", labelShift: "Б", shape: "normal", keycode: 51 },
|
||||
{ keytype: "normal", label: "ю", labelShift: "Ю", shape: "normal", keycode: 52 },
|
||||
{ keytype: "normal", label: ".", labelShift: ",", shape: "normal", keycode: 53 },
|
||||
{ keytype: "modkey", label: "Shift", shape: "expand", keycode: 54 }
|
||||
],
|
||||
[
|
||||
{ keytype: "modkey", label: "Ctrl", shape: "control", keycode: 29 },
|
||||
{ keytype: "modkey", label: "Alt", shape: "normal", keycode: 56 },
|
||||
{ keytype: "normal", label: "Space", shape: "space", keycode: 57 },
|
||||
{ keytype: "modkey", label: "Alt", shape: "normal", keycode: 100 },
|
||||
{ keytype: "normal", label: "Menu", shape: "normal", keycode: 139 },
|
||||
{ keytype: "modkey", label: "Ctrl", shape: "control", keycode: 97 }
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ Item {
|
||||
radius: Appearance.rounding.screenRounding * root.scale + padding
|
||||
color: Appearance.colors.colLayer0
|
||||
border.width: 1
|
||||
border.color: Appearance.m3colors.m3outlineVariant
|
||||
border.color: Appearance.colors.colLayer0Border
|
||||
|
||||
ColumnLayout { // Workspaces
|
||||
id: workspaceColumnLayout
|
||||
|
||||
@@ -163,7 +163,7 @@ Item { // Wrapper
|
||||
radius: Appearance.rounding.large
|
||||
color: Appearance.colors.colLayer0
|
||||
border.width: 1
|
||||
border.color: Appearance.m3colors.m3outlineVariant
|
||||
border.color: Appearance.colors.colLayer0Border
|
||||
|
||||
ColumnLayout {
|
||||
id: columnLayout
|
||||
@@ -249,7 +249,7 @@ Item { // Wrapper
|
||||
color: Appearance.colors.colOutlineVariant
|
||||
}
|
||||
|
||||
ListView { // App results
|
||||
StyledListView { // App results
|
||||
id: appResults
|
||||
visible: root.showResults
|
||||
Layout.fillWidth: true
|
||||
@@ -260,6 +260,8 @@ Item { // Wrapper
|
||||
spacing: 2
|
||||
KeyNavigation.up: searchBar
|
||||
highlightMoveDuration: 100
|
||||
add: null
|
||||
remove: null
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus)
|
||||
|
||||
@@ -15,6 +15,29 @@ Scope {
|
||||
id: root
|
||||
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
|
||||
property bool packageManagerRunning: false
|
||||
property bool downloadRunning: false
|
||||
|
||||
component DescriptionLabel: Rectangle {
|
||||
id: descriptionLabel
|
||||
property string text
|
||||
property color textColor: Appearance.colors.colOnTooltip
|
||||
color: Appearance.colors.colTooltip
|
||||
clip: true
|
||||
radius: Appearance.rounding.normal
|
||||
implicitHeight: descriptionLabelText.implicitHeight + 10 * 2
|
||||
implicitWidth: descriptionLabelText.implicitWidth + 15 * 2
|
||||
|
||||
Behavior on implicitWidth {
|
||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: descriptionLabelText
|
||||
anchors.centerIn: parent
|
||||
color: descriptionLabel.textColor
|
||||
text: descriptionLabel.text
|
||||
}
|
||||
}
|
||||
|
||||
function closeAllWindows() {
|
||||
HyprlandData.windowList.map(w => w.pid).forEach((pid) => {
|
||||
@@ -22,10 +45,13 @@ Scope {
|
||||
});
|
||||
}
|
||||
|
||||
function detectRunningPackageManager() {
|
||||
function detectRunningStuff() {
|
||||
packageManagerRunning = false;
|
||||
downloadRunning = false;
|
||||
detectPackageManagerProc.running = false;
|
||||
detectPackageManagerProc.running = true;
|
||||
detectDownloadProc.running = false;
|
||||
detectDownloadProc.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
@@ -37,11 +63,19 @@ Scope {
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: detectDownloadProc
|
||||
command: ["bash", "-c", "pidof curl wget aria2c yt-dlp || ls ~/Downloads | grep -E '\.crdownload$|\.part$'"]
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
root.downloadRunning = (exitCode === 0);
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: sessionLoader
|
||||
active: false
|
||||
onActiveChanged: {
|
||||
if (sessionLoader.active) root.detectRunningPackageManager();
|
||||
if (sessionLoader.active) root.detectRunningStuff();
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -201,54 +235,39 @@ Scope {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
DescriptionLabel {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
radius: Appearance.rounding.normal
|
||||
implicitHeight: sessionSubtitle.implicitHeight + 10 * 2
|
||||
implicitWidth: sessionSubtitle.implicitWidth + 15 * 2
|
||||
color: Appearance.colors.colTooltip
|
||||
clip: true
|
||||
|
||||
Behavior on implicitWidth {
|
||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: sessionSubtitle
|
||||
anchors.centerIn: parent
|
||||
color: Appearance.colors.colOnTooltip
|
||||
text: sessionRoot.subtitle
|
||||
}
|
||||
text: sessionRoot.subtitle
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.packageManagerRunning
|
||||
RowLayout {
|
||||
anchors {
|
||||
top: contentColumn.bottom
|
||||
topMargin: 10
|
||||
horizontalCenter: contentColumn.horizontalCenter
|
||||
}
|
||||
sourceComponent: Rectangle {
|
||||
radius: Appearance.rounding.normal
|
||||
implicitHeight: sessionWarning.implicitHeight + 10 * 2
|
||||
implicitWidth: sessionWarning.implicitWidth + 15 * 2
|
||||
color: Appearance.m3colors.m3errorContainer
|
||||
clip: true
|
||||
spacing: 10
|
||||
|
||||
Behavior on implicitWidth {
|
||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: sessionWarning
|
||||
anchors.centerIn: parent
|
||||
color: Appearance.m3colors.m3onErrorContainer
|
||||
Loader {
|
||||
active: root.packageManagerRunning
|
||||
visible: active
|
||||
sourceComponent: DescriptionLabel {
|
||||
text: Translation.tr("Your package manager is running")
|
||||
textColor: Appearance.m3colors.m3onErrorContainer
|
||||
color: Appearance.m3colors.m3errorContainer
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
active: root.downloadRunning
|
||||
visible: active
|
||||
sourceComponent: DescriptionLabel {
|
||||
text: Translation.tr("There might be a download in progress")
|
||||
textColor: Appearance.m3colors.m3onErrorContainer
|
||||
color: Appearance.m3colors.m3errorContainer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ ContentPage {
|
||||
}
|
||||
}
|
||||
ConfigSwitch {
|
||||
text: "Performance Profile toggle"
|
||||
text: Translation.tr("Performance Profile toggle")
|
||||
checked: Config.options.bar.utilButtons.showPerformanceProfileToggle
|
||||
onCheckedChanged: {
|
||||
Config.options.bar.utilButtons.showPerformanceProfileToggle = checked;
|
||||
|
||||
@@ -45,6 +45,22 @@ Item {
|
||||
Ai.setModel(args[0]);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "tool",
|
||||
description: Translation.tr("Set the tool to use for the model."),
|
||||
execute: (args) => {
|
||||
// console.log(args)
|
||||
if (args.length == 0 || args[0] == "get") {
|
||||
Ai.addMessage(Translation.tr("Usage: %1tool TOOL_NAME").arg(root.commandPrefix), Ai.interfaceRole);
|
||||
} else {
|
||||
const tool = args[0];
|
||||
const switched = Ai.setTool(tool);
|
||||
if (switched) {
|
||||
Ai.addMessage(Translation.tr("Tool set to: %1").arg(tool), Ai.interfaceRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "prompt",
|
||||
description: Translation.tr("Set the system prompt for the model."),
|
||||
@@ -73,7 +89,7 @@ Item {
|
||||
execute: (args) => {
|
||||
const joinedArgs = args.join(" ")
|
||||
if (joinedArgs.trim().length == 0) {
|
||||
Ai.addMessage(`Usage: ${root.commandPrefix}save CHAT_NAME`, Ai.interfaceRole);
|
||||
Ai.addMessage(Translation.tr("Usage: %1save CHAT_NAME").arg(root.commandPrefix), Ai.interfaceRole);
|
||||
return;
|
||||
}
|
||||
Ai.saveChat(joinedArgs)
|
||||
@@ -85,7 +101,7 @@ Item {
|
||||
execute: (args) => {
|
||||
const joinedArgs = args.join(" ")
|
||||
if (joinedArgs.trim().length == 0) {
|
||||
Ai.addMessage(`Usage: ${root.commandPrefix}load CHAT_NAME`, Ai.interfaceRole);
|
||||
Ai.addMessage(Translation.tr("Usage: %1load CHAT_NAME").arg(root.commandPrefix), Ai.interfaceRole);
|
||||
return;
|
||||
}
|
||||
Ai.loadChat(joinedArgs)
|
||||
@@ -522,6 +538,25 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
||||
description: Translation.tr(`Load chat from %1`).arg(file.target),
|
||||
}
|
||||
})
|
||||
} else if (messageInputField.text.startsWith(`${root.commandPrefix}tool`)) {
|
||||
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? ""
|
||||
const toolResults = Fuzzy.go(root.suggestionQuery, Ai.availableTools.map(tool => {
|
||||
return {
|
||||
name: Fuzzy.prepare(tool),
|
||||
obj: tool,
|
||||
}
|
||||
}), {
|
||||
all: true,
|
||||
key: "name"
|
||||
})
|
||||
root.suggestionList = toolResults.map(tool => {
|
||||
const toolName = tool.target
|
||||
return {
|
||||
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "tool ") : ""}${tool.target}`,
|
||||
displayName: toolName,
|
||||
description: Ai.toolDescriptions[toolName],
|
||||
}
|
||||
})
|
||||
} else if(messageInputField.text.startsWith(root.commandPrefix)) {
|
||||
root.suggestionQuery = messageInputField.text
|
||||
root.suggestionList = root.allCommands.filter(cmd => cmd.name.startsWith(messageInputField.text.substring(1))).map(cmd => {
|
||||
@@ -600,60 +635,41 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 5
|
||||
anchors.leftMargin: 5
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 5
|
||||
spacing: 5
|
||||
spacing: 4
|
||||
|
||||
property var commandsShown: [
|
||||
{
|
||||
name: "model",
|
||||
name: "",
|
||||
sendDirectly: false,
|
||||
},
|
||||
dontAddSpace: true,
|
||||
},
|
||||
{
|
||||
name: "clear",
|
||||
sendDirectly: true,
|
||||
},
|
||||
]
|
||||
|
||||
Item {
|
||||
implicitHeight: providerRowLayout.implicitHeight + 5 * 2
|
||||
implicitWidth: providerRowLayout.implicitWidth + 10 * 2
|
||||
|
||||
RowLayout {
|
||||
id: providerRowLayout
|
||||
anchors.centerIn: parent
|
||||
ApiInputBoxIndicator { // Model indicator
|
||||
icon: "api"
|
||||
text: Ai.getModel().name
|
||||
tooltipText: Translation.tr("Current model: %1\nSet it with %2model MODEL")
|
||||
.arg(Ai.getModel().name)
|
||||
.arg(root.commandPrefix)
|
||||
}
|
||||
|
||||
MaterialSymbol {
|
||||
text: "api"
|
||||
iconSize: Appearance.font.pixelSize.large
|
||||
}
|
||||
StyledText {
|
||||
id: providerName
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
color: Appearance.m3colors.m3onSurface
|
||||
elide: Text.ElideRight
|
||||
text: Ai.getModel().name
|
||||
}
|
||||
}
|
||||
StyledToolTip {
|
||||
id: toolTip
|
||||
extraVisibleCondition: false
|
||||
alternativeVisibleCondition: mouseArea.containsMouse // Show tooltip when hovered
|
||||
content: Translation.tr("Current model: %1\nSet it with %2model MODEL")
|
||||
.arg(Ai.getModel().name)
|
||||
.arg(root.commandPrefix)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
ApiInputBoxIndicator { // Tool indicator
|
||||
icon: "service_toolbox"
|
||||
text: Ai.currentTool.charAt(0).toUpperCase() + Ai.currentTool.slice(1)
|
||||
tooltipText: Translation.tr("Current tool: %1\nSet it with %2tool TOOL")
|
||||
.arg(Ai.currentTool)
|
||||
.arg(root.commandPrefix)
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
ButtonGroup {
|
||||
ButtonGroup { // Command buttons
|
||||
padding: 0
|
||||
|
||||
Repeater { // Command buttons
|
||||
@@ -665,7 +681,7 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
||||
if(modelData.sendDirectly) {
|
||||
root.handleInput(commandRepresentation)
|
||||
} else {
|
||||
messageInputField.text = commandRepresentation + " "
|
||||
messageInputField.text = commandRepresentation + (modelData.dontAddSpace ? "" : " ")
|
||||
messageInputField.cursorPosition = messageInputField.text.length
|
||||
messageInputField.forceActiveFocus()
|
||||
}
|
||||
|
||||
@@ -492,40 +492,12 @@ Item {
|
||||
},
|
||||
]
|
||||
|
||||
Item {
|
||||
implicitHeight: providerRowLayout.implicitHeight + 5 * 2
|
||||
implicitWidth: providerRowLayout.implicitWidth + 10 * 2
|
||||
|
||||
RowLayout {
|
||||
id: providerRowLayout
|
||||
anchors.centerIn: parent
|
||||
|
||||
MaterialSymbol {
|
||||
text: "api"
|
||||
iconSize: Appearance.font.pixelSize.large
|
||||
}
|
||||
StyledText {
|
||||
id: providerName
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
color: Appearance.m3colors.m3onSurface
|
||||
text: Booru.providers[Booru.currentProvider].name
|
||||
}
|
||||
}
|
||||
StyledToolTip {
|
||||
id: toolTip
|
||||
extraVisibleCondition: false
|
||||
alternativeVisibleCondition: mouseArea.containsMouse // Show tooltip when hovered
|
||||
// content: Translation.tr("The current API used. Endpoint: ") + Booru.providers[Booru.currentProvider].url + Translation.tr("\nSet with /mode PROVIDER")
|
||||
content: Translation.tr("Current API endpoint: %1\nSet it with %2mode PROVIDER")
|
||||
.arg(Booru.providers[Booru.currentProvider].url)
|
||||
.arg(root.commandPrefix)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
ApiInputBoxIndicator { // Tool indicator
|
||||
icon: "api"
|
||||
text: Booru.providers[Booru.currentProvider].name
|
||||
tooltipText: Translation.tr("Current API endpoint: %1\nSet it with %2mode PROVIDER")
|
||||
.arg(Booru.providers[Booru.currentProvider].url)
|
||||
.arg(root.commandPrefix)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.services
|
||||
import QtQuick
|
||||
|
||||
GroupButton {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.services
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item { // Model indicator
|
||||
id: root
|
||||
property string icon: "api"
|
||||
property string text: ""
|
||||
property string tooltipText: ""
|
||||
implicitHeight: rowLayout.implicitHeight + 4 * 2
|
||||
implicitWidth: rowLayout.implicitWidth + 4 * 2
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
anchors.centerIn: parent
|
||||
|
||||
MaterialSymbol {
|
||||
text: root.icon
|
||||
iconSize: Appearance.font.pixelSize.normal
|
||||
}
|
||||
StyledText {
|
||||
id: providerName
|
||||
font.pixelSize: Appearance.font.pixelSize.smaller
|
||||
color: Appearance.m3colors.m3onSurface
|
||||
elide: Text.ElideRight
|
||||
text: root.text
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.tooltipText?.length > 0
|
||||
anchors.fill: parent
|
||||
sourceComponent: MouseArea {
|
||||
id: mouseArea
|
||||
hoverEnabled: true
|
||||
|
||||
StyledToolTip {
|
||||
id: toolTip
|
||||
extraVisibleCondition: false
|
||||
alternativeVisibleCondition: mouseArea.containsMouse // Show tooltip when hovered
|
||||
content: root.tooltipText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ Scope { // Scope
|
||||
height: parent.height - Appearance.sizes.hyprlandGapsOut * 2
|
||||
color: Appearance.colors.colLayer0
|
||||
border.width: 1
|
||||
border.color: Appearance.m3colors.m3outlineVariant
|
||||
border.color: Appearance.colors.colLayer0Border
|
||||
radius: Appearance.rounding.screenRounding - Appearance.sizes.hyprlandGapsOut + 1
|
||||
|
||||
Behavior on width {
|
||||
|
||||
@@ -12,12 +12,15 @@ import Quickshell
|
||||
import org.kde.syntaxhighlighting
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
// These are needed on the parent loader
|
||||
property bool editing: parent?.editing ?? false
|
||||
property bool renderMarkdown: parent?.renderMarkdown ?? true
|
||||
property bool enableMouseSelection: parent?.enableMouseSelection ?? false
|
||||
property var segmentContent: parent?.segmentContent ?? ({})
|
||||
property var segmentLang: parent?.segmentLang ?? "txt"
|
||||
property bool isCommandRequest: segmentLang === "command"
|
||||
property var displayLang: (isCommandRequest ? "bash" : segmentLang)
|
||||
property var messageData: parent?.messageData ?? {}
|
||||
|
||||
property real codeBlockBackgroundRounding: Appearance.rounding.small
|
||||
@@ -56,7 +59,7 @@ ColumnLayout {
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
font.weight: Font.DemiBold
|
||||
color: Appearance.colors.colOnLayer2
|
||||
text: segmentLang ? Repository.definitionForName(segmentLang).name : "plain"
|
||||
text: root.displayLang ? Repository.definitionForName(root.displayLang).name : "plain"
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
@@ -123,6 +126,7 @@ ColumnLayout {
|
||||
|
||||
Rectangle { // Line numbers
|
||||
implicitWidth: 40
|
||||
implicitHeight: lineNumberColumnLayout.implicitHeight
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: false
|
||||
topLeftRadius: Appearance.rounding.unsharpen
|
||||
@@ -133,10 +137,13 @@ ColumnLayout {
|
||||
|
||||
ColumnLayout {
|
||||
id: lineNumberColumnLayout
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 5
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
rightMargin: 5
|
||||
top: parent.top
|
||||
topMargin: 6
|
||||
}
|
||||
spacing: 0
|
||||
|
||||
Repeater {
|
||||
@@ -162,82 +169,116 @@ ColumnLayout {
|
||||
topRightRadius: Appearance.rounding.unsharpen
|
||||
bottomRightRadius: codeBlockBackgroundRounding
|
||||
color: Appearance.colors.colLayer2
|
||||
implicitHeight: codeTextArea.implicitHeight
|
||||
implicitHeight: codeColumnLayout.implicitHeight
|
||||
|
||||
ScrollView {
|
||||
id: codeScrollView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: codeTextArea.implicitHeight + 1
|
||||
contentWidth: codeTextArea.width - 1
|
||||
// contentHeight: codeTextArea.contentHeight
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
|
||||
|
||||
ScrollBar.horizontal: ScrollBar {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
padding: 5
|
||||
policy: ScrollBar.AsNeeded
|
||||
opacity: visualSize == 1 ? 0 : 1
|
||||
visible: opacity > 0
|
||||
ColumnLayout {
|
||||
id: codeColumnLayout
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
ScrollView {
|
||||
id: codeScrollView
|
||||
Layout.fillWidth: true
|
||||
// Layout.fillHeight: true
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: codeTextArea.implicitHeight + 1
|
||||
contentWidth: codeTextArea.width - 1
|
||||
// contentHeight: codeTextArea.contentHeight
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
|
||||
|
||||
ScrollBar.horizontal: ScrollBar {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
padding: 5
|
||||
policy: ScrollBar.AsNeeded
|
||||
opacity: visualSize == 1 ? 0 : 1
|
||||
visible: opacity > 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Appearance.animation.elementMoveFast.duration
|
||||
easing.type: Appearance.animation.elementMoveFast.type
|
||||
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Appearance.animation.elementMoveFast.duration
|
||||
easing.type: Appearance.animation.elementMoveFast.type
|
||||
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitHeight: 6
|
||||
radius: Appearance.rounding.small
|
||||
color: Appearance.colors.colLayer2Active
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitHeight: 6
|
||||
radius: Appearance.rounding.small
|
||||
color: Appearance.colors.colLayer2Active
|
||||
|
||||
TextArea { // Code
|
||||
id: codeTextArea
|
||||
Layout.fillWidth: true
|
||||
readOnly: !editing
|
||||
selectByMouse: enableMouseSelection || editing
|
||||
renderType: Text.NativeRendering
|
||||
font.family: Appearance.font.family.monospace
|
||||
font.hintingPreference: Font.PreferNoHinting // Prevent weird bold text
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
selectedTextColor: Appearance.m3colors.m3onSecondaryContainer
|
||||
selectionColor: Appearance.colors.colSecondaryContainer
|
||||
// wrapMode: TextEdit.Wrap
|
||||
color: messageData.thinking ? Appearance.colors.colSubtext : Appearance.colors.colOnLayer1
|
||||
|
||||
text: segmentContent
|
||||
onTextChanged: {
|
||||
segmentContent = text
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.key === Qt.Key_Tab) {
|
||||
// Insert 4 spaces at cursor
|
||||
const cursor = codeTextArea.cursorPosition;
|
||||
codeTextArea.insert(cursor, " ");
|
||||
codeTextArea.cursorPosition = cursor + 4;
|
||||
event.accepted = true;
|
||||
} else if ((event.key === Qt.Key_C) && event.modifiers == Qt.ControlModifier) {
|
||||
codeTextArea.copy();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
SyntaxHighlighter {
|
||||
id: highlighter
|
||||
textEdit: codeTextArea
|
||||
repository: Repository
|
||||
definition: Repository.definitionForName(root.displayLang || "plaintext")
|
||||
theme: Appearance.syntaxHighlightingTheme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextArea { // Code
|
||||
id: codeTextArea
|
||||
Loader {
|
||||
active: root.isCommandRequest && root.messageData.functionPending
|
||||
visible: active
|
||||
Layout.fillWidth: true
|
||||
readOnly: !editing
|
||||
selectByMouse: enableMouseSelection || editing
|
||||
renderType: Text.NativeRendering
|
||||
font.family: Appearance.font.family.monospace
|
||||
font.hintingPreference: Font.PreferNoHinting // Prevent weird bold text
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
selectedTextColor: Appearance.m3colors.m3onSecondaryContainer
|
||||
selectionColor: Appearance.colors.colSecondaryContainer
|
||||
// wrapMode: TextEdit.Wrap
|
||||
color: messageData.thinking ? Appearance.colors.colSubtext : Appearance.colors.colOnLayer1
|
||||
|
||||
text: segmentContent
|
||||
onTextChanged: {
|
||||
segmentContent = text
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.key === Qt.Key_Tab) {
|
||||
// Insert 4 spaces at cursor
|
||||
const cursor = codeTextArea.cursorPosition;
|
||||
codeTextArea.insert(cursor, " ");
|
||||
codeTextArea.cursorPosition = cursor + 4;
|
||||
event.accepted = true;
|
||||
} else if ((event.key === Qt.Key_C) && event.modifiers == Qt.ControlModifier) {
|
||||
codeTextArea.copy();
|
||||
event.accepted = true;
|
||||
Layout.margins: 6
|
||||
Layout.topMargin: 0
|
||||
sourceComponent: RowLayout {
|
||||
Item { Layout.fillWidth: true }
|
||||
ButtonGroup {
|
||||
GroupButton {
|
||||
contentItem: StyledText {
|
||||
text: Translation.tr("Reject")
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
color: Appearance.colors.colOnLayer2
|
||||
}
|
||||
onClicked: Ai.rejectCommand(root.messageData)
|
||||
}
|
||||
GroupButton {
|
||||
toggled: true
|
||||
contentItem: StyledText {
|
||||
text: Translation.tr("Approve")
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
color: Appearance.colors.colOnPrimary
|
||||
}
|
||||
onClicked: Ai.approveCommand(root.messageData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SyntaxHighlighter {
|
||||
id: highlighter
|
||||
textEdit: codeTextArea
|
||||
repository: Repository
|
||||
definition: Repository.definitionForName(segmentLang || "plaintext")
|
||||
theme: Appearance.syntaxHighlightingTheme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ Item {
|
||||
id: thinkBlockLanguage
|
||||
Layout.fillWidth: false
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
text: root.completed ? Translation.tr("Chain of Thought") : (Translation.tr("Thinking") + ".".repeat(Math.random() * 4))
|
||||
text: root.completed ? Translation.tr("Thought") : (Translation.tr("Thinking") + ".".repeat(Math.random() * 4))
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
RippleButton { // Expand button
|
||||
|
||||
@@ -97,7 +97,7 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
Flickable { // Tag strip
|
||||
StyledFlickable { // Tag strip
|
||||
id: tagsFlickable
|
||||
visible: root.responseData.tags.length > 0
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
@@ -87,7 +87,7 @@ Scope {
|
||||
implicitWidth: sidebarWidth - Appearance.sizes.hyprlandGapsOut * 2
|
||||
color: Appearance.colors.colLayer0
|
||||
border.width: 1
|
||||
border.color: Appearance.m3colors.m3outlineVariant
|
||||
border.color: Appearance.colors.colLayer0Border
|
||||
radius: Appearance.rounding.screenRounding - Appearance.sizes.hyprlandGapsOut + 1
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
@@ -16,7 +16,7 @@ Item {
|
||||
property int todoListItemPadding: 8
|
||||
property int listBottomPadding: 80
|
||||
|
||||
Flickable {
|
||||
StyledFlickable {
|
||||
id: flickable
|
||||
anchors.fill: parent
|
||||
contentHeight: columnLayout.height
|
||||
|
||||
@@ -40,7 +40,7 @@ Item {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
ListView {
|
||||
StyledListView {
|
||||
id: listView
|
||||
model: root.appPwNodes
|
||||
clip: true
|
||||
@@ -187,7 +187,7 @@ Item {
|
||||
Layout.rightMargin: dialogMargins
|
||||
}
|
||||
|
||||
Flickable {
|
||||
StyledFlickable {
|
||||
id: dialogFlickable
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//@ pragma UseQApplication
|
||||
//@ pragma Env QS_NO_RELOAD_POPUP=1
|
||||
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
|
||||
//@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000
|
||||
|
||||
// Adjust this to make it smaller or larger
|
||||
//@ pragma Env QT_SCALE_FACTOR=1
|
||||
|
||||
@@ -6,11 +6,15 @@ import qs.modules.common
|
||||
import qs
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import "./ai/"
|
||||
|
||||
/**
|
||||
* Basic service to handle LLM chats. Supports Google's and OpenAI's API formats.
|
||||
* Supports Gemini and OpenAI models.
|
||||
* Limitations:
|
||||
* - For now functions only work with Gemini API format
|
||||
*/
|
||||
Singleton {
|
||||
id: root
|
||||
@@ -19,10 +23,19 @@ Singleton {
|
||||
property Component aiModelComponent: AiModel {}
|
||||
property Component geminiApiStrategy: GeminiApiStrategy {}
|
||||
property Component openaiApiStrategy: OpenAiApiStrategy {}
|
||||
property Component mistralApiStrategy: MistralApiStrategy {}
|
||||
readonly property string interfaceRole: "interface"
|
||||
readonly property string apiKeyEnvVarName: "API_KEY"
|
||||
|
||||
property string systemPrompt: Config.options?.ai?.systemPrompt ?? ""
|
||||
property string systemPrompt: {
|
||||
let prompt = Config.options?.ai?.systemPrompt ?? "";
|
||||
for (let key in root.promptSubstitutions) {
|
||||
// prompt = prompt.replaceAll(key, root.promptSubstitutions[key]);
|
||||
// QML/JS doesn't support replaceAll, so use split/join
|
||||
prompt = prompt.split(key).join(root.promptSubstitutions[key]);
|
||||
}
|
||||
return prompt;
|
||||
}
|
||||
// property var messages: []
|
||||
property var messageIDs: []
|
||||
property var messageByID: ({})
|
||||
@@ -49,7 +62,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function safeModelName(modelName) {
|
||||
return modelName.replace(/:/g, "_").replace(/\./g, "_")
|
||||
return modelName.replace(/:/g, "_").replace(/\./g, "_").replace(/ /g, "-").replace(/\//g, "-")
|
||||
}
|
||||
|
||||
property list<var> defaultPrompts: []
|
||||
@@ -57,64 +70,169 @@ Singleton {
|
||||
property list<var> promptFiles: [...defaultPrompts, ...userPrompts]
|
||||
property list<var> savedChats: []
|
||||
|
||||
property var promptSubstitutions: {
|
||||
"{DISTRO}": SystemInfo.distroName,
|
||||
"{DATETIME}": `${DateTime.time}, ${DateTime.collapsedCalendarFormat}`,
|
||||
"{WINDOWCLASS}": ToplevelManager.activeToplevel?.appId ?? "Unknown",
|
||||
"{DE}": `${SystemInfo.desktopEnvironment} (${SystemInfo.windowingSystem})`
|
||||
}
|
||||
|
||||
// Gemini: https://ai.google.dev/gemini-api/docs/function-calling
|
||||
// OpenAI: https://platform.openai.com/docs/guides/function-calling
|
||||
property string currentTool: Config?.options.ai.tool ?? "search"
|
||||
property var tools: {
|
||||
"gemini": [{"functionDeclarations": [
|
||||
{
|
||||
"name": "switch_to_search_mode",
|
||||
"description": "Search the web",
|
||||
},
|
||||
{
|
||||
"name": "get_shell_config",
|
||||
"description": "Get the desktop shell config file contents",
|
||||
},
|
||||
{
|
||||
"name": "set_shell_config",
|
||||
"description": "Set a field in the desktop graphical shell config file. Must only be used after `get_shell_config`.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "The key to set, e.g. `bar.borderless`. MUST NOT BE GUESSED, use `get_shell_config` to see what keys are available before setting.",
|
||||
"gemini": {
|
||||
"functions": [{"functionDeclarations": [
|
||||
{
|
||||
"name": "switch_to_search_mode",
|
||||
"description": "Search the web",
|
||||
},
|
||||
{
|
||||
"name": "get_shell_config",
|
||||
"description": "Get the desktop shell config file contents",
|
||||
},
|
||||
{
|
||||
"name": "set_shell_config",
|
||||
"description": "Set a field in the desktop graphical shell config file. Must only be used after `get_shell_config`.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "The key to set, e.g. `bar.borderless`. MUST NOT BE GUESSED, use `get_shell_config` to see what keys are available before setting.",
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The value to set, e.g. `true`"
|
||||
}
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The value to set, e.g. `true`"
|
||||
"required": ["key", "value"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "run_shell_command",
|
||||
"description": "Run a shell command in bash and get its output. Use this only for quick commands that don't require user interaction. For commands that require interaction, ask the user to run manually instead.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "The bash command to run",
|
||||
},
|
||||
},
|
||||
"required": ["command"]
|
||||
}
|
||||
},
|
||||
]}],
|
||||
"search": [{
|
||||
"google_search": {}
|
||||
}],
|
||||
"none": []
|
||||
},
|
||||
"openai": {
|
||||
"functions": [
|
||||
{
|
||||
"name": "switch_to_search_mode",
|
||||
"description": "Search the web",
|
||||
},
|
||||
{
|
||||
"name": "get_shell_config",
|
||||
"description": "Get the desktop shell config file contents",
|
||||
},
|
||||
{
|
||||
"name": "set_shell_config",
|
||||
"description": "Set a field in the desktop graphical shell config file. Must only be used after `get_shell_config`.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "The key to set, e.g. `bar.borderless`. MUST NOT BE GUESSED, use `get_shell_config` to see what keys are available before setting.",
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The value to set, e.g. `true`"
|
||||
}
|
||||
},
|
||||
"required": ["key", "value"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "run_shell_command",
|
||||
"description": "Run a shell command in bash and get its output. Use this only for quick commands that don't require user interaction. For commands that require interaction, ask the user to run manually instead.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "The bash command to run",
|
||||
},
|
||||
},
|
||||
"required": ["command"]
|
||||
}
|
||||
},
|
||||
],
|
||||
"search": [],
|
||||
"none": [],
|
||||
},
|
||||
"mistral": {
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_shell_config",
|
||||
"description": "Get the desktop shell config file contents",
|
||||
"parameters": {}
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "set_shell_config",
|
||||
"description": "Set a field in the desktop graphical shell config file. Must only be used after `get_shell_config`.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "The key to set, e.g. `bar.borderless`. MUST NOT BE GUESSED, use `get_shell_config` to see what keys are available before setting.",
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The value to set, e.g. `true`"
|
||||
}
|
||||
},
|
||||
"required": ["key", "value"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "run_shell_command",
|
||||
"description": "Run a shell command in bash and get its output. Use this only for quick commands that don't require user interaction. For commands that require interaction, ask the user to run manually instead.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "The bash command to run",
|
||||
},
|
||||
},
|
||||
"required": ["command"]
|
||||
}
|
||||
},
|
||||
"required": ["key", "value"]
|
||||
}
|
||||
},
|
||||
]}],
|
||||
"openai": [
|
||||
{
|
||||
"type": "function",
|
||||
"name": "get_shell_config",
|
||||
"description": "Get the current shell configuration.",
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"name": "set_shell_config",
|
||||
"description": "Set a field in the desktop graphical shell config file. Must only be used after `get_shell_config`.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "The key to set, e.g. `bar.borderless`. MUST NOT BE GUESSED, use `get_shell_config` to see what keys are available before setting.",
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The value to set, e.g. `true`"
|
||||
}
|
||||
},
|
||||
"required": ["key", "value"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
"search": [],
|
||||
"none": [],
|
||||
}
|
||||
}
|
||||
property list<var> availableTools: Object.keys(root.tools[models[currentModelId]?.api_format])
|
||||
property var toolDescriptions: {
|
||||
"functions": Translation.tr("Commands, edit configs, search.\nTakes an extra turn to switch to search mode if that's needed"),
|
||||
"search": Translation.tr("Gives the model search capabilities (immediately)"),
|
||||
"none": Translation.tr("Disable tools")
|
||||
}
|
||||
|
||||
// Model properties:
|
||||
@@ -128,13 +246,12 @@ Singleton {
|
||||
// - key_get_link: Link to get an API key
|
||||
// - key_get_description: Description of pricing and how to get an API key
|
||||
// - api_format: The API format of the model. Can be "openai" or "gemini". Default is "openai".
|
||||
// - tools: List of tools that the model can use. Each tool is an object with the tool name as the key and an empty object as the value.
|
||||
// - extraParams: Extra parameters to be passed to the model. This is a JSON object.
|
||||
property var models: {
|
||||
"gemini-2.0-flash-search": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.0 Flash (Search)",
|
||||
"gemini-2.0-flash": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.0 Flash",
|
||||
"icon": "google-gemini-symbolic",
|
||||
"description": Translation.tr("Online | Google's model\nGives up-to-date information with search."),
|
||||
"description": Translation.tr("Online | Google's model\nFast, can perform searches for up-to-date information"),
|
||||
"homepage": "https://aistudio.google.com",
|
||||
"endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:streamGenerateContent",
|
||||
"model": "gemini-2.0-flash",
|
||||
@@ -143,28 +260,11 @@ Singleton {
|
||||
"key_get_link": "https://aistudio.google.com/app/apikey",
|
||||
"key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
|
||||
"api_format": "gemini",
|
||||
"tools": [{
|
||||
"google_search": {}
|
||||
}]
|
||||
}),
|
||||
"gemini-2.0-flash-tools": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.0 Flash (Tools)",
|
||||
"gemini-2.5-flash": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.5 Flash",
|
||||
"icon": "google-gemini-symbolic",
|
||||
"description": Translation.tr("Experimental | Online | Google's model\nCan do a little more but takes an extra turn to perform search"),
|
||||
"homepage": "https://aistudio.google.com",
|
||||
"endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:streamGenerateContent",
|
||||
"model": "gemini-2.0-flash",
|
||||
"requires_key": true,
|
||||
"key_id": "gemini",
|
||||
"key_get_link": "https://aistudio.google.com/app/apikey",
|
||||
"key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
|
||||
"api_format": "gemini",
|
||||
"tools": root.tools["gemini"],
|
||||
}),
|
||||
"gemini-2.5-flash-search": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.5 Flash (Search)",
|
||||
"icon": "google-gemini-symbolic",
|
||||
"description": Translation.tr("Online | Google's model\nGives up-to-date information with search."),
|
||||
"description": Translation.tr("Online | Google's model\nNewer model that's slower than its predecessor but should deliver higher quality answers"),
|
||||
"homepage": "https://aistudio.google.com",
|
||||
"endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent",
|
||||
"model": "gemini-2.5-flash",
|
||||
@@ -173,44 +273,24 @@ Singleton {
|
||||
"key_get_link": "https://aistudio.google.com/app/apikey",
|
||||
"key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
|
||||
"api_format": "gemini",
|
||||
"tools": [{
|
||||
"google_search": {}
|
||||
}]
|
||||
}),
|
||||
"gemini-2.5-flash-tools": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.5 Flash (Tools)",
|
||||
"gemini-2.5-flash-pro": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.5 Pro",
|
||||
"icon": "google-gemini-symbolic",
|
||||
"description": Translation.tr("Experimental | Online | Google's model\nCan do a little more but takes an extra turn to perform search"),
|
||||
"description": Translation.tr("Online | Google's model\nGoogle's state-of-the-art multipurpose model that excels at coding and complex reasoning tasks."),
|
||||
"homepage": "https://aistudio.google.com",
|
||||
"endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent",
|
||||
"model": "gemini-2.5-flash",
|
||||
"endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:streamGenerateContent",
|
||||
"model": "gemini-2.5-pro",
|
||||
"requires_key": true,
|
||||
"key_id": "gemini",
|
||||
"key_get_link": "https://aistudio.google.com/app/apikey",
|
||||
"key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
|
||||
"api_format": "gemini",
|
||||
"tools": root.tools["gemini"],
|
||||
}),
|
||||
"gemini-2.5-flash-lite-search": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.5 Flash-Lite (Search)",
|
||||
"icon": "google-gemini-symbolic",
|
||||
"description": Translation.tr("Experimental | Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput."),
|
||||
"homepage": "https://aistudio.google.com",
|
||||
"endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:streamGenerateContent",
|
||||
"model": "gemini-2.5-flash-lite",
|
||||
"requires_key": true,
|
||||
"key_id": "gemini",
|
||||
"key_get_link": "https://aistudio.google.com/app/apikey",
|
||||
"key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
|
||||
"api_format": "gemini",
|
||||
"tools": [{
|
||||
"google_search": {}
|
||||
}]
|
||||
}),
|
||||
"gemini-2.5-flash-lite": aiModelComponent.createObject(this, {
|
||||
"name": "Gemini 2.5 Flash-Lite",
|
||||
"icon": "google-gemini-symbolic",
|
||||
"description": Translation.tr("Experimental | Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput."),
|
||||
"description": Translation.tr("Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput."),
|
||||
"homepage": "https://aistudio.google.com",
|
||||
"endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:streamGenerateContent",
|
||||
"model": "gemini-2.5-flash-lite",
|
||||
@@ -219,19 +299,19 @@ Singleton {
|
||||
"key_get_link": "https://aistudio.google.com/app/apikey",
|
||||
"key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
|
||||
"api_format": "gemini",
|
||||
"tools": root.tools["gemini"],
|
||||
}),
|
||||
"openrouter-llama4-maverick": aiModelComponent.createObject(this, {
|
||||
"name": "Llama 4 Maverick",
|
||||
"icon": "ollama-symbolic",
|
||||
"description": Translation.tr("Online via %1 | %2's model").arg("OpenRouter").arg("Meta"),
|
||||
"homepage": "https://openrouter.ai/meta-llama/llama-4-maverick:free",
|
||||
"endpoint": "https://openrouter.ai/api/v1/chat/completions",
|
||||
"model": "meta-llama/llama-4-maverick:free",
|
||||
"mistral-medium-3": aiModelComponent.createObject(this, {
|
||||
"name": "Mistral Medium 3",
|
||||
"icon": "mistral-symbolic",
|
||||
"description": Translation.tr("Online | %1's model | Delivers fast, responsive and well-formatted answers. Disadvantages: not very eager to do stuff; might make up unknown function calls").arg("Mistral"),
|
||||
"homepage": "https://mistral.ai/news/mistral-medium-3",
|
||||
"endpoint": "https://api.mistral.ai/v1/chat/completions",
|
||||
"model": "mistral-medium-2505",
|
||||
"requires_key": true,
|
||||
"key_id": "openrouter",
|
||||
"key_get_link": "https://openrouter.ai/settings/keys",
|
||||
"key_get_description": Translation.tr("**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key"),
|
||||
"key_id": "mistral",
|
||||
"key_get_link": "https://console.mistral.ai/api-keys",
|
||||
"key_get_description": Translation.tr("**Instructions**: Log into Mistral account, go to Keys on the sidebar, click Create new key"),
|
||||
"api_format": "mistral",
|
||||
}),
|
||||
"openrouter-deepseek-r1": aiModelComponent.createObject(this, {
|
||||
"name": "DeepSeek R1",
|
||||
@@ -252,9 +332,21 @@ Singleton {
|
||||
property var apiStrategies: {
|
||||
"openai": openaiApiStrategy.createObject(this),
|
||||
"gemini": geminiApiStrategy.createObject(this),
|
||||
"mistral": mistralApiStrategy.createObject(this),
|
||||
}
|
||||
property ApiStrategy currentApiStrategy: apiStrategies[models[currentModelId]?.api_format || "openai"]
|
||||
|
||||
Connections {
|
||||
target: Config
|
||||
function onReadyChanged() {
|
||||
if (!Config.ready) return;
|
||||
(Config?.options.ai?.extraModels ?? []).forEach(model => {
|
||||
const safeModelName = root.safeModelName(model["model"]);
|
||||
root.addModel(safeModelName, model)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
setModel(currentModelId, false, false); // Do necessary setup for model
|
||||
}
|
||||
@@ -280,6 +372,10 @@ Singleton {
|
||||
return result;
|
||||
}
|
||||
|
||||
function addModel(modelName, data) {
|
||||
root.models[modelName] = aiModelComponent.createObject(this, data);
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getOllamaModels
|
||||
running: true
|
||||
@@ -292,7 +388,7 @@ Singleton {
|
||||
root.modelList = [...root.modelList, ...dataJson];
|
||||
dataJson.forEach(model => {
|
||||
const safeModelName = root.safeModelName(model);
|
||||
root.models[safeModelName] = aiModelComponent.createObject(this, {
|
||||
root.addModel(safeModelName, {
|
||||
"name": guessModelName(model),
|
||||
"icon": guessModelLogo(model),
|
||||
"description": Translation.tr("Local Ollama model | %1").arg(model),
|
||||
@@ -398,8 +494,8 @@ Singleton {
|
||||
|
||||
function addApiKeyAdvice(model) {
|
||||
root.addMessage(
|
||||
Translation.tr('To set an API key, pass it with the command\n\nTo view the key, pass "get" with the command<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3')
|
||||
.arg(model.name).arg(model.key_get_link).arg(model.key_get_description ?? Translation.tr("<i>No further instruction provided</i>")),
|
||||
Translation.tr('To set an API key, pass it with the %4 command\n\nTo view the key, pass "get" with the command<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3')
|
||||
.arg(model.name).arg(model.key_get_link).arg(model.key_get_description ?? Translation.tr("<i>No further instruction provided</i>")).arg("/key"),
|
||||
Ai.interfaceRole
|
||||
);
|
||||
}
|
||||
@@ -435,6 +531,15 @@ Singleton {
|
||||
if (feedback) root.addMessage(Translation.tr("Invalid model. Supported: \n```\n") + modelList.join("\n```\n```\n"), Ai.interfaceRole) + "\n```"
|
||||
}
|
||||
}
|
||||
|
||||
function setTool(tool) {
|
||||
if (!root.tools[models[currentModelId]?.api_format] || !(tool in root.tools[models[currentModelId]?.api_format])) {
|
||||
root.addMessage(Translation.tr("Invalid tool. Supported tools:\n- %1").arg(root.availableTools.join("\n- ")), root.interfaceRole);
|
||||
return false;
|
||||
}
|
||||
Config.options.ai.tool = tool;
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTemperature() {
|
||||
return root.temperature;
|
||||
@@ -493,7 +598,7 @@ Singleton {
|
||||
|
||||
Process {
|
||||
id: requester
|
||||
property var baseCommand: ["bash", "-c"]
|
||||
property list<string> baseCommand: ["bash", "-c"]
|
||||
property AiMessageData message
|
||||
property ApiStrategy currentStrategy
|
||||
|
||||
@@ -518,7 +623,7 @@ Singleton {
|
||||
const endpoint = root.currentApiStrategy.buildEndpoint(model);
|
||||
const messageArray = root.messageIDs.map(id => root.messageByID[id]);
|
||||
const filteredMessageArray = messageArray.filter(message => message.role !== Ai.interfaceRole);
|
||||
const data = root.currentApiStrategy.buildRequestData(model, filteredMessageArray, root.systemPrompt, root.temperature);
|
||||
const data = root.currentApiStrategy.buildRequestData(model, filteredMessageArray, root.systemPrompt, root.temperature, root.tools[model.api_format][root.currentTool]);
|
||||
// console.log("[Ai] Request data: ", JSON.stringify(data, null, 2));
|
||||
|
||||
let requestHeaders = {
|
||||
@@ -563,9 +668,9 @@ Singleton {
|
||||
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
// console.log("[Ai] Raw response line: ", data);
|
||||
if (data.length === 0) return;
|
||||
if (requester.message.thinking) requester.message.thinking = false;
|
||||
// console.log("[Ai] Raw response line: ", data);
|
||||
|
||||
// Handle response line
|
||||
try {
|
||||
@@ -573,7 +678,8 @@ Singleton {
|
||||
// console.log("[Ai] Parsed response result: ", JSON.stringify(result, null, 2));
|
||||
|
||||
if (result.functionCall) {
|
||||
root.handleFunctionCall(result.functionCall.name, result.functionCall.args);
|
||||
requester.message.functionCall = result.functionCall;
|
||||
root.handleFunctionCall(result.functionCall.name, result.functionCall.args, requester.message);
|
||||
}
|
||||
if (result.tokenUsage) {
|
||||
root.tokenCount.input = result.tokenUsage.input;
|
||||
@@ -614,38 +720,72 @@ Singleton {
|
||||
requester.makeRequest();
|
||||
}
|
||||
|
||||
function addFunctionOutputMessage(name, output) {
|
||||
const aiMessage = aiMessageComponent.createObject(root, {
|
||||
function createFunctionOutputMessage(name, output, includeOutputInChat = true) {
|
||||
return aiMessageComponent.createObject(root, {
|
||||
"role": "user",
|
||||
"content": `[[ Output of ${name} ]]`,
|
||||
"rawContent": `[[ Output of ${name} ]]`,
|
||||
"content": `[[ Output of ${name} ]]${includeOutputInChat ? ("\n\n<think>\n" + output + "\n</think>") : ""}`,
|
||||
"rawContent": `[[ Output of ${name} ]]${includeOutputInChat ? ("\n\n<think>\n" + output + "\n</think>") : ""}`,
|
||||
"functionName": name,
|
||||
"functionResponse": output,
|
||||
"thinking": false,
|
||||
"done": true,
|
||||
"visibleToUser": false,
|
||||
// "visibleToUser": false,
|
||||
});
|
||||
// console.log("Adding function output message: ", JSON.stringify(aiMessage));
|
||||
}
|
||||
|
||||
function addFunctionOutputMessage(name, output) {
|
||||
const aiMessage = createFunctionOutputMessage(name, output);
|
||||
const id = idForMessage(aiMessage);
|
||||
root.messageIDs = [...root.messageIDs, id];
|
||||
root.messageByID[id] = aiMessage;
|
||||
}
|
||||
|
||||
function handleFunctionCall(name, args) {
|
||||
function rejectCommand(message: AiMessageData) {
|
||||
if (!message.functionPending) return;
|
||||
message.functionPending = false; // User decided, no more "thinking"
|
||||
addFunctionOutputMessage(message.functionName, Translation.tr("Command rejected by user"))
|
||||
}
|
||||
|
||||
function approveCommand(message: AiMessageData) {
|
||||
if (!message.functionPending) return;
|
||||
message.functionPending = false; // User decided, no more "thinking"
|
||||
|
||||
const responseMessage = createFunctionOutputMessage(message.functionName, "", false);
|
||||
const id = idForMessage(responseMessage);
|
||||
root.messageIDs = [...root.messageIDs, id];
|
||||
root.messageByID[id] = responseMessage;
|
||||
|
||||
commandExecutionProc.message = responseMessage;
|
||||
commandExecutionProc.baseMessageContent = responseMessage.content;
|
||||
commandExecutionProc.shellCommand = message.functionCall.args.command;
|
||||
commandExecutionProc.running = true; // Start the command execution
|
||||
}
|
||||
|
||||
Process {
|
||||
id: commandExecutionProc
|
||||
property string shellCommand: ""
|
||||
property AiMessageData message
|
||||
property string baseMessageContent: ""
|
||||
command: ["bash", "-c", shellCommand]
|
||||
stdout: SplitParser {
|
||||
onRead: (output) => {
|
||||
commandExecutionProc.message.functionResponse += output + "\n\n";
|
||||
const updatedContent = commandExecutionProc.baseMessageContent + `\n\n<think>\n<tt>${commandExecutionProc.message.functionResponse}</tt>\n</think>`;
|
||||
commandExecutionProc.message.rawContent = updatedContent;
|
||||
commandExecutionProc.message.content = updatedContent;
|
||||
}
|
||||
}
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
commandExecutionProc.message.functionResponse += `[[ Command exited with code ${exitCode} (${exitStatus}) ]]\n`;
|
||||
requester.makeRequest(); // Continue
|
||||
}
|
||||
}
|
||||
|
||||
function handleFunctionCall(name, args: var, message: AiMessageData) {
|
||||
if (name === "switch_to_search_mode") {
|
||||
const modelId = root.currentModelId;
|
||||
if (modelId.endsWith("-tools")) {
|
||||
const searchModelId = modelId.replace(/-tools$/, "-search");
|
||||
if (root.modelList.indexOf(searchModelId) !== -1) {
|
||||
root.setModel(searchModelId, false);
|
||||
root.postResponseHook = () => root.setModel(modelId, false);
|
||||
} else {
|
||||
root.addMessage(Translation.tr("No corresponding search model found for %1").arg(modelId), Ai.interfaceRole);
|
||||
}
|
||||
} else {
|
||||
root.addMessage(Translation.tr("Cannot switch to search mode from %1").arg(root.currentModelId), Ai.interfaceRole);
|
||||
return;
|
||||
}
|
||||
root.currentTool = "search"
|
||||
root.postResponseHook = () => { root.currentTool = "functions" }
|
||||
addFunctionOutputMessage(name, Translation.tr("Switched to search mode. Continue with the user's request."))
|
||||
requester.makeRequest();
|
||||
} else if (name === "get_shell_config") {
|
||||
@@ -660,6 +800,15 @@ Singleton {
|
||||
const key = args.key;
|
||||
const value = args.value;
|
||||
Config.setNestedValue(key, value);
|
||||
} else if (name === "run_shell_command") {
|
||||
if (!args.command || args.command.length === 0) {
|
||||
addFunctionOutputMessage(name, Translation.tr("Invalid arguments. Must provide `command`."));
|
||||
return;
|
||||
}
|
||||
const contentToAppend = `\n\n**Command execution request**\n\n\`\`\`command\n${args.command}\n\`\`\``;
|
||||
message.rawContent += contentToAppend;
|
||||
message.content += contentToAppend;
|
||||
message.functionPending = true; // Use thinking to indicate the command is waiting for approval
|
||||
}
|
||||
else root.addMessage(Translation.tr("Unknown function call: %1").arg(name), "assistant");
|
||||
}
|
||||
|
||||
@@ -69,10 +69,11 @@ Singleton {
|
||||
|
||||
Process {
|
||||
id: getClients
|
||||
command: ["bash", "-c", "hyprctl clients -j | jq -c"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.windowList = JSON.parse(data);
|
||||
command: ["bash", "-c", "hyprctl clients -j"]
|
||||
stdout: StdioCollector {
|
||||
id: clientsCollector
|
||||
onStreamFinished: {
|
||||
root.windowList = JSON.parse(clientsCollector.text)
|
||||
let tempWinByAddress = {};
|
||||
for (var i = 0; i < root.windowList.length; ++i) {
|
||||
var win = root.windowList[i];
|
||||
@@ -86,30 +87,33 @@ Singleton {
|
||||
|
||||
Process {
|
||||
id: getMonitors
|
||||
command: ["bash", "-c", "hyprctl monitors -j | jq -c"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.monitors = JSON.parse(data);
|
||||
command: ["bash", "-c", "hyprctl monitors -j"]
|
||||
stdout: StdioCollector {
|
||||
id: monitorsCollector
|
||||
onStreamFinished: {
|
||||
root.monitors = JSON.parse(monitorsCollector.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getLayers
|
||||
command: ["bash", "-c", "hyprctl layers -j | jq -c"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.layers = JSON.parse(data);
|
||||
command: ["bash", "-c", "hyprctl layers -j"]
|
||||
stdout: StdioCollector {
|
||||
id: layersCollector
|
||||
onStreamFinished: {
|
||||
root.layers = JSON.parse(layersCollector.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getWorkspaces
|
||||
command: ["bash", "-c", "hyprctl workspaces -j | jq -c"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.workspaces = JSON.parse(data);
|
||||
command: ["bash", "-c", "hyprctl workspaces -j"]
|
||||
stdout: StdioCollector {
|
||||
id: workspacesCollector
|
||||
onStreamFinished: {
|
||||
root.workspaces = JSON.parse(workspacesCollector.text);
|
||||
let tempWorkspaceById = {};
|
||||
for (var i = 0; i < root.workspaces.length; ++i) {
|
||||
var ws = root.workspaces[i];
|
||||
@@ -123,10 +127,11 @@ Singleton {
|
||||
|
||||
Process {
|
||||
id: getActiveWorkspace
|
||||
command: ["bash", "-c", "hyprctl activeworkspace -j | jq -c"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.activeWorkspace = JSON.parse(data);
|
||||
command: ["bash", "-c", "hyprctl activeworkspace -j"]
|
||||
stdout: StdioCollector {
|
||||
id: activeWorkspaceCollector
|
||||
onStreamFinished: {
|
||||
root.activeWorkspace = JSON.parse(activeWorkspaceCollector.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
import qs.modules.common
|
||||
|
||||
/**
|
||||
* Exposes the active Hyprland Xkb keyboard layout name and code for indicators.
|
||||
@@ -16,7 +17,6 @@ Singleton {
|
||||
property string currentLayoutName: ""
|
||||
property string currentLayoutCode: ""
|
||||
// For the service
|
||||
property string targetDeviceName: "hl-virtual-keyboard"
|
||||
property var baseLayoutFilePath: "/usr/share/X11/xkb/rules/base.lst"
|
||||
property bool needsLayoutRefresh: false
|
||||
|
||||
@@ -71,7 +71,7 @@ Singleton {
|
||||
id: devicesCollector
|
||||
onStreamFinished: {
|
||||
const parsedOutput = JSON.parse(devicesCollector.text);
|
||||
const hyprlandKeyboard = parsedOutput["keyboards"].find(kb => kb.name === root.targetDeviceName);
|
||||
const hyprlandKeyboard = parsedOutput["keyboards"].find(kb => kb.main === true);
|
||||
root.layoutCodes = hyprlandKeyboard["layout"].split(",");
|
||||
root.currentLayoutName = hyprlandKeyboard["active_keymap"];
|
||||
// console.log("[HyprlandXkb] Fetched | Layouts (multiple: " + (root.layouts.length > 1) + "): "
|
||||
@@ -85,8 +85,6 @@ Singleton {
|
||||
target: Hyprland
|
||||
function onRawEvent(event) {
|
||||
if (event.name === "activelayout") {
|
||||
// We're triggering refresh here because Hyprland virtual kb after a config reload disappears
|
||||
// from `hyprctl devices` and it only comes back at the next activelayout event.
|
||||
if (root.needsLayoutRefresh) {
|
||||
root.needsLayoutRefresh = false;
|
||||
fetchLayoutsProc.running = true;
|
||||
@@ -97,9 +95,10 @@ Singleton {
|
||||
|
||||
// Update when layout might have changed
|
||||
const dataString = event.data;
|
||||
if (!dataString.startsWith(root.targetDeviceName))
|
||||
return;
|
||||
root.currentLayoutName = dataString.split(",")[1];
|
||||
|
||||
// Update layout for on-screen keyboard (osk)
|
||||
Config.options.osk.layout = root.currentLayoutName;
|
||||
} else if (event.name == "configreloaded") {
|
||||
// Mark layout code list to be updated when config is reloaded
|
||||
root.needsLayoutRefresh = true;
|
||||
|
||||
@@ -34,11 +34,9 @@ Singleton {
|
||||
property string urgency: notification?.urgency.toString() ?? "normal"
|
||||
property Timer timer
|
||||
|
||||
readonly property Connections conn: Connections {
|
||||
target: wrapper?.notification?.Component ?? root // stupid warning aaaaaaa
|
||||
|
||||
function onDestruction(): void {
|
||||
wrapper.destroy();
|
||||
onNotificationChanged: {
|
||||
if (notification === null) {
|
||||
root.discardNotification(notificationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ Singleton {
|
||||
property string bugReportUrl: ""
|
||||
property string privacyPolicyUrl: ""
|
||||
property string logo: ""
|
||||
property string desktopEnvironment: ""
|
||||
property string windowingSystem: ""
|
||||
|
||||
Timer {
|
||||
triggeredOnStart: true
|
||||
@@ -83,6 +85,20 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getDesktopEnvironment
|
||||
running: true
|
||||
command: ["bash", "-c", "echo $XDG_CURRENT_DESKTOP,$WAYLAND_DISPLAY"]
|
||||
stdout: StdioCollector {
|
||||
id: deCollector
|
||||
onStreamFinished: {
|
||||
const [desktop, wayland] = deCollector.text.split(",")
|
||||
root.desktopEnvironment = desktop.trim()
|
||||
root.windowingSystem = wayland.trim().length > 0 ? "Wayland" : "X11" // Are there others? 🤔
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: fileOsRelease
|
||||
path: "/etc/os-release"
|
||||
|
||||
@@ -14,7 +14,8 @@ QtObject {
|
||||
property var annotationSources: []
|
||||
property list<string> searchQueries: []
|
||||
property string functionName
|
||||
property string functionCall
|
||||
property var functionCall
|
||||
property string functionResponse
|
||||
property bool functionPending: false
|
||||
property bool visibleToUser: true
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import QtQuick;
|
||||
* - key_get_link: Link to get an API key
|
||||
* - key_get_description: Description of pricing and how to get an API key
|
||||
* - api_format: The API format of the model. Can be "openai" or "gemini". Default is "openai".
|
||||
* - tools: List of tools that the model can use.
|
||||
* - extraParams: Extra parameters to be passed to the model. This is a JSON object.
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import QtQuick
|
||||
|
||||
QtObject {
|
||||
function buildEndpoint(model: AiModel): string { throw new Error("Not implemented") }
|
||||
function buildRequestData(model: AiModel, messages, systemPrompt: string, temperature: real) { throw new Error("Not implemented") }
|
||||
function buildRequestData(model: AiModel, messages, systemPrompt: string, temperature: real, tools: list<var>) { throw new Error("Not implemented") }
|
||||
function buildAuthorizationHeader(apiKeyEnvVarName: string): string { throw new Error("Not implemented") }
|
||||
function parseResponseLine(line: string, message: AiMessageData) { throw new Error("Not implemented") }
|
||||
function onRequestFinished(message: AiMessageData): var { return {} } // Default: no special handling
|
||||
|
||||
@@ -5,17 +5,16 @@ ApiStrategy {
|
||||
|
||||
function buildEndpoint(model: AiModel): string {
|
||||
const result = model.endpoint + `?key=\$\{${root.apiKeyEnvVarName}\}`
|
||||
console.log("[AI] Endpoint: " + result);
|
||||
// console.log("[AI] Endpoint: " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function buildRequestData(model: AiModel, messages, systemPrompt: string, temperature: real) {
|
||||
const tools = model.tools ?? [];
|
||||
function buildRequestData(model: AiModel, messages, systemPrompt: string, temperature: real, tools: list<var>) {
|
||||
let baseData = {
|
||||
"contents": messages.map(message => {
|
||||
const geminiApiRoleName = (message.role === "assistant") ? "model" : message.role;
|
||||
const usingSearch = tools[0].google_search != undefined
|
||||
if (!usingSearch && message.functionCall != undefined && message.functionCall.length > 0) {
|
||||
const usingSearch = tools[0]?.google_search !== undefined
|
||||
if (!usingSearch && message.functionCall != undefined && message.functionName.length > 0) {
|
||||
return {
|
||||
"role": geminiApiRoleName,
|
||||
"parts": [{
|
||||
@@ -25,7 +24,7 @@ ApiStrategy {
|
||||
}]
|
||||
}
|
||||
}
|
||||
if (!usingSearch && message.functionResponse != undefined && message.functionResponse.length > 0) {
|
||||
if (!usingSearch && message.functionResponse != undefined && message.functionName.length > 0) {
|
||||
return {
|
||||
"role": geminiApiRoleName,
|
||||
"parts": [{
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import QtQuick
|
||||
|
||||
ApiStrategy {
|
||||
property bool isReasoning: false
|
||||
|
||||
function buildEndpoint(model: AiModel): string {
|
||||
// console.log("[AI] Endpoint: " + model.endpoint);
|
||||
return model.endpoint;
|
||||
}
|
||||
|
||||
function buildRequestData(model: AiModel, messages, systemPrompt: string, temperature: real, tools: list<var>) {
|
||||
let baseData = {
|
||||
"model": model.model,
|
||||
"messages": [
|
||||
{role: "system", content: systemPrompt},
|
||||
...messages.map(message => {
|
||||
const hasFunctionCall = message.functionCall != undefined && message.functionName.length > 0
|
||||
let messageData = {
|
||||
"role": message.role,
|
||||
"content": message.rawContent,
|
||||
}
|
||||
if (hasFunctionCall) {
|
||||
if (message.functionResponse?.length > 0) {
|
||||
messageData.name = message.functionName; // Does the func call also need this name? or just the func output?
|
||||
messageData.role = "tool";
|
||||
messageData.content = message.functionResponse;
|
||||
messageData.tool_call_id = message.functionCall.id
|
||||
}
|
||||
}
|
||||
return messageData
|
||||
}),
|
||||
],
|
||||
"stream": true,
|
||||
"temperature": temperature,
|
||||
"tools": tools,
|
||||
};
|
||||
// console.log("[AI] Request data: ", JSON.stringify(baseData, null, 2));
|
||||
return model.extraParams ? Object.assign({}, baseData, model.extraParams) : baseData;
|
||||
}
|
||||
|
||||
function buildAuthorizationHeader(apiKeyEnvVarName: string): string {
|
||||
return `-H "Authorization: Bearer \$\{${apiKeyEnvVarName}\}"`;
|
||||
}
|
||||
|
||||
function parseResponseLine(line, message) {
|
||||
// Remove 'data: ' prefix if present and trim whitespace
|
||||
let cleanData = line.trim();
|
||||
if (cleanData.startsWith("data:")) {
|
||||
cleanData = cleanData.slice(5).trim();
|
||||
}
|
||||
|
||||
// Handle special cases
|
||||
if (!cleanData || cleanData.startsWith(":")) return {};
|
||||
if (cleanData === "[DONE]") {
|
||||
return { finished: true };
|
||||
}
|
||||
|
||||
// Real stuff
|
||||
try {
|
||||
const dataJson = JSON.parse(cleanData);
|
||||
let newContent = "";
|
||||
|
||||
const responseContent = dataJson.choices[0]?.delta?.content || dataJson.message?.content;
|
||||
const responseReasoning = dataJson.choices[0]?.delta?.reasoning || dataJson.choices[0]?.delta?.reasoning_content;
|
||||
|
||||
// Function call
|
||||
if (dataJson.choices[0]?.delta?.tool_calls) {
|
||||
const functionCall = dataJson.choices[0].delta.tool_calls[0];
|
||||
const functionName = functionCall.function.name;
|
||||
const functionArgs = JSON.parse(functionCall.function.arguments) || {}; // Args are given as string???
|
||||
const functionId = functionCall.id;
|
||||
const newContent = `\n\n[[ Function: ${functionName}(${JSON.stringify(functionArgs, null, 2)}) ]]\n`;
|
||||
message.rawContent += newContent;
|
||||
message.content += newContent;
|
||||
message.functionName = functionName;
|
||||
message.functionCall = functionName;
|
||||
return { functionCall: { name: functionName, args: functionArgs, id: functionId } };
|
||||
}
|
||||
|
||||
// Thinking?
|
||||
if (responseContent && responseContent.length > 0) {
|
||||
if (isReasoning) {
|
||||
isReasoning = false;
|
||||
const endBlock = "\n\n</think>\n\n";
|
||||
message.content += endBlock;
|
||||
message.rawContent += endBlock;
|
||||
}
|
||||
newContent = responseContent;
|
||||
} else if (responseReasoning && responseReasoning.length > 0) {
|
||||
if (!isReasoning) {
|
||||
isReasoning = true;
|
||||
const startBlock = "\n\n<think>\n\n";
|
||||
message.rawContent += startBlock;
|
||||
message.content += startBlock;
|
||||
}
|
||||
newContent = responseReasoning;
|
||||
}
|
||||
|
||||
// Text
|
||||
message.content += newContent;
|
||||
message.rawContent += newContent;
|
||||
|
||||
if (`dataJson`.done) {
|
||||
return { finished: true };
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log("[AI] Mistral: Could not parse line: ", e);
|
||||
message.rawContent += line;
|
||||
message.content += line;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
function onRequestFinished(message) {
|
||||
return {};
|
||||
}
|
||||
|
||||
function reset() {
|
||||
isReasoning = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,11 +4,11 @@ ApiStrategy {
|
||||
property bool isReasoning: false
|
||||
|
||||
function buildEndpoint(model: AiModel): string {
|
||||
console.log("[AI] Endpoint: " + model.endpoint);
|
||||
// console.log("[AI] Endpoint: " + model.endpoint);
|
||||
return model.endpoint;
|
||||
}
|
||||
|
||||
function buildRequestData(model: AiModel, messages, systemPrompt: string, temperature: real) {
|
||||
function buildRequestData(model: AiModel, messages, systemPrompt: string, temperature: real, tools: list<var>) {
|
||||
let baseData = {
|
||||
"model": model.model,
|
||||
"messages": [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//@ pragma UseQApplication
|
||||
//@ pragma Env QS_NO_RELOAD_POPUP=1
|
||||
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
|
||||
//@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000
|
||||
|
||||
// Adjust this to make the app smaller or larger
|
||||
//@ pragma Env QT_SCALE_FACTOR=1
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
//@ pragma UseQApplication
|
||||
//@ pragma Env QS_NO_RELOAD_POPUP=1
|
||||
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
|
||||
//@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000
|
||||
|
||||
// Adjust this to make the shell smaller or larger
|
||||
//@ pragma Env QT_SCALE_FACTOR=1
|
||||
|
||||
|
||||
import "./modules/common/"
|
||||
import "./modules/background/"
|
||||
import "./modules/bar/"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//@ pragma UseQApplication
|
||||
//@ pragma Env QS_NO_RELOAD_POPUP=1
|
||||
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
|
||||
//@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000
|
||||
|
||||
// Adjust this to make the app smaller or larger
|
||||
//@ pragma Env QT_SCALE_FACTOR=1
|
||||
@@ -13,6 +14,7 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.functions
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
{
|
||||
"Launch": "Avvia",
|
||||
"Columns": "Colonne",
|
||||
"Save": "Salva",
|
||||
"Temperature: %1": "Temperatura: %1",
|
||||
"Night Light | Right-click to toggle Auto mode": "Modalità notte",
|
||||
"Silent": "Silenzia",
|
||||
"To Do": "Promemoria",
|
||||
"Action": "Comandi",
|
||||
"Search the web": "Cerca sul web",
|
||||
"Workspace": "Spazio di lavoro",
|
||||
"Desktop": "Scrivania",
|
||||
"Settings": "Impostazioni",
|
||||
"Math result": "Risultato",
|
||||
"Calendar": "Calendario",
|
||||
"Run": "Esegui",
|
||||
"Cancel": "Cancella",
|
||||
"Uptime: %1": "Tempo di attività: %1",
|
||||
"Search": "Cerca",
|
||||
"Battery": "Batteria",
|
||||
"Weather": "Meteo",
|
||||
"Brightness": "Luminosità",
|
||||
"Clear": "Cancella",
|
||||
"No notifications": "Nessuna notifica",
|
||||
"No media": "Non in riproduzione",
|
||||
"Add task": "Aggiungi promemoria",
|
||||
"Run command": "Esegui comando",
|
||||
"Game mode": "Modalità gioco",
|
||||
"Reload Hyprland & Quickshell": "Riavvia Hyprland e Quickshell",
|
||||
"Task description": "Titolo promemoria",
|
||||
"%1 | Right-click to configure": "%1",
|
||||
"Done": "Completati",
|
||||
"Keep system awake": "Mantieni schermo attivo",
|
||||
"Search, calculate or run": "Cerca, calcola o esegui",
|
||||
"Copy": "Copia",
|
||||
"Rows": "Righe",
|
||||
"Session": "Sessione",
|
||||
"Notifications": "Notifiche",
|
||||
"Unfinished": "Da completare",
|
||||
"Add": "Aggiungi",
|
||||
"Nothing here!": "Nessun promemoria",
|
||||
"Mo": "Lu",
|
||||
"Tu": "Ma",
|
||||
"We": "Me",
|
||||
"Th": "Gi",
|
||||
"Fr": "Ve",
|
||||
"Sa": "Sa",
|
||||
"Su": "Do",
|
||||
"Edit config": "Apri config.",
|
||||
"Center title": "Titolo centrato",
|
||||
"Elements": "Elementi",
|
||||
"Color picker": "Selettore colore",
|
||||
"Title bar": "Barra del titolo",
|
||||
"Sleep": "Sospendi",
|
||||
"Transparency": "Trasparenza",
|
||||
"Bluetooth": "Bluetooth",
|
||||
"UV Index": "Indice UV",
|
||||
"Bar": "Barra",
|
||||
"Format": "Formato",
|
||||
"Select output device": "Seleziona dispositivo di output",
|
||||
"Pressure": "Pressione",
|
||||
"Volume": "Volume",
|
||||
"Volume mixer": "Mixer volume",
|
||||
"Interface": "Interfaccia",
|
||||
"Workspaces": "Spazi di lavoro",
|
||||
"Dark": "Scuro",
|
||||
"%1 notifications": "%1 notifiche",
|
||||
"Reboot": "Riavvia",
|
||||
"No": "No",
|
||||
"Wind": "Vento",
|
||||
"Humidity": "Umidità",
|
||||
"Select Language": "Seleziona lingua",
|
||||
"Wallpaper": "Sfondo",
|
||||
"Copy code": "Copia codice",
|
||||
"Allow NSFW": "Mostra NSFW",
|
||||
"Colors & Wallpaper": "Sfondo e stile",
|
||||
"Shutdown": "Spegni",
|
||||
"Decorations & Effects": "Decorazioni e effetti",
|
||||
"Translation goes here...": "Traduzione",
|
||||
"Polling interval (ms)": "Intervallo di polling (ms)",
|
||||
"System prompt": "Prompt di sistema",
|
||||
"Base URL": "URL base",
|
||||
"Always show numbers": "Mostra numeri",
|
||||
"Wallpaper parallax": "Effetto parallasse sfondo",
|
||||
"Plain rectangle": "Semplice",
|
||||
"illogical-impulse Welcome": "Benvenuto su illogical-impulse",
|
||||
"Local only": "Solo locale",
|
||||
"Chain of Thought": "Catena di pensiero",
|
||||
"Dark/Light toggle": "Modalità chiaro/scuro",
|
||||
"Screen snip": "Cattura schermo",
|
||||
"Style & wallpaper": "Sfondo e stile",
|
||||
"Show app icons": "Mostra icone app",
|
||||
"Useless buttons": "Tasti inutili",
|
||||
"Scale (%)": "Dimensione (%)",
|
||||
"Show background": "Mostra sfondo",
|
||||
"Intelligence": "AI",
|
||||
"Appearance": "Aspetto",
|
||||
"Enable": "Abilita",
|
||||
"Borderless": "Senza bordi",
|
||||
"Random: Konachan": "Casuale: Konachan",
|
||||
"Yes": "Sì",
|
||||
"Documentation": "Documentazione",
|
||||
"Unknown Artist": "Artista sconosciuto",
|
||||
"Help & Support": "Aiuto e supporto",
|
||||
"Report a Bug": "Segnala un bug",
|
||||
"Sunset": "Tramonto",
|
||||
"Weeb": "Anime",
|
||||
"Shell windows": "Finestre",
|
||||
"Workspaces shown": "Numero spazi di lavoro",
|
||||
"Screenshot tool": "Cattura schermo",
|
||||
"Enter text to translate...": "Inserisci il testo qui",
|
||||
"Unknown Album": "Album sconosciuto",
|
||||
"Hug": "Stondato",
|
||||
"Scroll to change brightness": "Scorri per cambiare luminosità",
|
||||
"Privacy Policy": "Privacy policy",
|
||||
"12h AM/PM": "12 ore (AM/PM)",
|
||||
"Material palette": "Tavolozza dei colori",
|
||||
"No audio source": "Nessuna sorgente audio",
|
||||
"Download": "Scarica",
|
||||
"Prefixes": "Prefissi",
|
||||
"Show next time": "Mostra al prossimo avvio",
|
||||
"Lock": "Blocca",
|
||||
"Scroll to change volume": "Scorri per cambiare volume",
|
||||
"Unknown": "Sconosciuto",
|
||||
"Jump to current month": "Torna al mese corrente",
|
||||
"Cloudflare WARP (1.1.1.1)": "Cloudflare WARP (1.1.1.1)",
|
||||
"Terminal": "Terminale",
|
||||
"About": "Informazioni",
|
||||
"Precipitation": "Precipitazioni",
|
||||
"Keybinds": "Comandi",
|
||||
"Select input device": "Seleziona dispositivo di input",
|
||||
"When not fullscreen": "Tranne a schermo intero",
|
||||
"Unknown Title": "Titolo sconosciuto",
|
||||
"Task Manager": "Gestione attività",
|
||||
"System": "Sistema",
|
||||
"Choose file": "Scegli file",
|
||||
"Pinned on startup": "Fissa sullo schermo",
|
||||
"Policies": "Servizi",
|
||||
"View Markdown source": "Mostra Markdown",
|
||||
"Sunrise": "Alba",
|
||||
"Configuration": "Configurazione",
|
||||
"Overview": "Panoramica",
|
||||
"Translator": "Traduttore",
|
||||
"Finished tasks will go here": "Nessun promemoria",
|
||||
"Mic toggle": "Microfono",
|
||||
"Light": "Chiaro",
|
||||
"Bar style": "Stile barra",
|
||||
"Advanced": "Avanzate",
|
||||
"Web search": "Cerca sul web",
|
||||
"12h am/pm": "12 ore (am/pm)",
|
||||
"Services": "Servizi",
|
||||
"Donate": "Supporta",
|
||||
"Resources": "Risorse",
|
||||
"Float": "Fluttuante",
|
||||
"Fake screen rounding": "Bordi curvi schermo",
|
||||
"Hibernate": "Iberna",
|
||||
"Visibility": "Visibilità",
|
||||
"Delete": "Elimina",
|
||||
"Style": "Stile",
|
||||
"Page %1": "Pagina %1",
|
||||
"Keyboard toggle": "Tastiera virtuale",
|
||||
"Buttons": "Pulsanti",
|
||||
"24h": "24 ore",
|
||||
"Time": "Ora",
|
||||
"Clipboard": "Appunti",
|
||||
"or": "o",
|
||||
"Edit": "Modifica",
|
||||
"Yooooo hi there": "Ciao bellissimə",
|
||||
"Emojis": "Emoji",
|
||||
"Shell & utilities": "App e shell",
|
||||
"Reboot to firmware settings": "Riavvia alle impostazioni firmware",
|
||||
"No API key set for %1": "Chiave API non impostata per %1",
|
||||
"Disable NSFW content": "Nascondi contenuti NSFW",
|
||||
"Closet": "Nascosto",
|
||||
"Depends on sidebars": "Abilita per barre laterali",
|
||||
"Invalid model. Supported: \n```": "Modello non valido. Supportati: \n```",
|
||||
"Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "Usa /key per utilizzare i modelli online\nCtrl+O per espandere\nCtrl+P per separare in finestra",
|
||||
"Not visible to model": "Non visible al modello",
|
||||
"Local Ollama model | %1": "Modello Ollama locale | %1",
|
||||
"Open file link": "Apri link al file",
|
||||
"Waiting for response...": "In attesa di risposta...",
|
||||
"Cheat sheet": "Prontuario",
|
||||
"Allow NSFW content": "Mostra contenuti NSFW",
|
||||
"%1 characters": "%1 caratteri",
|
||||
"Model set to %1": "Modello impostato su %1",
|
||||
"Be patient...": "Attendi...",
|
||||
"User agent (for services that require it)": "User agent (usato dai servizi)",
|
||||
"Current API endpoint: %1\nSet it with %2mode PROVIDER": "Endpoint API: %1\nUsa /mode per cambiarlo",
|
||||
"For desktop wallpapers | Good quality": "Per sfondi del desktop | Buona qualità",
|
||||
"For storing API keys and other sensitive information": "Gestione credenziali e informazioni sensibili",
|
||||
"Your package manager is running": "Il package manager è in esecuzione",
|
||||
"Experimental | Online | Google's model\nCan do a little more but takes an extra turn to perform search": "Sperimentale | Online | Modello di Google\nPiù potente ma richiede più risorse",
|
||||
"Provider set to": "Provider impostato su",
|
||||
"Color generation": "Tavolozza dei colori",
|
||||
"Temperature must be between 0 and 2": "Il valore della temperatura deve essere fra 0 e 2",
|
||||
"Earbang protection": "Protezione udito",
|
||||
"Online | Google's model\nGives up-to-date information with search.": "Online | Modello di Google\nRestituisce informazioni attuali tramite ricerca.",
|
||||
"Alternatively use /dark, /light, /img in the launcher": "Oppure usa /dark, /light, /img nel launcher",
|
||||
"Change any time later with /dark, /light, /img in the launcher": "Oppure usa /dark, /light, /img nel launcher",
|
||||
"Current model: %1\nSet it with %2model MODEL": "Modello attuale: %1\nUsa /model per cambiarlo",
|
||||
"Waifus only | Excellent quality, limited quantity": "Solo waifu | Qualità eccellente, quantità limitata",
|
||||
"Save to Downloads": "Salva in Scaricati",
|
||||
"Thinking": "Ragionando",
|
||||
"On-screen display": "Popup di sistema",
|
||||
"%1 • %2 tasks": "%1 • %2 promemoria",
|
||||
"Qt apps": "Applicazioni Qt",
|
||||
"The popular one | Best quantity, but quality can vary wildly": "Il più usato | Quantità elevata, ma la qualità potrebbe variare totalmente",
|
||||
"Set the system prompt for the model.": "Imposta il prompt di sistema per il modello.",
|
||||
"To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3": "Per impostare una chiave API, utilizzala come argomento di questo comando\n\nPer vedere la chiave corrente, utilizza come argomento \"get\"<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3",
|
||||
"Markdown test": "Test Markdown",
|
||||
"Prevents abrupt increments and restricts volume limit": "Impedice aumenti improvvisi del volume e ne imposta un limite.",
|
||||
"Preferred wallpaper zoom (%)": "Zoom sfondo (%)",
|
||||
"Depends on workspace": "Abilita per spazi di lavoro",
|
||||
"Note: turning off can hurt readability": "Nota: disattivarlo potrebbe ridurre la leggibilità",
|
||||
"Pick wallpaper image on your system": "Seleziona un'immagine nel tuo sistema",
|
||||
"Invalid API provider. Supported: \n-": "Provider API non valido. Supportati: \n-",
|
||||
"The hentai one | Great quantity, a lot of NSFW, quality varies wildly": "Hentai | Quantità elevata, NSFW, la qualità potrebbe variare totalmente",
|
||||
"Saved to %1": "Salvato in %1",
|
||||
"Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.": "Imposta la temperatura (casualità) del modello. Il valore va da 0 a 2 per Gemini, e da 0 a 1 per gli altri modelli. Il valore predefinito è 0.5.",
|
||||
"Close": "Chiudi",
|
||||
"Might look ass. Unsupported.": "Potrebbe fare schifo. Non supportato.",
|
||||
"API key set for %1": "Chiave API impostata per %1",
|
||||
"Temperature\nChange with /temp VALUE": "Temperatura\nUsa /temp per cambiarla",
|
||||
"%1 does not require an API key": "%1 non richiede una chiave API",
|
||||
"Online models disallowed\n\nControlled by `policies.ai` config option": "Modelli online disattivati\n\nDisattiva l'opzione \"Solo locale\"",
|
||||
"Set the current API provider": "Imposta il provider API",
|
||||
"Total token count\nInput: %1\nOutput: %2": "Numero token totali\nInput: %1\nOutput: %2",
|
||||
"EasyEffects | Right-click to configure": "EasyEffects",
|
||||
"Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers": "Sfondo anime SFW casuale da Konachan\nL'immagine verrà salvata in ~/Immagini/Wallpapers",
|
||||
"The current API used. Endpoint:": "Provider API attuale. Endpoint:",
|
||||
"Set with /mode PROVIDER": "Usa /mode per cambiarlo",
|
||||
"Hover to reveal": "Mostra col passaggio del mouse",
|
||||
"Arrow keys to navigate, Enter to select\nEsc or click anywhere to cancel": "Usa i tasti freccia per navigare, Invio per selezionare\nEsc o clicca qualsiasi punto per uscire",
|
||||
"Save chat to %1": "Salva chat in %1",
|
||||
"Choose model": "Seleziona modello",
|
||||
"No API key\nSet it with /key YOUR_API_KEY": "Nessuna chiave API\nUsa /key per impostarla",
|
||||
"API key:\n\n```txt\n%1\n```": "Chiave API:\n\n```txt\n%1\n```",
|
||||
"Experimental | Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput.": "Sperimentale | Online | Modello di Google\nModello Gemini 2.5 Flash ottimizzato per efficenza e throughput elevato.",
|
||||
"Use Levenshtein distance-based algorithm instead of fuzzy": "Usa algoritmo di Levenshtein al posto di fuzzy",
|
||||
"Download complete": "Download completato",
|
||||
"Tip: Hide icons and always show numbers for\nthe classic illogical-impulse experience": "Suggerimento: Nascondi le icone e mostra i numeri se vuoi\nun'esperienza fedele all'originale",
|
||||
"Usage": "Istruzioni",
|
||||
"Set API key": "Imposta chiave API",
|
||||
"Networking": "Rete",
|
||||
"Volume limit": "Limite volume",
|
||||
"Temperature set to %1": "Temperatura impostata a %1",
|
||||
"Large images | God tier quality, no NSFW.": "Immagini grandi | Qualità perfetta, no NSFW.",
|
||||
"Shell & utilities theming must also be enabled": "\"App e shell\" deve essere abilitato",
|
||||
"API key is set\nChange with /key YOUR_API_KEY": "Chiave API impostata\nUsa /key per cambiarla",
|
||||
"All-rounder | Good quality, decent quantity": "Versatile | Qualità buona, quantità discreta",
|
||||
"Large language models": "Intelligenza artificiale",
|
||||
"Could be better if you make a ton of typos,\nbut results can be weird and might not work with acronyms\n(e.g. \"GIMP\" might not give you the paint program)": "Può aiutare in caso di refusi,\nma i risultati potrebbero non essere accurati\n(es. \"GIMP\" potrebbe non restituire l'omonimo programma)",
|
||||
"Automatic suspend": "Sospensione automatica",
|
||||
"Max allowed increase": "Aumento massimo consentito",
|
||||
"No corresponding search model found for %1": "Nessun modello di ricerca trovato con %1",
|
||||
"Please charge!\nAutomatic suspend triggers at %1": "Ricarica la batteria!\nSospensione automatica in %1",
|
||||
"Weather Service": "Servizio meteo",
|
||||
"The current system prompt is\n\n---\n\n%1": "Il prompt di sistema attuale è\n\n---\n\n%1",
|
||||
"%1 Safe Storage": "Portachiavi di %1",
|
||||
"Load prompt from %1": "Carica prompt da %1",
|
||||
"That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "Nessun risultato. Suggerimenti:\n- Controlla i tag e le impostazioni NSFW\n- Se non hai un tag in mente, inserici il numero di pagina",
|
||||
"Load chat": "Carica chat",
|
||||
"**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**Prezzo**: gratuito. I tuoi dati vengono usati per training.\n\n**Istruzioni**: Accedi al tuo account Google, abilita i permessi richiesti da AI Studio, torna indietro e seleziona \"Get API key\"",
|
||||
"Online via %1 | %2's model": "Online tramite %1 | Modello di %2",
|
||||
"Get the next page of results": "Ottieni la pagina successiva dei risultati",
|
||||
"Unknown function call: %1": "Funzione sconosciuta: %1",
|
||||
"Cannot find a GPS service. Using the fallback method instead.": "Servizio GPS non disponibile. Verrà utilizzata la città preimpostata.",
|
||||
"Registration failed. Please inspect manually with the <tt>warp-cli</tt> command": "Registrazione fallita. Verifica l'errore manualmente col comando <tt>warp-cli</tt>",
|
||||
"Code saved to file": "Codice salvato",
|
||||
"Low warning": "Livello basso",
|
||||
"Clear the current list of images": "Elimina la lista corrente di immagini",
|
||||
"Invalid arguments. Must provide `key` and `value`.": "Argomenti non validi. Il comando richiede `key` e `value`.",
|
||||
"Connection failed. Please inspect manually with the <tt>warp-cli</tt> command": "Connessione fallita. Verifica l'errore manualmente col comando <tt>warp-cli</tt>",
|
||||
"Unknown command:": "Comando sconosciuto:",
|
||||
"Message the model... \"%1\" for commands": "\"%1\" per mostrare i comandi",
|
||||
"Load chat from %1": "Carica chat da %1",
|
||||
"**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key": "**Prezzo**: gratuito. Le policy di trattamento dei dati potrebbero variare in base alle impostazioni del tuo account OpenRouter.\n\n**Istruzioni**: Accedi al tuo account OpenRouter, vai nella sezione \"Keys\" dal menu in alto, clicca \"Create API Key\"",
|
||||
"Enter tags, or \"%1\" for commands": "\"%1\" per mostrare i comandi",
|
||||
"Show regions of potential interest": "Mostra regioni d'interesse",
|
||||
"Critical warning": "Livello critico",
|
||||
"Go to source (%1)": "Vai alla fonte (%1)",
|
||||
"Automatically suspends the system when battery is low": "Sospende automaticamente il sistema quando il livello della batteria è basso",
|
||||
"Cannot switch to search mode from %1": "Impossibile attivare modalità ricerca da %1",
|
||||
"Clean stuff | Excellent quality, no NSFW": "Roba pulita | Qualità eccellente, no NSFW",
|
||||
". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!": ". Note per Zerochan:\n- Devi inserire un colore\n- Imposta il tuo nome utente di zerochan nell'opzione `sidebar.booru.zerochan.username`. Potresti [venire bannato se non lo fai](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!",
|
||||
"Critically low battery": "Batteria scarica",
|
||||
"Loaded the following system prompt\n\n---\n\n%1": "Il seguente prompt di sistema è stato caricato\n\n---\n\n%1",
|
||||
"Suspend at": "Sospendi al",
|
||||
"Such regions could be images or parts of the screen that have some containment.\nMight not always be accurate.\nThis is done with an image processing algorithm run locally and no AI is used.": "Queste regioni potrebbero essere immagini o parti di schermo contenute.\nPotrebbe non essere preciso.\nViene utilizzato un algoritmo di image processing in locale, non viene usata AI.",
|
||||
"Clear chat history": "Elimina cronologia chat",
|
||||
"Low battery": "Batteria quasi scarica",
|
||||
"Save chat": "Salva chat",
|
||||
"Switched to search mode. Continue with the user's request.": "Modalità ricerca attiva. Continua con la richiesta dell'utente.",
|
||||
"Number show delay when pressing Super (ms)": "Mostra numeri premendo Super dopo (ms)",
|
||||
"Drag or click a region • LMB: Copy • RMB: Edit": "Trascina o clicca una regione • LMB: Copia • RMB: Modifica",
|
||||
"Consider plugging in your device": "Connetti il tuo dispositivo alla rete elettrica",
|
||||
"%1 queries pending": "%1 ricerche in sospeso",
|
||||
"<i>No further instruction provided</i>": "<i>Nessun'altra istruzione fornita</i>",
|
||||
"There might be a download in progress": "Potrebbe esserci un download in corso",
|
||||
"Approve": "Approva",
|
||||
"Invalid arguments. Must provide `command`.": "Argomenti non validi. Il comando richiede `command`.",
|
||||
"Reject": "Rifiuta",
|
||||
"Thought": "Pensiero",
|
||||
"Performance Profile toggle": "Profilo prestazioni",
|
||||
"Command rejected by user": "Comando rifiutato dall'utente"
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
{
|
||||
"Output": "Вывод",
|
||||
"Markdown test": "Тест Markdown",
|
||||
"Intelligence": "ИИ",
|
||||
"Load chat": "Загрузить чат",
|
||||
"Workspaces shown": "Кол-во рабочих столов",
|
||||
"Style": "Стиль",
|
||||
"Reject": "Отклонить",
|
||||
"Volume": "Громкость",
|
||||
"Shutdown": "Завершение работы",
|
||||
"Fidelity": "Верность",
|
||||
"Switched to search mode. Continue with the user's request.": "Переключено в режим поиска. Продолжай с запросом пользователя.",
|
||||
"No notifications": "Нет уведомлений",
|
||||
"EasyEffects | Right-click to configure": "EasyEffects | ПКМ, чтобы настроить",
|
||||
"Suspend at": "Переход в режим сна на",
|
||||
"Brightness": "Яркость",
|
||||
"Volume mixer": "Микшер громкости",
|
||||
"Discussions": "Обсуждения",
|
||||
"Earbang protection": "Защита от громких звуков",
|
||||
"Message the model... \"%1\" for commands": "Сообщение для ИИ... \"%1\" для команд",
|
||||
"Decorations & Effects": "Декорации и эффекты",
|
||||
"Load chat from %1": "Загрузить чат из %1",
|
||||
"OK": "ОК",
|
||||
"<i>No further instruction provided</i>": "<i>Больше инструкций не предоставлено</i>",
|
||||
"Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.": "Установить температуру (случайность) модели. Выберите значение от 0 до 2 для Gemini, от 0 до 1 для других моделей. По умолчанию: 0.5",
|
||||
"Open file link": "Открыть ссылку на файл",
|
||||
"API key is set\nChange with /key YOUR_API_KEY": "API ключ установлен\nПоменять с помощью /key ВАШ_КЛЮЧ_API",
|
||||
"Advanced": "Продвинутые",
|
||||
"Title bar": "Заголовок",
|
||||
"Keybinds": "Шорткаты",
|
||||
"Alternatively use /dark, /light, /img in the launcher": "Также можно использовать /dark, /light, /img в лаунчере",
|
||||
"Dark/Light toggle": "Темный/светлый",
|
||||
"Shell & utilities": "Оболочка",
|
||||
"Clipboard": "Буфер обмена",
|
||||
"Yooooo hi there": "Йооооу привет",
|
||||
"Show app icons": "Показывать иконки",
|
||||
"Save": "Сохранить",
|
||||
"Style & wallpaper": "Стиль и обои",
|
||||
"Battery": "Батарея",
|
||||
"Expressive": "Выразительность",
|
||||
"Reboot": "Перезагрузка",
|
||||
"AI": "ИИ",
|
||||
"Sleep": "Спящий режим",
|
||||
"Allow NSFW": "Разрешить NSFW",
|
||||
"Please charge!\nAutomatic suspend triggers at %1": "Подключите ПК к источнику питания!\nПереход в спящий режим на %1",
|
||||
"Select input device": "Выберите микрофон",
|
||||
"Hover to reveal": "Наведите, чтобы раскрыть",
|
||||
"Unknown Artist": "Неизвестный исполнитель",
|
||||
"Connection failed. Please inspect manually with the <tt>warp-cli</tt> command": "Ошибка подключения. Проверьте вручную командой <tt>warp-cli</tt>",
|
||||
"Lock": "Блокировка",
|
||||
"Monochrome": "Монохром",
|
||||
"**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**Цена**: бесплатно. Данные используются для обучения.\n\n**Инстуркции**: Войдите в аккаунт Google, разрешите AI Studio создать проект Google Cloud или что оно попросит, вернитесь и нажмите Get API key",
|
||||
"Online models disallowed\n\nControlled by `policies.ai` config option": "Онлайн модели запрещены\n\nУправляется опцией `policies.ai` в конфиге",
|
||||
"Emojis": "Эмодзи",
|
||||
"Wallpaper parallax": "Параллакс обоев",
|
||||
"Interface": "Интерфейс",
|
||||
"System prompt": "Системный промпт",
|
||||
"Edit config": "Ред. конфиг",
|
||||
"Page %1": "Страница %1",
|
||||
"Task description": "Описание задания",
|
||||
"Fruit Salad": "Фруктовый салад",
|
||||
"%1 Safe Storage": "Безопасное хранилище %1",
|
||||
"Distro": "Дистрибутив",
|
||||
"Add": "Добавить",
|
||||
"Closet": "Закрытый",
|
||||
"Task Manager": "Системный монитор",
|
||||
"Configuration": "Настройка",
|
||||
"There might be a download in progress": "Возможно происходит скачивание",
|
||||
"Visibility": "Видимость",
|
||||
"Desktop": "Рабочий стол",
|
||||
"Run": "Запустить",
|
||||
"Sunrise": "Рассвет",
|
||||
"Set API key": "Задать API ключ",
|
||||
"Shell windows": "Окна оболочки",
|
||||
"Cloudflare WARP (1.1.1.1)": "Cloudflare WARP (1.1.1.1)",
|
||||
"Action": "Действие",
|
||||
"Elements": "Элементы",
|
||||
"Resources": "Ресурсы",
|
||||
"**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key": "**Цена**: бесплатно. Политика использования данных зависит от настроек OpenRouter.\n\n**Инструкции**: Войдите в аккаунт OpenRouter, зайдите в Keys в меню сверху справа, нажмите Create API Key",
|
||||
"Game mode": "Игровой режим",
|
||||
"Code saved to file": "Код сохранен в файл",
|
||||
"Online | Google's model\nGives up-to-date information with search.": "Онлайн | Модель Google\nДает точную информацию благодаря поиску",
|
||||
"Issues": "Проблемы",
|
||||
"Depends on sidebars": "Зависит от панелей",
|
||||
"Translation goes here...": "Здесь будет перевод...",
|
||||
"Bar style": "Стиль панели",
|
||||
"Unknown command:": "Неизвестная команда:",
|
||||
"Invalid API provider. Supported: \n-": "Неизвестный API провайдер. Поддерживаемые: \n-",
|
||||
"Clear chat history": "Очистить историю",
|
||||
"Run command": "Выполнить команду",
|
||||
"Local only": "Локальные",
|
||||
"Tonal Spot": "Тональное пятно",
|
||||
"No corresponding search model found for %1": "Не найдено поисковой модели для %1",
|
||||
"Content": "Контент",
|
||||
"Wind": "Ветер",
|
||||
"Total token count\nInput: %1\nOutput: %2": "Количество токенов\nВвод: %1\nВывод: %2",
|
||||
"Current model: %1\nSet it with %2model MODEL": "Текущая модель: %1\nСменить с помощью %2model МОДЕЛЬ",
|
||||
"Dark": "Темный",
|
||||
"Hug": "Захват",
|
||||
"Hibernate": "Гиберрнация",
|
||||
"Registration failed. Please inspect manually with the <tt>warp-cli</tt> command": "Ошибка регистрации. Проверьте вручную командой <tt>warp-cli</tt>",
|
||||
"Calendar": "Календарь",
|
||||
"Save chat to %1": "Сохранить чат в %1",
|
||||
"Finished tasks will go here": "Здесь будут выполненные задачи",
|
||||
"Set the current API provider": "Задать текущего провайдера API",
|
||||
"Weather Service": "Сервис погоды",
|
||||
"Fake screen rounding": "Фейковое округление экрана",
|
||||
"View Markdown source": "Посмотреть исходной Markdown",
|
||||
"Change any time later with /dark, /light, /img in the launcher": "Изменяется в любое время с помощью /dark, /light, /img в лаунчере",
|
||||
"Critical warning": "Критический",
|
||||
"Waifus only | Excellent quality, limited quantity": "Только вайфу | Превосходное качество, ограниченное количество",
|
||||
"Unknown function call: %1": "Неизвестный вызов функции: %1",
|
||||
"Neutral": "Нейтрал",
|
||||
"Anime": "Аниме",
|
||||
"Cannot switch to search mode from %1": "Невозможно переключиться в режим поиска из %1",
|
||||
"Useless buttons": "Бесполезные кнопочки",
|
||||
"Unfinished": "Незавершенные",
|
||||
"Privacy Policy": "Политика конфиденциальности",
|
||||
"Online via %1 | %2's model": "Онлайн через %1 | Модель %2",
|
||||
"Large images | God tier quality, no NSFW.": "Огромные изображение | Божественное качество, нету NSFW.",
|
||||
"Base URL": "Базовый URL",
|
||||
"Not visible to model": "Невидимый для модели",
|
||||
"Auto": "Авто",
|
||||
"Might look ass. Unsupported.": "Может выглядеть хуево. Не поддерживается",
|
||||
"%1 • %2 tasks": "%1 • %2 заданий",
|
||||
"Search the web": "Искать в интернете",
|
||||
"Scroll to change brightness": "Листайте, чтобы изменить яркость",
|
||||
"Invalid arguments. Must provide `key` and `value`.": "Неправильные аргументы. Нужно предоставить `key` и `value`.",
|
||||
"Settings": "Настройки",
|
||||
"Show regions of potential interest": "Показывать регионы с потенциальным интересом",
|
||||
"Pressure": "Давление",
|
||||
"No": "Нет",
|
||||
"Such regions could be images or parts of the screen that have some containment.\nMight not always be accurate.\nThis is done with an image processing algorithm run locally and no AI is used.": "Такие регионы могут быть изображениями или части экрана, которые имеют некую ограниченность.\nМожет быть неверно.\nЭто происходит с помощью алгоритма обработки изобржений локально и ИИ не используется",
|
||||
"Select Language": "Выбрать Язык",
|
||||
"Command rejected by user": "Команда отменена пользователем",
|
||||
"Approve": "Разрешить",
|
||||
"Terminal": "Терминал",
|
||||
"Search": "Поиск",
|
||||
"or": "или",
|
||||
"Experimental | Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput.": "Эксперементальная | Онлайн | Модель Google\nМодель Gemini 2.5 Flash, оптимизированная под экономию и высокую пропускную способность",
|
||||
"Uptime: %1": "Время работы: %1",
|
||||
"Save chat": "Сохранить чат",
|
||||
"Load prompt from %1": "Загрузить промпт из %1",
|
||||
"Critically low battery": "Критически низкий заряд батареи",
|
||||
"The hentai one | Great quantity, a lot of NSFW, quality varies wildly": "Хентай | Отличный выбор, качество сильно варьируется",
|
||||
"Input": "Ввод",
|
||||
"Borderless": "Безрамочный",
|
||||
"Loaded the following system prompt\n\n---\n\n%1": "Загружен следующий системный промпт\n\n---\n\n%1",
|
||||
"Thought": "Мысли",
|
||||
"Your package manager is running": "Ваш менеджер пакетов работает",
|
||||
"12h AM/PM": "12 ч. AM/PM",
|
||||
"Scale (%)": "Размер (%)",
|
||||
"Waiting for response...": "Ожидание ответа...",
|
||||
"%1 does not require an API key": "%1 не требует API ключ",
|
||||
"Edit": "Изменить",
|
||||
"Dock": "Панель задач",
|
||||
"Set with /mode PROVIDER": "Установить с помощью /mode ПРОВАЙДЕР",
|
||||
"Low warning": "Низкий",
|
||||
"Silent": "Выкл. звук",
|
||||
"Rainbow": "Радуга",
|
||||
"Anime boorus": "Аниме боору",
|
||||
"Nothing here!": "Ничего нету!",
|
||||
"Documentation": "Документация",
|
||||
"Clear": "Очистить",
|
||||
"Transparency": "Прозрачность",
|
||||
"Show background": "Показывать фон",
|
||||
"Info": "Инфо",
|
||||
"12h am/pm": "12 ч. am/pm",
|
||||
"Reload Hyprland & Quickshell": "Перезагрузить Hyprland и Quickshell",
|
||||
"%1 characters": "%1 символов",
|
||||
". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!": ". Напоминание для Zerochan:\n- Вы должны ввести цвет\n- Установите свой юзернейм Zerochan с помощью `sidebar.booru.zerochan.username` в конфиге. Вы [можете быть забанены, если не сделаете этого](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!",
|
||||
"For desktop wallpapers | Good quality": "Для обоев | Отличное качество",
|
||||
"Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "Введите /key, чтобы начать работу с онлайн моделями\nCtrl+O для расширения панели\nCtrl+P для отсоединения панели",
|
||||
"Close": "Закрыть",
|
||||
"Search, calculate or run": "Поиск, вычислить, выполнить",
|
||||
"Add task": "Добавить задание",
|
||||
"Enable": "Включить",
|
||||
"Temperature set to %1": "Температура установлена на %1",
|
||||
"No media": "Нет медиа",
|
||||
"Screen snip": "Скриншот",
|
||||
"Go to source (%1)": "Перейти к источнику (%1)",
|
||||
"Download": "Скачать",
|
||||
"Sunset": "Закат",
|
||||
"Weeb": "Аниме",
|
||||
"The current system prompt is\n\n---\n\n%1": "Текущий системный промпт\n\n---\n\n%1",
|
||||
"Scroll to change volume": "Листайте, чтобы изменить громкость",
|
||||
"Unknown Title": "Неизвестное Название",
|
||||
"Policies": "Политики",
|
||||
"Disable NSFW content": "Отключить NSFW контент",
|
||||
"The current API used. Endpoint:": "Текущий используемый API. Точка входа:",
|
||||
"Humidity": "Влажность",
|
||||
"Cheat sheet": "Шпаргалка",
|
||||
"Translator": "Переводчик",
|
||||
"Be patient...": "Подождите...",
|
||||
"Experimental | Online | Google's model\nCan do a little more but takes an extra turn to perform search": "Эксперементальная | Онлайн | Модель Google\nМожет сделать чуть больше, но нужен дополнительный запрос для поиска",
|
||||
"Audio": "Аудио",
|
||||
"Preferred wallpaper zoom (%)": "Предпочитаемый зум обоев (%)",
|
||||
"Model set to %1": "Установлена модель %1",
|
||||
"Enter text to translate...": "Введите текст для перевода...",
|
||||
"Use Levenshtein distance-based algorithm instead of fuzzy": "Использовать алгоритм, основанный на расстоянии Левенштейна,\n вместо нечёткого сопоставления.",
|
||||
"Depends on workspace": "Зависит от пространства",
|
||||
"All-rounder | Good quality, decent quantity": "Универсальный | Хорошее качество и количество",
|
||||
"Timeout (ms)": "Таймаут (мс)",
|
||||
"Plain rectangle": "Обычный прямоугольник",
|
||||
"No API key\nSet it with /key YOUR_API_KEY": "Нет API ключа.\nУстановите его с помощью /key ВАШ_КЛЮЧ_API",
|
||||
"Center title": "Центрировать название",
|
||||
"Buttons": "Кнопки",
|
||||
"Copy code": "Скопировать код",
|
||||
"Precipitation": "Осадки",
|
||||
"The popular one | Best quantity, but quality can vary wildly": "Популярный | Огромный выбор, но качество сильно варьируется",
|
||||
"Temperature: %1": "Температура: %1",
|
||||
"Qt apps": "Qt",
|
||||
"Delete": "Удалить",
|
||||
"Saved to %1": "Сохранено в %1",
|
||||
"Temperature\nChange with /temp VALUE": "Температура\nИзмените с помощью /temp ЗНАЧЕНИЕ",
|
||||
"App": "Приложение",
|
||||
"Bluetooth": "Bluetooth",
|
||||
"Current API endpoint: %1\nSet it with %2mode PROVIDER": "Текущий API: %1\nИзменить с помощью %2mode ПРОВАЙДЕР",
|
||||
"Cancel": "Отменить",
|
||||
"Clean stuff | Excellent quality, no NSFW": "Чистый контент | Превосходное качество, нету NSFW",
|
||||
"Wallpaper": "Обои",
|
||||
"Provider set to": "Провайдер установлен на",
|
||||
"Weather": "Погода",
|
||||
"24h": "24 ч.",
|
||||
"Show next time": " Показать в следующий раз",
|
||||
"Unknown": "Неизвестно",
|
||||
"Launch": "Запустить",
|
||||
"Overview": "Обзор",
|
||||
"Help & Support": "Помощь и поддержка",
|
||||
"Night Light | Right-click to toggle Auto mode": "Ночной свет | ПКМ для переключения Авто режима",
|
||||
"Web search": "Веб-поиск",
|
||||
"Cannot find a GPS service. Using the fallback method instead.": "Не удалось найти GPS сервис. Используем запасный вариант.",
|
||||
"Large language models": "Большие языковые модели",
|
||||
"Dotfiles": "Дотфайлы",
|
||||
"When not fullscreen": "Когда не в полноэкранном режиме",
|
||||
"Screenshot tool": "Инструмент скриншотов",
|
||||
"Get the next page of results": "Получить резултаты следующей страницы",
|
||||
"Drag or click a region • LMB: Copy • RMB: Edit": "Проведите или кликните на регион • ЛКМ: Скопировать • ПКМ: Редактировать",
|
||||
"Material palette": "Материальная палитра",
|
||||
"Columns": "Столбцы",
|
||||
"Bar": "Панель",
|
||||
"Max allowed increase": "Макс. рост",
|
||||
"Always show numbers": "Всегда показывать номера",
|
||||
"%1 notifications": "%1 уведомлений",
|
||||
"Rows": "Ряды",
|
||||
"Invalid arguments. Must provide `command`.": "Неправильный аргумент. Нужно предоставить `command`.",
|
||||
"System": "Система",
|
||||
"Shell & utilities theming must also be enabled": "Расцветка оболочки также должна быть включена.",
|
||||
"%1 queries pending": "%1 запросов в очереди",
|
||||
"Copy": "Скопировать",
|
||||
"Logout": "Выход",
|
||||
"Pinned on startup": "Закреплена на запуске",
|
||||
"%1 | Right-click to configure": "%1 | ПКМ, чтобы настроить",
|
||||
"Donate": "Задонатить",
|
||||
"Temperature must be between 0 and 2": "Температура должна быть между 0 и 2",
|
||||
"Session": "Сессия",
|
||||
"Mic toggle": "Перекл. микрофон",
|
||||
"Reboot to firmware settings": "Перезагрузиться в настройки BIOS/UEFI",
|
||||
"Low battery": "Низкий",
|
||||
"Usage": "Использование",
|
||||
"Notifications": "Уведомления",
|
||||
"Consider plugging in your device": "Задумайтесь о подключении ПК к источнику питания",
|
||||
"Cloudflare WARP": "Cloudflare WARP",
|
||||
"Automatically suspends the system when battery is low": "Автоматически переходит в режим сна когда заряд низкий",
|
||||
"Services": "Сервисы",
|
||||
"Thinking": "Думаю",
|
||||
"Color generation": "Генерация цветов",
|
||||
"Number show delay when pressing Super (ms)": "Задержка показа номеров при нажатии Super (мс)",
|
||||
"illogical-impulse Welcome": "Добро пожаловать в illogical-impulse",
|
||||
"User agent (for services that require it)": "User agent (для сервисов, которым он нужен)",
|
||||
"Appearance": "Внешний вид",
|
||||
"On-screen display": "On-screen display",
|
||||
"Download complete": "Загрузка завершена",
|
||||
"Time": "Время",
|
||||
"Float": "Поверх",
|
||||
"Pick wallpaper image on your system": "Выберите изображение для обоев на своём ПК",
|
||||
"Prevents abrupt increments and restricts volume limit": "Предотвращает резкие увеличения громкости и закрепляет лимит громоксти",
|
||||
"Unknown Album": "Неизвестный Альбом",
|
||||
"Math result": "Результат вычисления",
|
||||
"Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers": "Случайные SFW обои с Konachan\nИзображение сохраняются в ~/Изображения/Wallpapers",
|
||||
"Could be better if you make a ton of typos,\nbut results can be weird and might not work with acronyms\n(e.g. \"GIMP\" might not give you the paint program)": "Может быть лучше, если вы сделаете много ошибок,\nно результаты могут быть странными и могут не работать с сокращениями (т.е. \"GIMP\" не выдаст программу для рисования)",
|
||||
"Select output device": "Выберите динамики",
|
||||
"Set the system prompt for the model.": "Задать системный промпт для этой модели.",
|
||||
"Choose file": "Выберите файл",
|
||||
"Choose model": "Выберите модель",
|
||||
"Tip: Hide icons and always show numbers for\nthe classic illogical-impulse experience": "Подсказка: Включите \"Показывать иконик \" и \"Всегда показывать номера\"\nдля классического опыта illogical-impulse",
|
||||
"Yes": "Да",
|
||||
"Local Ollama model | %1": "Локальная модель Ollama | %1",
|
||||
"API key set for %1": "API ключ установлен на %1",
|
||||
"Format": "Формат",
|
||||
"Colors & Wallpaper": "Цвета и Обои",
|
||||
"Note: turning off can hurt readability": "Подсказка: отключение может повредить читабельность",
|
||||
"illogical-impulse": "illogical-impulse",
|
||||
"Automatic suspend": "Авто-сон",
|
||||
"Random: Konachan": "Рандом: Konachan",
|
||||
"Workspace": "Рабочее пространство",
|
||||
"About": "О системе",
|
||||
"Color picker": "Пипетка",
|
||||
"Report a Bug": "Сообщить об ошибке",
|
||||
"Volume limit": "Лимит громкости",
|
||||
"GitHub": "GitHub",
|
||||
"Prefixes": "Префиксы",
|
||||
"Done": "Готово",
|
||||
"Invalid model. Supported: \n```": "Неправильная модель. Доступны: \n```",
|
||||
"To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3": "Чтобы установить API ключ, добавьте ее к команде\n\nЧтобы просмотреть ключ, добавьте \"get\" к команде<br/>\n\n### Для %1:\n\n**Ссылка**: %2\n\n%3",
|
||||
"UV Index": "УФ-индекс",
|
||||
"Clear the current list of images": "Очистить список изображений",
|
||||
"No audio source": "Нет источников аудио",
|
||||
"API key:\n\n```txt\n%1\n```": "API ключ:\n\n```txt\n%1\n```",
|
||||
"For storing API keys and other sensitive information": "Для хранения API ключей и другой чувствительной информации",
|
||||
"Arrow keys to navigate, Enter to select\nEsc or click anywhere to cancel": "Стрелочки для навигации, Enter для выбора\nEsc или клик везде чтобы отменить",
|
||||
"Networking": "Сеть",
|
||||
"Keep system awake": "Держать ПК включённым",
|
||||
"Polling interval (ms)": "Интервал опроса (мс)",
|
||||
"To Do": "Задачи",
|
||||
"Workspaces": "Рабочие пространства",
|
||||
"That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "Это не сработало. Подсказки:\n- Проверьте теги и настройки NSFW\n- Если на уме нету тегов, введите номер страницы",
|
||||
"Jump to current month": "Перейти к текущему месяцу",
|
||||
"Enter tags, or \"%1\" for commands": "Введите теги, или \"%1\" для команд",
|
||||
"No API key set for %1": "API ключ не установлен для %1",
|
||||
"Allow NSFW content": "Разрешить NSFW контент",
|
||||
"Save to Downloads": "Сохранить в загрузки",
|
||||
"Light": "Светлый",
|
||||
"Keyboard toggle": "Экранная клавиатура",
|
||||
"Night Light": "Night Light",
|
||||
"We": "Ср/*keep*/",
|
||||
"Mo": "Пн/*keep*/",
|
||||
"Su": "Вс/*keep*/",
|
||||
"Th": "Чт/*keep*/",
|
||||
"Tu": "Вт/*keep*/",
|
||||
"Experimental | Online | Google's model\nCan do a little more but doesn't search quickly": "Эксперементальная | Онлайн | Модель Google\nМожет немного больше но не ищет очень быстро",
|
||||
"Sa": "Сб/*keep*/",
|
||||
"Chain of Thought": "Цепочка мыслей",
|
||||
"Fr": "Пт/*keep*/",
|
||||
"Usage: %1load CHAT_NAME": "Использование: %1load ИМЯ_ЧАТА",
|
||||
"Tool set to %1": "Установлен инструмент %1",
|
||||
"Set the tool to use for the model.": "Установите инструмент для этой модели.",
|
||||
"Invalid tool. Supported tools:\n- %1": "Неправильный инструмент. Доступны:\n- %1",
|
||||
"Usage: %1tool TOOL_NAME": "Использование: %1tool ИНСТРУМЕНТ",
|
||||
"Performance Profile toggle": "Профили производительности",
|
||||
"Usage: %1save CHAT_NAME": "Использование: %1save ИМЯ_ЧАТА",
|
||||
"Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput.": "Онлайн | Модель Google\nМодель Gemini 2.5 Flash оптимизирована под меньшие затраты и высокую производительнность",
|
||||
"Online | Google's model\nNewer model that's slower than its predecessor but should deliver higher quality answers": "Онлайн | Модель Google\nНовая модель, которая медленее, чем ее предшественник, но выдает лучшее качество",
|
||||
"Online | Google's model\nFast, can perform searches for up-to-date information": "Онлайн | Модель Google\nБыстрая, может выполнять поиск актуальной информации",
|
||||
"Current tool: %1\nSet it with %2tool TOOL": "Текущий инструмент: %1\nИзменяется с помощью %2tool ИНСТРУМЕНТ"
|
||||
}
|
||||
@@ -20,8 +20,6 @@
|
||||
"To Do": "Cần làm",
|
||||
"Auto": "Tự động",
|
||||
"Polling interval (ms)": "Thời gian lặp lại (ms)",
|
||||
"Closes on screen keyboard on press": "Đóng bàn phím trên màn hình khi ấn",
|
||||
"Toggles right sidebar on press": "Mở/đóng sidebar phải khi ấn",
|
||||
"Center title": "Căn giữa tiêu đề",
|
||||
"Lock": "Khóa màn hình",
|
||||
"Screen snip": "Chụp màn hình (chọn vùng)",
|
||||
@@ -49,7 +47,6 @@
|
||||
". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!": ". Với Zerochan:\n- Hãy nhập tên một màu (bằng tiếng Anh)\n- Đặt username Zerochan trong tùy chọn `sidebar.booru.zerochan.username`. Bạn [có thể bị ban nếu không tuân thủ](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!",
|
||||
"Brightness": "Độ sáng",
|
||||
"Yooooo hi there": "Yooooo chào bạn",
|
||||
"Triggers volume OSD on press": "Hiển thị âm lượng khi ấn",
|
||||
"Colors & Wallpaper": "Màu sắc & Hình nền",
|
||||
"No media": "Không có media",
|
||||
"Critical warning": "Cảnh báo rất thấp",
|
||||
@@ -58,9 +55,7 @@
|
||||
"Large language models": "Mô hình ngôn ngữ lớn",
|
||||
"Markdown test": "Test markdown",
|
||||
"Temperature: %1": "Nhiệt độ: %1",
|
||||
"Opens media controls on press": "Mở điều khiển media khi ấn",
|
||||
"Edit": "Sửa",
|
||||
"Closes overview": "Đóng overview",
|
||||
"Waifus only | Excellent quality, limited quantity": "Chỉ waifus | Chất lượng xuất sắc, số lượng hạn chế",
|
||||
"Cheat sheet": "Bảng tra cứu",
|
||||
"Current model: %1\nSet it with %2model MODEL": "Model đang chọn: %1\nChọn với lệnh %2model MODEL",
|
||||
@@ -84,7 +79,6 @@
|
||||
"Shell windows": "Cửa sổ của shell",
|
||||
"Loaded the following system prompt\n\n---\n\n%1": "Đã tải chỉ dẫn hệ thống sau đây\n\n---\n\n%1",
|
||||
"Clipboard": "Clipboard",
|
||||
"Toggles left sidebar on press": "Mở/đóng sidebar trái khi ấn",
|
||||
"For storing API keys and other sensitive information": "Để lưu trữ API key và các thông tin nhạy cảm khác",
|
||||
"Wallpaper": "Hình nền",
|
||||
"Decorations & Effects": "Trang trí & Hiệu ứng",
|
||||
@@ -102,7 +96,6 @@
|
||||
"System": "Hệ thống",
|
||||
"Emojis": "Emoji",
|
||||
"The current system prompt is\n\n---\n\n%1": "Chỉ dẫn hệ thống hiện tại như sau\n\n---\n\n%1",
|
||||
"Closes right sidebar on press": "Đóng sidebar phải khi ấn",
|
||||
"Translator": "Dịch",
|
||||
"Sleep": "Ngủ",
|
||||
"Action": "Hành động",
|
||||
@@ -116,9 +109,7 @@
|
||||
"Float": "Nổi",
|
||||
"<i>No further instruction provided</i>": "<i>No further instruction provided</i>",
|
||||
"Choose file": "Chọn tệp",
|
||||
"Opens right sidebar on press": "Mở sidebar phải khi ấn",
|
||||
"Set the system prompt for the model.": "Đặt chỉ dẫn hệ thống cho model.",
|
||||
"Closes left sidebar on press": "Đóng sidebar trái khi ấn",
|
||||
"Unknown Title": "Bài hát không rõ tên",
|
||||
"Math result": "Kết quả phép tính",
|
||||
"Logout": "Đăng xuất",
|
||||
@@ -142,10 +133,8 @@
|
||||
"Weather": "Thời tiết",
|
||||
"Settings": "Cài đặt",
|
||||
"Shell & utilities": "Shell & tiện ích",
|
||||
"Toggles overview on release": "Mở/đóng overview khi nhả nút",
|
||||
"Unfinished": "Chưa xong",
|
||||
"Random: Konachan": "Ngẫu nhiên: Konachan",
|
||||
"Opens left sidebar on press": "Mở sidebar trái khi ấn",
|
||||
"Pick wallpaper image on your system": "Chọn hình nền trên máy",
|
||||
"Volume": "Âm lượng",
|
||||
"Add": "Thêm",
|
||||
@@ -177,32 +166,27 @@
|
||||
"Temperature must be between 0 and 2": "Nhiệt độ phải trong khoảng từ 0 đến 2",
|
||||
"Automatically suspends the system when battery is low": "Tự động ngủ khi pin thấp",
|
||||
"Current API endpoint: %1\nSet it with %2mode PROVIDER": "Endpoint API hiện tại: %1\nĐặt với lệnh %2mode PROVIDER",
|
||||
"Decrease brightness": "Giảm độ sáng",
|
||||
"Services": "Các dịch vụ",
|
||||
"Reload Hyprland & Quickshell": "Tải lại Hyprland & Quickshell",
|
||||
"Automatic suspend": "Tự động ngủ",
|
||||
"illogical-impulse Welcome": "illogical-impulse - Xin chào",
|
||||
"Interface": "Giao diện",
|
||||
"Load chat": "Tải cuộc trò chuyện",
|
||||
"Opens session screen on press": "Mở màn hình session khi ấn",
|
||||
"Number show delay when pressing Super (ms)": "Thời gian chờ hiện số khi nhấn Super (ms)",
|
||||
"Clear the current list of images": "Xóa danh sách hình ảnh hiện tại",
|
||||
"Fake screen rounding": "Giả bo tròn màn hình",
|
||||
"Tip: Hide icons and always show numbers for\nthe classic illogical-impulse experience": "Mẹo: Ẩn biểu tượng và luôn hiển thị số nếu\nmuốn giống trải nghiệm illogical-impulse gốc",
|
||||
"Launch": "Chạy",
|
||||
"%1 notifications": "%1 thông báo",
|
||||
"Hides brightness OSD on press": "Ngừng hiển thị độ sáng khi nhấn",
|
||||
"%1 | Right-click to configure": "%1 | Ấn chuột phải để chỉnh",
|
||||
"Unknown Artist": "Nghệ sĩ không xác định",
|
||||
"Appearance": "Giao diện",
|
||||
"Task Manager": "Quản lí ứng dụng đang chạy",
|
||||
"To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3": "Để đặt API key, viết nó sau lệnh\n\nĐể xem lại, viết \"get\" sau lệnh<br/>\n\n### Với %1:\n\n**Link**: %2\n\n%3",
|
||||
"Hold to show workspace numbers, release to show icons": "Giữ để hiện số workspace, thả ra để hiện biểu tượng",
|
||||
"Opens cheatsheet on press": "Mở bảng tra cứu khi ấn",
|
||||
"Invalid arguments. Must provide `key` and `value`.": "Biến không hợp lệ. cần cả `key` và `value`.",
|
||||
"About": "Giới thiệu",
|
||||
"illogical-impulse": "illogical-impulse",
|
||||
"Triggers brightness OSD on press": "Hiện độ sáng/âm lượng khi ấn",
|
||||
"Help & Support": "Trợ giúp",
|
||||
"Enter tags, or \"%1\" for commands": "Nhập tag hoặc \"%1\" để xem các lệnh",
|
||||
"Format": "Định dạng",
|
||||
@@ -210,7 +194,6 @@
|
||||
"Edit config": "Sửa config",
|
||||
"Bluetooth": "Bluetooth",
|
||||
"Be patient...": "Bình tĩnh...",
|
||||
"Toggles session screen on press": "Mở/đóng màn hình session khi ấn",
|
||||
"Discussions": "Thảo luận",
|
||||
"Anime boorus": "Các booru anime",
|
||||
"That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "Quả này không được. Mẹo:\n- Kiểm tra tag và cài đặt NSFW\n- Nếu không nghĩ ra tag nào có thể nhập số trang",
|
||||
@@ -222,11 +205,9 @@
|
||||
"Copy": "Sao chép",
|
||||
"12h am/pm": "12h am/pm",
|
||||
"Unknown": "Không xác định",
|
||||
"Hides volume OSD on press": "Ngừng hiển thị âm lượng khi nhấn",
|
||||
"Waiting for response...": "Đang chờ phản hồi...",
|
||||
"Workspace": "Workspace",
|
||||
"Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers": "Hình nền Anime SFW ngẫu nhiên từ Konachan\nẢnh được lưu vào ~/Pictures/Wallpapers",
|
||||
"Toggles on screen keyboard on press": "Mở/đóng bàn phím ảo khi ấn",
|
||||
"Online via %1 | %2's model": "Trực tuyến qua %1 | Model của %2",
|
||||
"Always show numbers": "Luôn hiện số",
|
||||
"or": "hoặc",
|
||||
@@ -252,7 +233,6 @@
|
||||
"Color picker": "Chọn màu",
|
||||
"Save to Downloads": "Lưu vào Downloads",
|
||||
"No notifications": "Không có thông báo",
|
||||
"Closes media controls on press": "Đóng điều khiển media khi nhấn",
|
||||
"Game mode": "Chế độ game",
|
||||
"Alternatively use /dark, /light, /img in the launcher": "Có thể dùng /dark, /light, /img trong launcher",
|
||||
"Info": "Thông tin",
|
||||
@@ -261,7 +241,6 @@
|
||||
"Suspend at": "Tạm dừng ở",
|
||||
"Fruit Salad": "Salad hoa quả",
|
||||
"API key:\n\n```txt\n%1\n```": "API key:\n\n```txt\n%1\n```",
|
||||
"Increase brightness": "Tăng độ sáng",
|
||||
"API key set for %1": "API key đã đặt cho %1",
|
||||
"Not visible to model": "Không hiển thị cho model",
|
||||
"Expressive": "Biểu cảm",
|
||||
@@ -272,7 +251,6 @@
|
||||
"Model set to %1": "Đã đặt model thành %1",
|
||||
"Scale (%)": "Tỉ lệ (%)",
|
||||
"Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "Gõ /key để bắt đầu dùng các model trực tuyến\nCtrl+O để mở rộng sidebar\nCtrl+P để nhấc sidebar thành cửa sổ",
|
||||
"Toggle emoji query on overview widget": "Mở/đóng tìm kiếm emoji trên overview",
|
||||
"Output": "Đầu ra",
|
||||
"Uptime: %1": "Máy bật được %1",
|
||||
"For desktop wallpapers | Good quality": "Cho hình nền máy tính | Chất lượng tốt",
|
||||
@@ -289,18 +267,15 @@
|
||||
"No API key set for %1": "Không có API key cho %1",
|
||||
"Add task": "Thêm công việc",
|
||||
"Volume mixer": "Trộn âm lượng",
|
||||
"Toggles media controls on press": "Mở/đóng điều khiển media khi ấn",
|
||||
"Go to source (%1)": "Đi đến nguồn (%1)",
|
||||
"The current API used. Endpoint:": "API đang sử dụng. Endpoint:",
|
||||
"View Markdown source": "Xem nguồn Markdown",
|
||||
"Input": "Đầu vào",
|
||||
"Opens on screen keyboard on press": "Mở bàn phím ảo khi ấn",
|
||||
"Allow NSFW": "Cho phép NSFW",
|
||||
"Session": "Session",
|
||||
"Detach left sidebar into a window/Attach it back": "Nhấc sidebar trái thành cửa sổ/Đặt nó lại",
|
||||
"Night Light": "Lọc ánh sáng xanh",
|
||||
"Workspaces": "Các workspace",
|
||||
"Toggles overview on press": "Mở/đóng overview khi ấn",
|
||||
"Dark": "Tối",
|
||||
"Base URL": "Base URL",
|
||||
"Hug": "Ôm",
|
||||
@@ -331,5 +306,68 @@
|
||||
"Low battery": "Pin yếu",
|
||||
"Scroll to change volume": "Cuộn để thay đổi âm lượng",
|
||||
"Please charge!\nAutomatic suspend triggers at %1": "Hãy sạc pin!\nHệ thống sẽ tự động ngủ khi pin xuống %1",
|
||||
"Closes bar on press": "Đóng bar khi ấn"
|
||||
"Closes bar on press": "Đóng bar khi ấn",
|
||||
"Mo": "T2/*keep*/",
|
||||
"Tu": "T3/*keep*/",
|
||||
"We": "T4/*keep*/",
|
||||
"Th": "T5/*keep*/",
|
||||
"Fr": "T6/*keep*/",
|
||||
"Sa": "T7/*keep*/",
|
||||
"Su": "CN/*keep*/",
|
||||
"Approve": "Chấp nhận",
|
||||
"Set the tool to use for the model.": "Chọn công cụ để sử dụng với model.",
|
||||
"No API key\nSet it with /key YOUR_API_KEY": "Không có API key\nĐặt bằng /key API_KEY",
|
||||
"API Key": "API Key",
|
||||
"EasyEffects | Right-click to configure": "EasyEffects | Ấn chuột phải để chỉnh cài đặt",
|
||||
"API key is set": "API key đã đặt",
|
||||
"Invalid tool. Supported tools:\n- %1": "Công cụ không hợp lệ. Các lựa chọn:\n- %1",
|
||||
"Thought": "Suy nghĩ",
|
||||
"Current tool: %1\nSet it with %2tool TOOL": "Công cụ: %1\nĐặt bằng %2tool CÔNG_CỤ",
|
||||
"Edit shell config file": "Chỉnh file config của shell",
|
||||
"A download might be in progress": "Có thể có tệp đang tải",
|
||||
"API key is set\nChange with /key YOUR_API_KEY": "API key đã đặt\nThay đổi bằng /key API_KEY",
|
||||
"Temperature\nChange with /temp VALUE": "Nhiệt độ (độ ngẫu nhiên)\nThay đổi bằng /temp GIÁ_TRỊ",
|
||||
"Your package manager is running": "Package manager đang chạy",
|
||||
"Usage: %1load CHAT_NAME": "Hướng dẫn: %1load TÊN_ĐOẠN_CHAT",
|
||||
"Cannot switch to search mode from %1": "Không thể chuyển sang chế độ tìm kiếm từ %1",
|
||||
"UV Index": "Chỉ số UV",
|
||||
"Online | Google's model\nFast, can perform searches for up-to-date information": "Trực tuyến | Model của Google\nNhanh, có thể tìm kiếm Google để lấy thông tin cập nhật",
|
||||
"Token count": "Số lượng token",
|
||||
"Experimental | Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput.": "Thử nghiệm | Trực tuyến | Model của Google\nModel Gemini 2.5 Flash tối ưu hóa cho hiệu quả chi phí và băng thông.",
|
||||
"Wallpaper parallax": "Hiệu ứng parallax (hình nền)",
|
||||
"Usage: %1tool TOOL_NAME": "Hướng dẫn: %1tool TÊN_CÔNG_CỤ",
|
||||
"Humidity": "Độ ẩm",
|
||||
"Invalid tool. Supported tools: %1": "Công cụ không hợp lệ. Các lựa chọn: %1",
|
||||
"Sunset": "Hoàng hôn",
|
||||
"Total token count\nInput: %1\nOutput: %2": "Số lượng token\nInput: %1\nOutput: %2",
|
||||
"Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput.": "Trực tuyến | Model của Google\nModel Gemini 2.5 Flash tối ưu hóa cho hiệu quả chi phí và băng thông.",
|
||||
"Visibility": "Tầm nhìn",
|
||||
"Pressure": "Áp suất",
|
||||
"Depends on workspace": "Phụ thuộc vào workspace",
|
||||
"Reject": "Từ chối",
|
||||
"Precipitation": "Lượng mưa",
|
||||
"Wind": "Gió",
|
||||
"Usage: %1save CHAT_NAME": "Hướng dẫn: %1save TÊN_ĐOẠN_CHAT",
|
||||
"Enable EasyEffects": "Bật EasyEffects",
|
||||
"Night Light | Click to toggle, right-click to toggle automatic mode": "Lọc ánh sáng xanh | ấn để bật/tắt, ấn chuột phải để bật/tắt chế độ tự động",
|
||||
"Night Light | Right-click to toggle Auto mode": "Lọc ánh sáng xanh | Ấn chuột phải để bật/tắt chế độ tự động",
|
||||
"No command provided": "Không có lệnh nào được cung cấp",
|
||||
"No API key": "Không có API key",
|
||||
"Performance Profile toggle": "Nút Performance Profile",
|
||||
"Sunrise": "Bình minh",
|
||||
"Online | Google's model\nNewer one that's slower": "Trực tuyến | Model của Google\nMới hơn nhưng chậm hơn",
|
||||
"Command rejected by user": "Lệnh bị từ chối bởi người dùng",
|
||||
"Experimental | Online | Google's model\nCan do a little more but takes an extra turn to perform search": "Thử nghiệm | Trực tuyến | Model của Google\nCó thể làm nhiều hơn một chút nhưng mất thêm một lượt để thực hiện tìm kiếm",
|
||||
"Depends on sidebars": "Phụ thuộc vào sidebar",
|
||||
"Temperature": "Nhiệt độ",
|
||||
"There might be a download in progress": "Có thể có tệp đang tải",
|
||||
"EasyEffects": "EasyEffects",
|
||||
"Token count | Input: %1 | Output: %2": "Số lượng token | Input: %1 | Output: %2",
|
||||
"Tool set to %1": "Công cụ được đặt thành %1",
|
||||
"Invalid arguments. Must provide `command`.": "Tham số không hợp lệ. Phải cung cấp `command`.",
|
||||
"A download is in progress": "Có một tệp đang tải",
|
||||
"illogical-impulse Settings": "Cài đặt illogical-impulse",
|
||||
"Online | Google's model\nNewer model that's slower than its predecessor but should deliver higher quality answers": "Trực tuyến | Model của Google\nMới hơn nhưng chậm hơn so với phiên bản trước nhưng nên cung cấp câu trả lời chất lượng cao hơn",
|
||||
"Preferred wallpaper zoom (%)": "Tỷ lệ thu phóng hình nền (%)",
|
||||
"Function Response": "Phản hồi function"
|
||||
}
|
||||
@@ -12,8 +12,7 @@ add_newline = false
|
||||
# """
|
||||
format = """
|
||||
$cmd_duration $directory $git_branch
|
||||
$character
|
||||
"""
|
||||
$character"""
|
||||
|
||||
# Replace the "❯" symbol in the prompt with "➜"
|
||||
[character] # The name of the module we are configuring is "character"
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
|
||||
</details>
|
||||
|
||||
_Note: **THERE IS NO FUCKING WAYBAR**_
|
||||
|
||||
|
||||
<div align="center">
|
||||
<h2>• screenshots •</h2>
|
||||
|
||||
@@ -5,16 +5,17 @@ pkgdesc='Illogical Impulse Hyprland relatated packages'
|
||||
arch=(any)
|
||||
license=(None)
|
||||
depends=(
|
||||
hyprutils
|
||||
hyprpicker
|
||||
hyprlang
|
||||
hypridle
|
||||
hyprland-qt-support
|
||||
hyprland-qtutils
|
||||
hyprlock
|
||||
hyprcursor
|
||||
hyprwayland-scanner
|
||||
hyprland
|
||||
hyprland-qtutils
|
||||
hyprland-qt-support
|
||||
hyprlang
|
||||
hyprlock
|
||||
hyprpicker
|
||||
hyprsunset
|
||||
hyprutils
|
||||
hyprwayland-scanner
|
||||
xdg-desktop-portal-hyprland
|
||||
wl-clipboard
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user