Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions entities.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"people": [
"Abhinav Gautam"
],
"projects": [
"stringcast"
],
"topics": [
"Rust",
"Python",
"Linux",
"Windows",
"Wayland",
"Gemini",
"OpenAI",
"Goals",
"Provider"
]
}
7 changes: 7 additions & 0 deletions wayland-ui-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

.venv
venv
build
dist
.env
__pycache__
21 changes: 21 additions & 0 deletions wayland-ui-app/LICENCE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) [2026] [mclovin22117]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
73 changes: 73 additions & 0 deletions wayland-ui-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Stringcast (Wayland UI Edition)

## Introduction

Stringcast is a lightweight, floating desktop utility that uses AI to instantly transform your text.

Whether you need to fix grammar, adopt a professional tone, or translate a paragraph, Stringcast acts as your persistent, "always-on-top" AI assistant right on your desktop.

This project is specifically designed as a secure, root-free solution for modern Linux desktops running Wayland.

## 🛡️ Why a UI App instead of a Keystroke Listener?

If you are using a modern Linux desktop environment (like GNOME or KDE on Wayland), you might wonder why this isn't a background script that listens to your keyboard.

### The Wayland Security Sandbox: By design, Wayland strictly isolates applications. It intentionally blocks global key-logging and synthetic keystroke injection to protect users from malicious software.

### The Root Privilege Problem: While workarounds exist (like reading raw hardware events via /dev/input), they absolutely require running scripts as root (using sudo).

### The Environment Conflict: Running desktop scripts as root is highly insecure, cumbersome for daily use, and breaks standard Python virtual environments.

### The UI Solution: This application uses a native PyQt6 interface configured to hover "always on top" of your other windows. It provides a frictionless workflow that fully respects Wayland's security sandbox—meaning no sudo is required!

## 🚀 Installation & Usage (For Users)

You do not need to install Python, run pip, or touch terminal commands to use Stringcast.

### Download the App: Go to the Releases page of this repository and download the latest standalone executable (e.g., stringcast_ui or system_enhancer).

### Setup your API Key: In the exact same folder where you downloaded the app, create a new text file named .env. Open it and add your Gemini API key like this:
GEMINI_API_KEY="your_actual_key_here"

### Make it Executable: Linux requires you to give downloaded apps permission to run. Right-click the downloaded file -> Properties -> Permissions -> check "Allow executing file as program". (Alternatively, run chmod +x filename in your terminal).

### Run Stringcast: Double-click the file! Type or paste your text into the floating window, select a transformation mode from the dropdown, and hit "Transform Text".

## 🛠️ Cloning & Tweaking (For Developers)

Want to add your own custom AI prompts (like "Rewrite as a Pirate" or "Translate to Python code")? It is incredibly easy to modify.

### Clone the repository:
git clone https://github.com/mclovin22117/stringcast-wayland.git
cd stringcast-wayland

### Set up a virtual environment:
python3 -m venv venv
source venv/bin/activate

### Install dependencies:
pip install PyQt6 google-generativeai openai python-dotenv pyinstaller

### Make your changes:
Open your main Python UI script and simply modify the dropdown list items
(e.g., self.option_dropdown.addItems([...])) to add new features.
The backend AI automatically understands natural language commands!

### Rebuild the standalone app:
pyinstaller --noconsole --onefile your_script_name.py

Your new custom app will be compiled and waiting for you inside the dist/ folder.

## 🤝 Contributing

Contributions are always welcome! If you have an idea to improve the UI, add new AI providers, or optimize the codebase:

Fork the Project

Create your Feature Branch (git checkout -b feature/AmazingFeature)

Commit your Changes (git commit -m 'Add some AmazingFeature')

Push to the Branch (git push origin feature/AmazingFeature)

Open a Pull Request
61 changes: 61 additions & 0 deletions wayland-ui-app/setup_environment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash

# ===============================================
# AI Text Enhancer Setup and Launcher
# Instructions:
# 1. Make sure you have python3 installed (sudo apt install python3)
# 2. Place this script in the same folder as 'system_enhancer.py'
# 3. Run: ./setup_environment.sh
# =================================================

# Exit immediately if any command fails
set -e

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
PYTHON_SCRIPT="${SCRIPT_DIR}/system_enhancer.py"

echo "==================================================="
echo " AI Text Enhancer Setup and Launcher"
echo "========================================================="

# --- Dependency Check ---
if ! command -v python3 &> /dev/null; then
echo "❌ ERROR: python3 command not found."
echo "Please install Python 3 first (e.g., sudo apt update && sudo apt install python3)."
exit 1
fi

# --- 1. Virtual Environment Setup ---
VENV_DIR=".venv"
if [ ! -d "$VENV_DIR" ]; then
echo "✅ Creating isolated Python virtual environment in '$VENV_DIR'..."
python3 -m venv "$VENV_DIR"
else
echo "✅ Virtual environment already exists at '$VENV_DIR'. Skipping creation."
fi

# --- 2. Dependency Installation ---
echo "Activating virtual environment..."
source "$VENV_DIR/bin/activate"

# *** FIX APPLIED HERE: Installing the missing SDK ***
echo "Installing required Python packages (including google-generativeai)..."
pip install google-generativeai
# *** FIX APPLIED HERE: Installing the missing SDKs ***
echo "Installing required Python packages..."
pip install google-generativeai openai python-dotenv
# Add any other packages your code uses (e.g., pip install requests)

# --- 3. Execution ---
echo -e "\n============================================================"
echo "Setup Complete. Running the application now..."
echo "============================================================"

# Execute the main script using the activated environment's Python interpreter
python "$PYTHON_SCRIPT"

# --- 4. Cleanup ---
echo -e "\n=================================================="
echo "Application finished."
deactivate
echo "=========================================================="
124 changes: 124 additions & 0 deletions wayland-ui-app/stringcast_ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import sys
from PyQt6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QTextEdit, QPushButton, QComboBox, QLabel)
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtGui import QGuiApplication

# Import your working AI engine
from system_enhancer import try_transform_text

class AIWorker(QThread):
"""Runs the API call in the background so the UI doesn't freeze."""
finished = pyqtSignal(str)

def __init__(self, text, function_name):
super().__init__()
self.text = text
self.function_name = function_name

def run(self):
try:
result = try_transform_text(self.text, self.function_name)
self.finished.emit(result)
except Exception as e:
self.finished.emit(f"Error: {str(e)}")

class StringcastApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()

def initUI(self):
# --- Window Settings ---
self.setWindowTitle('Stringcast - Hover Mode')
self.resize(400, 500)

# Make the window float on top of all other applications
self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)

# --- Layout & Widgets ---
layout = QVBoxLayout()

# Input Area
self.input_label = QLabel("Input Text:")
self.input_box = QTextEdit()
self.input_box.setPlaceholderText("Type or paste your text here...")

# Options
self.option_dropdown = QComboBox()
self.option_dropdown.addItems([
"Improve Grammar & Flow",
"Enhance Tone to Professional",
"Make it More Engaging",
"Translate to English",
"Translate to Hindi",
"Enoji based on this text",
"Translate to Spanish",
"Translate to French",
"Summarize concisely"
])

# Transform Button
self.transform_btn = QPushButton("✨ Transform Text")
self.transform_btn.setStyleSheet("background-color: #2b5797; color: white; font-weight: bold; padding: 10px;")
self.transform_btn.clicked.connect(self.run_transformation)

# Output Area
self.output_label = QLabel("Enhanced Output:")
self.output_box = QTextEdit()
self.output_box.setReadOnly(True)
self.output_box.setStyleSheet("background-color: #f4f4f4; color: #000000;")

# Copy Button
self.copy_btn = QPushButton("📋 Copy to Clipboard")
self.copy_btn.clicked.connect(self.copy_to_clipboard)

# Assemble Layout
layout.addWidget(self.input_label)
layout.addWidget(self.input_box)
layout.addWidget(self.option_dropdown)
layout.addWidget(self.transform_btn)
layout.addWidget(self.output_label)
layout.addWidget(self.output_box)
layout.addWidget(self.copy_btn)

self.setLayout(layout)

def run_transformation(self):
text = self.input_box.toPlainText().strip()
if not text:
return

mode = self.option_dropdown.currentText()

# Update UI state
self.transform_btn.setText("⏳ Processing...")
self.transform_btn.setEnabled(False)
self.output_box.setText("")

# Run AI in background thread
self.worker = AIWorker(text, mode)
self.worker.finished.connect(self.on_transformation_complete)
self.worker.start()

def on_transformation_complete(self, result):
# Restore UI state and show result
self.output_box.setText(result)
self.transform_btn.setText("✨ Transform Text")
self.transform_btn.setEnabled(True)

def copy_to_clipboard(self):
clipboard = QGuiApplication.clipboard()
clipboard.setText(self.output_box.toPlainText())
self.copy_btn.setText("✅ Copied!")

# Reset button text after 2 seconds
from PyQt6.QtCore import QTimer
QTimer.singleShot(2000, lambda: self.copy_btn.setText("📋 Copy to Clipboard"))

if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('Fusion') # Clean, modern default look
ex = StringcastApp()
ex.show()
sys.exit(app.exec())
Loading
Loading