UntilDot commited on
Commit
718aa48
·
verified ·
1 Parent(s): c78d1b6

Upload 10 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a slim Python base
2
+ FROM python:3.11-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install dependencies
8
+ COPY requirements.txt ./
9
+ RUN pip install --no-cache-dir -r requirements.txt
10
+
11
+ # Copy source code
12
+ COPY . .
13
+
14
+ # Expose the default Hugging Face Spaces port
15
+ EXPOSE 7860
16
+
17
+ # Run the app
18
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, jsonify
2
+ from llm.agents import query_all_llms
3
+ from llm.aggregator import aggregate_responses
4
+ import os
5
+ import dotenv
6
+
7
+ # Load secrets from .env
8
+ dotenv.load_dotenv()
9
+
10
+ app = Flask(__name__)
11
+
12
+ @app.route("/")
13
+ def index():
14
+ return render_template("index.html")
15
+
16
+ @app.route("/chat", methods=["POST"])
17
+ def chat():
18
+ data = request.get_json()
19
+ user_input = data.get("prompt", "")
20
+ settings = data.get("settings", {})
21
+
22
+ if not user_input:
23
+ return jsonify({"error": "Empty prompt."}), 400
24
+
25
+ try:
26
+ # Step 1: Query all agents asynchronously
27
+ agent_outputs = query_all_llms(user_input, settings)
28
+
29
+ # Step 2: Aggregate responses
30
+ final_response = aggregate_responses(agent_outputs)
31
+
32
+ return jsonify({"response": final_response})
33
+
34
+ except Exception as e:
35
+ return jsonify({"error": str(e)}), 500
36
+
37
+ if __name__ == "__main__":
38
+ app.run(host="0.0.0.0", port=7860, debug=False) # Hugging Face uses port 7860
llm/agents.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+
3
+ async def query_llm_agent(name: str, prompt: str, settings: dict) -> str:
4
+ # Placeholder for real LLM API calls (OpenAI, Claude, etc.)
5
+ await asyncio.sleep(0.5) # Simulate network latency
6
+ return f"[{name}] thinks: '{prompt[::-1]}'" # Reverse input for mock
7
+
8
+ async def query_all_llms(prompt: str, settings: dict) -> list:
9
+ agents = ["LLM-A", "LLM-B", "LLM-C"]
10
+ tasks = [query_llm_agent(agent, prompt, settings) for agent in agents]
11
+ results = await asyncio.gather(*tasks)
12
+ return results
13
+
14
+ # Wrapper for sync Flask usage
15
+ def query_all_llms_sync(prompt: str, settings: dict) -> list:
16
+ return asyncio.run(query_all_llms(prompt, settings))
llm/aggregator.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ def aggregate_responses(responses: list) -> str:
2
+ if not responses:
3
+ return "No responses received."
4
+
5
+ combined = "\n".join(responses)
6
+ # In real use, you’d prompt another LLM to summarize/combine them
7
+ return f"Final synthesized response based on multiple agents:\n{combined}"
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ flask==2.3.3
2
+ httpx==0.27.0
3
+ python-dotenv==1.0.1
routes/chat.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template
2
+ from routes.chat import chat_bp
3
+ import os
4
+ import dotenv
5
+
6
+ # Load secrets from .env
7
+ dotenv.load_dotenv()
8
+
9
+ app = Flask(__name__, static_url_path='/static')
10
+ app.register_blueprint(chat_bp)
11
+
12
+ @app.route("/")
13
+ def index():
14
+ return render_template("index.html")
15
+
16
+ if __name__ == "__main__":
17
+ app.run(host="0.0.0.0", port=7860, debug=False) # Hugging Face uses port 7860
static/script.js ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // === Theme Toggle ===
2
+ const themeToggle = document.getElementById("themeToggle");
3
+ const html = document.documentElement;
4
+
5
+ // Load from localStorage or system preference
6
+ function setInitialTheme() {
7
+ const savedTheme = localStorage.getItem("theme");
8
+ if (savedTheme === "dark") {
9
+ html.classList.add("dark");
10
+ } else if (savedTheme === "light") {
11
+ html.classList.remove("dark");
12
+ } else {
13
+ // Auto-detect
14
+ const prefersDark = window.matchMedia(
15
+ "(prefers-color-scheme: dark)",
16
+ ).matches;
17
+ if (prefersDark) html.classList.add("dark");
18
+ else html.classList.remove("dark");
19
+ }
20
+ }
21
+
22
+ setInitialTheme();
23
+
24
+ // Toggle theme
25
+ themeToggle.addEventListener("click", () => {
26
+ const isDark = html.classList.toggle("dark");
27
+ localStorage.setItem("theme", isDark ? "dark" : "light");
28
+ });
29
+
30
+ // === Chat Handling ===
31
+ const chatForm = document.getElementById("chatForm");
32
+ const userInput = document.getElementById("userInput");
33
+ const chatContainer = document.getElementById("chatContainer");
34
+
35
+ function appendMessage(role, text) {
36
+ const div = document.createElement("div");
37
+ div.className = `p-3 rounded shadow max-w-2xl ${role === "user" ? "bg-blue text-fg0 self-end" : "bg-green text-fg0 self-start"}`;
38
+ div.innerText = text;
39
+ chatContainer.appendChild(div);
40
+ chatContainer.scrollTop = chatContainer.scrollHeight;
41
+ }
42
+
43
+ chatForm.addEventListener("submit", async (e) => {
44
+ e.preventDefault();
45
+ const prompt = userInput.value.trim();
46
+ if (!prompt) return;
47
+ appendMessage("user", prompt);
48
+ userInput.value = "";
49
+
50
+ appendMessage("bot", "Thinking...");
51
+
52
+ const response = await fetch("/chat", {
53
+ method: "POST",
54
+ headers: { "Content-Type": "application/json" },
55
+ body: JSON.stringify({ prompt }),
56
+ });
57
+
58
+ chatContainer.lastChild.remove(); // remove 'Thinking...'
59
+
60
+ if (response.ok) {
61
+ const data = await response.json();
62
+ appendMessage("bot", data.response);
63
+ } else {
64
+ appendMessage("bot", "An error occurred. Please try again.");
65
+ }
66
+ });
static/style.css ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Gruvbox Material Theme: Light & Dark */
2
+ :root {
3
+ --bg0: #f2e5bc;
4
+ --bg1: #eddeb5;
5
+ --bg-statusline1: #ebdbb2;
6
+ --bg-statusline2: #ebdbb2;
7
+ --fg0: #654735;
8
+ --fg1: #4f3829;
9
+ --blue: #45707a;
10
+ --green: #6c782e;
11
+ --purple: #945e80;
12
+ --visual_green: #d7d9ae;
13
+ }
14
+
15
+ .dark {
16
+ --bg0: #32302f;
17
+ --bg1: #3c3836;
18
+ --bg-statusline1: #3c3836;
19
+ --bg-statusline2: #46413e;
20
+ --fg0: #d4be98;
21
+ --fg1: #ddc7a1;
22
+ --blue: #7daea3;
23
+ --green: #a9b665;
24
+ --purple: #d3869b;
25
+ --visual_green: #a9b665;
26
+ }
27
+
28
+ body {
29
+ background-color: var(--bg0);
30
+ color: var(--fg0);
31
+ }
32
+
33
+ input,
34
+ button,
35
+ #chatContainer {
36
+ background-color: var(--bg1);
37
+ color: var(--fg0);
38
+ }
39
+
40
+ input::placeholder {
41
+ color: var(--fg1);
42
+ }
43
+
44
+ button {
45
+ background-color: var(--green);
46
+ transition: background-color 0.3s;
47
+ }
48
+
49
+ button:hover {
50
+ background-color: var(--visual_green);
51
+ }
templates/.DS_Store ADDED
Binary file (6.15 kB). View file
 
templates/index.html ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en" class="bg0 text-fg0 dark">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>MoA Chat</title>
7
+ <link
8
+ href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css"
9
+ rel="stylesheet"
10
+ />
11
+ <link rel="stylesheet" href="/static/style.css" />
12
+ </head>
13
+ <body class="bg0 text-fg0 transition-colors duration-300">
14
+ <div class="min-h-screen flex flex-col justify-between p-4">
15
+ <header class="flex items-center justify-between mb-4">
16
+ <h1 class="text-2xl font-bold">MoA Chat</h1>
17
+ <button
18
+ id="themeToggle"
19
+ class="bg-blue px-3 py-1 rounded text-fg0 hover:bg-purple transition"
20
+ >
21
+ Toggle Theme
22
+ </button>
23
+ </header>
24
+
25
+ <main
26
+ id="chatContainer"
27
+ class="flex-1 overflow-y-auto bg1 p-4 rounded shadow-md space-y-4"
28
+ >
29
+ <!-- Messages injected here -->
30
+ </main>
31
+
32
+ <form id="chatForm" class="mt-4 flex">
33
+ <input
34
+ id="userInput"
35
+ type="text"
36
+ placeholder="Ask something..."
37
+ class="flex-1 px-4 py-2 rounded-l border-none bg-statusline1 text-fg0 placeholder-fg1 focus:outline-none"
38
+ />
39
+ <button
40
+ type="submit"
41
+ class="px-4 py-2 bg-green text-fg0 rounded-r hover:bg-visual_green transition"
42
+ >
43
+ Send
44
+ </button>
45
+ </form>
46
+ </div>
47
+
48
+ <script src="/static/script.js"></script>
49
+ </body>
50
+ </html>