File size: 4,031 Bytes
e489749
 
 
cf929e7
e489749
cf929e7
 
 
e489749
cf929e7
e489749
 
 
 
 
cf929e7
e489749
 
 
 
 
 
cf929e7
 
 
 
 
e489749
cf929e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e489749
 
 
cf929e7
 
 
 
 
 
e489749
 
 
 
 
 
 
 
cf929e7
e489749
cf929e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e489749
 
 
 
cf929e7
e489749
cf929e7
 
 
 
 
 
e489749
 
cf929e7
 
e489749
cf929e7
 
 
e489749
cf929e7
e489749
 
 
cf929e7
 
e489749
 
cf929e7
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
import gradio as gr
from dotenv import load_dotenv
from openai import OpenAI
from duckduckgo_search import DDGS
import os
import requests
import json
import re

# Load environment variables
load_dotenv()

API_KEY = os.getenv("OPENAI_API_KEY")
MODEL_NAME = os.getenv("MODEL_NAME")
BASE_URL = os.getenv("BASE_URL")
IMAGE_SEARCH_ENDPOINT = os.getenv("IMAGE_SEARCH_ENDPOINT")

client = OpenAI(
    api_key=API_KEY,
    base_url=BASE_URL,
)

# MCP TOOL: Search via DuckDuckGo
def search(query: str) -> list[dict]:
    with DDGS() as ddgs:
        results = ddgs.text(query, max_results=5)
    return results

# MCP TOOL: Analyze Image URL to get caption for further searching
def analyze_image(data: str) -> str:
    try:
        response = requests.post(IMAGE_SEARCH_ENDPOINT, json={"image_url": data})
        if response.status_code == 200:
            return response.json().get("caption", "No caption found")
        else:
            return f"Image analysis failed: {response.status_code}"
    except Exception as e:
        return f"Error during image analysis: {str(e)}"

# Helper to extract tool_code from model response
def extract_tool_code(text):
    match = re.search(r"```tool_code\\n(.*?)```", text, re.DOTALL)
    return match.group(1).strip() if match else None

# Helper to format tool output back to model
def format_tool_output(output):
    return f"```tool_output\n{json.dumps(output)}\n```"

# CHAT HANDLER
def chat_with_gemma(history, message, image_url):
    messages = [
        {"role": "system", "content": "You are a helpful assistant who helps users find products online using search and image analysis. Wrap tool use in ```tool_code``` and return results in ```tool_output```."}  ]
    for user_msg, bot_msg in history:
        messages.append({"role": "user", "content": user_msg})
        messages.append({"role": "assistant", "content": bot_msg})

    if image_url:
        image_caption = analyze_image(image_url)
        message = f"Image URL: {image_url}\nCaption: {image_caption}\nUser says: {message}"

    messages.append({"role": "user", "content": message})

    try:
        response = client.chat.completions.create(
            model=MODEL_NAME,
            messages=messages,
            temperature=0.7,
            max_tokens=512,
        )

        reply = response.choices[0].message.content.strip()

        tool_code = extract_tool_code(reply)
        if tool_code:
            tool_result = eval(tool_code)  # Note: Only safe in dev/testing
            tool_output = format_tool_output(tool_result)

            messages.append({"role": "user", "content": tool_output})

            response2 = client.chat.completions.create(
                model=MODEL_NAME,
                messages=messages,
                temperature=0.7,
                max_tokens=512,
            )

            reply = response2.choices[0].message.content.strip()

    except Exception as e:
        reply = f"⚠️ Error: {str(e)}"

    history.append((message, reply))
    return history, "", ""

# GRADIO UI
with gr.Blocks(title="🧠 Gemma Product Finder - MCP Tool", theme=gr.themes.Soft()) as demo:
    gr.Markdown("""
        <h1 style='text-align: center; color: #4e73df;'>πŸ›οΈ Gemma Product Finder</h1>
        <p style='text-align: center; color: #6c757d;'>Find Amazon & Flipkart products with AI</p>
    """)

    with gr.Row():
        chatbot = gr.Chatbot(height=420, label="🧠 Chat with Gemma", bubble_full_width=False)

    with gr.Row():
        msg = gr.Textbox(label="πŸ’¬ Ask something", placeholder="e.g. Red Nike shoes under 4000", scale=3)
        image_url = gr.Textbox(label="πŸŒ† Optional image URL", placeholder="Paste image URL here", scale=2)

    with gr.Row():
        clear = gr.Button("πŸ”„ Clear Chat", variant="secondary")

    state = gr.State([])

    msg.submit(chat_with_gemma, [state, msg, image_url], [chatbot, msg, image_url])
    clear.click(lambda: ([], "", ""), outputs=[chatbot, msg, image_url])

if __name__ == "__main__":
    demo.launch(mcp_server=True)