Explain Java¶
import streamlit as st
from openai import OpenAI
import os
import re
import pyperclip
from typing import Tuple
import json
from collections import defaultdict
import tiktoken
st.set_page_config(
page_title="Explain Java",
layout="wide",
)
Prints a stylized banner to the console when the application starts.
@st.cache_data
def print_banner():
print("""
▗▞▀▚▖▄ ▄ ▄▄▄▄ █ ▗▞▀▜▌▄ ▄▄▄▄ ▗▖▗▞▀▜▌▄ ▄ ▗▞▀▜▌
▐▛▀▀▘ ▀▄▀ █ █ █ ▝▚▄▟▌▄ █ █ ▄▄ ▗▖▝▚▄▟▌█ █ ▝▚▄▟▌
▝▚▄▄▖▄▀ ▀▄ █▄▄▄▀ █ █ █ █ ▄ ▐▌ ▀▄▀
█ █ █ ▀▄▄▞▘
▀
""")
return 1
print_banner()
Print current folder name as a title
current_folder = os.path.basename(os.getcwd())
st.write(f"### {current_folder}")
overwrite_files = st.toggle("Overwrite files")
st.write("---")
Save Java class
base_dir = 'src'
def dir_path(package_name: str) -> str:
# Build directory path
if package_name:
package_path = package_name.replace('.', os.sep)
dir_path = os.path.join(base_dir, package_path)
else:
dir_path = base_dir
return dir_path
def save_java_class(java_code: str, overwrite: bool) -> Tuple[str, str]:
# Extract package name
package_match = re.search(r'^\s*package\s+([\w\.]+)\s*;', java_code, re.MULTILINE)
package_name = package_match.group(1) if package_match else None
# Extract class name (public class, interface, or enum)
class_match = re.search(r'^\s*(public\s+)?(class|interface|enum)\s+(\w+)', java_code, re.MULTILINE)
class_name = class_match.group(3) if class_match else None
if not class_name:
raise ValueError("Could not find class name in the provided Java code.")
# Build directory path
d_path = dir_path(package_name)
# Ensure directory exists
os.makedirs(d_path, exist_ok=True)
# File path
file_path = os.path.join(d_path, f"{class_name}.java")
if (os.path.exists(file_path) and not overwrite):
st.toast(f"File exists: {file_path}")
return None, None
# Save the file
with open(file_path, 'w', encoding='utf-8') as f:
f.write(java_code)
st.toast(f"Saved {class_name}.java in {d_path}")
return package_name, class_name
Load existing classes from json file
package_names: list[str] = []
class_names = []
classes_by_package = defaultdict(list)
classes_by_package_json = "classes_by_package.json"
def save_classes_by_package():
with open(classes_by_package_json, 'w') as f:
# Convert defaultdict to dict before saving
json.dump(dict(classes_by_package), f)
def load_classes_by_package():
with open(classes_by_package_json, 'r') as f:
data = json.load(f)
# Convert dict back to defaultdict(list)
return defaultdict(list, data)
try:
classes_by_package = load_classes_by_package()
except Exception as e:
st.warning(f"There are no Java files to explain. Please paste one.")
Select package, class and method
col1c, col2c, col3c = st.columns(3)
with col1c:
package_names = list(classes_by_package.keys())
package_name = st.selectbox("Package", package_names)
with col2c:
class_names = classes_by_package[package_name]
class_name = st.selectbox("Class", class_names)
with col3c:
method_name = st.text_input("Method")
Get java code from clipboard and save it to file
def paste_java():
java_code = pyperclip.paste()
try:
package_name, class_name = save_java_class(java_code, overwrite=overwrite_files)
except ValueError as e:
st.toast(e)
return
classes_by_package[package_name].append(class_name)
save_classes_by_package()
Load Java code
def load_java_code(package_name: str, class_name: str):
# File path
file_path = os.path.join(dir_path(package_name), f"{class_name}.java")
with open(file_path, 'r', encoding='utf-8') as file:
java_code = file.read()
return java_code
try:
java_code = load_java_code(package_name, class_name)
except Exception as e:
java_code = ""
Load and save markdown result of LLM prompt
def load_markdown(package_name: str, class_name: str, method_name: str):
method_suffix = f"-{method_name}" if method_name else ""
file_path = os.path.join(dir_path(package_name), f"{class_name}{method_suffix}.md")
with open(file_path, 'r', encoding='utf-8') as file:
markdown = file.read()
return markdown
def save_markdown(package_name: str, class_name: str, method_name: str, markdown: str, overwrite: bool):
d_path = dir_path(package_name)
method_suffix = f"-{method_name}" if method_name else ""
file_path = os.path.join(d_path, f"{class_name}{method_suffix}.md")
if (os.path.exists(file_path) and not overwrite):
st.toast(f"File exists: {file_path}")
return None, None
# Save the file
with open(file_path, 'w', encoding='utf-8') as f:
f.write(markdown)
st.toast(f"Saved {class_name}.md in {d_path}")
Select LLM¶
llm_prices = {
"gemma-3-27b-it": 0.0,
"gemini-2.0-flash": 0.0,
"gpt-4.1-mini": 0.4,
"gpt-4.1-nano": 0.1,
"gpt-4.1": 2.0,
"gpt-4o-mini": 0.15,
"o4-mini": 1.10,
"o3-mini": 1.10,
"gpt-4o": 2.5,
"o1": 15.0,
}
llm_models = list(llm_prices.keys())
Explain Java
explain_prompt = "Explain Java code you are provided."
explain_method_prompt = f"Explain method `{method_name}` in Java code you are provided."
OpenAI client
client = OpenAI()
llm_temperature = 0.1
Google client
g_key = os.getenv("GEMINI_API_KEY")
g_client = OpenAI(
api_key=g_key,
base_url="https://generativelanguage.googleapis.com/v1beta/openai/"
)
Calling different LLMs
def call_o_model(prompt, text):
messages = [
{"role": "developer", "content": prompt},
{"role": "user", "content": text},
]
response = client.chat.completions.create(
model=llm_model,
messages=messages,
)
return response.choices[0]
def call_gpt(prompt, text):
messages = [
{"role": "developer", "content": prompt},
{"role": "user", "content": text},
]
response = client.chat.completions.create(
model=llm_model,
messages=messages,
temperature=llm_temperature,
)
return response.choices[0]
def call_gemini(prompt, text):
messages = [
{"role": "developer", "content": prompt},
{"role": "user", "content": text},
]
response = g_client.chat.completions.create(
model=llm_model,
messages=messages,
temperature=llm_temperature,
)
return response.choices[0]
def call_gemma(prompt, text):
g_client = OpenAI(
api_key=g_key,
base_url="https://generativelanguage.googleapis.com/v1beta/openai/"
)
messages = [
{"role": "user", "content": f"<instructions>{prompt}</instructions>\n<user_input>{text}</user_input>"},
{"role": "user", "content": text},
]
response = g_client.chat.completions.create(
model=llm_model,
messages=messages,
temperature=llm_temperature,
)
return response.choices[0]
def call_llm(prompt, text):
if llm_model.startswith("gemini"):
response = call_gemini(prompt, text)
elif llm_model.startswith("gemma"):
response = call_gemma(prompt, text)
elif llm_model.startswith("gpt"):
response = call_gpt(prompt, text)
elif llm_model.startswith("o"):
response = call_o_model(prompt, text)
else:
st.error(f"Unknown model: {llm_model}")
st.stop()
return response
Get response from LLM and save it to file
def explain(package_name, class_name, java_code):
global method_name
method_name = method_name.strip()
if len(method_name) > 0:
response = call_llm(explain_method_prompt, java_code)
else:
response = call_llm(explain_prompt, java_code)
markdown = response.message.content
try:
save_markdown(package_name, class_name, method_name, markdown, overwrite=overwrite_files)
except ValueError as e:
st.toast(e)
Buttons to “Paste” and “Explain”
col1b, col2b, col3b = st.columns(3)
with col1b:
if st.button(":clipboard: Paste", use_container_width=True):
paste_java()
with col2b:
llm_model = st.selectbox("LLM Model", llm_models, label_visibility="collapsed")
llm_model_tiktoken = "gpt-4o-mini"
encoding = tiktoken.encoding_for_model(llm_model_tiktoken)
tokens = encoding.encode(java_code)
cents = round(len(tokens) * llm_prices[llm_model]/10000, 5)
st.write(f'**Tokens:** {len(tokens)}, **Cents:** {cents}')
with col3b:
if st.button(":exclamation: Explain", use_container_width=True):
explain(package_name, class_name, java_code)
Original java file and LLM explanation
col1j, col2j = st.columns(2)
with col1j:
if len(java_code) > 0:
st.write(f"```java\n{java_code}\n```\n")
with col2j:
try:
markdown = load_markdown(package_name, class_name, method_name)
st.write(markdown)
except Exception as e:
pass