SlouchyBuffalo's picture
Create app.py
5948255 verified
import gradio as gr
import requests
from huggingface_hub import InferenceClient
import spaces
from citation_validator import validate_citation, format_authors
# Create icons on startup
try:
import subprocess
subprocess.run(['python', 'create_icons.py'], check=True)
print("Icons created successfully")
except Exception as e:
print(f"Could not create icons: {e}")
# Initialize Llama 4 client with Cerebras provider
model_id = "meta-llama/Llama-4-Scout-17B-16E-Instruct"
# Use Cerebras as the inference provider
client = InferenceClient(model=model_id, provider="cerebras")
def search_crossref(query):
"""Search Crossref API for publication metadata"""
try:
# Check if input is a DOI
if query.startswith('10.'):
url = f"https://api.crossref.org/works/{query}"
else:
# Search by title/author
url = f"https://api.crossref.org/works?query={query}&rows=1"
response = requests.get(url, headers={'User-Agent': 'CitationTool/1.0 (mailto:your-email@example.com)'})
if response.status_code == 200:
data = response.json()
if 'message' in data:
if 'items' in data['message']:
return data['message']['items'][0] if data['message']['items'] else None
else:
return data['message']
return None
except Exception as e:
print(f"Crossref API error: {e}")
return None
def generate_intext_citation(crossref_data, citation_style, page_numbers=""):
"""Generate in-text citation from Crossref data"""
if not crossref_data:
return None
work = crossref_data
authors = work.get('author', [])
year = work.get('published-print', {}).get('date-parts', [[None]])[0][0] or \
work.get('published-online', {}).get('date-parts', [[None]])[0][0]
if citation_style == "APA7":
if len(authors) == 0:
return f"(Unknown Author, {year or 'n.d.'}{', p. ' + page_numbers if page_numbers else ''})"
elif len(authors) == 1:
author_name = authors[0].get('family', 'Unknown')
return f"({author_name}, {year or 'n.d.'}{', p. ' + page_numbers if page_numbers else ''})"
elif len(authors) == 2:
author1 = authors[0].get('family', 'Unknown')
author2 = authors[1].get('family', 'Unknown')
return f"({author1} & {author2}, {year or 'n.d.'}{', p. ' + page_numbers if page_numbers else ''})"
else:
author_name = authors[0].get('family', 'Unknown')
return f"({author_name} et al., {year or 'n.d.'}{', p. ' + page_numbers if page_numbers else ''})"
elif citation_style == "Chicago":
if len(authors) == 0:
title = work.get('title', ['Unknown Title'])[0]
short_title = title.split(':')[0][:30] + "..." if len(title) > 30 else title
return f"({short_title}, {year or 'n.d.'}{', ' + page_numbers if page_numbers else ''})"
elif len(authors) == 1:
author_name = authors[0].get('family', 'Unknown')
return f"({author_name}, {year or 'n.d.'}{', ' + page_numbers if page_numbers else ''})"
else:
author_name = authors[0].get('family', 'Unknown')
return f"({author_name} et al., {year or 'n.d.'}{', ' + page_numbers if page_numbers else ''})"
elif citation_style == "MLA":
if len(authors) == 0:
return f"(Unknown Author{' ' + page_numbers if page_numbers else ''})"
elif len(authors) == 1:
author_name = authors[0].get('family', 'Unknown')
return f"({author_name}{' ' + page_numbers if page_numbers else ''})"
elif len(authors) == 2:
author1 = authors[0].get('family', 'Unknown')
author2 = authors[1].get('family', 'Unknown')
return f"({author1} and {author2}{' ' + page_numbers if page_numbers else ''})"
else:
author_name = authors[0].get('family', 'Unknown')
return f"({author_name} et al.{' ' + page_numbers if page_numbers else ''})"
@spaces.GPU
def generate_citation(input_text, citation_style, citation_type, page_numbers=""):
if not input_text.strip():
return "Please enter some text to generate a citation."
# First, try to get structured data from Crossref
crossref_data = search_crossref(input_text)
# Generate in-text citation if requested
if citation_type == "In-Text Citation" and crossref_data:
intext = generate_intext_citation(crossref_data, citation_style, page_numbers)
if intext:
return intext + "\n✅ In-text citation generated"
# Prepare the prompt for Llama 4 for full citations
if crossref_data:
# Extract and format key information from Crossref
work = crossref_data
authors = format_authors(work.get('author', []))
title = work.get('title', [''])[0] if work.get('title') else ''
journal = work.get('container-title', [''])[0] if work.get('container-title') else ''
year = work.get('published-print', {}).get('date-parts', [[None]])[0][0] or \
work.get('published-online', {}).get('date-parts', [[None]])[0][0]
doi = work.get('DOI', '')
if citation_type == "In-Text Citation":
if citation_style == "MLA":
prompt = f"""Create an MLA in-text citation using this data:
Authors: {authors}
Page numbers: {page_numbers}
Generate only the in-text citation (e.g., (Author page) or (Author and Author page))."""
else:
prompt = f"""Create a {citation_style} in-text citation using this data:
Authors: {authors}
Year: {year}
Page numbers: {page_numbers}
Generate only the in-text citation (e.g., (Author, Year) or (Author, Year, p. X))."""
else:
prompt = f"""Create a perfect {citation_style} full reference citation using this verified publication data:
Authors: {authors}
Title: {title}
Journal/Publication: {journal}
Year: {year}
DOI: {doi}
Format this as a complete, properly formatted {citation_style} reference citation following all style guidelines exactly."""
else:
if citation_type == "In-Text Citation":
prompt = f"""Create a {citation_style} in-text citation from this information: {input_text}
Page numbers: {page_numbers}
Generate only the in-text citation format. Follow {citation_style} guidelines exactly."""
else:
prompt = f"""Create a {citation_style} full reference citation from this information: {input_text}
Follow {citation_style} formatting guidelines exactly. If information is missing, use appropriate placeholders like [Author] or [Year]."""
try:
# Use conversational approach with Cerebras
messages = [{"role": "user", "content": prompt}]
response = client.chat_completion(
messages=messages,
max_tokens=500,
temperature=0.1
)
# Extract the citation from the response
citation = response.choices[0].message.content
# Validate the generated citation
errors = validate_citation(citation, citation_style)
if errors:
warning = "\n⚠️ Validation warnings:\n" + "\n".join(f"• {error}" for error in errors)
return citation + warning
else:
return citation + "\n✅ Citation validated"
except Exception as e:
return f"Error generating citation: {str(e)}"
# Create Gradio interface
with gr.Blocks(title="Citation Tool PWA") as app:
gr.Markdown("# 📚 Citation Generation Tool")
gr.Markdown("*AI-powered citations for APA7, Chicago, and MLA styles*")
with gr.Row():
with gr.Column():
input_text = gr.Textbox(
label="Enter DOI, title, or citation information",
placeholder="e.g., 10.1038/nature12373 or 'The Structure of Scientific Revolutions'",
lines=3
)
with gr.Row():
citation_style = gr.Dropdown(
choices=["APA7", "Chicago", "MLA"],
value="APA7",
label="Citation Style"
)
citation_type = gr.Dropdown(
choices=["Full Citation", "In-Text Citation"],
value="Full Citation",
label="Citation Type"
)
page_numbers = gr.Textbox(
label="Page numbers (for in-text citations)",
placeholder="e.g., 15-20 or 42",
visible=False
)
generate_btn = gr.Button("Generate Citation", variant="primary")
with gr.Row():
output = gr.Textbox(
label="Generated Citation",
lines=5,
interactive=False
)
# Example section
gr.Markdown("### Examples:")
gr.Markdown("- **DOI**: `10.1038/nature12373`")
gr.Markdown("- **Title**: `The Structure of Scientific Revolutions`")
gr.Markdown("- **Author + Title**: `Kuhn Scientific Revolutions`")
# Show/hide page numbers based on citation type
def toggle_page_numbers(citation_type):
return gr.update(visible=(citation_type == "In-Text Citation"))
citation_type.change(
toggle_page_numbers,
inputs=[citation_type],
outputs=[page_numbers]
)
generate_btn.click(
generate_citation,
inputs=[input_text, citation_style, citation_type, page_numbers],
outputs=output
)
if __name__ == "__main__":
app.launch()