13 Commits

Author SHA1 Message Date
herel 6f3c7bf8d2 🛠️ pyproject.toml -> Updated version from v0.1.6 to v0.2.0 2024-11-01 15:24:14 +01:00
herel 2c67596d38 🛠️ myice/myice.py -> Added new AI functionality using Infomaniak LLM API
🛠️ poetry.lock -> Added rl-ai-tools package dependency
🛠️ pyproject.toml -> Updated dependencies and added rl-ai-tools source
2024-11-01 15:23:51 +01:00
herel a39899ebb1 chore: myice.py -> Added file parameter to save_cookies function and used Path object for file handling. 2024-11-01 14:02:10 +01:00
herel 320ec291e6 🟢 pyproject.toml: Added Poetry project configuration file
🛠️ pyproject.toml -> Updated version from 'v0.1.5' to 'v0.1.6'
2024-11-01 13:18:38 +01:00
herel 85f84b540a 🟢 README.md -> added installation instructions and introduction section
🛠️ .mdlrc -> set style path
🛠️ mdl.rb -> created a new ruby script
🔴 RECUPE\_SCHEDULE.sh -> removed shell script
2024-11-01 13:15:35 +01:00
herel 7939414995 🛠️ myice.py -> updated error messages to redirect to stderr
🛠️ myice.py -> changed login and get\_userid prints to write to stderr
🔴 pyproject.toml -> removed version v0.1.3
🟢 pyproject.toml -> added version v0.1.5
2024-11-01 11:23:05 +01:00
herel b2baa07371 🛠️ myice/myice.py -> updated function get_login by simplifying config reading; renamed functions open, get_game_pdf, get_practice_pdf to os_open, get_game_pdf_os, get_practice_pdf_os respectively
🔴 pyproject.toml -> removed version 'v0.1.2', now at 'v0.1.3'
2024-11-01 11:17:26 +01:00
herel 56e7ba92e8 🛠️ myice/myice.py -> added EventType enum and updated search command to support optional event type filtering
- Added `EventType` enum with two values: 'game' and 'practice'.
- Updated `parse_schedule` function to accept an optional `event_type_filter` argument which filters displayed events based on their type.
- Changed `age_group` parameter in `parse_schedule` to allow `None`.
2024-11-01 11:06:10 +01:00
herel a3e1d9ccbf 🛠️ pyproject.toml -> updated project dependencies and version number from 0.1.0 to v0.1.1
🛠️ poetry.lock -> content-hash changed from e11a99... to 32eb77...
2024-11-01 10:53:58 +01:00
herel 3b2351efc6 🟢 LICENSE.txt (New MIT license added)
🛠️ pyproject.toml -> Updated poetry dependencies, authors email changed, added license info
2024-11-01 10:41:39 +01:00
herel e313b824d7 🟢 README.md: Updated command to retrieve schedule and added new commands for searching events by age group and retrieving match details
🛠️ myice/myice.py: Implemented a function to parse the schedule JSON file based on given age groups, improved error handling, enhanced formatting when printing results, added a new command `myice search`
2024-11-01 10:38:43 +01:00
herel 11bbfdfc10 chore: add from Python.gitignore 2024-11-01 10:07:04 +01:00
herel 1644523d40 initial import 2024-11-01 09:59:45 +01:00
6 changed files with 120 additions and 17 deletions
+1
View File
@@ -0,0 +1 @@
style "#{File.dirname(__FILE__)}/mdl.rb"
+19
View File
@@ -1,5 +1,24 @@
# myice # myice
## intro
Avec tout ça on va aller chercher sur MyIce les planning des gamins et générer
les pdf qu'on veut
## install
with [uv](https://docs.astral.sh/uv/getting-started/installation/):
```shell
uv tool install --extra-index-url https://gitea.parano.ch/api/packages/herel/pypi/simple/ myice
```
with [pipx](https://pipx.pypa.io/stable/installation/):
```shell
pipx install --extra-index-url https://gitea.parano.ch/api/packages/herel/pypi/simple/ myice
```
## récupérer le schedule ## récupérer le schedule
```shell ```shell
+2
View File
@@ -0,0 +1,2 @@
all
rule 'MD013', :ignore_code_blocks => true
+68 -14
View File
@@ -12,6 +12,8 @@ import sys
from enum import Enum from enum import Enum
from pathlib import Path from pathlib import Path
from typing import Annotated from typing import Annotated
from typing import List, Tuple
from rl_ai_tools import utils # type: ignore
import requests import requests
import typer import typer
@@ -31,6 +33,11 @@ class AgeGroup(str, Enum):
u15a = "U15 (A)" u15a = "U15 (A)"
class EventType(str, Enum):
game = "game"
practice = "practice"
def load_cookies(file: str = "cookies.txt") -> requests.cookies.RequestsCookieJar: def load_cookies(file: str = "cookies.txt") -> requests.cookies.RequestsCookieJar:
cookie_jar_file = Path(file) cookie_jar_file = Path(file)
cj_dict = {} cj_dict = {}
@@ -40,8 +47,9 @@ def load_cookies(file: str = "cookies.txt") -> requests.cookies.RequestsCookieJa
return requests.cookies.cookiejar_from_dict(cj_dict) return requests.cookies.cookiejar_from_dict(cj_dict)
def save_cookies(): def save_cookies(file: str = "cookies.txt"):
with open("cookies.txt", "w") as f: cookie_jar_file = Path(file)
with cookie_jar_file.open("w") as f:
f.write(json.dumps(requests.utils.dict_from_cookiejar(session.cookies))) f.write(json.dumps(requests.utils.dict_from_cookiejar(session.cookies)))
@@ -61,10 +69,12 @@ def get_login(local_file: str = "myice.ini") -> tuple[str, str, int]:
password = default_config.get("password") password = default_config.get("password")
userid = default_config.getint("userid") userid = default_config.getint("userid")
if not username or not password: if not username or not password:
print("Error: please configure username/password in ini file") print(
"Error: please configure username/password in ini file", file=sys.stderr
)
sys.exit(1) sys.exit(1)
else: else:
print("Error: please configure username/password in ini file") print("Error: please configure username/password in ini file", file=sys.stderr)
sys.exit(1) sys.exit(1)
return username, password, userid return username, password, userid
@@ -118,12 +128,12 @@ def wrapper_session(func):
session.cookies = load_cookies() session.cookies = load_cookies()
session.cookies.clear_expired_cookies() session.cookies.clear_expired_cookies()
if not session.cookies.get("mih_v3_cookname"): if not session.cookies.get("mih_v3_cookname"):
print("login...") print("login...", file=sys.stderr)
do_login() do_login()
save_cookies() save_cookies()
_, _, userid = get_login() _, _, userid = get_login()
if not userid: if not userid:
print("get userid...") print("get userid...", file=sys.stderr)
userid = get_userid() userid = get_userid()
return func(*args, **kwargs) return func(*args, **kwargs)
@@ -207,11 +217,10 @@ def schedule(
with outfile.open("w") as f: with outfile.open("w") as f:
f.write(schedule) f.write(schedule)
else: else:
print("Schedule:", file=sys.stderr)
print(schedule) print(schedule)
def open(file: str) -> None: def os_open(file: str) -> None:
if os.uname().sysname == "Linux": if os.uname().sysname == "Linux":
os.system(f"xdg-open {file}") os.system(f"xdg-open {file}")
else: else:
@@ -228,7 +237,7 @@ def get_game_pdf(
""" """
output_filename = f"game_{game_id}.pdf" output_filename = f"game_{game_id}.pdf"
game_pdf(game_id, Path(output_filename)) game_pdf(game_id, Path(output_filename))
open(output_filename) os_open(output_filename)
@app.command("practice") @app.command("practice")
@@ -240,12 +249,16 @@ def get_practice_pdf(
""" """
output_filename = f"practice_{game_id}.pdf" output_filename = f"practice_{game_id}.pdf"
practice_pdf(game_id, Path(output_filename)) practice_pdf(game_id, Path(output_filename))
open(output_filename) os_open(output_filename)
@app.command("search") @app.command("search")
def parse_schedule( def parse_schedule(
age_group: Annotated[AgeGroup, typer.Argument(...)], age_group: Annotated[AgeGroup | None, typer.Option(...)] = None,
event_type_filter: Annotated[
EventType | None,
typer.Option("--type", help="Only display events of this type"),
] = None,
schedule_file: Annotated[ schedule_file: Annotated[
Path, typer.Option(help="schedule json file to parse") Path, typer.Option(help="schedule json file to parse")
] = Path("schedule.json"), ] = Path("schedule.json"),
@@ -255,9 +268,22 @@ def parse_schedule(
""" """
with schedule_file.open("r") as f: with schedule_file.open("r") as f:
data = json.load(f) data = json.load(f)
for event in [x for x in data if x["agegroup"] == age_group]: # age_group filter
# print(json.dumps(event, indent=2)) if age_group:
raw_title = event["title"].removeprefix(age_group + "\n") events = [x for x in data if x["agegroup"] == age_group]
else:
events = [x for x in data if x["agegroup"] in AgeGroup]
# event_type filter
if event_type_filter:
if event_type_filter.value == EventType.game:
events = [x for x in events if "event" in x and x["event"] == "Jeu"]
else:
events = [x for x in events if "event" not in x or x["event"] == "Jeu"]
for event in events:
if age_group:
raw_title = event["title"].removeprefix(age_group + "\n")
else:
raw_title = event["title"]
title = " ".join(raw_title.split("\n")) title = " ".join(raw_title.split("\n"))
start = datetime.datetime.fromisoformat(event["start"]) start = datetime.datetime.fromisoformat(event["start"])
start_fmt = start.strftime("%H:%M") start_fmt = start.strftime("%H:%M")
@@ -273,5 +299,33 @@ def parse_schedule(
print(f"{event_type}: {title}\n") print(f"{event_type}: {title}\n")
@app.command("ai")
def check_with_ai(
schedule_file: Annotated[
Path, typer.Option(help="schedule json file to parse")
] = Path("schedule.json"),
):
"""
Search through the schedule with natural language using Infomaniak LLM API
"""
if not utils.init():
sys.exit(1)
with schedule_file.open("r") as f:
schedule_data = json.load(f)
system = (
"Tu es une IA connaissant bien les données suivantes, qui décrivent les match et entraînements d'équipes de hockey sur glace:\n"
+ json.dumps(schedule_data)
)
history: List[Tuple[str, str]] = []
while True:
try:
question = input("> ")
except EOFError:
break
answer = utils.llm_inference(question, history, system=system)
print(">", answer)
history.append((question, answer))
if __name__ == "__main__": if __name__ == "__main__":
app() app()
Generated
+21 -1
View File
@@ -890,6 +890,26 @@ pygments = ">=2.13.0,<3.0.0"
[package.extras] [package.extras]
jupyter = ["ipywidgets (>=7.5.1,<9)"] jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "rl-ai-tools"
version = "1.9.0"
description = "Tools using AI"
optional = false
python-versions = ">=3.11,<4.0"
files = [
{file = "rl_ai_tools-1.9.0-py3-none-any.whl", hash = "sha256:c986a17e39afe6bd5bc21eb8d259e465dcc52e60a73b81db3931b45599e94fc1"},
{file = "rl_ai_tools-1.9.0.tar.gz", hash = "sha256:80c43d434a330544e5d201f3a99460996cc31276fb360cb45a0962f743a342bb"},
]
[package.dependencies]
requests = ">=2.32.3,<3.0.0"
typer = ">=0.12.5,<0.13.0"
[package.source]
type = "legacy"
url = "https://pypi.purple.infomaniak.ch"
reference = "infomaniak"
[[package]] [[package]]
name = "shellingham" name = "shellingham"
version = "1.5.4" version = "1.5.4"
@@ -1025,4 +1045,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "e11a9960c50f8b210bd0942533a30915eb56bed47cf5f67ac33f405cb1ef5859" content-hash = "c8b74100d5c4f5889db217b5fb249f55248d1955787fd76dbda5ded8b73875b3"
+9 -2
View File
@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "myice" name = "myice"
version = "0.1.0" version = "v0.2.0"
description = "myice parsing" description = "myice parsing"
authors = ["Rene Luria <rene@luria.ch>"] authors = ["Rene Luria <rene@luria.ch>"]
license = "MIT" license = "MIT"
@@ -9,12 +9,19 @@ readme = "README.md"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.12" python = "^3.12"
requests = "^2.32.3" requests = "^2.32.3"
typer = {extras = ["all"], version = "^0.12.5"} typer = "^0.12.5"
rl-ai-tools = {version = "^1.9.0", source = "infomaniak"}
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
ipykernel = "^6.29.5" ipykernel = "^6.29.5"
[[tool.poetry.source]]
name = "infomaniak"
url = "https://pypi.purple.infomaniak.ch"
priority = "supplemental"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"