4 Commits

Author SHA1 Message Date
herel 6ad0587246 🟢 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 7a19f9acb7 🟢 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 6c502f94f1 chore: add from Python.gitignore 2024-11-01 10:07:04 +01:00
herel e102cfa9c8 initial import 2024-11-01 09:59:45 +01:00
6 changed files with 22 additions and 150 deletions
-1
View File
@@ -1 +0,0 @@
style "#{File.dirname(__FILE__)}/mdl.rb"
+1 -30
View File
@@ -1,24 +1,5 @@
# 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
@@ -29,7 +10,7 @@ myice schedule -o schedule.json
### listing ### listing
Pour récupérer les event des U13 Elite par example: Pour récupérer les event des U13 Elite par exemple:
```shell ```shell
myice search "U13 (Elite)" myice search "U13 (Elite)"
@@ -76,13 +57,3 @@ et pour la convoc d'un entraînement:
Opening file practice_561855.pdf Opening file practice_561855.pdf
``` ```
### AI
```text
myice ai
> prochain match u13 top ?
< Le prochain match de l'équipe U13 Top se déroulera le dimanche 10 novembre 2024 contre HC Ajoie à la Raffeisen Arena de Porrentruy. Le match débutera à 14h00 et se terminera à 16h15.
> et les u13 a ?
< Le prochain match de l'équipe U13 A se déroulera le samedi 9 novembre 2024 contre HC Vallorbe à P. du Frézillon, 1337 Vallorbe VD. Le match débutera à 13h00 et se terminera à 15h00. Le prochain match à domicile de l'équipe U13 A se déroulera le dimanche 10 novembre 2024 contre CP Meyrin à Les Vernets, Glace extérieure, 1227 Les Acacias GE. Le match débutera à 13h00 et se terminera à 15h00.
```
-2
View File
@@ -1,2 +0,0 @@
all
rule 'MD013', :ignore_code_blocks => true
+14 -83
View File
@@ -12,8 +12,6 @@ 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
@@ -33,11 +31,6 @@ 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 = {}
@@ -47,9 +40,8 @@ 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(file: str = "cookies.txt"): def save_cookies():
cookie_jar_file = Path(file) with open("cookies.txt", "w") as f:
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)))
@@ -69,12 +61,10 @@ 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( print("Error: please configure username/password in ini file")
"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", file=sys.stderr) print("Error: please configure username/password in ini file")
sys.exit(1) sys.exit(1)
return username, password, userid return username, password, userid
@@ -128,12 +118,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...", file=sys.stderr) print("login...")
do_login() do_login()
save_cookies() save_cookies()
_, _, userid = get_login() _, _, userid = get_login()
if not userid: if not userid:
print("get userid...", file=sys.stderr) print("get userid...")
userid = get_userid() userid = get_userid()
return func(*args, **kwargs) return func(*args, **kwargs)
@@ -146,7 +136,7 @@ def get_schedule() -> str:
global userid global userid
assert session and userid assert session and userid
now = datetime.datetime.now() now = datetime.datetime.now()
date_start = now date_start = now + datetime.timedelta(days=1)
date_end = date_start + datetime.timedelta(days=7) date_end = date_start + datetime.timedelta(days=7)
r = session.post( r = session.post(
"https://app.myice.hockey/inc/processclubplanning.php", "https://app.myice.hockey/inc/processclubplanning.php",
@@ -217,10 +207,11 @@ 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 os_open(file: str) -> None: def 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:
@@ -237,7 +228,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))
os_open(output_filename) open(output_filename)
@app.command("practice") @app.command("practice")
@@ -249,16 +240,12 @@ 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))
os_open(output_filename) open(output_filename)
@app.command("search") @app.command("search")
def parse_schedule( def parse_schedule(
age_group: Annotated[AgeGroup | None, typer.Option(...)] = None, age_group: Annotated[AgeGroup, typer.Argument(...)],
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"),
@@ -268,22 +255,9 @@ 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)
# age_group filter for event in [x for x in data if x["agegroup"] == age_group]:
if age_group: # print(json.dumps(event, indent=2))
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") 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")
@@ -299,48 +273,5 @@ 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)
schedule_data = [x for x in schedule_data if x["agegroup"] in AgeGroup]
for event in schedule_data:
event["team"] = event["agegroup"].replace("(", "").replace(")", "")
del event["agegroup"]
when = datetime.datetime.now().strftime("%d-%m-%Y et il est %H:%M")
system = "\n".join(
[
"Tu es une IA connaissant bien les données suivantes, qui décrivent les match et entraînements d'équipes de hockey sur glace.",
f"aujourd'hui, nous sommes le {when}"
"attention: ce qu'il y a entre parenthèse après la catégorie est une catégorie à part entière, example, u13 a = U13 (A) et ça correspond aux agegroup",
"assure-toi de ne pas confondre les catégories d'age dans tes réponses. ne donne pas une réponse pour la mauvaise équipe",
"ne confond pas top, elite, a, prép",
"```json",
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, model="mixtral8x22b"
)
print("<", answer)
history.append((question, answer))
if __name__ == "__main__": if __name__ == "__main__":
app() app()
Generated
+4 -24
View File
@@ -874,13 +874,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]] [[package]]
name = "rich" name = "rich"
version = "13.9.4" version = "13.9.3"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false optional = false
python-versions = ">=3.8.0" python-versions = ">=3.8.0"
files = [ files = [
{file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, {file = "rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283"},
{file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, {file = "rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e"},
] ]
[package.dependencies] [package.dependencies]
@@ -890,26 +890,6 @@ 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.10.1"
description = "Tools using AI"
optional = false
python-versions = ">=3.11,<4.0"
files = [
{file = "rl_ai_tools-1.10.1-py3-none-any.whl", hash = "sha256:72f3e939c7688d1696ec1744a1e64ba1ce61737e30dab0ebe2f1722761b5683e"},
{file = "rl_ai_tools-1.10.1.tar.gz", hash = "sha256:53f64a4b677d022d64b6cc99cf925d1b7172a3a56589f29053b2083103899f20"},
]
[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"
@@ -1045,4 +1025,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "c8b74100d5c4f5889db217b5fb249f55248d1955787fd76dbda5ded8b73875b3" content-hash = "e11a9960c50f8b210bd0942533a30915eb56bed47cf5f67ac33f405cb1ef5859"
+2 -9
View File
@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "myice" name = "myice"
version = "v0.2.5" version = "0.1.0"
description = "myice parsing" description = "myice parsing"
authors = ["Rene Luria <rene@luria.ch>"] authors = ["Rene Luria <rene@luria.ch>"]
license = "MIT" license = "MIT"
@@ -9,19 +9,12 @@ readme = "README.md"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.12" python = "^3.12"
requests = "^2.32.3" requests = "^2.32.3"
typer = "^0.12.5" typer = {extras = ["all"], version = "^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"