Robovojtik/robovojtik.py
2025-03-19 23:52:21 +01:00

200 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import openai
import subprocess
import time
import configparser
import json
import sys
# === 1. Načtení konfigurace z config.ini ===
config = configparser.ConfigParser()
config.read("config.ini")
openai.api_key = config["OpenAI"]["api_key"]
ASSISTANT_ID = config["OpenAI"]["assistant_id"]
thread_id = None
# === 2. Definice funkcí, které asistent může volat ===
FUNCTIONS = [
{
"name": "execute_shell_command",
"description": "Spustí shellový příkaz a vrátí jeho výstup.",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "Shellový příkaz k vykonání."
}
},
"additionalProperties": False,
"required": ["command"]
}
}
]
# === 3. Pomocné funkce ===
def vytvor_nove_vlakno():
"""Vytvoří nové vlákno pro zachování historie konverzace."""
thread = openai.beta.threads.create()
return thread.id
def spust_prikaz(prikaz):
"""Spustí shellový příkaz a vrátí jeho výstup."""
try:
output = subprocess.check_output(prikaz, shell=True, stderr=subprocess.STDOUT, universal_newlines=True)
return output.strip()
except subprocess.CalledProcessError as e:
return f"Chyba při vykonávání příkazu:\n{e.output}"
def posli_dotaz_do_assistenta(prompt):
"""Odesílá dotaz v přirozeném jazyce do asistenta a vrací jeho odpověď."""
global thread_id
if thread_id is None:
thread_id = vytvor_nove_vlakno()
openai.beta.threads.messages.create(
thread_id=thread_id,
role="user",
content=prompt
)
run = openai.beta.threads.runs.create(
thread_id=thread_id,
assistant_id=ASSISTANT_ID
)
while True:
run_status = openai.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run.id)
if run_status.status == "completed":
break
time.sleep(1)
messages = openai.beta.threads.messages.list(thread_id=thread_id)
return messages.data[0].content[0].text.value
def posli_prikaz_do_assistenta(command):
"""Odesílá schválený příkaz k vykonání asistentovi a vrací výstup příkazu."""
global thread_id
if thread_id is None:
thread_id = vytvor_nove_vlakno()
run = openai.beta.threads.runs.create(
thread_id=thread_id,
assistant_id=ASSISTANT_ID,
instructions=f"Prosím, spusť tento příkaz: {command}"
)
while True:
run_status = openai.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run.id)
if run_status.status == "requires_action":
tool_calls = run_status.required_action.submit_tool_outputs.tool_calls
tool_outputs = []
for tool_call in tool_calls:
tool_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
if tool_name == "execute_shell_command":
vysledek = spust_prikaz(arguments["command"])
else:
vysledek = "Neznámá funkce."
tool_outputs.append({
"tool_call_id": tool_call.id,
"output": vysledek
})
openai.beta.threads.runs.submit_tool_outputs(
thread_id=thread_id,
run_id=run.id,
tool_outputs=tool_outputs
)
elif run_status.status == "completed":
break
time.sleep(1)
messages = openai.beta.threads.messages.list(thread_id=thread_id)
return messages.data[0].content[0].text.value
def is_command_response(response):
"""Vrací True, pokud odpověď začíná prefixem indikujícím návrh příkazu."""
return response.strip().lower().startswith("navrhovaný příkaz:")
def extract_command(response):
"""Odstraní prefix 'Navrhovaný příkaz:' a vrátí čistý shellový příkaz."""
prefix = "navrhovaný příkaz:"
if response.strip().lower().startswith(prefix):
return response.strip()[len(prefix):].strip()
return response.strip()
def provide_help():
"""Vrací text s nápovědou o funkcích Robovojtíka."""
help_text = (
"Nápověda k Robovojtikovi Linuxový Shell Asistent:\n\n"
"Funkce:\n"
" • Převádí dotazy v přirozeném jazyce na návrhy shellových příkazů.\n"
" • Před spuštěním příkazu vždy čeká na potvrzení od uživatele.\n"
" • Přímé příkazy zadejte s prefixem 'cmd:' (např. 'cmd: ls -la').\n"
" • Pro ukončení Robovojtíka zadejte 'vypni' nebo 'exit'.\n\n"
"Pokud potřebujete další pomoc, zeptejte se!"
)
return help_text
# === 4. Hlavní interaktivní smyčka ===
def main():
print("Linuxový shell s OpenAI Assistant v2 API a funkcemi.")
print("Pro přímý příkaz použij prefix 'cmd:'")
print("Pro ukončení Robovojtíka zadej 'vypni' nebo 'exit'.")
print("Pro nápovědu zadej 'nápověda' nebo 'help'.")
while True:
user_input = input("\nZadej příkaz v přirozeném jazyce: ").strip()
# Ukončení Robovojtíka
if user_input.lower() in ["vypni", "exit"]:
potvrzeni = input("Skutečně chceš ukončit Robovojtíka? (y/n): ").strip().lower()
if potvrzeni == "y":
print("Ukončuji Robovojtíka...")
sys.exit(0)
else:
print("Ukončení zrušeno. Pokračuji.")
continue
# Zobrazení nápovědy
if user_input.lower() in ["nápověda", "help"]:
print("\n" + provide_help())
continue
# Přímý příkaz bez asistenta
if user_input.startswith("cmd:"):
command = user_input[4:].strip()
print(f"Rozpoznán přímý příkaz: {command}")
potvrzeni = input("Spustit tento příkaz? (y/n): ").strip().lower()
if potvrzeni == "y":
vysledek = spust_prikaz(command)
print("\nVýstup příkazu:")
print(vysledek)
else:
print("Příkaz nebyl spuštěn.")
continue
# Dotaz pro asistenta očekává návrh příkazu
assistant_response = posli_dotaz_do_assistenta(user_input)
# Pokud odpověď nevypadá jako návrh příkazu, zobrazíme ji jako informativní odpověď
if not is_command_response(assistant_response):
print("\nRobovojtík odpovídá:")
print(assistant_response)
continue
# Pokud odpověď obsahuje navržený příkaz, vyzveme uživatele k potvrzení
print("\nRobovojtík navrhuje příkaz:")
print(assistant_response)
potvrzeni = input("Spustit tento příkaz? (y/n): ").strip().lower()
if potvrzeni == "y":
command_to_execute = extract_command(assistant_response)
execution_result = posli_prikaz_do_assistenta(command_to_execute)
print("\nVýstup příkazu:")
print(execution_result)
else:
print("Příkaz nebyl spuštěn. Čekám na další vstup.")
if __name__ == "__main__":
main(