Skip to content

Commit dd13cb0

Browse files
committed
first commit
0 parents  commit dd13cb0

14 files changed

Lines changed: 511 additions & 0 deletions

File tree

.github/dependabot.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
version: 2
2+
3+
updates:
4+
- package-ecosystem: pip
5+
directory: "/"
6+
schedule:
7+
interval: daily
8+
time: "15:00"
9+
10+
- package-ecosystem: github-actions
11+
directory: "/"
12+
schedule:
13+
interval: daily
14+
time: "15:00"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: Docker Image CI(GitHub)
3+
4+
on:
5+
push:
6+
7+
8+
jobs:
9+
build:
10+
name: Build & Push
11+
runs-on: ubuntu-latest
12+
env:
13+
REPOSITORY_URL: ghcr.io
14+
IMAGE_NAME: oldtyt/python-ai-console
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4.1.2
18+
- name: Variables
19+
id: vars
20+
run: echo "::set-output name=SHORT_COMMIT_ID::$(git rev-parse --short HEAD)"
21+
- name: Build image
22+
id: docker-build
23+
run: >-
24+
docker build
25+
-t $IMAGE_NAME
26+
-t $REPOSITORY_URL/$IMAGE_NAME:latest .
27+
- name: Docker Login
28+
uses: docker/login-action@v3
29+
with:
30+
registry: ${{ env.REPOSITORY_URL }}
31+
username: ${{ github.actor }}
32+
password: ${{ secrets.GITHUB_TOKEN }}
33+
- name: Publish Image
34+
id: docker-push
35+
run: docker push --all-tags $REPOSITORY_URL/$IMAGE_NAME

.gitignore

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[codz]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
share/python-wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
MANIFEST
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.nox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*.cover
49+
*.py.cover
50+
.hypothesis/
51+
.pytest_cache/
52+
cover/
53+
54+
# Translations
55+
*.mo
56+
*.pot
57+
58+
# Django stuff:
59+
*.log
60+
local_settings.py
61+
db.sqlite3
62+
db.sqlite3-journal
63+
64+
# Flask stuff:
65+
instance/
66+
.webassets-cache
67+
68+
# Scrapy stuff:
69+
.scrapy
70+
71+
# Sphinx documentation
72+
docs/_build/
73+
74+
# PyBuilder
75+
.pybuilder/
76+
target/
77+
78+
# Jupyter Notebook
79+
.ipynb_checkpoints
80+
81+
# IPython
82+
profile_default/
83+
ipython_config.py
84+
85+
# pyenv
86+
# For a library or package, you might want to ignore these files since the code is
87+
# intended to run in multiple environments; otherwise, check them in:
88+
# .python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# UV
98+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99+
# This is especially recommended for binary packages to ensure reproducibility, and is more
100+
# commonly ignored for libraries.
101+
#uv.lock
102+
103+
# poetry
104+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105+
# This is especially recommended for binary packages to ensure reproducibility, and is more
106+
# commonly ignored for libraries.
107+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108+
#poetry.lock
109+
#poetry.toml
110+
111+
# pdm
112+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115+
#pdm.lock
116+
#pdm.toml
117+
.pdm-python
118+
.pdm-build/
119+
120+
# pixi
121+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122+
#pixi.lock
123+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124+
# in the .venv directory. It is recommended not to include this directory in version control.
125+
.pixi
126+
127+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128+
__pypackages__/
129+
130+
# Celery stuff
131+
celerybeat-schedule
132+
celerybeat.pid
133+
134+
# SageMath parsed files
135+
*.sage.py
136+
137+
# Environments
138+
.env
139+
.envrc
140+
.venv
141+
env/
142+
venv/
143+
ENV/
144+
env.bak/
145+
venv.bak/
146+
147+
# Spyder project settings
148+
.spyderproject
149+
.spyproject
150+
151+
# Rope project settings
152+
.ropeproject
153+
154+
# mkdocs documentation
155+
/site
156+
157+
# mypy
158+
.mypy_cache/
159+
.dmypy.json
160+
dmypy.json
161+
162+
# Pyre type checker
163+
.pyre/
164+
165+
# pytype static type analyzer
166+
.pytype/
167+
168+
# Cython debug symbols
169+
cython_debug/
170+
171+
# PyCharm
172+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174+
# and can be added to the global gitignore or merged into this file. For a more nuclear
175+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
176+
#.idea/
177+
178+
# Abstra
179+
# Abstra is an AI-powered process automation framework.
180+
# Ignore directories containing user credentials, local state, and settings.
181+
# Learn more at https://abstra.io/docs
182+
.abstra/
183+
184+
# Visual Studio Code
185+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
188+
# you could uncomment the following to ignore the entire vscode folder
189+
# .vscode/
190+
191+
# Ruff stuff:
192+
.ruff_cache/
193+
194+
# PyPI configuration file
195+
.pypirc
196+
197+
# Marimo
198+
marimo/_static/
199+
marimo/_lsp/
200+
__marimo__/
201+
202+
# Streamlit
203+
.streamlit/secrets.toml

Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
ARG IMAGE=python:3.13-alpine
2+
3+
FROM $IMAGE AS builder
4+
5+
COPY requirements.txt .
6+
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
7+
8+
FROM $IMAGE
9+
10+
WORKDIR /app
11+
COPY --from=builder /app/wheels /wheels
12+
13+
RUN apk add --no-cache musl-locales musl-locales-lang
14+
ENV LANG=C.UTF-8 \
15+
LC_ALL=C.UTF-8 \
16+
PYTHONIOENCODING=utf-8
17+
18+
RUN pip install --no-cache /wheels/*
19+
20+
COPY . .
21+
22+
ENTRYPOINT [ "python3" ]
23+
24+
CMD ["/app/main.py"]

README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# 🚀 **Python AI Console: The Ultimate AI-Powered Coding EXPLOSION!** 🌟💥🐍
2+
3+
**WOWZA!** Dive headfirst into this **AMAZING**, **WONDERFUL**, **MIND-BLOWING** interactive command-line beast that turns your craziest prompts into **EXECUTABLE PYTHON MAGIC** using the sheer power of OpenAI! Generate code like a wizard, run it on the spot, capture every wild stdout/stderr outburst, and keep a super-smart history in JSON for non-stop contextual awesomeness! It's not just a tool – it's a **CODE REVOLUTION** for hackers, dreamers, and AI fanatics! 🔥🚀
4+
5+
## 🌈 **Features That'll Make Your Eyes POP!** 🎉
6+
- **INTERACTIVE PROMPT MADNESS**: Type your wild ideas and watch AI spit out Python gold! 💡
7+
- **AI-GENERATED CODE WIZARDRY**: Powered by OpenAI – prompts + history = PERFECT scripts! 🤖✨
8+
- **SAFE EXECUTION EXTRAVAGANZA**: Run code with output capturing – no disasters, just pure thrill! ⚡
9+
- **PERSISTENT HISTORY OVERLOAD**: Pydantic models store EVERYTHING in JSON – context forever! 📜
10+
- **ENV VAR CUSTOMIZATION FRENZY**: Tweak it your way for ultimate control! 🔧
11+
- **DOCKER DOMINATION**: Run it anywhere, anytime – easy-peasy deployment! 🐳
12+
13+
## 🛠️ **Installation: Get This Party Started in SECONDS!** 🚀
14+
15+
### **From Source: Clone, Install, BLAST OFF!** 🌌
16+
1. **CLONE THE AWESOMENESS**:
17+
```
18+
git clone https://github.com/OldTyT/python-ai-console.git
19+
```
20+
2. **JUMP IN**:
21+
```
22+
cd python-ai-console
23+
```
24+
3. **INSTALL THE MAGIC**:
25+
```
26+
pip install -r requirements.txt
27+
```
28+
4. **LAUNCH THE BEAST**:
29+
```
30+
python3 main.py
31+
```
32+
**BOOM! You're in the zone!** 💣
33+
34+
### **Using Docker: Containerized CHAOS – Ready to RUMBLE!** 🐳🔥
35+
Fire it up with this epic command:
36+
```
37+
docker run --rm -ti -e HISTORY_PATH=/history/history.json -e OPENAI_API_KEY=YOUR_KEY -v my_history:/history ghcr.io/oldtyt/autopost-python-ai-console
38+
```
39+
- Plug in `YOUR_KEY` with your OpenAI super-key! 🔑
40+
**DOCKER DELIGHT: Persistent history, zero hassle!** 🌟
41+
42+
## 🎮 **Usage: Dive into the FUN ZONE!** 🕹️
43+
Fire it up and get prompted:
44+
- **SMASH IN A PROMPT** (e.g., "Code me a factorial frenzy!").
45+
- **AI UNLEASHES CODE CHAOS** based on your prompt + history vibes.
46+
- **EXECUTE? Y/N – YOU DECIDE!** Run it, capture outputs, and watch the sparks fly! ⚡
47+
- **HISTORY SAVES THE DAY**: Everything logged for eternal glory.
48+
49+
**EXIT? Ctrl+C – but why would you? It's TOO MUCH FUN!** 😎
50+
51+
## 🔑 **Environment Variables: Customize Like a BOSS!** 💪
52+
Supercharge your setup with these **EPIC** vars:
53+
- **HISTORY_PATH**: Your JSON history fortress! Default: `history.json`. 🏰
54+
- **HISTORY_SIZE**: How many past blasts to feed the AI? Default: `20` – keep it contextual! 📈
55+
- **OPENAI_API_KEY**: **MUST-HAVE** – your ticket to AI heaven! (Required, duh!) 🔒
56+
57+
**Example (Unix-style domination)**:
58+
```
59+
export OPENAI_API_KEY=your-api-key
60+
export HISTORY_SIZE=10
61+
python3 main.py
62+
```
63+
**TWEAK AND CONQUER!** 🛡️
64+
65+
## 📦 **Dependencies: The Power Behind the THRILL!** ⚙️
66+
- **Python 3.10+** (Blasting up to 3.13 – future-proofed!) 🐍
67+
- **Libraries of LEGEND**: openai, pydantic, loguru, and more! Check `requirements.txt` for the full squad. 📚
68+
69+
## 🤝 **Contributing: Join the CODE CARNIVAL!** 🎪
70+
**GOT IDEAS?** Open an issue or slam in a pull request – let's make this even MORE INSANE! 🌟 Contributions = Eternal Fame!

history.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"history": [{"datetime": "2025-08-11T14:41:08.915812", "user_prompt": null, "ai_model_response": null, "stdout_result_code_execute": null, "stderr_result_code_execute": null}, {"datetime": "2025-08-11T14:41:08.915524", "user_prompt": "\u041f\u0440\u0438\u0432\u0435\u0442! \u041a\u0430\u043a \u0434\u0435\u043b\u0430? \u041a\u0430\u043a\u0430\u044f \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u043c\u043e\u0441\u043a\u0432\u0435?", "ai_model_response": "import datetime, sys\ntry:\n import requests\n def fetch():\n r = requests.get('https://wttr.in/Moscow?format=%l:+%c+%t+%h+%w&lang=ru', timeout=10)\n r.encoding = 'utf-8'\n if r.status_code == 200 and r.text.strip():\n return r.text.strip()\n raise Exception(f'HTTP {r.status_code}')\nexcept Exception:\n from urllib import request, error\n def fetch():\n try:\n with request.urlopen('https://wttr.in/Moscow?format=%l:+%c+%t+%h+%w&lang=ru', timeout=10) as r:\n return r.read().decode('utf-8').strip()\n except error.HTTPError as e:\n raise Exception(f'HTTP {e.code}')\n except Exception as e:\n raise\n\nnow = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')\ntry:\n weather = fetch()\n print(\"\u041f\u0440\u0438\u0432\u0435\u0442! \u0423 \u043c\u0435\u043d\u044f \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e, \u0441\u043f\u0430\u0441\u0438\u0431\u043e.\")\n print(f\"\u0412\u0440\u0435\u043c\u044f: {now}\")\n print(f\"\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435: {weather}\")\nexcept Exception as e:\n print(\"\u041f\u0440\u0438\u0432\u0435\u0442! \u0423 \u043c\u0435\u043d\u044f \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e, \u0441\u043f\u0430\u0441\u0438\u0431\u043e.\")\n print(f\"\u0412\u0440\u0435\u043c\u044f: {now}\")\n print(\"\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0433\u043e\u0434\u0443 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u043e\u0437\u0436\u0435.\")", "stdout_result_code_execute": "\u041f\u0440\u0438\u0432\u0435\u0442! \u0423 \u043c\u0435\u043d\u044f \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e, \u0441\u043f\u0430\u0441\u0438\u0431\u043e.\n\u0412\u0440\u0435\u043c\u044f: 2025-08-11 14:41:24\n\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435: Moscow: \u26c5\ufe0f +15\u00b0C 94% \u21977km/h\n", "stderr_result_code_execute": ""}, {"datetime": "2025-08-11T14:41:50.094569", "user_prompt": "\u041c\u043e\u0436\u0435\u0448\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c? \u0423 \u043c\u0435\u043d\u044f \u0432\u044b\u0432\u043e\u0434 \u043f\u0440\u043e\u043f\u0430\u043b", "ai_model_response": "import datetime, sys\ntry:\n import requests\n def fetch():\n try:\n r = requests.get('https://wttr.in/Moscow?format=%l:+%c+%t+%h+%w&lang=ru', timeout=10)\n r.encoding = 'utf-8'\n if r.status_code == 200 and r.text.strip():\n return r.text.strip()\n raise Exception(f'HTTP {r.status_code}')\n except Exception:\n raise\nexcept Exception:\n from urllib import request, error\n def fetch():\n try:\n with request.urlopen('https://wttr.in/Moscow?format=%l:+%c+%t+%h+%w&lang=ru', timeout=10) as r:\n return r.read().decode('utf-8').strip()\n except error.HTTPError as e:\n raise Exception(f'HTTP {e.code}')\n except Exception:\n raise\n\nnow = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')\ntry:\n weather = fetch()\n print(\"\u041f\u0440\u0438\u0432\u0435\u0442! \u0423 \u043c\u0435\u043d\u044f \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e, \u0441\u043f\u0430\u0441\u0438\u0431\u043e.\")\n print(f\"\u0412\u0440\u0435\u043c\u044f: {now}\")\n print(f\"\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435: {weather}\")\nexcept Exception:\n print(\"\u041f\u0440\u0438\u0432\u0435\u0442! \u0423 \u043c\u0435\u043d\u044f \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e, \u0441\u043f\u0430\u0441\u0438\u0431\u043e.\")\n print(f\"\u0412\u0440\u0435\u043c\u044f: {now}\")\n print(\"\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0433\u043e\u0434\u0443 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u043e\u0437\u0436\u0435.\")", "stdout_result_code_execute": "\u041f\u0440\u0438\u0432\u0435\u0442! \u0423 \u043c\u0435\u043d\u044f \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e, \u0441\u043f\u0430\u0441\u0438\u0431\u043e.\n\u0412\u0440\u0435\u043c\u044f: 2025-08-11 14:42:03\n\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435: Moscow: \u26c5\ufe0f +15\u00b0C 94% \u21977km/h\n", "stderr_result_code_execute": ""}, {"datetime": "2025-08-11T14:45:50.573751", "user_prompt": "\u041a\u0430\u043a\u0430\u044f \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u043c\u0441\u043a?", "ai_model_response": "import datetime, sys\ntry:\n import requests\n def fetch():\n r = requests.get('https://wttr.in/Moscow?format=%l:+%c+%t+%h+%w&lang=ru', timeout=10)\n r.encoding = 'utf-8'\n if r.status_code == 200 and r.text.strip():\n return r.text.strip()\n raise Exception(f'HTTP {r.status_code}')\nexcept Exception:\n from urllib import request, error\n def fetch():\n try:\n with request.urlopen('https://wttr.in/Moscow?format=%l:+%c+%t+%h+%w&lang=ru', timeout=10) as r:\n return r.read().decode('utf-8').strip()\n except error.HTTPError as e:\n raise Exception(f'HTTP {e.code}')\n except Exception:\n raise\n\nnow = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')\ntry:\n weather = fetch()\n print(f\"\u0412\u0440\u0435\u043c\u044f: {now}\")\n print(f\"\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435: {weather}\")\nexcept Exception:\n print(f\"\u0412\u0440\u0435\u043c\u044f: {now}\")\n print(\"\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0433\u043e\u0434\u0443 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u043e\u0437\u0436\u0435.\")", "stdout_result_code_execute": "\u0412\u0440\u0435\u043c\u044f: 2025-08-11 14:46:00\n\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435: Moscow: \u26c5\ufe0f +15\u00b0C 94% \u21977km/h\n", "stderr_result_code_execute": ""}]}

history/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# history/__init__.py
2+
from .models import HistoryModel, HistoryList
3+
from .state import History

history/models.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from __future__ import annotations
2+
3+
from datetime import datetime
4+
from typing import List, Optional
5+
6+
from pydantic import BaseModel
7+
8+
9+
class HistoryModel(BaseModel):
10+
datetime: datetime
11+
user_prompt: Optional[str] = None
12+
ai_model_response: Optional[str] = None
13+
stdout_result_code_execute: Optional[str] = None
14+
stderr_result_code_execute: Optional[str] = None
15+
16+
17+
class HistoryList(BaseModel):
18+
history: List[HistoryModel]

0 commit comments

Comments
 (0)