Spaces:
Runtime error
Runtime error
File size: 6,764 Bytes
6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff 36ca333 6a263ff | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | import pandas as pd
import requests
from bs4 import BeautifulSoup
import re
from sentence_transformers import SentenceTransformer, util
from huggingface_hub import InferenceClient
import gradio as gr
import os
print("π Loading Script Intelligence Engine...")
fallback_script = """
[ Scene starts in FBI facility ]
RESSLER: Heβs demanding to speak with you.
ELIZABETH: Me? Why me? I don't know him.
RESSLER: We don't know why. But we need to hear what he has to say.
[ Elizabeth walks into the interrogation room ]
REDDINGTON: You got rid of your highlights. You look much less... Baltimore.
ELIZABETH: You asked to see me. Why?
REDDINGTON: I'm a criminal, Lizzie. You're a profiler. You tell me.
ELIZABETH: I think you're bored. I think you're using us.
REDDINGTON: I'm going to make you famous. I have a list.
REDDINGTON: A blacklist of the worst criminals in the world.
REDDINGTON: Starting with Ranko Zamani.
REDDINGTON: He is in town, Lizzie.
REDDINGTON: And he plans to kidnap the general's daughter.
"""
url = "https://subslikescript.com/series/The_Blacklist-2741602/season-1/episode-1-Pilot"
headers = {'User-Agent': 'Mozilla/5.0'}
try:
response = requests.get(url, headers=headers, timeout=8)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
script_div = soup.find('div', class_='full-script')
raw_text = script_div.get_text(separator="\n") if script_div else fallback_script
print("β
Live script loaded")
except Exception as e:
print(f"β οΈ Scrape blocked: {e}")
raw_text = fallback_script
print("π§ Processing unstructured data...")
lines = raw_text.split("\n")
structured_data = []
dialogue_pattern = re.compile(r"^([A-Z\s]+):\s*(.*)")
for line in lines:
line = line.strip()
if not line:
continue
match = dialogue_pattern.match(line)
if match:
structured_data.append({
"Character": match.group(1).strip(),
"Dialogue": match.group(2).strip()
})
df = pd.DataFrame(structured_data)
df["Full_Line"] = df["Character"] + ": " + df["Dialogue"]
window_size = 1
context_chunks = []
for i in range(len(df)):
start = max(0, i - window_size)
end = min(len(df), i + window_size + 1)
chunk = "\n".join(df["Full_Line"].iloc[start:end])
context_chunks.append({
"context_block": chunk
})
ai_df = pd.DataFrame(context_chunks)
print("β‘ Loading embedding model...")
model = SentenceTransformer("all-MiniLM-L6-v2")
vector_database = model.encode(ai_df["context_block"].tolist())
hf_token = os.environ.get("HF_TOKEN")
client = InferenceClient(model="meta-llama/Meta-Llama-3-8B-Instruct", token=hf_token)
def search_script(user_query, history):
if not user_query.strip():
return history, ""
try:
query_vector = model.encode(user_query)
hits = util.semantic_search(query_vector, vector_database, top_k=2)
retrieved_contexts = [
ai_df["context_block"].iloc[hit["corpus_id"]]
for hit in hits[0]
]
combined_context = "\n\nββββββββββββββ\n\n".join(retrieved_contexts)
messages = [
{
"role": "system",
"content": "You are an expert TV Script Analyst AI.\n\nRules:\n- Answer ONLY from provided excerpts\n- Never invent lore\n- Explain naturally\n- Be concise and smart"
},
{
"role": "user",
"content": f"Question:\n{user_query}\n\nScript Excerpts:\n{combined_context}"
}
]
response = client.chat.completions.create(
messages=messages,
max_tokens=220,
temperature=0.25
)
ai_answer = response.choices[0].message.content.strip()
except Exception as e:
ai_answer = f"β Error: {str(e)}"
combined_context = "No context retrieved."
formatted_response = f"## π€ AI Analysis\n\n{ai_answer}\n\n---\n\n### π Retrieved Script Context\n\n```text\n{combined_context}\n```\n"
history.append({"role": "user", "content": user_query})
history.append({"role": "assistant", "content": formatted_response})
return history, ""
custom_css = """
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700&family=Inter:wght@300;400;500;600&display=swap');
body { background: #050816 !important; }
.gradio-container { background: radial-gradient(circle at top left, #101935 0%, #050816 60%, #02030a 100%) !important; color: white !important; font-family: 'Inter', sans-serif; }
.main-title { text-align: center; font-size: 42px; font-family: 'Orbitron', sans-serif; font-weight: 700; background: linear-gradient(90deg, #00eaff, #6f8cff, #00eaff); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-shadow: 0 0 10px #00eaff, 0 0 20px #00eaff; }
.subtitle { text-align: center; color: #9ab0ff; font-size: 17px; margin-top: -10px; margin-bottom: 25px; }
.glass-chat { border-radius: 24px !important; background: rgba(255,255,255,0.06) !important; border: 1px solid rgba(255,255,255,0.08) !important; backdrop-filter: blur(20px); box-shadow: 0 0 35px rgba(0,255,255,0.12); }
textarea { background: rgba(255,255,255,0.06) !important; color: white !important; border-radius: 18px !important; border: 1px solid rgba(0,255,255,0.2) !important; box-shadow: 0 0 15px rgba(0,255,255,0.1); }
button { background: linear-gradient(135deg, #00d9ff, #6b63ff) !important; border: none !important; border-radius: 16px !important; color: white !important; font-weight: bold !important; box-shadow: 0 0 20px rgba(0,217,255,0.5) !important; transition: all 0.3s ease !important; }
button:hover { transform: scale(1.04); }
footer { display: none !important; }
"""
with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
gr.HTML("""
<div class="main-title">AI Narrative Intelligence Engine</div>
<div class="subtitle">Semantic Retrieval + LLM Reasoning on Unstructured TV Dialogue</div>
""")
chatbot = gr.Chatbot(type="messages", height=600, elem_classes="glass-chat")
with gr.Row():
user_input = gr.Textbox(placeholder="Ask anything about the script...", lines=2, scale=8)
send_btn = gr.Button("π Analyze", scale=1)
gr.Examples(
examples=[
["Who is Ranko Zamani?"],
["Why does Reddington want Elizabeth?"],
["What is the blacklist?"],
["What is Reddington offering?"]
],
inputs=user_input
)
send_btn.click(fn=search_script, inputs=[user_input, chatbot], outputs=[chatbot, user_input])
user_input.submit(fn=search_script, inputs=[user_input, chatbot], outputs=[chatbot, user_input])
demo.launch() |