|
import os |
|
import base64 |
|
import gradio as gr |
|
import requests |
|
import json |
|
from io import BytesIO |
|
from PIL import Image |
|
|
|
|
|
OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY", "") |
|
|
|
|
|
models = [ |
|
("Google Gemini Pro 2.0", "google/gemini-2.0-pro-exp-02-05:free"), |
|
("Google Gemini 2.5 Pro", "google/gemini-2.5-pro-exp-03-25:free"), |
|
("Meta Llama 3.2 Vision", "meta-llama/llama-3.2-11b-vision-instruct:free"), |
|
("Qwen 2.5 VL", "qwen/qwen2.5-vl-72b-instruct:free"), |
|
("DeepSeek R1", "deepseek/deepseek-r1:free"), |
|
("Mistral 3.1", "mistralai/mistral-small-3.1-24b-instruct:free") |
|
] |
|
|
|
def get_ai_response(message, history, model_name, image=None, file=None): |
|
"""Get response from AI""" |
|
|
|
model_id = next((mid for name, mid in models if name == model_name), models[0][1]) |
|
|
|
|
|
messages = [] |
|
for human, ai in history: |
|
messages.append({"role": "user", "content": human}) |
|
if ai: |
|
messages.append({"role": "assistant", "content": ai}) |
|
|
|
|
|
if file is not None: |
|
try: |
|
with open(file.name, 'r', encoding='utf-8') as f: |
|
file_content = f.read() |
|
message = f"{message}\n\nFile content:\n```\n{file_content}\n```" |
|
except Exception as e: |
|
message = f"{message}\n\nError reading file: {str(e)}" |
|
|
|
|
|
if image is not None: |
|
try: |
|
buffered = BytesIO() |
|
image.save(buffered, format="JPEG") |
|
base64_image = base64.b64encode(buffered.getvalue()).decode("utf-8") |
|
|
|
content = [ |
|
{"type": "text", "text": message}, |
|
{ |
|
"type": "image_url", |
|
"image_url": { |
|
"url": f"data:image/jpeg;base64,{base64_image}" |
|
} |
|
} |
|
] |
|
messages.append({"role": "user", "content": content}) |
|
except Exception as e: |
|
messages.append({"role": "user", "content": message}) |
|
return f"Error processing image: {str(e)}" |
|
else: |
|
messages.append({"role": "user", "content": message}) |
|
|
|
|
|
try: |
|
response = requests.post( |
|
"https://openrouter.ai/api/v1/chat/completions", |
|
headers={ |
|
"Content-Type": "application/json", |
|
"Authorization": f"Bearer {OPENROUTER_API_KEY}", |
|
"HTTP-Referer": "https://huggingface.co/spaces", |
|
}, |
|
json={ |
|
"model": model_id, |
|
"messages": messages, |
|
"temperature": 0.7, |
|
"max_tokens": 1000 |
|
}, |
|
timeout=60 |
|
) |
|
response.raise_for_status() |
|
|
|
result = response.json() |
|
return result.get("choices", [{}])[0].get("message", {}).get("content", "No response") |
|
except Exception as e: |
|
return f"Error: {str(e)}" |
|
|
|
def clear_inputs(): |
|
"""Clear input fields""" |
|
return "", None, None |
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("# 🔆 CrispChat") |
|
|
|
chatbot = gr.Chatbot( |
|
height=450, |
|
type="messages" |
|
) |
|
|
|
model_selector = gr.Dropdown( |
|
choices=[name for name, _ in models], |
|
value=models[0][0], |
|
label="Model" |
|
) |
|
|
|
msg_input = gr.Textbox( |
|
placeholder="Type your message here...", |
|
lines=3, |
|
label="Message" |
|
) |
|
|
|
img_input = gr.Image( |
|
type="pil", |
|
label="Image (optional)" |
|
) |
|
|
|
file_input = gr.File( |
|
label="Text File (optional)" |
|
) |
|
|
|
with gr.Row(): |
|
submit_btn = gr.Button("Send") |
|
clear_btn = gr.Button("Clear Chat") |
|
|
|
|
|
def clear_chat(): |
|
return [] |
|
|
|
|
|
def submit_message(message, chat_history, model, image, file): |
|
if not message and not image and not file: |
|
return chat_history, "", None, None |
|
|
|
response = get_ai_response(message, chat_history, model, image, file) |
|
chat_history.append((message, response)) |
|
return chat_history, "", None, None |
|
|
|
|
|
submit_btn.click( |
|
fn=submit_message, |
|
inputs=[msg_input, chatbot, model_selector, img_input, file_input], |
|
outputs=[chatbot, msg_input, img_input, file_input] |
|
) |
|
|
|
msg_input.submit( |
|
fn=submit_message, |
|
inputs=[msg_input, chatbot, model_selector, img_input, file_input], |
|
outputs=[chatbot, msg_input, img_input, file_input] |
|
) |
|
|
|
clear_btn.click( |
|
fn=clear_chat, |
|
outputs=[chatbot] |
|
) |
|
|
|
|
|
from fastapi import FastAPI |
|
from pydantic import BaseModel |
|
|
|
app = FastAPI() |
|
|
|
class GenerateRequest(BaseModel): |
|
message: str |
|
model: str = None |
|
image_data: str = None |
|
|
|
@app.post("/api/generate") |
|
async def api_generate(request: GenerateRequest): |
|
"""API endpoint for text generation""" |
|
try: |
|
model_id = request.model or models[0][1] |
|
|
|
|
|
messages = [] |
|
|
|
|
|
if request.image_data: |
|
try: |
|
|
|
image_bytes = base64.b64decode(request.image_data) |
|
image = Image.open(BytesIO(image_bytes)) |
|
|
|
|
|
buffered = BytesIO() |
|
image.save(buffered, format="JPEG") |
|
base64_image = base64.b64encode(buffered.getvalue()).decode("utf-8") |
|
|
|
content = [ |
|
{"type": "text", "text": request.message}, |
|
{ |
|
"type": "image_url", |
|
"image_url": { |
|
"url": f"data:image/jpeg;base64,{base64_image}" |
|
} |
|
} |
|
] |
|
messages.append({"role": "user", "content": content}) |
|
except Exception as e: |
|
return {"error": f"Image processing error: {str(e)}"} |
|
else: |
|
messages.append({"role": "user", "content": request.message}) |
|
|
|
|
|
response = requests.post( |
|
"https://openrouter.ai/api/v1/chat/completions", |
|
headers={ |
|
"Content-Type": "application/json", |
|
"Authorization": f"Bearer {OPENROUTER_API_KEY}", |
|
"HTTP-Referer": "https://huggingface.co/spaces", |
|
}, |
|
json={ |
|
"model": model_id, |
|
"messages": messages, |
|
"temperature": 0.7 |
|
}, |
|
timeout=60 |
|
) |
|
response.raise_for_status() |
|
|
|
result = response.json() |
|
reply = result.get("choices", [{}])[0].get("message", {}).get("content", "No response") |
|
|
|
return {"response": reply} |
|
except Exception as e: |
|
return {"error": f"Error: {str(e)}"} |
|
|
|
|
|
app = gr.mount_gradio_app(app, demo, path="/") |
|
|
|
|
|
if __name__ == "__main__": |
|
import uvicorn |
|
uvicorn.run(app, host="0.0.0.0", port=7860) |