|
|
import streamlit as st |
|
|
import openai |
|
|
import re |
|
|
from duckduckgo_search import DDGS |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def search_tool(query: str): |
|
|
"""A web search tool that uses DuckDuckGo to find information.""" |
|
|
st.write(f"🔎 Web'de aranıyor: `{query}`") |
|
|
try: |
|
|
with DDGS() as ddgs: |
|
|
results = [r for r in ddgs.text(query, max_results=5)] |
|
|
return "\n".join(results) if results else "Aramada sonuç bulunamadı." |
|
|
except Exception as e: |
|
|
return f"Arama sırasında bir hata oluştu: {e}" |
|
|
|
|
|
def calculator_tool(expression: str): |
|
|
"""A calculator tool that evaluates a mathematical expression.""" |
|
|
st.write(f"🧮 Hesaplama yapılıyor: `{expression}`") |
|
|
try: |
|
|
|
|
|
if not re.match(r"^[0-9+\-*/.() \t]+$", expression): |
|
|
return "Geçersiz karakterler içerdiği için hesaplama yapılamadı." |
|
|
result = eval(expression) |
|
|
return f"Sonuç: {result}" |
|
|
except Exception as e: |
|
|
return f"Hesaplama hatası: {e}" |
|
|
|
|
|
|
|
|
|
|
|
def call_llm(prompt, api_key): |
|
|
"""Calls the OpenAI API to get the agent's next thought and action.""" |
|
|
openai.api_key = api_key |
|
|
try: |
|
|
response = openai.chat.completions.create( |
|
|
model="gpt-4o", |
|
|
messages=[{"role": "user", "content": prompt}], |
|
|
temperature=0.0, |
|
|
max_tokens=500, |
|
|
) |
|
|
return response.choices[0].message.content |
|
|
except Exception as e: |
|
|
st.error(f"OpenAI API çağrısı sırasında hata: {e}") |
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
def run_agent_loop(goal, api_key): |
|
|
"""Runs the main ReAct (Reason-Act) agent loop.""" |
|
|
|
|
|
|
|
|
system_prompt_template = f""" |
|
|
Sen, bir amaca ulaşmak için adım adım düşünen ve araçları kullanan bir AI ajanısın. |
|
|
Her adımda, amacına yönelik bir 'Düşünce' ve bu düşünceyi hayata geçirecek bir 'Eylem' üretmelisin. |
|
|
|
|
|
Kullanabileceğin araçlar şunlardır: |
|
|
1. `search(sorgu)`: İnternette arama yapmak için kullanılır. Örneğin: `search(Türkiye'nin başkenti)` |
|
|
2. `calculator(ifade)`: Matematiksel bir ifadeyi hesaplamak için kullanılır. Örneğin: `calculator(100 * (3 + 5))` |
|
|
3. `finish(cevap)`: Görevi tamamladığında ve nihai cevabı bulduğunda kullanılır. Örneğin: `finish(Ankara, Türkiye'nin başkentidir.)` |
|
|
|
|
|
Süreç şu şekilde işler: |
|
|
1. Amacı analiz edersin. |
|
|
2. Bir 'Düşünce' oluşturursun. |
|
|
3. Bir 'Eylem' seçersin. |
|
|
4. Ben sana 'Gözlem' olarak eylemin sonucunu veririm. |
|
|
5. Amaca ulaşana kadar 2-4 adımlarını tekrarlarsın. |
|
|
|
|
|
Amacımız: "{goal}" |
|
|
|
|
|
Şimdi, ilk Düşünce ve Eylemini yaz. |
|
|
""" |
|
|
|
|
|
history = [system_prompt_template] |
|
|
max_steps = 10 |
|
|
|
|
|
for step in range(max_steps): |
|
|
st.write("---") |
|
|
st.info(f"🚀 Adım {step + 1}") |
|
|
|
|
|
prompt = "\n".join(history) |
|
|
|
|
|
with st.spinner("Ajan düşünüyor..."): |
|
|
response = call_llm(prompt, api_key) |
|
|
|
|
|
if not response: |
|
|
st.error("Ajan bir yanıt üretemedi. Lütfen API anahtarınızı kontrol edin veya tekrar deneyin.") |
|
|
break |
|
|
|
|
|
|
|
|
try: |
|
|
thought = re.search(r"Düşünce: (.*?)\n", response, re.DOTALL).group(1).strip() |
|
|
action_full = re.search(r"Eylem: (.*?)$", response, re.DOTALL).group(1).strip() |
|
|
except AttributeError as e: |
|
|
st.error("Ajan geçerli bir 'Düşünce' veya 'Eylem' formatı üretmedi.") |
|
|
st.write(response) |
|
|
break |
|
|
|
|
|
with st.expander("🤖 Ajanın Düşünce Süreci", expanded=True): |
|
|
st.markdown(f"**Düşünce:** {thought}") |
|
|
st.markdown(f"**Eylem:** `{action_full}`") |
|
|
|
|
|
|
|
|
action_name_match = re.match(r"(\w+)\((.*)\)", action_full) |
|
|
if not action_name_match: |
|
|
st.error(f"Geçersiz eylem formatı: {action_full}") |
|
|
break |
|
|
|
|
|
action_name = action_name_match.group(1) |
|
|
action_input = action_name_match.group(2).strip(' "') |
|
|
|
|
|
|
|
|
observation = "" |
|
|
if action_name == "search": |
|
|
observation = search_tool(action_input) |
|
|
elif action_name == "calculator": |
|
|
observation = calculator_tool(action_input) |
|
|
elif action_name == "finish": |
|
|
st.success(f"✅ Ajan görevi tamamladı!") |
|
|
st.balloons() |
|
|
st.markdown("### Nihai Cevap:") |
|
|
st.write(action_input) |
|
|
break |
|
|
else: |
|
|
observation = f"Bilinmeyen eylem: {action_name}. Lütfen `search`, `calculator` veya `finish` kullanın." |
|
|
|
|
|
st.warning(f"**Gözlem:**\n{observation}") |
|
|
|
|
|
|
|
|
history.append(response) |
|
|
history.append(f"Gözlem: {observation}") |
|
|
else: |
|
|
st.error("Ajan maksimum adım sayısına ulaştı ama görevi tamamlayamadı.") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.set_page_config(page_title="AI Agent App", page_icon="🤖") |
|
|
|
|
|
st.title("🤖 AI Agent Uygulaması") |
|
|
st.markdown(""" |
|
|
Bu uygulama, bir amaca ulaşmak için **ReAct (Reason + Act)** mantığıyla çalışan bir AI ajanıdır. |
|
|
Ajan, hedefe ulaşmak için **düşünür**, **araçlar kullanır** (web araması, hesap makinesi) ve sonuçları **gözlemler**. |
|
|
""") |
|
|
|
|
|
st.sidebar.header("Yapılandırma") |
|
|
api_key = st.sidebar.text_input("OpenAI API Anahtarınız", type="password", help="API anahtarınız asla saklanmaz.") |
|
|
|
|
|
st.header("Ajanın Amacını Belirleyin") |
|
|
goal = st.text_input( |
|
|
"Amaç:", |
|
|
placeholder="Örnek: 'Matrix filminin başrol oyuncusunun bugünkü yaşı kaçtır ve bu yaşın karekökü nedir?'" |
|
|
) |
|
|
|
|
|
if st.button("Ajanı Başlat", disabled=(not api_key or not goal)): |
|
|
if api_key and goal: |
|
|
run_agent_loop(goal, api_key) |
|
|
else: |
|
|
st.warning("Lütfen OpenAI API anahtarınızı ve bir amaç girin.") |
|
|
|