Skip to content
Open
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
3 changes: 2 additions & 1 deletion .github/scripts/checkTranslation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

import sys
import os
import sys

from crowdin_api import CrowdinClient


Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/manual-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
$curDate = Get-Date -Format "yyyyMMdd"
$curYear = Get-Date -Format "yyyy"
$tagName = "v" + (Get-Date -Format "yy.MM.dd")

echo "CUR_DATE=$curDate" >> $env:GITHUB_ENV
echo "CUR_YEAR=$curYear" >> $env:GITHUB_ENV
echo "TAG_NAME=$tagName" >> $env:GITHUB_ENV
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ repos:
- id: check-hooks-apply

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
# Prevents commits to certain branches
- id: no-commit-to-branch
Expand Down Expand Up @@ -60,7 +60,7 @@ repos:
# Avoids using reserved Windows filenames.
- id: check-illegal-windows-names
- repo: https://github.com/asottile/add-trailing-comma
rev: v3.2.0
rev: v4.0.0
hooks:
# Ruff preserves indent/new-line formatting of function arguments, list items, and similar iterables,
# if a trailing comma is added.
Expand All @@ -69,7 +69,7 @@ repos:

- repo: https://github.com/astral-sh/ruff-pre-commit
# Matches Ruff version in pyproject.
rev: v0.12.7
rev: v0.16.1
hooks:
- id: ruff
name: lint with ruff
Expand Down
12 changes: 7 additions & 5 deletions addon/globalPlugins/askOpenRouter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

import scriptHandler
import config
import wx
from collections.abc import Callable

import addonHandler
import config
import globalPluginHandler
import gui
from typing import Callable
from .dialogs import addonSummary, OpenRouterSettingsPanel, ChatDialog
import scriptHandler
import wx
from gui.settingsDialogs import NVDASettingsDialog

from .dialogs import ChatDialog, OpenRouterSettingsPanel, addonSummary
from .functions import disableInSecureMode

addonHandler.initTranslation()
Expand Down
18 changes: 10 additions & 8 deletions addon/globalPlugins/askOpenRouter/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
# Copyright(C) 2026-2028 Abdel <abdelkrim.bensaid@gmail.com>
# Released under GPL 2

import wx
from collections.abc import Callable
from typing import Optional, cast

import addonHandler
import config
import gui
from typing import Callable, List, Dict, Optional, cast

import wx
from gui.settingsDialogs import SettingsPanel
from .functions import askOpenRouter, inputBox, getAvailableModels

from .functions import askOpenRouter, getAvailableModels, inputBox

addonHandler.initTranslation()

Expand Down Expand Up @@ -235,7 +237,7 @@ def makeSettings(self, settingsSizer: wx.Sizer) -> None:
self.sHelper.addItem(self.modelsList, flag=wx.EXPAND)

self.modelsList.Hide()
self.modelsData: List[Dict[str, object]] = []
self.modelsData: list[dict[str, object]] = []

wx.CallAfter(self.onToggleModelsList, None)

Expand All @@ -256,7 +258,7 @@ def onToggleApiVisibility(self, evt: wx.CommandEvent) -> None:

self.Layout()

def onToggleModelsList(self, evt: Optional[wx.CommandEvent]) -> None:
def onToggleModelsList(self, evt: wx.CommandEvent | None) -> None:
"""
Show or hide the models list depending on checkbox state.
"""
Expand Down Expand Up @@ -286,15 +288,15 @@ def _loadModelsIfNeeded(self) -> None:
return

try:
models: List[Dict[str, object]] = getAvailableModels(apiKey)
models: list[dict[str, object]] = getAvailableModels(apiKey)
except Exception:
return

models.sort(key=lambda m: cast(float, m["promptPricing"]))

self.modelsData = models

displayNames: List[str] = []
displayNames: list[str] = []

for m in models:
price: float = cast(float, m["promptPricing"])
Expand Down
54 changes: 28 additions & 26 deletions addon/globalPlugins/askOpenRouter/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,32 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

import wx
import globalPluginHandler
import globalVars
import json
import os
import addonHandler
import pickle
import random
import markdown
import json
import time
import urllib.error
import urllib.request
from collections.abc import Callable
from typing import Any

import addonHandler
import config
import ui
import globalPluginHandler
import globalVars
import gui
import urllib.request
import urllib.error
import time
from typing import List, Dict, Callable, Optional, Any
import markdown
import ui
import wx

addonHandler.initTranslation()


_: Callable[[str], str]

# Temporary in-memory blacklist for unavailable models
_unavailableModels: Dict[str, float] = {}
_unavailableModels: dict[str, float] = {}

# Cooldowns (seconds)
_RATE_LIMIT_COOLDOWN: int = 300 # 429
Expand Down Expand Up @@ -76,7 +78,7 @@ def loadModel(filename: str) -> str:
return ""


def saveHistory(history: List[Dict[str, str]], filename: str) -> None:
def saveHistory(history: list[dict[str, str]], filename: str) -> None:
"""
Serialize and save conversation history to disk.

Expand All @@ -91,7 +93,7 @@ def saveHistory(history: List[Dict[str, str]], filename: str) -> None:
pickle.dump(history, f)


def loadHistory(filename: str) -> List[Dict[str, str]]:
def loadHistory(filename: str) -> list[dict[str, str]]:
"""
Load serialized conversation history from disk.

Expand Down Expand Up @@ -171,7 +173,7 @@ def getRandomFreeModel(apiKey: str) -> str:

modelsURL: str = "https://openrouter.ai/api/v1/models"

headers: Dict[str, str] = {
headers: dict[str, str] = {
"Authorization": f"Bearer {apiKey}",
"User-Agent": "Python-urllib",
}
Expand All @@ -183,7 +185,7 @@ def getRandomFreeModel(apiKey: str) -> str:

models = data["data"]

candidates: List[str] = [
candidates: list[str] = [
m["id"]
for m in models
if float(m.get("pricing", {}).get("prompt", 1)) == 0
Expand All @@ -201,7 +203,7 @@ def getRandomFreeModel(apiKey: str) -> str:
return random.choice(candidates)


def getAvailableModels(apiKey: str) -> List[Dict[str, object]]:
def getAvailableModels(apiKey: str) -> list[dict[str, object]]:
"""
Retrieve the full list of available models for the current user.

Expand Down Expand Up @@ -232,7 +234,7 @@ def getAvailableModels(apiKey: str) -> List[Dict[str, object]]:
"""
modelsURL: str = "https://openrouter.ai/api/v1/models"

headers: Dict[str, str] = {
headers: dict[str, str] = {
"Authorization": f"Bearer {apiKey}",
"User-Agent": "Python-urllib",
}
Expand All @@ -244,7 +246,7 @@ def getAvailableModels(apiKey: str) -> List[Dict[str, object]]:

models = data.get("data", [])

availableModels: List[Dict[str, object]] = []
availableModels: list[dict[str, object]] = []

for m in models:
if m.get("deprecated", False):
Expand All @@ -266,7 +268,7 @@ def getAvailableModels(apiKey: str) -> List[Dict[str, object]]:
return availableModels


def _sendRequest(url: str, headers: Dict[str, str], data: Dict) -> str:
def _sendRequest(url: str, headers: dict[str, str], data: dict) -> str:
"""
Send an HTTP POST request to OpenRouter.

Expand Down Expand Up @@ -326,8 +328,8 @@ def getHistory(filename: str) -> str:
str: HTML-formatted conversation history,
or an empty string if no history exists.
"""
historyLines: List[str] = []
allChat: List[Dict[str, str]] = []
historyLines: list[str] = []
allChat: list[dict[str, str]] = []
# Translators: Message announcing what the user said.
userQuestion: str = _("You said:")
# Translators: Message announcing what the model responded.
Expand Down Expand Up @@ -427,7 +429,7 @@ def askOpenRouter(prompt: str, apiKey: str, new: bool = True) -> None:
)
return

history: List[Dict[str, str]] = loadHistory(historyFile)
history: list[dict[str, str]] = loadHistory(historyFile)

history.append(
{
Expand All @@ -436,21 +438,21 @@ def askOpenRouter(prompt: str, apiKey: str, new: bool = True) -> None:
},
)

headers: Dict[str, str] = {
headers: dict[str, str] = {
"Authorization": f"Bearer {apiKey}",
"Content-Type": "application/json",
"HTTP-Referer": "http://localhost",
"X-Title": "My question",
}

data: Dict[str, Any] = {
data: dict[str, Any] = {
"model": model,
"messages": history,
}

maxAttempts: int = 5
attempt: int = 0
answer: Optional[str] = None
answer: str | None = None

while attempt < maxAttempts:
try:
Expand Down
Loading
Loading