Skip to content

Commit 645f3d8

Browse files
[python] support shiny apps
1 parent b9a1c22 commit 645f3d8

File tree

5 files changed

+97
-25
lines changed

5 files changed

+97
-25
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Changelog
22

3-
## 2.8.12
3+
## 2.8.14
4+
5+
- Support describing app.R files
6+
7+
## 2.8.13
48

59
- Fix edit link to stl, obj, gltf and step files
610

apps/hal9/app.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from tools.hal9 import answer_hal9_questions_description, answer_hal9_questions
77
from tools.text_agent import analyze_text_file_description, analyze_text_file
88
from tools.streamlit import streamlit_generator, streamlit_generator_description
9+
from tools.shiny import shiny_generator, shiny_generator_description
910
from tools.fastapi import fastapi_generator, fastapi_generator_description
1011
from tools.other_tools import final_response_description, final_response
1112
from tools.python_execution import python_execution_description ,python_execution
@@ -14,8 +15,8 @@
1415
messages = load_messages()
1516

1617
# load tools
17-
tools_descriptions = [python_execution_description, final_response_description, solve_math_problem_description, answer_generic_question_description, analyze_csv_description, images_management_system_description, answer_hal9_questions_description, analyze_text_file_description, fastapi_generator_description, streamlit_generator_description]
18-
tools_functions = [python_execution, final_response, solve_math_problem, answer_generic_question, analyze_csv, images_management_system, answer_hal9_questions, analyze_text_file, fastapi_generator, streamlit_generator]
18+
tools_descriptions = [python_execution_description, final_response_description, solve_math_problem_description, answer_generic_question_description, analyze_csv_description, images_management_system_description, answer_hal9_questions_description, analyze_text_file_description, fastapi_generator_description, streamlit_generator_description, shiny_generator_description]
19+
tools_functions = [python_execution, final_response, solve_math_problem, answer_generic_question, analyze_csv, images_management_system, answer_hal9_questions, analyze_text_file, fastapi_generator, streamlit_generator, shiny_generator]
1920

2021
if len(messages) < 1:
2122
messages = insert_message(messages, "system", "You are Hal9, a helpful and highly capable AI assistant. Your primary responsibility is to analyze user questions and select the most appropriate tool to provide precise, relevant, and actionable responses. Always prioritize using the right tool to ensure efficiency and clarity in your answers. If a tool is needed, follow these steps: 1. Identify the best tool for the task. 2. Execute the tool and process its response. 3. If the tool provides a valid result, return it to the user. 4. If the tool fails, do NOT retry with the same tool. Instead, explain the failure and suggest improvements in the prompt or alternative approaches.")

apps/hal9/tools/shiny.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from utils import generate_response, load_messages, insert_message, extract_code_block, save_messages
2+
import os
3+
import traceback
4+
from clients import openai_client
5+
6+
def debug_code(python_code):
7+
try:
8+
exec(python_code)
9+
return "About to show your app...", "", ""
10+
except Exception as e:
11+
tb = traceback.format_exc()
12+
relevant_error_info = tb.splitlines()
13+
last_line = relevant_error_info[-1]
14+
complete_traceback="\n".join(relevant_error_info)
15+
return "App fails to run", last_line, complete_traceback
16+
17+
def save_shiny_code(code):
18+
directory = "./.storage/app.R"
19+
# Ensure the target directory exists
20+
if not os.path.exists(directory):
21+
os.makedirs(directory)
22+
23+
# Write the code to the app.R file
24+
python_file_path = os.path.join(directory, "app.R")
25+
with open(python_file_path, 'w') as file:
26+
file.write(code)
27+
28+
def shiny_generator(prompt):
29+
# load messages
30+
messages = load_messages(file_path="./.storage/.shiny_messages.json")
31+
32+
if len(messages) < 1:
33+
messages = insert_message(messages, "system", f"""This is a R Shiny generator system that automates the creation of R shiny apps based on user prompts. It interprets natural language queries, and the response is an complete python script with the including imports for a interactive R Shiny app, return the code as fenced code block with triple backticks (```) as ```python```""")
34+
messages = insert_message(messages, "user", f"Generates an app that fullfills this user request -> {prompt}")
35+
model_response = generate_response("openai", "gpt-4-turbo", messages)
36+
response_content = model_response.choices[0].message.content
37+
shiny_code = extract_code_block(response_content, "python")
38+
39+
save_shiny_code(shiny_code)
40+
messages = insert_message(messages, "assistant", shiny_code)
41+
save_messages(messages, file_path="./.storage/.shiny_messages.json")
42+
return "About to show your app..."
43+
44+
shiny_generator_description = {
45+
"type": "function",
46+
"function": {
47+
"name": "shiny_generator",
48+
"description": "Generates a complete R Shiny app based on user-provided natural language prompts. It automates the creation of interactive applications that requires interactions (This tool do not interact with files uploaded)",
49+
"strict": True,
50+
"parameters": {
51+
"type": "object",
52+
"properties": {
53+
"prompt": {
54+
"type": "string",
55+
"description": "A detailed natural language description of the desired R Shiny app, including specific requirements or features to implement.",
56+
}
57+
},
58+
"required": ["prompt"],
59+
"additionalProperties": False,
60+
},
61+
}
62+
}

python/hal9/describe.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
11
import os
22

3+
type_checks = {
4+
'fastapi': {
5+
'files': ['app.py', 'main.py'],
6+
'contents': ['import FastAPI', 'import Flask']
7+
},
8+
'shiny': {
9+
'files': ['app.R'],
10+
'contents': ['library(shiny)']
11+
}
12+
}
13+
314
def describe_content(target_path):
415
result = {'type': ''}
5-
6-
if os.path.isfile(target_path) and target_path.endswith('.py'):
7-
python_files = [os.path.basename(target_path)]
8-
folder = os.path.dirname(target_path) or '.'
16+
17+
if os.path.isfile(target_path):
18+
all_files = [target_path]
19+
elif os.path.isdir(target_path):
20+
all_files = os.listdir(target_path)
921
else:
10-
folder = target_path
11-
python_files = [f for f in os.listdir(folder) if f.endswith('.py')]
12-
13-
target_file = None
14-
15-
if 'app.py' in python_files:
16-
target_file = 'app.py'
17-
elif 'main.py' in python_files:
18-
target_file = 'main.py'
19-
elif len(python_files) == 1:
20-
target_file = python_files[0]
21-
22-
if target_file:
23-
with open(os.path.join(folder, target_file), 'r', encoding='utf-8') as file:
24-
content = file.read()
25-
if 'import FastAPI' in content or 'import Flask' in content:
26-
result['type'] = 'fastapi'
22+
return result
2723

24+
for type_name, criteria in type_checks.items():
25+
for target_file in criteria['files']:
26+
if target_file in all_files:
27+
with open(os.path.join(target_path, target_file), 'r', encoding='utf-8') as file:
28+
content = file.read()
29+
if any(keyword in content for keyword in criteria['contents']):
30+
result['type'] = type_name
31+
break
32+
2833
return result

python/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "hal9"
3-
version = "2.8.13"
3+
version = "2.8.14"
44
description = ""
55
authors = ["Javier Luraschi <javier@hal9.ai>"]
66
readme = "README.md"

0 commit comments

Comments
 (0)