Spaces:
Sleeping
Sleeping
import streamlit as st | |
import requests | |
import json | |
# API URL | |
API_URL = "https://startrz-devi.hf.space/api/v1/prediction/e54adffc-ae77-42e5-9fc0-c4584e081093" | |
def safe_get(obj, *keys, default=None): | |
""" | |
Safely navigate through nested dictionaries | |
Args: | |
obj: Starting object | |
*keys: Sequence of keys to navigate | |
default: Value to return if navigation fails | |
Returns: | |
Value at the specified path or default | |
""" | |
try: | |
for key in keys: | |
obj = obj[key] | |
return obj | |
except (TypeError, KeyError, IndexError): | |
return default | |
def parse_text_content(data): | |
""" | |
Parse text content from the API response | |
Args: | |
data (dict): Full API response | |
Returns: | |
dict: Parsed text content with title and content | |
""" | |
try: | |
# Try to parse the text field as JSON | |
text_content = json.loads(safe_get(data, "text", default="{}")) | |
return { | |
"title": text_content.get("title", "No Title Available"), | |
"content": text_content.get("content", "No Content Available"), | |
"outline": text_content.get("outline", []) | |
} | |
except (json.JSONDecodeError, TypeError): | |
# Fallback if parsing fails | |
return { | |
"title": "Analysis Result", | |
"content": safe_get(data, "text", default="No content available"), | |
"outline": [] | |
} | |
def parse_tool_details(tool): | |
""" | |
Parse tool details with robust handling of different input types | |
Args: | |
tool (dict): A single tool dictionary from the API response | |
Returns: | |
dict: Parsed tool details with consistent structure | |
""" | |
# Ensure tool is a dictionary | |
if not isinstance(tool, dict): | |
return { | |
"tool": "Unknown Tool", | |
"toolInput": "Invalid tool data", | |
"toolOutput": "No output available" | |
} | |
# Parse toolInput | |
input_value = "" | |
tool_input = tool.get("toolInput", {}) | |
if isinstance(tool_input, dict): | |
input_value = tool_input.get("input", "") | |
# Fallback to full input dict as string if no 'input' key | |
if not input_value: | |
try: | |
input_value = json.dumps(tool_input, indent=2) | |
except Exception: | |
input_value = str(tool_input) | |
elif isinstance(tool_input, str): | |
input_value = tool_input | |
else: | |
input_value = str(tool_input) if tool_input is not None else "No input details" | |
# Parse toolOutput | |
output_value = tool.get("toolOutput") | |
# Flexible output handling | |
if output_value is None: | |
output_value = "No output available" | |
elif isinstance(output_value, (list, dict)): | |
# Convert to formatted JSON string for better readability | |
try: | |
output_value = json.dumps(output_value, indent=2) | |
except Exception: | |
output_value = str(output_value) | |
else: | |
# Convert to string for any other type | |
output_value = str(output_value) | |
return { | |
"tool": tool.get("tool", "Unknown Tool"), | |
"toolInput": input_value, | |
"toolOutput": output_value | |
} | |
def query(payload): | |
""" | |
Query the API and process the response | |
Args: | |
payload (dict): Question payload to send to the API | |
Returns: | |
dict: Processed response with tool details | |
""" | |
try: | |
# Send POST request to the API | |
response = requests.post(API_URL, json=payload) | |
response.raise_for_status() | |
# Parse the JSON response | |
data = response.json() | |
# Extract text content | |
text_content = parse_text_content(data) | |
# Extract tool details | |
tool_details = [] | |
# Handle different potential response structures | |
agent_reasoning = safe_get(data, "agentReasoning", default=[]) | |
for reasoning in agent_reasoning: | |
# Safely extract used tools | |
used_tools = safe_get(reasoning, "usedTools", default=[]) | |
for tool in used_tools: | |
if tool is not None: | |
parsed_tool = parse_tool_details(tool) | |
tool_details.append(parsed_tool) | |
return { | |
"raw_response": data, | |
"text_content": text_content, | |
"tool_details": tool_details | |
} | |
except requests.exceptions.RequestException as e: | |
return {"error": f"API Request Error: {str(e)}"} | |
except json.JSONDecodeError as e: | |
return {"error": f"JSON Parsing Error: {str(e)}"} | |
except Exception as e: | |
return {"error": f"Unexpected Error: {str(e)}"} | |
def display_outline(outline): | |
""" | |
Display the document outline in an expandable section | |
Args: | |
outline (list): List of outline sections | |
""" | |
if not outline: | |
return | |
with st.expander("π Document Outline"): | |
for section in outline: | |
st.markdown(f"### {section.get('section_title', 'Untitled Section')}") | |
key_points = section.get('key_points', []) | |
for point in key_points: | |
st.markdown(f"- {point}") | |
def main(): | |
""" | |
Main Streamlit application function | |
""" | |
st.set_page_config( | |
page_title="DEVI Research Assistant", | |
page_icon="π", | |
layout="wide" | |
) | |
st.title("π¬ DEVI RESEARCH ASSISTANT") | |
st.write("Explore insights by asking a research question!") | |
# User input section | |
user_input = st.text_input( | |
"What would you like to research?", | |
placeholder="Enter your research query here..." | |
) | |
# Submit button | |
if st.button("Explore Insights", type="primary"): | |
if user_input: | |
# Progress spinner during API call | |
with st.spinner("Gathering research insights..."): | |
response = query({"question": user_input}) | |
# Error handling | |
if "error" in response: | |
st.error(response["error"]) | |
return | |
# Display Text Content | |
st.header("π Research Insights") | |
# Extract text content | |
text_content = response.get("text_content", {}) | |
# Display Title | |
st.subheader(text_content.get("title", "Research Analysis")) | |
# Display Content | |
st.write(text_content.get("content", "No content available")) | |
# Display Outline | |
display_outline(text_content.get("outline", [])) | |
# Display Online Resources | |
st.header("π Online Resources") | |
tool_details = response.get("tool_details", []) | |
if tool_details: | |
# Create tabs for each resource | |
tabs = st.tabs([ | |
f"{idx+1}. {tool.get('tool', 'Unknown')}" | |
for idx, tool in enumerate(tool_details) | |
]) | |
# Populate each tab with resource details | |
for idx, (tool, tab) in enumerate(zip(tool_details, tabs)): | |
with tab: | |
st.subheader("Research Name") | |
st.code(tool.get('toolInput', 'No input'), language=None) | |
st.subheader("Research Findings") | |
# Use st.code for better formatting | |
st.code(tool.get('toolOutput', 'No output'), language=None) | |
else: | |
st.info("No resources found for this query.") | |
# Raw response in expander for advanced users | |
with st.expander("π Advanced: Full API Response"): | |
st.json(response.get("raw_response", {})) | |
else: | |
st.warning("Please enter a research question!") | |
if __name__ == "__main__": | |
main() |