Tools: Gemini-Integrated Debian: A Practical Desktop AI Integration

Tools: Gemini-Integrated Debian: A Practical Desktop AI Integration

Source: Dev.to

Introduction ## Code Attribution and Licensing ## Original Authentication Code ## Modified Authentication: API Key Only ## Simplified Authentication Implementation ## Installation and Setup ## Step 1: Initial Setup Script ## Step 2: Systemd Service Integration ## Step 3: Login Integration ## Desktop Environment Integration ## KDE Plasma Integration ## 1. Plasma Widget (Plasmoid) ## 2. KDE Configuration Module (KCM) ## XFCE Panel Plugin Integration ## DBus API for Desktop Integration ## Advanced Features ## Login Window AI Content ## GUI Configuration Editor ## Security Considerations ## Troubleshooting ## Service Won't Start ## API Key Errors ## Widget Not Appearing ## Future Enhancements ## Conclusion ## Building Custom Debian/Ubuntu ISOs with live-build ## Resources ## License and Attribution ## Code Generation Attribution ⚠️ CODE GENERATION NOTICE All code implementations shown in this article were generated by Claude AI (Sonnet 4.5) based on my specifications and requirements. I provided Claude with: The code presented here represents a minimal setup needed for the integration concept described in my original DEV.to article. While I directed what needed to be created, Claude AI generated the actual implementation code. This article presents a practical approach to integrating Google's Gemini AI into a Debian-based Linux system, focusing on seamless desktop environment integration with KDE Plasma and XFCE. This concept is inspired by the larger NeuroShellOS vision - a more ambitious project that explores deep OS-level AI integration. Rather than keeping AI as a separate application, this implementation embeds Gemini into the operating system workflow through systemd services, desktop widgets, and configuration modules. The goal is to make AI assistance a natural part of the Linux desktop experience. This implementation builds upon the official Google Gemini CLI, specifically adapting authentication code from packages/cli/src/config/auth.ts. The original Gemini CLI code is licensed under Apache License 2.0, which means: Here's the authentication validation code from the Gemini CLI (Apache 2.0 licensed): For this Debian integration, we simplify authentication to use API keys only, stored in ~/.config/gemini/config. This approach: Here's the modified authentication code that only supports API key authentication (USE_GEMINI mode): Key Changes from Original: Create an installer that prompts for the API key during first boot: Make it executable and run during installation: Create a systemd service to run Gemini as a background daemon: System-wide service (/etc/systemd/system/gemini.service): Per-user service (~/.config/systemd/user/gemini.service): Enable and start the service: To start Gemini automatically when users log in, create an XDG autostart entry: ~/.config/autostart/gemini-session.desktop: KDE Plasma offers powerful customization through widgets (Plasmoids) and configuration modules (KCM). Create a Plasma widget that displays Gemini status and accepts prompts: contents/ui/main.qml: Create a configuration module for Gemini settings in System Settings: CMakeLists.txt for KCM: For XFCE, create a panel plugin using libxfce4panel: gemini-plugin.c (simplified): Create a DBus service for communication between desktop components and Gemini: /usr/share/dbus-1/services/com.gemini.service: DBus interface implementation (Python example): Make it executable and create a systemd service: Display AI-generated tips or system status on the login screen by integrating with the display manager: For LightDM (/etc/lightdm/lightdm-gtk-greeter.conf): Create a script that generates daily tips: Users can edit Gemini's behavior through configuration files. For non-technical users, create a graphical editor: This implementation opens doors for many exciting possibilities: This Gemini integration demonstrates how AI can become a natural part of the Linux desktop experience. By leveraging existing technologies like systemd, DBus, and desktop environment frameworks, we create a seamless integration that feels native to the system. The simplified API key authentication approach makes deployment practical while maintaining security. Desktop environment integration through KDE Plasma widgets and XFCE panel plugins provides users with familiar interfaces to interact with AI capabilities. This minimal setup is specifically designed to be integrated into custom Debian or Ubuntu distributions using live-build. To create a custom ISO with Gemini pre-integrated: The setup script will automatically run on first boot, prompting users to configure their Gemini API key during the initial system setup. While this is a more modest implementation compared to the ambitious NeuroShellOS vision, it represents a practical step toward AI-integrated operating systems that can be built and tested today. Using live-build ensures the integration is baked directly into the ISO, making it truly part of the base system rather than an afterthought. This is the minimal setup needed for integrating Gemini into Debian/Ubuntu distributions and creating bootable ISOs with live-build. This article and concept implementation are licensed under CC BY-SA 4.0. The original Gemini CLI authentication code is licensed under Apache License 2.0 by Google LLC. Author: Muhammed Shafin P (@hejhdiss) Original Article: A Practical Gemini-Integrated Debian Concept All code implementations in this article were generated by Claude AI (Sonnet 4.5). I (Muhammed Shafin P) provided Claude with: Claude AI then generated: This represents a minimal working setup for the integration concept described in my original article. The code serves as a starting point and proof-of-concept that developers can build upon. Technology Used: Claude AI (Sonnet 4.5) via claude.ai Generation Date: January 2026 For questions, contributions, or collaboration: Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { AuthType } from '@google/gemini-cli-core'; import { loadEnvironment, loadSettings } from './settings.js'; export function validateAuthMethod(authMethod: string): string | null { loadEnvironment(loadSettings().merged); if ( authMethod === AuthType.LOGIN_WITH_GOOGLE || authMethod === AuthType.COMPUTE_ADC ) { return null; } if (authMethod === AuthType.USE_GEMINI) { if (!process.env['GEMINI_API_KEY']) { return ( 'When using Gemini API, you must specify the GEMINI_API_KEY environment variable.\n' + 'Update your environment and try again (no reload needed if using .env)!' ); } return null; } if (authMethod === AuthType.USE_VERTEX_AI) { const hasVertexProjectLocationConfig = !!process.env['GOOGLE_CLOUD_PROJECT'] && !!process.env['GOOGLE_CLOUD_LOCATION']; const hasGoogleApiKey = !!process.env['GOOGLE_API_KEY']; if (!hasVertexProjectLocationConfig && !hasGoogleApiKey) { return ( 'When using Vertex AI, you must specify either:\n' + '• GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION environment variables.\n' + '• GOOGLE_API_KEY environment variable (if using express mode).\n' + 'Update your environment and try again (no reload needed if using .env)!' ); } return null; } return 'Invalid auth method selected.'; } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { AuthType } from '@google/gemini-cli-core'; import { loadEnvironment, loadSettings } from './settings.js'; export function validateAuthMethod(authMethod: string): string | null { loadEnvironment(loadSettings().merged); if ( authMethod === AuthType.LOGIN_WITH_GOOGLE || authMethod === AuthType.COMPUTE_ADC ) { return null; } if (authMethod === AuthType.USE_GEMINI) { if (!process.env['GEMINI_API_KEY']) { return ( 'When using Gemini API, you must specify the GEMINI_API_KEY environment variable.\n' + 'Update your environment and try again (no reload needed if using .env)!' ); } return null; } if (authMethod === AuthType.USE_VERTEX_AI) { const hasVertexProjectLocationConfig = !!process.env['GOOGLE_CLOUD_PROJECT'] && !!process.env['GOOGLE_CLOUD_LOCATION']; const hasGoogleApiKey = !!process.env['GOOGLE_API_KEY']; if (!hasVertexProjectLocationConfig && !hasGoogleApiKey) { return ( 'When using Vertex AI, you must specify either:\n' + '• GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION environment variables.\n' + '• GOOGLE_API_KEY environment variable (if using express mode).\n' + 'Update your environment and try again (no reload needed if using .env)!' ); } return null; } return 'Invalid auth method selected.'; } CODE_BLOCK: /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { AuthType } from '@google/gemini-cli-core'; import { loadEnvironment, loadSettings } from './settings.js'; export function validateAuthMethod(authMethod: string): string | null { loadEnvironment(loadSettings().merged); if ( authMethod === AuthType.LOGIN_WITH_GOOGLE || authMethod === AuthType.COMPUTE_ADC ) { return null; } if (authMethod === AuthType.USE_GEMINI) { if (!process.env['GEMINI_API_KEY']) { return ( 'When using Gemini API, you must specify the GEMINI_API_KEY environment variable.\n' + 'Update your environment and try again (no reload needed if using .env)!' ); } return null; } if (authMethod === AuthType.USE_VERTEX_AI) { const hasVertexProjectLocationConfig = !!process.env['GOOGLE_CLOUD_PROJECT'] && !!process.env['GOOGLE_CLOUD_LOCATION']; const hasGoogleApiKey = !!process.env['GOOGLE_API_KEY']; if (!hasVertexProjectLocationConfig && !hasGoogleApiKey) { return ( 'When using Vertex AI, you must specify either:\n' + '• GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION environment variables.\n' + '• GOOGLE_API_KEY environment variable (if using express mode).\n' + 'Update your environment and try again (no reload needed if using .env)!' ); } return null; } return 'Invalid auth method selected.'; } CODE_BLOCK: /** * @license * Copyright 2025 Google LLC (Original) * Modified for Debian Integration by Muhammed Shafin P * SPDX-License-Identifier: Apache-2.0 * * MODIFICATIONS: * - Removed LOGIN_WITH_GOOGLE and COMPUTE_ADC authentication methods * - Removed VERTEX_AI authentication method * - Only USE_GEMINI (API key) mode is supported * - Modified to read API key from ~/.config/gemini/config * - Added error message for unsupported authentication methods */ import { AuthType } from '@google/gemini-cli-core'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; export function validateAuthMethod(authMethod: string): string | null { // Only USE_GEMINI authentication method is supported in this minimal setup if (authMethod !== AuthType.USE_GEMINI) { return ( '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + '⚠️ UNSUPPORTED AUTHENTICATION METHOD\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + '\n' + 'This Debian/Ubuntu integration only supports API key authentication.\n' + '\n' + `Attempted method: ${authMethod}\n` + 'Supported method: USE_GEMINI (API key)\n' + '\n' + 'Other authentication methods (LOGIN_WITH_GOOGLE, COMPUTE_ADC, USE_VERTEX_AI)\n' + 'are not supported in this minimal setup.\n' + '\n' + 'To configure API key authentication:\n' + ' 1. Run: ./gemini-setup.sh\n' + ' 2. Enter your Gemini API key when prompted\n' + ' 3. API key will be stored in ~/.config/gemini/config\n' + '\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + 'ℹ️ This is the minimal setup needed for integrating Gemini into\n' + ' Debian/Ubuntu distributions using live-build for creating ISOs.\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' ); } // Read API key from config file const configPath = path.join(os.homedir(), '.config', 'gemini', 'config'); if (!fs.existsSync(configPath)) { return ( 'Gemini API key not configured.\n' + 'Configuration file not found at: ' + configPath + '\n' + 'Please run the setup script: ./gemini-setup.sh' ); } // Load and validate API key from config try { const configData = fs.readFileSync(configPath, 'utf-8'); const lines = configData.split('\n'); let apiKey = ''; for (const line of lines) { if (line.trim().startsWith('API_KEY=')) { apiKey = line.split('=')[1].trim(); break; } } if (!apiKey) { return ( 'API_KEY not found in configuration file.\n' + 'Please run the setup script to configure: ./gemini-setup.sh' ); } if (apiKey.length < 20) { return ( 'Invalid API key in configuration file.\n' + 'API key appears to be too short. Please reconfigure: ./gemini-setup.sh' ); } // All checks passed return null; } catch (error) { return ( 'Error reading Gemini configuration: ' + error.message + '\n' + 'Please run the setup script: ./gemini-setup.sh' ); } } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: /** * @license * Copyright 2025 Google LLC (Original) * Modified for Debian Integration by Muhammed Shafin P * SPDX-License-Identifier: Apache-2.0 * * MODIFICATIONS: * - Removed LOGIN_WITH_GOOGLE and COMPUTE_ADC authentication methods * - Removed VERTEX_AI authentication method * - Only USE_GEMINI (API key) mode is supported * - Modified to read API key from ~/.config/gemini/config * - Added error message for unsupported authentication methods */ import { AuthType } from '@google/gemini-cli-core'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; export function validateAuthMethod(authMethod: string): string | null { // Only USE_GEMINI authentication method is supported in this minimal setup if (authMethod !== AuthType.USE_GEMINI) { return ( '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + '⚠️ UNSUPPORTED AUTHENTICATION METHOD\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + '\n' + 'This Debian/Ubuntu integration only supports API key authentication.\n' + '\n' + `Attempted method: ${authMethod}\n` + 'Supported method: USE_GEMINI (API key)\n' + '\n' + 'Other authentication methods (LOGIN_WITH_GOOGLE, COMPUTE_ADC, USE_VERTEX_AI)\n' + 'are not supported in this minimal setup.\n' + '\n' + 'To configure API key authentication:\n' + ' 1. Run: ./gemini-setup.sh\n' + ' 2. Enter your Gemini API key when prompted\n' + ' 3. API key will be stored in ~/.config/gemini/config\n' + '\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + 'ℹ️ This is the minimal setup needed for integrating Gemini into\n' + ' Debian/Ubuntu distributions using live-build for creating ISOs.\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' ); } // Read API key from config file const configPath = path.join(os.homedir(), '.config', 'gemini', 'config'); if (!fs.existsSync(configPath)) { return ( 'Gemini API key not configured.\n' + 'Configuration file not found at: ' + configPath + '\n' + 'Please run the setup script: ./gemini-setup.sh' ); } // Load and validate API key from config try { const configData = fs.readFileSync(configPath, 'utf-8'); const lines = configData.split('\n'); let apiKey = ''; for (const line of lines) { if (line.trim().startsWith('API_KEY=')) { apiKey = line.split('=')[1].trim(); break; } } if (!apiKey) { return ( 'API_KEY not found in configuration file.\n' + 'Please run the setup script to configure: ./gemini-setup.sh' ); } if (apiKey.length < 20) { return ( 'Invalid API key in configuration file.\n' + 'API key appears to be too short. Please reconfigure: ./gemini-setup.sh' ); } // All checks passed return null; } catch (error) { return ( 'Error reading Gemini configuration: ' + error.message + '\n' + 'Please run the setup script: ./gemini-setup.sh' ); } } CODE_BLOCK: /** * @license * Copyright 2025 Google LLC (Original) * Modified for Debian Integration by Muhammed Shafin P * SPDX-License-Identifier: Apache-2.0 * * MODIFICATIONS: * - Removed LOGIN_WITH_GOOGLE and COMPUTE_ADC authentication methods * - Removed VERTEX_AI authentication method * - Only USE_GEMINI (API key) mode is supported * - Modified to read API key from ~/.config/gemini/config * - Added error message for unsupported authentication methods */ import { AuthType } from '@google/gemini-cli-core'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; export function validateAuthMethod(authMethod: string): string | null { // Only USE_GEMINI authentication method is supported in this minimal setup if (authMethod !== AuthType.USE_GEMINI) { return ( '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + '⚠️ UNSUPPORTED AUTHENTICATION METHOD\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + '\n' + 'This Debian/Ubuntu integration only supports API key authentication.\n' + '\n' + `Attempted method: ${authMethod}\n` + 'Supported method: USE_GEMINI (API key)\n' + '\n' + 'Other authentication methods (LOGIN_WITH_GOOGLE, COMPUTE_ADC, USE_VERTEX_AI)\n' + 'are not supported in this minimal setup.\n' + '\n' + 'To configure API key authentication:\n' + ' 1. Run: ./gemini-setup.sh\n' + ' 2. Enter your Gemini API key when prompted\n' + ' 3. API key will be stored in ~/.config/gemini/config\n' + '\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' + 'ℹ️ This is the minimal setup needed for integrating Gemini into\n' + ' Debian/Ubuntu distributions using live-build for creating ISOs.\n' + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' ); } // Read API key from config file const configPath = path.join(os.homedir(), '.config', 'gemini', 'config'); if (!fs.existsSync(configPath)) { return ( 'Gemini API key not configured.\n' + 'Configuration file not found at: ' + configPath + '\n' + 'Please run the setup script: ./gemini-setup.sh' ); } // Load and validate API key from config try { const configData = fs.readFileSync(configPath, 'utf-8'); const lines = configData.split('\n'); let apiKey = ''; for (const line of lines) { if (line.trim().startsWith('API_KEY=')) { apiKey = line.split('=')[1].trim(); break; } } if (!apiKey) { return ( 'API_KEY not found in configuration file.\n' + 'Please run the setup script to configure: ./gemini-setup.sh' ); } if (apiKey.length < 20) { return ( 'Invalid API key in configuration file.\n' + 'API key appears to be too short. Please reconfigure: ./gemini-setup.sh' ); } // All checks passed return null; } catch (error) { return ( 'Error reading Gemini configuration: ' + error.message + '\n' + 'Please run the setup script: ./gemini-setup.sh' ); } } COMMAND_BLOCK: #!/bin/bash # gemini-setup.sh - First-time Gemini configuration set -e echo "===================================" echo "Gemini AI Setup for Debian" echo "===================================" echo "" CONFIG_DIR="$HOME/.config/gemini" CONFIG_FILE="$CONFIG_DIR/config" # Create config directory mkdir -p "$CONFIG_DIR" # Check if already configured if [ -f "$CONFIG_FILE" ]; then read -p "Gemini is already configured. Reconfigure? (y/N): " RECONFIGURE if [[ ! "$RECONFIGURE" =~ ^[Yy]$ ]]; then echo "Setup cancelled." exit 0 fi fi # Prompt for API key echo "Please enter your Gemini API key." echo "Get your API key from: https://makersuite.google.com/app/apikey" echo "" read -sp "API Key: " GEMINI_KEY echo "" if [ -z "$GEMINI_KEY" ]; then echo "Error: API key cannot be empty" exit 1 fi # Optional: Prompt for model preference echo "" echo "Select default model:" echo "1) gemini-pro (default)" echo "2) gemini-pro-vision" echo "3) gemini-ultra" read -p "Choice [1]: " MODEL_CHOICE case $MODEL_CHOICE in 2) MODEL="gemini-pro-vision" ;; 3) MODEL="gemini-ultra" ;; *) MODEL="gemini-pro" ;; esac # Write configuration cat > "$CONFIG_FILE" << EOF # Gemini API Configuration # Generated on $(date) API_KEY=$GEMINI_KEY MODEL=$MODEL TEMPERATURE=0.7 MAX_TOKENS=2048 EOF # Secure the config file chmod 600 "$CONFIG_FILE" echo "" echo "✓ Configuration saved to $CONFIG_FILE" echo "✓ File permissions set to 600 (owner read/write only)" echo "" echo "Setup complete! Gemini is ready to use." echo "You can now enable the systemd service:" echo " systemctl --user enable --now gemini.service" Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: #!/bin/bash # gemini-setup.sh - First-time Gemini configuration set -e echo "===================================" echo "Gemini AI Setup for Debian" echo "===================================" echo "" CONFIG_DIR="$HOME/.config/gemini" CONFIG_FILE="$CONFIG_DIR/config" # Create config directory mkdir -p "$CONFIG_DIR" # Check if already configured if [ -f "$CONFIG_FILE" ]; then read -p "Gemini is already configured. Reconfigure? (y/N): " RECONFIGURE if [[ ! "$RECONFIGURE" =~ ^[Yy]$ ]]; then echo "Setup cancelled." exit 0 fi fi # Prompt for API key echo "Please enter your Gemini API key." echo "Get your API key from: https://makersuite.google.com/app/apikey" echo "" read -sp "API Key: " GEMINI_KEY echo "" if [ -z "$GEMINI_KEY" ]; then echo "Error: API key cannot be empty" exit 1 fi # Optional: Prompt for model preference echo "" echo "Select default model:" echo "1) gemini-pro (default)" echo "2) gemini-pro-vision" echo "3) gemini-ultra" read -p "Choice [1]: " MODEL_CHOICE case $MODEL_CHOICE in 2) MODEL="gemini-pro-vision" ;; 3) MODEL="gemini-ultra" ;; *) MODEL="gemini-pro" ;; esac # Write configuration cat > "$CONFIG_FILE" << EOF # Gemini API Configuration # Generated on $(date) API_KEY=$GEMINI_KEY MODEL=$MODEL TEMPERATURE=0.7 MAX_TOKENS=2048 EOF # Secure the config file chmod 600 "$CONFIG_FILE" echo "" echo "✓ Configuration saved to $CONFIG_FILE" echo "✓ File permissions set to 600 (owner read/write only)" echo "" echo "Setup complete! Gemini is ready to use." echo "You can now enable the systemd service:" echo " systemctl --user enable --now gemini.service" COMMAND_BLOCK: #!/bin/bash # gemini-setup.sh - First-time Gemini configuration set -e echo "===================================" echo "Gemini AI Setup for Debian" echo "===================================" echo "" CONFIG_DIR="$HOME/.config/gemini" CONFIG_FILE="$CONFIG_DIR/config" # Create config directory mkdir -p "$CONFIG_DIR" # Check if already configured if [ -f "$CONFIG_FILE" ]; then read -p "Gemini is already configured. Reconfigure? (y/N): " RECONFIGURE if [[ ! "$RECONFIGURE" =~ ^[Yy]$ ]]; then echo "Setup cancelled." exit 0 fi fi # Prompt for API key echo "Please enter your Gemini API key." echo "Get your API key from: https://makersuite.google.com/app/apikey" echo "" read -sp "API Key: " GEMINI_KEY echo "" if [ -z "$GEMINI_KEY" ]; then echo "Error: API key cannot be empty" exit 1 fi # Optional: Prompt for model preference echo "" echo "Select default model:" echo "1) gemini-pro (default)" echo "2) gemini-pro-vision" echo "3) gemini-ultra" read -p "Choice [1]: " MODEL_CHOICE case $MODEL_CHOICE in 2) MODEL="gemini-pro-vision" ;; 3) MODEL="gemini-ultra" ;; *) MODEL="gemini-pro" ;; esac # Write configuration cat > "$CONFIG_FILE" << EOF # Gemini API Configuration # Generated on $(date) API_KEY=$GEMINI_KEY MODEL=$MODEL TEMPERATURE=0.7 MAX_TOKENS=2048 EOF # Secure the config file chmod 600 "$CONFIG_FILE" echo "" echo "✓ Configuration saved to $CONFIG_FILE" echo "✓ File permissions set to 600 (owner read/write only)" echo "" echo "Setup complete! Gemini is ready to use." echo "You can now enable the systemd service:" echo " systemctl --user enable --now gemini.service" CODE_BLOCK: chmod +x gemini-setup.sh ./gemini-setup.sh Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: chmod +x gemini-setup.sh ./gemini-setup.sh CODE_BLOCK: chmod +x gemini-setup.sh ./gemini-setup.sh COMMAND_BLOCK: [Unit] Description=Gemini AI Background Service After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/gemini daemon Restart=on-failure RestartSec=10 StandardOutput=journal StandardError=journal # Security hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=read-only [Install] WantedBy=multi-user.target Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: [Unit] Description=Gemini AI Background Service After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/gemini daemon Restart=on-failure RestartSec=10 StandardOutput=journal StandardError=journal # Security hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=read-only [Install] WantedBy=multi-user.target COMMAND_BLOCK: [Unit] Description=Gemini AI Background Service After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/gemini daemon Restart=on-failure RestartSec=10 StandardOutput=journal StandardError=journal # Security hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=read-only [Install] WantedBy=multi-user.target CODE_BLOCK: [Unit] Description=Gemini AI User Session Service After=graphical-session.target Wants=graphical-session.target [Service] Type=simple ExecStart=/usr/local/bin/gemini daemon --user-mode Restart=on-failure RestartSec=5 Environment="GEMINI_CONFIG=%h/.config/gemini/config" [Install] WantedBy=default.target Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: [Unit] Description=Gemini AI User Session Service After=graphical-session.target Wants=graphical-session.target [Service] Type=simple ExecStart=/usr/local/bin/gemini daemon --user-mode Restart=on-failure RestartSec=5 Environment="GEMINI_CONFIG=%h/.config/gemini/config" [Install] WantedBy=default.target CODE_BLOCK: [Unit] Description=Gemini AI User Session Service After=graphical-session.target Wants=graphical-session.target [Service] Type=simple ExecStart=/usr/local/bin/gemini daemon --user-mode Restart=on-failure RestartSec=5 Environment="GEMINI_CONFIG=%h/.config/gemini/config" [Install] WantedBy=default.target COMMAND_BLOCK: # System-wide (requires root) sudo systemctl enable gemini.service sudo systemctl start gemini.service # Per-user (recommended) systemctl --user enable gemini.service systemctl --user start gemini.service Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # System-wide (requires root) sudo systemctl enable gemini.service sudo systemctl start gemini.service # Per-user (recommended) systemctl --user enable gemini.service systemctl --user start gemini.service COMMAND_BLOCK: # System-wide (requires root) sudo systemctl enable gemini.service sudo systemctl start gemini.service # Per-user (recommended) systemctl --user enable gemini.service systemctl --user start gemini.service CODE_BLOCK: [Desktop Entry] Type=Application Name=Gemini AI Session Comment=Start Gemini AI assistance on login Exec=systemctl --user start gemini.service Terminal=false StartupNotify=false X-GNOME-Autostart-enabled=true X-KDE-autostart-after=panel Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: [Desktop Entry] Type=Application Name=Gemini AI Session Comment=Start Gemini AI assistance on login Exec=systemctl --user start gemini.service Terminal=false StartupNotify=false X-GNOME-Autostart-enabled=true X-KDE-autostart-after=panel CODE_BLOCK: [Desktop Entry] Type=Application Name=Gemini AI Session Comment=Start Gemini AI assistance on login Exec=systemctl --user start gemini.service Terminal=false StartupNotify=false X-GNOME-Autostart-enabled=true X-KDE-autostart-after=panel CODE_BLOCK: ~/.local/share/plasma/plasmoids/com.gemini.widget/ ├── metadata.json ├── contents/ │ ├── ui/ │ │ └── main.qml │ └── code/ │ └── gemini-dbus.js Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: ~/.local/share/plasma/plasmoids/com.gemini.widget/ ├── metadata.json ├── contents/ │ ├── ui/ │ │ └── main.qml │ └── code/ │ └── gemini-dbus.js CODE_BLOCK: ~/.local/share/plasma/plasmoids/com.gemini.widget/ ├── metadata.json ├── contents/ │ ├── ui/ │ │ └── main.qml │ └── code/ │ └── gemini-dbus.js CODE_BLOCK: { "KPlugin": { "Name": "Gemini AI Assistant", "Description": "Interact with Gemini AI directly from your panel", "Category": "Productivity", "Version": "1.0", "Authors": [ { "Name": "Your Name" } ] }, "X-Plasma-API": "declarativeappletscript", "X-Plasma-MainScript": "ui/main.qml" } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: { "KPlugin": { "Name": "Gemini AI Assistant", "Description": "Interact with Gemini AI directly from your panel", "Category": "Productivity", "Version": "1.0", "Authors": [ { "Name": "Your Name" } ] }, "X-Plasma-API": "declarativeappletscript", "X-Plasma-MainScript": "ui/main.qml" } CODE_BLOCK: { "KPlugin": { "Name": "Gemini AI Assistant", "Description": "Interact with Gemini AI directly from your panel", "Category": "Productivity", "Version": "1.0", "Authors": [ { "Name": "Your Name" } ] }, "X-Plasma-API": "declarativeappletscript", "X-Plasma-MainScript": "ui/main.qml" } CODE_BLOCK: import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.plasmoid 2.0 Item { id: root Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation // Compact representation (panel icon) Plasmoid.compactRepresentation: Item { PlasmaCore.IconItem { id: geminiIcon anchors.fill: parent source: "ai-assistant" active: geminiMouseArea.containsMouse PlasmaCore.ToolTipArea { anchors.fill: parent mainText: "Gemini AI" subText: geminiStatus.statusText } } MouseArea { id: geminiMouseArea anchors.fill: parent hoverEnabled: true onClicked: plasmoid.expanded = !plasmoid.expanded } } // Full representation (popup dialog) Plasmoid.fullRepresentation: Item { Layout.preferredWidth: 400 Layout.preferredHeight: 500 ColumnLayout { anchors.fill: parent spacing: 10 // Status indicator RowLayout { PlasmaComponents.Label { text: "Status:" font.bold: true } PlasmaComponents.Label { id: statusLabel text: geminiStatus.statusText color: geminiStatus.isActive ? "green" : "red" } } // Input area PlasmaComponents.TextArea { id: promptInput Layout.fillWidth: true Layout.preferredHeight: 100 placeholderText: "Ask Gemini anything..." } // Submit button PlasmaComponents.Button { text: "Submit" icon.name: "arrow-right" Layout.alignment: Qt.AlignRight onClicked: submitPrompt() } // Response area PlasmaComponents.ScrollView { Layout.fillWidth: true Layout.fillHeight: true PlasmaComponents.TextArea { id: responseArea readOnly: true wrapMode: Text.Wrap text: geminiResponse.text } } } } // DBus interface for communication PlasmaCore.DataSource { id: geminiStatus engine: "executable" connectedSources: ["systemctl --user is-active gemini.service"] interval: 5000 property string statusText: "Checking..." property bool isActive: false onNewData: { statusText = data["exit code"] === 0 ? "Active" : "Inactive" isActive = data["exit code"] === 0 } } // Response handler QtObject { id: geminiResponse property string text: "" } function submitPrompt() { var prompt = promptInput.text.trim() if (prompt === "") return responseArea.text = "Processing..." // Call Gemini via DBus or local API var cmd = "gemini query '" + prompt + "'" executable.connectSource(cmd) } PlasmaCore.DataSource { id: executable engine: "executable" onNewData: { geminiResponse.text = data.stdout || "No response" promptInput.text = "" } } } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.plasmoid 2.0 Item { id: root Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation // Compact representation (panel icon) Plasmoid.compactRepresentation: Item { PlasmaCore.IconItem { id: geminiIcon anchors.fill: parent source: "ai-assistant" active: geminiMouseArea.containsMouse PlasmaCore.ToolTipArea { anchors.fill: parent mainText: "Gemini AI" subText: geminiStatus.statusText } } MouseArea { id: geminiMouseArea anchors.fill: parent hoverEnabled: true onClicked: plasmoid.expanded = !plasmoid.expanded } } // Full representation (popup dialog) Plasmoid.fullRepresentation: Item { Layout.preferredWidth: 400 Layout.preferredHeight: 500 ColumnLayout { anchors.fill: parent spacing: 10 // Status indicator RowLayout { PlasmaComponents.Label { text: "Status:" font.bold: true } PlasmaComponents.Label { id: statusLabel text: geminiStatus.statusText color: geminiStatus.isActive ? "green" : "red" } } // Input area PlasmaComponents.TextArea { id: promptInput Layout.fillWidth: true Layout.preferredHeight: 100 placeholderText: "Ask Gemini anything..." } // Submit button PlasmaComponents.Button { text: "Submit" icon.name: "arrow-right" Layout.alignment: Qt.AlignRight onClicked: submitPrompt() } // Response area PlasmaComponents.ScrollView { Layout.fillWidth: true Layout.fillHeight: true PlasmaComponents.TextArea { id: responseArea readOnly: true wrapMode: Text.Wrap text: geminiResponse.text } } } } // DBus interface for communication PlasmaCore.DataSource { id: geminiStatus engine: "executable" connectedSources: ["systemctl --user is-active gemini.service"] interval: 5000 property string statusText: "Checking..." property bool isActive: false onNewData: { statusText = data["exit code"] === 0 ? "Active" : "Inactive" isActive = data["exit code"] === 0 } } // Response handler QtObject { id: geminiResponse property string text: "" } function submitPrompt() { var prompt = promptInput.text.trim() if (prompt === "") return responseArea.text = "Processing..." // Call Gemini via DBus or local API var cmd = "gemini query '" + prompt + "'" executable.connectSource(cmd) } PlasmaCore.DataSource { id: executable engine: "executable" onNewData: { geminiResponse.text = data.stdout || "No response" promptInput.text = "" } } } CODE_BLOCK: import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.plasmoid 2.0 Item { id: root Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation // Compact representation (panel icon) Plasmoid.compactRepresentation: Item { PlasmaCore.IconItem { id: geminiIcon anchors.fill: parent source: "ai-assistant" active: geminiMouseArea.containsMouse PlasmaCore.ToolTipArea { anchors.fill: parent mainText: "Gemini AI" subText: geminiStatus.statusText } } MouseArea { id: geminiMouseArea anchors.fill: parent hoverEnabled: true onClicked: plasmoid.expanded = !plasmoid.expanded } } // Full representation (popup dialog) Plasmoid.fullRepresentation: Item { Layout.preferredWidth: 400 Layout.preferredHeight: 500 ColumnLayout { anchors.fill: parent spacing: 10 // Status indicator RowLayout { PlasmaComponents.Label { text: "Status:" font.bold: true } PlasmaComponents.Label { id: statusLabel text: geminiStatus.statusText color: geminiStatus.isActive ? "green" : "red" } } // Input area PlasmaComponents.TextArea { id: promptInput Layout.fillWidth: true Layout.preferredHeight: 100 placeholderText: "Ask Gemini anything..." } // Submit button PlasmaComponents.Button { text: "Submit" icon.name: "arrow-right" Layout.alignment: Qt.AlignRight onClicked: submitPrompt() } // Response area PlasmaComponents.ScrollView { Layout.fillWidth: true Layout.fillHeight: true PlasmaComponents.TextArea { id: responseArea readOnly: true wrapMode: Text.Wrap text: geminiResponse.text } } } } // DBus interface for communication PlasmaCore.DataSource { id: geminiStatus engine: "executable" connectedSources: ["systemctl --user is-active gemini.service"] interval: 5000 property string statusText: "Checking..." property bool isActive: false onNewData: { statusText = data["exit code"] === 0 ? "Active" : "Inactive" isActive = data["exit code"] === 0 } } // Response handler QtObject { id: geminiResponse property string text: "" } function submitPrompt() { var prompt = promptInput.text.trim() if (prompt === "") return responseArea.text = "Processing..." // Call Gemini via DBus or local API var cmd = "gemini query '" + prompt + "'" executable.connectSource(cmd) } PlasmaCore.DataSource { id: executable engine: "executable" onNewData: { geminiResponse.text = data.stdout || "No response" promptInput.text = "" } } } COMMAND_BLOCK: # Install locally cp -r com.gemini.widget ~/.local/share/plasma/plasmoids/ # Restart Plasma kquitapp5 plasmashell && kstart5 plasmashell Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Install locally cp -r com.gemini.widget ~/.local/share/plasma/plasmoids/ # Restart Plasma kquitapp5 plasmashell && kstart5 plasmashell COMMAND_BLOCK: # Install locally cp -r com.gemini.widget ~/.local/share/plasma/plasmoids/ # Restart Plasma kquitapp5 plasmashell && kstart5 plasmashell CODE_BLOCK: cmake_minimum_required(VERSION 3.16) project(kcm_gemini) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) find_package(Qt5 REQUIRED COMPONENTS Core Widgets) find_package(KF5 REQUIRED COMPONENTS I18n ConfigWidgets KCMUtils) add_library(kcm_gemini MODULE kcm_gemini.cpp) target_link_libraries(kcm_gemini Qt5::Core Qt5::Widgets KF5::ConfigWidgets KF5::KCMUtils ) install(TARGETS kcm_gemini DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(FILES kcm_gemini.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: cmake_minimum_required(VERSION 3.16) project(kcm_gemini) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) find_package(Qt5 REQUIRED COMPONENTS Core Widgets) find_package(KF5 REQUIRED COMPONENTS I18n ConfigWidgets KCMUtils) add_library(kcm_gemini MODULE kcm_gemini.cpp) target_link_libraries(kcm_gemini Qt5::Core Qt5::Widgets KF5::ConfigWidgets KF5::KCMUtils ) install(TARGETS kcm_gemini DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(FILES kcm_gemini.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) CODE_BLOCK: cmake_minimum_required(VERSION 3.16) project(kcm_gemini) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) find_package(Qt5 REQUIRED COMPONENTS Core Widgets) find_package(KF5 REQUIRED COMPONENTS I18n ConfigWidgets KCMUtils) add_library(kcm_gemini MODULE kcm_gemini.cpp) target_link_libraries(kcm_gemini Qt5::Core Qt5::Widgets KF5::ConfigWidgets KF5::KCMUtils ) install(TARGETS kcm_gemini DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(FILES kcm_gemini.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) CODE_BLOCK: #include <KPluginFactory> #include <KAboutData> #include <QVBoxLayout> #include <QLineEdit> #include <QLabel> #include <QPushButton> #include <QComboBox> #include <KConfigGroup> #include <KSharedConfig> class GeminiKCM : public KQuickAddons::ConfigModule { Q_OBJECT public: explicit GeminiKCM(QWidget *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args) { KAboutData *about = new KAboutData( "kcm_gemini", i18n("Gemini AI Settings"), "1.0", i18n("Configure Gemini AI integration"), KAboutLicense::GPL ); setAboutData(about); setupUI(); load(); } private slots: void save() override { KSharedConfigPtr config = KSharedConfig::openConfig("geminirc"); KConfigGroup group(config, "General"); group.writeEntry("ApiKey", apiKeyEdit->text()); group.writeEntry("Model", modelCombo->currentText()); group.sync(); // Restart service to apply changes QProcess::execute("systemctl", QStringList() << "--user" << "restart" << "gemini.service"); } void load() override { KSharedConfigPtr config = KSharedConfig::openConfig("geminirc"); KConfigGroup group(config, "General"); apiKeyEdit->setText(group.readEntry("ApiKey", "")); modelCombo->setCurrentText(group.readEntry("Model", "gemini-pro")); } private: void setupUI() { QVBoxLayout *layout = new QVBoxLayout(this); // API Key layout->addWidget(new QLabel(i18n("API Key:"))); apiKeyEdit = new QLineEdit(this); apiKeyEdit->setEchoMode(QLineEdit::Password); layout->addWidget(apiKeyEdit); // Model selection layout->addWidget(new QLabel(i18n("Model:"))); modelCombo = new QComboBox(this); modelCombo->addItems({"gemini-pro", "gemini-pro-vision", "gemini-ultra"}); layout->addWidget(modelCombo); // Test connection button QPushButton *testBtn = new QPushButton(i18n("Test Connection"), this); connect(testBtn, &QPushButton::clicked, this, &GeminiKCM::testConnection); layout->addWidget(testBtn); layout->addStretch(); } void testConnection() { // Test API connection QProcess process; process.start("gemini", QStringList() << "test"); process.waitForFinished(); QString result = process.readAllStandardOutput(); // Show result dialog } QLineEdit *apiKeyEdit; QComboBox *modelCombo; }; K_PLUGIN_FACTORY(GeminiKCMFactory, registerPlugin<GeminiKCM>();) #include "kcm_gemini.moc" Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: #include <KPluginFactory> #include <KAboutData> #include <QVBoxLayout> #include <QLineEdit> #include <QLabel> #include <QPushButton> #include <QComboBox> #include <KConfigGroup> #include <KSharedConfig> class GeminiKCM : public KQuickAddons::ConfigModule { Q_OBJECT public: explicit GeminiKCM(QWidget *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args) { KAboutData *about = new KAboutData( "kcm_gemini", i18n("Gemini AI Settings"), "1.0", i18n("Configure Gemini AI integration"), KAboutLicense::GPL ); setAboutData(about); setupUI(); load(); } private slots: void save() override { KSharedConfigPtr config = KSharedConfig::openConfig("geminirc"); KConfigGroup group(config, "General"); group.writeEntry("ApiKey", apiKeyEdit->text()); group.writeEntry("Model", modelCombo->currentText()); group.sync(); // Restart service to apply changes QProcess::execute("systemctl", QStringList() << "--user" << "restart" << "gemini.service"); } void load() override { KSharedConfigPtr config = KSharedConfig::openConfig("geminirc"); KConfigGroup group(config, "General"); apiKeyEdit->setText(group.readEntry("ApiKey", "")); modelCombo->setCurrentText(group.readEntry("Model", "gemini-pro")); } private: void setupUI() { QVBoxLayout *layout = new QVBoxLayout(this); // API Key layout->addWidget(new QLabel(i18n("API Key:"))); apiKeyEdit = new QLineEdit(this); apiKeyEdit->setEchoMode(QLineEdit::Password); layout->addWidget(apiKeyEdit); // Model selection layout->addWidget(new QLabel(i18n("Model:"))); modelCombo = new QComboBox(this); modelCombo->addItems({"gemini-pro", "gemini-pro-vision", "gemini-ultra"}); layout->addWidget(modelCombo); // Test connection button QPushButton *testBtn = new QPushButton(i18n("Test Connection"), this); connect(testBtn, &QPushButton::clicked, this, &GeminiKCM::testConnection); layout->addWidget(testBtn); layout->addStretch(); } void testConnection() { // Test API connection QProcess process; process.start("gemini", QStringList() << "test"); process.waitForFinished(); QString result = process.readAllStandardOutput(); // Show result dialog } QLineEdit *apiKeyEdit; QComboBox *modelCombo; }; K_PLUGIN_FACTORY(GeminiKCMFactory, registerPlugin<GeminiKCM>();) #include "kcm_gemini.moc" CODE_BLOCK: #include <KPluginFactory> #include <KAboutData> #include <QVBoxLayout> #include <QLineEdit> #include <QLabel> #include <QPushButton> #include <QComboBox> #include <KConfigGroup> #include <KSharedConfig> class GeminiKCM : public KQuickAddons::ConfigModule { Q_OBJECT public: explicit GeminiKCM(QWidget *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args) { KAboutData *about = new KAboutData( "kcm_gemini", i18n("Gemini AI Settings"), "1.0", i18n("Configure Gemini AI integration"), KAboutLicense::GPL ); setAboutData(about); setupUI(); load(); } private slots: void save() override { KSharedConfigPtr config = KSharedConfig::openConfig("geminirc"); KConfigGroup group(config, "General"); group.writeEntry("ApiKey", apiKeyEdit->text()); group.writeEntry("Model", modelCombo->currentText()); group.sync(); // Restart service to apply changes QProcess::execute("systemctl", QStringList() << "--user" << "restart" << "gemini.service"); } void load() override { KSharedConfigPtr config = KSharedConfig::openConfig("geminirc"); KConfigGroup group(config, "General"); apiKeyEdit->setText(group.readEntry("ApiKey", "")); modelCombo->setCurrentText(group.readEntry("Model", "gemini-pro")); } private: void setupUI() { QVBoxLayout *layout = new QVBoxLayout(this); // API Key layout->addWidget(new QLabel(i18n("API Key:"))); apiKeyEdit = new QLineEdit(this); apiKeyEdit->setEchoMode(QLineEdit::Password); layout->addWidget(apiKeyEdit); // Model selection layout->addWidget(new QLabel(i18n("Model:"))); modelCombo = new QComboBox(this); modelCombo->addItems({"gemini-pro", "gemini-pro-vision", "gemini-ultra"}); layout->addWidget(modelCombo); // Test connection button QPushButton *testBtn = new QPushButton(i18n("Test Connection"), this); connect(testBtn, &QPushButton::clicked, this, &GeminiKCM::testConnection); layout->addWidget(testBtn); layout->addStretch(); } void testConnection() { // Test API connection QProcess process; process.start("gemini", QStringList() << "test"); process.waitForFinished(); QString result = process.readAllStandardOutput(); // Show result dialog } QLineEdit *apiKeyEdit; QComboBox *modelCombo; }; K_PLUGIN_FACTORY(GeminiKCMFactory, registerPlugin<GeminiKCM>();) #include "kcm_gemini.moc" CODE_BLOCK: gemini-panel-plugin/ ├── panel-plugin/ │ ├── gemini-plugin.c │ ├── gemini-plugin.h │ └── gemini.desktop.in ├── configure.ac └── Makefile.am Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: gemini-panel-plugin/ ├── panel-plugin/ │ ├── gemini-plugin.c │ ├── gemini-plugin.h │ └── gemini.desktop.in ├── configure.ac └── Makefile.am CODE_BLOCK: gemini-panel-plugin/ ├── panel-plugin/ │ ├── gemini-plugin.c │ ├── gemini-plugin.h │ └── gemini.desktop.in ├── configure.ac └── Makefile.am CODE_BLOCK: #include <gtk/gtk.h> #include <libxfce4panel/libxfce4panel.h> typedef struct { XfcePanelPlugin *plugin; GtkWidget *button; GtkWidget *popup; GtkWidget *entry; GtkWidget *response_view; } GeminiPlugin; static void gemini_plugin_construct(XfcePanelPlugin *plugin); XFCE_PANEL_PLUGIN_REGISTER(gemini_plugin_construct); static void on_submit_clicked(GtkButton *button, GeminiPlugin *gemini) { const gchar *prompt = gtk_entry_get_text(GTK_ENTRY(gemini->entry)); // Execute Gemini CLI gchar *command = g_strdup_printf("gemini query '%s'", prompt); gchar *output = NULL; g_spawn_command_line_sync(command, &output, NULL, NULL, NULL); // Display response GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gemini->response_view)); gtk_text_buffer_set_text(buffer, output ? output : "No response", -1); g_free(command); g_free(output); } static void create_popup(GeminiPlugin *gemini) { gemini->popup = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(gemini->popup), 400, 300); gtk_window_set_title(GTK_WINDOW(gemini->popup), "Gemini AI"); GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); gtk_container_add(GTK_CONTAINER(gemini->popup), vbox); // Input entry gemini->entry = gtk_entry_new(); gtk_entry_set_placeholder_text(GTK_ENTRY(gemini->entry), "Ask Gemini..."); gtk_box_pack_start(GTK_BOX(vbox), gemini->entry, FALSE, FALSE, 0); // Submit button GtkWidget *submit = gtk_button_new_with_label("Submit"); g_signal_connect(submit, "clicked", G_CALLBACK(on_submit_clicked), gemini); gtk_box_pack_start(GTK_BOX(vbox), submit, FALSE, FALSE, 0); // Response view GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); gemini->response_view = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(gemini->response_view), FALSE); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gemini->response_view), GTK_WRAP_WORD); gtk_container_add(GTK_CONTAINER(scroll), gemini->response_view); gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0); } static void on_button_clicked(GtkWidget *button, GeminiPlugin *gemini) { if (!gemini->popup) { create_popup(gemini); } gtk_widget_show_all(gemini->popup); } static void gemini_plugin_construct(XfcePanelPlugin *plugin) { GeminiPlugin *gemini = g_new0(GeminiPlugin, 1); gemini->plugin = plugin; // Create button with icon gemini->button = gtk_button_new(); GtkWidget *icon = gtk_image_new_from_icon_name("ai-assistant", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(gemini->button), icon); g_signal_connect(gemini->button, "clicked", G_CALLBACK(on_button_clicked), gemini); gtk_container_add(GTK_CONTAINER(plugin), gemini->button); xfce_panel_plugin_add_action_widget(plugin, gemini->button); gtk_widget_show_all(GTK_WIDGET(plugin)); } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: #include <gtk/gtk.h> #include <libxfce4panel/libxfce4panel.h> typedef struct { XfcePanelPlugin *plugin; GtkWidget *button; GtkWidget *popup; GtkWidget *entry; GtkWidget *response_view; } GeminiPlugin; static void gemini_plugin_construct(XfcePanelPlugin *plugin); XFCE_PANEL_PLUGIN_REGISTER(gemini_plugin_construct); static void on_submit_clicked(GtkButton *button, GeminiPlugin *gemini) { const gchar *prompt = gtk_entry_get_text(GTK_ENTRY(gemini->entry)); // Execute Gemini CLI gchar *command = g_strdup_printf("gemini query '%s'", prompt); gchar *output = NULL; g_spawn_command_line_sync(command, &output, NULL, NULL, NULL); // Display response GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gemini->response_view)); gtk_text_buffer_set_text(buffer, output ? output : "No response", -1); g_free(command); g_free(output); } static void create_popup(GeminiPlugin *gemini) { gemini->popup = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(gemini->popup), 400, 300); gtk_window_set_title(GTK_WINDOW(gemini->popup), "Gemini AI"); GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); gtk_container_add(GTK_CONTAINER(gemini->popup), vbox); // Input entry gemini->entry = gtk_entry_new(); gtk_entry_set_placeholder_text(GTK_ENTRY(gemini->entry), "Ask Gemini..."); gtk_box_pack_start(GTK_BOX(vbox), gemini->entry, FALSE, FALSE, 0); // Submit button GtkWidget *submit = gtk_button_new_with_label("Submit"); g_signal_connect(submit, "clicked", G_CALLBACK(on_submit_clicked), gemini); gtk_box_pack_start(GTK_BOX(vbox), submit, FALSE, FALSE, 0); // Response view GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); gemini->response_view = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(gemini->response_view), FALSE); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gemini->response_view), GTK_WRAP_WORD); gtk_container_add(GTK_CONTAINER(scroll), gemini->response_view); gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0); } static void on_button_clicked(GtkWidget *button, GeminiPlugin *gemini) { if (!gemini->popup) { create_popup(gemini); } gtk_widget_show_all(gemini->popup); } static void gemini_plugin_construct(XfcePanelPlugin *plugin) { GeminiPlugin *gemini = g_new0(GeminiPlugin, 1); gemini->plugin = plugin; // Create button with icon gemini->button = gtk_button_new(); GtkWidget *icon = gtk_image_new_from_icon_name("ai-assistant", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(gemini->button), icon); g_signal_connect(gemini->button, "clicked", G_CALLBACK(on_button_clicked), gemini); gtk_container_add(GTK_CONTAINER(plugin), gemini->button); xfce_panel_plugin_add_action_widget(plugin, gemini->button); gtk_widget_show_all(GTK_WIDGET(plugin)); } CODE_BLOCK: #include <gtk/gtk.h> #include <libxfce4panel/libxfce4panel.h> typedef struct { XfcePanelPlugin *plugin; GtkWidget *button; GtkWidget *popup; GtkWidget *entry; GtkWidget *response_view; } GeminiPlugin; static void gemini_plugin_construct(XfcePanelPlugin *plugin); XFCE_PANEL_PLUGIN_REGISTER(gemini_plugin_construct); static void on_submit_clicked(GtkButton *button, GeminiPlugin *gemini) { const gchar *prompt = gtk_entry_get_text(GTK_ENTRY(gemini->entry)); // Execute Gemini CLI gchar *command = g_strdup_printf("gemini query '%s'", prompt); gchar *output = NULL; g_spawn_command_line_sync(command, &output, NULL, NULL, NULL); // Display response GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gemini->response_view)); gtk_text_buffer_set_text(buffer, output ? output : "No response", -1); g_free(command); g_free(output); } static void create_popup(GeminiPlugin *gemini) { gemini->popup = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(gemini->popup), 400, 300); gtk_window_set_title(GTK_WINDOW(gemini->popup), "Gemini AI"); GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); gtk_container_add(GTK_CONTAINER(gemini->popup), vbox); // Input entry gemini->entry = gtk_entry_new(); gtk_entry_set_placeholder_text(GTK_ENTRY(gemini->entry), "Ask Gemini..."); gtk_box_pack_start(GTK_BOX(vbox), gemini->entry, FALSE, FALSE, 0); // Submit button GtkWidget *submit = gtk_button_new_with_label("Submit"); g_signal_connect(submit, "clicked", G_CALLBACK(on_submit_clicked), gemini); gtk_box_pack_start(GTK_BOX(vbox), submit, FALSE, FALSE, 0); // Response view GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); gemini->response_view = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(gemini->response_view), FALSE); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gemini->response_view), GTK_WRAP_WORD); gtk_container_add(GTK_CONTAINER(scroll), gemini->response_view); gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0); } static void on_button_clicked(GtkWidget *button, GeminiPlugin *gemini) { if (!gemini->popup) { create_popup(gemini); } gtk_widget_show_all(gemini->popup); } static void gemini_plugin_construct(XfcePanelPlugin *plugin) { GeminiPlugin *gemini = g_new0(GeminiPlugin, 1); gemini->plugin = plugin; // Create button with icon gemini->button = gtk_button_new(); GtkWidget *icon = gtk_image_new_from_icon_name("ai-assistant", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(gemini->button), icon); g_signal_connect(gemini->button, "clicked", G_CALLBACK(on_button_clicked), gemini); gtk_container_add(GTK_CONTAINER(plugin), gemini->button); xfce_panel_plugin_add_action_widget(plugin, gemini->button); gtk_widget_show_all(GTK_WIDGET(plugin)); } CODE_BLOCK: ./autogen.sh make sudo make install Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: ./autogen.sh make sudo make install CODE_BLOCK: ./autogen.sh make sudo make install CODE_BLOCK: [D-BUS Service] Name=com.gemini.AI Exec=/usr/local/bin/gemini-dbus-service User=root SystemdService=gemini.service Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: [D-BUS Service] Name=com.gemini.AI Exec=/usr/local/bin/gemini-dbus-service User=root SystemdService=gemini.service CODE_BLOCK: [D-BUS Service] Name=com.gemini.AI Exec=/usr/local/bin/gemini-dbus-service User=root SystemdService=gemini.service CODE_BLOCK: #!/usr/bin/env python3 """ Gemini DBus Service Provides system-wide access to Gemini AI functionality """ import dbus import dbus.service from dbus.mainloop.glib import DBusGMainLoop from gi.repository import GLib import subprocess import json BUS_NAME = 'com.gemini.AI' OBJECT_PATH = '/com/gemini/AI' class GeminiDBusService(dbus.service.Object): def __init__(self): bus_name = dbus.service.BusName(BUS_NAME, bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, OBJECT_PATH) @dbus.service.method(BUS_NAME, in_signature='s', out_signature='s') def Query(self, prompt): """Send a query to Gemini and return the response""" try: result = subprocess.run( ['gemini', 'query', prompt], capture_output=True, text=True, timeout=30 ) return result.stdout or result.stderr except Exception as e: return f"Error: {str(e)}" @dbus.service.method(BUS_NAME, out_signature='s') def GetStatus(self): """Get Gemini service status""" try: result = subprocess.run( ['systemctl', '--user', 'is-active', 'gemini.service'], capture_output=True, text=True ) return "active" if result.returncode == 0 else "inactive" except: return "unknown" @dbus.service.method(BUS_NAME, out_signature='b') def RestartService(self): """Restart the Gemini service""" try: subprocess.run( ['systemctl', '--user', 'restart', 'gemini.service'], check=True ) return True except: return False @dbus.service.signal(BUS_NAME, signature='s') def ResponseReceived(self, response): """Signal emitted when a response is received""" pass if __name__ == '__main__': DBusGMainLoop(set_as_default=True) service = GeminiDBusService() loop = GLib.MainLoop() print("Gemini DBus service started") loop.run() Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: #!/usr/bin/env python3 """ Gemini DBus Service Provides system-wide access to Gemini AI functionality """ import dbus import dbus.service from dbus.mainloop.glib import DBusGMainLoop from gi.repository import GLib import subprocess import json BUS_NAME = 'com.gemini.AI' OBJECT_PATH = '/com/gemini/AI' class GeminiDBusService(dbus.service.Object): def __init__(self): bus_name = dbus.service.BusName(BUS_NAME, bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, OBJECT_PATH) @dbus.service.method(BUS_NAME, in_signature='s', out_signature='s') def Query(self, prompt): """Send a query to Gemini and return the response""" try: result = subprocess.run( ['gemini', 'query', prompt], capture_output=True, text=True, timeout=30 ) return result.stdout or result.stderr except Exception as e: return f"Error: {str(e)}" @dbus.service.method(BUS_NAME, out_signature='s') def GetStatus(self): """Get Gemini service status""" try: result = subprocess.run( ['systemctl', '--user', 'is-active', 'gemini.service'], capture_output=True, text=True ) return "active" if result.returncode == 0 else "inactive" except: return "unknown" @dbus.service.method(BUS_NAME, out_signature='b') def RestartService(self): """Restart the Gemini service""" try: subprocess.run( ['systemctl', '--user', 'restart', 'gemini.service'], check=True ) return True except: return False @dbus.service.signal(BUS_NAME, signature='s') def ResponseReceived(self, response): """Signal emitted when a response is received""" pass if __name__ == '__main__': DBusGMainLoop(set_as_default=True) service = GeminiDBusService() loop = GLib.MainLoop() print("Gemini DBus service started") loop.run() CODE_BLOCK: #!/usr/bin/env python3 """ Gemini DBus Service Provides system-wide access to Gemini AI functionality """ import dbus import dbus.service from dbus.mainloop.glib import DBusGMainLoop from gi.repository import GLib import subprocess import json BUS_NAME = 'com.gemini.AI' OBJECT_PATH = '/com/gemini/AI' class GeminiDBusService(dbus.service.Object): def __init__(self): bus_name = dbus.service.BusName(BUS_NAME, bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, OBJECT_PATH) @dbus.service.method(BUS_NAME, in_signature='s', out_signature='s') def Query(self, prompt): """Send a query to Gemini and return the response""" try: result = subprocess.run( ['gemini', 'query', prompt], capture_output=True, text=True, timeout=30 ) return result.stdout or result.stderr except Exception as e: return f"Error: {str(e)}" @dbus.service.method(BUS_NAME, out_signature='s') def GetStatus(self): """Get Gemini service status""" try: result = subprocess.run( ['systemctl', '--user', 'is-active', 'gemini.service'], capture_output=True, text=True ) return "active" if result.returncode == 0 else "inactive" except: return "unknown" @dbus.service.method(BUS_NAME, out_signature='b') def RestartService(self): """Restart the Gemini service""" try: subprocess.run( ['systemctl', '--user', 'restart', 'gemini.service'], check=True ) return True except: return False @dbus.service.signal(BUS_NAME, signature='s') def ResponseReceived(self, response): """Signal emitted when a response is received""" pass if __name__ == '__main__': DBusGMainLoop(set_as_default=True) service = GeminiDBusService() loop = GLib.MainLoop() print("Gemini DBus service started") loop.run() COMMAND_BLOCK: sudo chmod +x /usr/local/bin/gemini-dbus-service systemctl --user enable gemini-dbus.service systemctl --user start gemini-dbus.service Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: sudo chmod +x /usr/local/bin/gemini-dbus-service systemctl --user enable gemini-dbus.service systemctl --user start gemini-dbus.service COMMAND_BLOCK: sudo chmod +x /usr/local/bin/gemini-dbus-service systemctl --user enable gemini-dbus.service systemctl --user start gemini-dbus.service CODE_BLOCK: [greeter] background=/usr/share/backgrounds/gemini-tip-bg.jpg theme-name=gemini-theme indicators=~host;~spacer;~clock;~spacer;~session;~a11y;~power Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: [greeter] background=/usr/share/backgrounds/gemini-tip-bg.jpg theme-name=gemini-theme indicators=~host;~spacer;~clock;~spacer;~session;~a11y;~power CODE_BLOCK: [greeter] background=/usr/share/backgrounds/gemini-tip-bg.jpg theme-name=gemini-theme indicators=~host;~spacer;~clock;~spacer;~session;~a11y;~power COMMAND_BLOCK: #!/bin/bash # /usr/local/bin/gemini-login-tip TIP_FILE="/var/cache/gemini/login-tip.txt" mkdir -p /var/cache/gemini # Generate new tip daily if [ ! -f "$TIP_FILE" ] || [ $(find "$TIP_FILE" -mtime +1) ]; then gemini query "Give me a helpful Linux productivity tip" > "$TIP_FILE" fi # Display on greeter cat "$TIP_FILE" Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: #!/bin/bash # /usr/local/bin/gemini-login-tip TIP_FILE="/var/cache/gemini/login-tip.txt" mkdir -p /var/cache/gemini # Generate new tip daily if [ ! -f "$TIP_FILE" ] || [ $(find "$TIP_FILE" -mtime +1) ]; then gemini query "Give me a helpful Linux productivity tip" > "$TIP_FILE" fi # Display on greeter cat "$TIP_FILE" COMMAND_BLOCK: #!/bin/bash # /usr/local/bin/gemini-login-tip TIP_FILE="/var/cache/gemini/login-tip.txt" mkdir -p /var/cache/gemini # Generate new tip daily if [ ! -f "$TIP_FILE" ] || [ $(find "$TIP_FILE" -mtime +1) ]; then gemini query "Give me a helpful Linux productivity tip" > "$TIP_FILE" fi # Display on greeter cat "$TIP_FILE" COMMAND_BLOCK: #!/usr/bin/env python3 """ Gemini Configuration GUI Editor Simple interface for editing ~/.config/gemini/config """ import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk import os class GeminiConfigEditor(Gtk.Window): def __init__(self): super().__init__(title="Gemini Configuration") self.set_border_width(10) self.set_default_size(500, 400) self.config_path = os.path.expanduser("~/.config/gemini/config") self.config = self.load_config() # Layout vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.add(vbox) # API Key hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="API Key:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.api_key_entry = Gtk.Entry() self.api_key_entry.set_visibility(False) self.api_key_entry.set_text(self.config.get('API_KEY', '')) hbox.pack_start(self.api_key_entry, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Model hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="Model:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.model_combo = Gtk.ComboBoxText() models = ["gemini-pro", "gemini-pro-vision", "gemini-ultra"] for model in models: self.model_combo.append_text(model) self.model_combo.set_active(models.index(self.config.get('MODEL', 'gemini-pro'))) hbox.pack_start(self.model_combo, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Temperature hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="Temperature:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.temp_scale = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 0, 1, 0.1) self.temp_scale.set_value(float(self.config.get('TEMPERATURE', '0.7'))) self.temp_scale.set_digits(1) hbox.pack_start(self.temp_scale, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Save button save_btn = Gtk.Button(label="Save Configuration") save_btn.connect("clicked", self.on_save) vbox.pack_end(save_btn, False, False, 0) def load_config(self): config = {} if os.path.exists(self.config_path): with open(self.config_path, 'r') as f: for line in f: if '=' in line and not line.startswith('#'): key, value = line.strip().split('=', 1) config[key] = value return config def on_save(self, button): with open(self.config_path, 'w') as f: f.write(f"# Gemini Configuration\n") f.write(f"API_KEY={self.api_key_entry.get_text()}\n") f.write(f"MODEL={self.model_combo.get_active_text()}\n") f.write(f"TEMPERATURE={self.temp_scale.get_value()}\n") f.write(f"MAX_TOKENS=2048\n") # Set proper permissions os.chmod(self.config_path, 0o600) dialog = Gtk.MessageDialog( transient_for=self, flags=0, message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, text="Configuration Saved" ) dialog.format_secondary_text("Restart Gemini service to apply changes") dialog.run() dialog.destroy() if __name__ == "__main__": win = GeminiConfigEditor() win.connect("destroy", Gtk.main_quit) win.show_all() Gtk.main() Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: #!/usr/bin/env python3 """ Gemini Configuration GUI Editor Simple interface for editing ~/.config/gemini/config """ import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk import os class GeminiConfigEditor(Gtk.Window): def __init__(self): super().__init__(title="Gemini Configuration") self.set_border_width(10) self.set_default_size(500, 400) self.config_path = os.path.expanduser("~/.config/gemini/config") self.config = self.load_config() # Layout vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.add(vbox) # API Key hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="API Key:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.api_key_entry = Gtk.Entry() self.api_key_entry.set_visibility(False) self.api_key_entry.set_text(self.config.get('API_KEY', '')) hbox.pack_start(self.api_key_entry, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Model hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="Model:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.model_combo = Gtk.ComboBoxText() models = ["gemini-pro", "gemini-pro-vision", "gemini-ultra"] for model in models: self.model_combo.append_text(model) self.model_combo.set_active(models.index(self.config.get('MODEL', 'gemini-pro'))) hbox.pack_start(self.model_combo, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Temperature hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="Temperature:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.temp_scale = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 0, 1, 0.1) self.temp_scale.set_value(float(self.config.get('TEMPERATURE', '0.7'))) self.temp_scale.set_digits(1) hbox.pack_start(self.temp_scale, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Save button save_btn = Gtk.Button(label="Save Configuration") save_btn.connect("clicked", self.on_save) vbox.pack_end(save_btn, False, False, 0) def load_config(self): config = {} if os.path.exists(self.config_path): with open(self.config_path, 'r') as f: for line in f: if '=' in line and not line.startswith('#'): key, value = line.strip().split('=', 1) config[key] = value return config def on_save(self, button): with open(self.config_path, 'w') as f: f.write(f"# Gemini Configuration\n") f.write(f"API_KEY={self.api_key_entry.get_text()}\n") f.write(f"MODEL={self.model_combo.get_active_text()}\n") f.write(f"TEMPERATURE={self.temp_scale.get_value()}\n") f.write(f"MAX_TOKENS=2048\n") # Set proper permissions os.chmod(self.config_path, 0o600) dialog = Gtk.MessageDialog( transient_for=self, flags=0, message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, text="Configuration Saved" ) dialog.format_secondary_text("Restart Gemini service to apply changes") dialog.run() dialog.destroy() if __name__ == "__main__": win = GeminiConfigEditor() win.connect("destroy", Gtk.main_quit) win.show_all() Gtk.main() COMMAND_BLOCK: #!/usr/bin/env python3 """ Gemini Configuration GUI Editor Simple interface for editing ~/.config/gemini/config """ import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk import os class GeminiConfigEditor(Gtk.Window): def __init__(self): super().__init__(title="Gemini Configuration") self.set_border_width(10) self.set_default_size(500, 400) self.config_path = os.path.expanduser("~/.config/gemini/config") self.config = self.load_config() # Layout vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.add(vbox) # API Key hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="API Key:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.api_key_entry = Gtk.Entry() self.api_key_entry.set_visibility(False) self.api_key_entry.set_text(self.config.get('API_KEY', '')) hbox.pack_start(self.api_key_entry, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Model hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="Model:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.model_combo = Gtk.ComboBoxText() models = ["gemini-pro", "gemini-pro-vision", "gemini-ultra"] for model in models: self.model_combo.append_text(model) self.model_combo.set_active(models.index(self.config.get('MODEL', 'gemini-pro'))) hbox.pack_start(self.model_combo, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Temperature hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) label = Gtk.Label(label="Temperature:", xalign=0) label.set_size_request(120, -1) hbox.pack_start(label, False, False, 0) self.temp_scale = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 0, 1, 0.1) self.temp_scale.set_value(float(self.config.get('TEMPERATURE', '0.7'))) self.temp_scale.set_digits(1) hbox.pack_start(self.temp_scale, True, True, 0) vbox.pack_start(hbox, False, False, 0) # Save button save_btn = Gtk.Button(label="Save Configuration") save_btn.connect("clicked", self.on_save) vbox.pack_end(save_btn, False, False, 0) def load_config(self): config = {} if os.path.exists(self.config_path): with open(self.config_path, 'r') as f: for line in f: if '=' in line and not line.startswith('#'): key, value = line.strip().split('=', 1) config[key] = value return config def on_save(self, button): with open(self.config_path, 'w') as f: f.write(f"# Gemini Configuration\n") f.write(f"API_KEY={self.api_key_entry.get_text()}\n") f.write(f"MODEL={self.model_combo.get_active_text()}\n") f.write(f"TEMPERATURE={self.temp_scale.get_value()}\n") f.write(f"MAX_TOKENS=2048\n") # Set proper permissions os.chmod(self.config_path, 0o600) dialog = Gtk.MessageDialog( transient_for=self, flags=0, message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, text="Configuration Saved" ) dialog.format_secondary_text("Restart Gemini service to apply changes") dialog.run() dialog.destroy() if __name__ == "__main__": win = GeminiConfigEditor() win.connect("destroy", Gtk.main_quit) win.show_all() Gtk.main() COMMAND_BLOCK: # Check service status systemctl --user status gemini.service # View logs journalctl --user -u gemini.service -f # Verify config cat ~/.config/gemini/config Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Check service status systemctl --user status gemini.service # View logs journalctl --user -u gemini.service -f # Verify config cat ~/.config/gemini/config COMMAND_BLOCK: # Check service status systemctl --user status gemini.service # View logs journalctl --user -u gemini.service -f # Verify config cat ~/.config/gemini/config COMMAND_BLOCK: # Test API key manually gemini query "test" # Re-run setup ./gemini-setup.sh Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Test API key manually gemini query "test" # Re-run setup ./gemini-setup.sh COMMAND_BLOCK: # Test API key manually gemini query "test" # Re-run setup ./gemini-setup.sh COMMAND_BLOCK: # Restart Plasma kquitapp5 plasmashell && kstart5 plasmashell # Check widget installation ls ~/.local/share/plasma/plasmoids/ Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Restart Plasma kquitapp5 plasmashell && kstart5 plasmashell # Check widget installation ls ~/.local/share/plasma/plasmoids/ COMMAND_BLOCK: # Restart Plasma kquitapp5 plasmashell && kstart5 plasmashell # Check widget installation ls ~/.local/share/plasma/plasmoids/ COMMAND_BLOCK: # Install live-build sudo apt-get install live-build # Create build directory mkdir gemini-debian-build cd gemini-debian-build # Initialize live-build configuration lb config \ --distribution bookworm \ --architectures amd64 \ --archive-areas "main contrib non-free" \ --debian-installer live # Add Gemini integration scripts to config/includes.chroot/ mkdir -p config/includes.chroot/usr/local/bin mkdir -p config/includes.chroot/etc/systemd/system mkdir -p config/includes.chroot/etc/skel/.config/gemini # Copy your Gemini setup scripts and service files cp gemini-setup.sh config/includes.chroot/usr/local/bin/ cp gemini.service config/includes.chroot/etc/systemd/system/ # Add packages to config/package-lists/gemini.list.chroot echo "nodejs npm python3 python3-dbus" > config/package-lists/gemini.list.chroot # Build the ISO sudo lb build # The resulting ISO will be in the current directory # gemini-debian-amd64.hybrid.iso Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Install live-build sudo apt-get install live-build # Create build directory mkdir gemini-debian-build cd gemini-debian-build # Initialize live-build configuration lb config \ --distribution bookworm \ --architectures amd64 \ --archive-areas "main contrib non-free" \ --debian-installer live # Add Gemini integration scripts to config/includes.chroot/ mkdir -p config/includes.chroot/usr/local/bin mkdir -p config/includes.chroot/etc/systemd/system mkdir -p config/includes.chroot/etc/skel/.config/gemini # Copy your Gemini setup scripts and service files cp gemini-setup.sh config/includes.chroot/usr/local/bin/ cp gemini.service config/includes.chroot/etc/systemd/system/ # Add packages to config/package-lists/gemini.list.chroot echo "nodejs npm python3 python3-dbus" > config/package-lists/gemini.list.chroot # Build the ISO sudo lb build # The resulting ISO will be in the current directory # gemini-debian-amd64.hybrid.iso COMMAND_BLOCK: # Install live-build sudo apt-get install live-build # Create build directory mkdir gemini-debian-build cd gemini-debian-build # Initialize live-build configuration lb config \ --distribution bookworm \ --architectures amd64 \ --archive-areas "main contrib non-free" \ --debian-installer live # Add Gemini integration scripts to config/includes.chroot/ mkdir -p config/includes.chroot/usr/local/bin mkdir -p config/includes.chroot/etc/systemd/system mkdir -p config/includes.chroot/etc/skel/.config/gemini # Copy your Gemini setup scripts and service files cp gemini-setup.sh config/includes.chroot/usr/local/bin/ cp gemini.service config/includes.chroot/etc/systemd/system/ # Add packages to config/package-lists/gemini.list.chroot echo "nodejs npm python3 python3-dbus" > config/package-lists/gemini.list.chroot # Build the ISO sudo lb build # The resulting ISO will be in the current directory # gemini-debian-amd64.hybrid.iso - The original source code from auth.ts and related files from the Gemini CLI repository - Specific instructions on what modifications to make (simplify to API key-only authentication) - Requirements for systemd service integration - Desktop environment integration needs (KDE Plasma, XFCE) - ✅ You can use, modify, and distribute the code - ✅ You can use it for commercial purposes - ✅ You must include the original license and copyright notice - ✅ You must state significant changes made to the code - ✅ Patent protection is included - Eliminates complex OAuth flows during system startup - Works seamlessly with systemd services - Provides simple configuration for users - Maintains security through proper file permissions - Single Authentication Mode: Only AuthType.USE_GEMINI (API key) is supported - Clear Error Messages: If someone tries to use LOGIN_WITH_GOOGLE, COMPUTE_ADC, or USE_VERTEX_AI, they get a detailed error message explaining: What they tried to use What is supported Why other methods aren't available How to set up API key authentication That this is a minimal setup for Debian/Ubuntu integration - What they tried to use - What is supported - Why other methods aren't available - How to set up API key authentication - That this is a minimal setup for Debian/Ubuntu integration - Config File Location: Reads from ~/.config/gemini/config instead of environment variables - Validation: Checks that the API key exists and has a reasonable length - What they tried to use - What is supported - Why other methods aren't available - How to set up API key authentication - That this is a minimal setup for Debian/Ubuntu integration - Config File Permissions: Always ensure ~/.config/gemini/config has 600 permissions - API Key Storage: Never commit API keys to version control - Service Isolation: Run services with minimal privileges using systemd security features - Network Security: Consider using HTTPS proxies for API communication - Audit Logging: Log all API requests for security auditing - Context-Aware Assistance: Gemini can analyze open windows and offer relevant suggestions - System Command Integration: Execute system commands through natural language - File Management: AI-powered file organization and search - Code Assistance: Real-time coding help integrated into IDEs - Automation: Create AI-driven automation workflows - Voice Integration: Voice command interface using speech recognition - Gemini CLI GitHub Repository - Apache License 2.0 - KDE Plasma Widget Development - XFCE Panel Plugin Documentation - DBus Specification - systemd Service Documentation - Debian live-build Manual - Ubuntu Live Build Documentation - Original source files from the Gemini CLI repository (specifically auth.ts) - Detailed requirements for modifications (API key-only authentication, systemd integration, KDE/XFCE desktop integration) - The overall vision from my NeuroShellOS concept - Modified authentication code - Setup scripts - Systemd service configurations - KDE Plasma widget and KCM module code - XFCE panel plugin implementation - DBus service implementation - Configuration GUI tools - Discord: hejhdiss (handle: hejhdiss_16738_37295) - Email: [email protected] - Bio: bio.link/hejhdiss