結論
日本語記事が存在しなかったので人柱として記録
そこまで使えるような気がしないが、もしかしたら使えるかもしれない
大人しくCurorに20$課金
有志が今後色々試す or アプデに期待
賢さ(感覚):chatgpt thinking(free) >= claude-3.7 sonet thinking(Cursor) >>>> deepseek-r1:14b(AgenticSeek) > deepseek-r1:32b(AgenticSeek)
14bの方がなんか良い気がする(3090環境)
動作イメージ
※当たり前だが普通にググったほうが早い
python -m uvicorn api:api --reload --host 0.0.0.0 --port 8000
(agentic_seek_env) PS D:\Project\agenticSeek\agenticSeek>
(agentic_seek_env) PS D:\Project\agenticSeek\agenticSeek> python -m uvicorn api:api --reload --host 0.0.0.0 --port 8000
INFO: Will watch for changes in these directories: ['D:\\Project\\agenticSeek\\agenticSeek']
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: Started reloader process [16692] using StatReload
DevTools listening on ws://127.0.0.1:53719/devtools/browser/2b9e6328-6561-4e1f-96a9-ea83930c550a
▉▁▁▁▁▁ Loading language utility...[nltk_data] Downloading package vader_lexicon to
[nltk_data] C:\Users\user\AppData\Roaming\nltk_data...
[nltk_data] Package vader_lexicon is already up-to-date!
▉▉▉▃▁▁ Loading zero-shot pipeline...Device set to use cpu
AgenticSeek is ready.
INFO: Started server process [29888]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: 192.168.1.11:53777 - "GET /health HTTP/1.1" 200 OK
INFO: 192.168.1.11:53775 - "GET /latest_answer HTTP/1.1" 404 Not Found
INFO: 192.168.1.11:53774 - "GET /screenshots/updated_screen.png?timestamp=1746649023706 HTTP/1.1" 200 OK
INFO: 192.168.1.11:53775 - "GET /health HTTP/1.1" 200 OK
INFO: 192.168.1.11:53777 - "GET /latest_answer HTTP/1.1" 404 Not Found
INFO: 192.168.1.11:53774 - "GET /screenshots/updated_screen.png?timestamp=1746649026715 HTTP/1.1" 200 OK
Created TensorFlow Lite XNNPACK delegate for CPU.
INFO: 192.168.1.11:53775 - "GET /latest_answer HTTP/1.1" 404 Not Found
INFO: 192.168.1.11:53777 - "GET /health HTTP/1.1" 200 OK
INFO: 192.168.1.11:53774 - "GET /screenshots/updated_screen.png?timestamp=1746649029706 HTTP/1.1" 200 OK
INFO: 192.168.1.11:53775 - "GET /latest_answer HTTP/1.1" 404 Not Found
INFO: 192.168.1.11:53777 - "GET /health HTTP/1.1" 200 OK
INFO: 192.168.1.11:53774 - "GET /screenshots/updated_screen.png?timestamp=1746649032703 HTTP/1.1" 200 OK
INFO: 192.168.1.11:53774 - "OPTIONS /query HTTP/1.1" 200 OK
INFO: 192.168.1.11:53777 - "GET /health HTTP/1.1" 200 OK
Selected agent: Browser (roles: web)
▉▉▉▉▇▅ Thinking...INFO: 192.168.1.11:53777 - "GET /health HTTP/1.1" 200 OK
INFO: 192.168.1.11:53776 - "GET /latest_answer HTTP/1.1" 200 OK
INFO: 192.168.1.11:53794 - "GET /screenshots/updated_screen.png?timestamp=1746649038540 HTTP/1.1" 200 OK
▃▇▉▇▉▅ Thinking...INFO: 192.168.1.11:53777 - "GET /latest_answer HTTP/1.1" 200 OK
INFO: 192.168.1.11:53776 - "GET /health HTTP/1.1" 200 OK
INFO: 192.168.1.11:53794 - "GET /screenshots/updated_screen.png?timestamp=1746649041548 HTTP/1.1" 200 OK
Search results:
Title: Yahoo!天気・災害 - 天気予報 / 防災情報 - Link: https://weather.yahoo.co.jp/weather/
Title: 東京都の天気 - Yahoo!天気・災害 - Link: https://weather.yahoo.co.jp/weather/jp/13/
Title: Jo bizpu ju eni doj You: "search: 今日の東京の天気を教えて" Busomuk. - Link: http://geb.mx/sopfa
Title: 東京(東京)の天気 - Yahoo!天気・災害 - Link: https://weather.yahoo.co.jp/weather/jp/13/4410.html
Title: 【ウェザーニュース】天気 - 台風・地震・防災情報|予報精度 ... - Link: https://weathernews.jp/
Title: Fi zarta davuk You: "search: 今日の東京の天気を教えて" Sape ika ub. - Link: http://ucikenba.me/im
Title: 東京の天気 - ウェザーニュース - Link: https://weathernews.jp/onebox/tenki/tokyo/
Title: 港区の3時間天気 - 日本気象協会 tenki.jp - Link: https://tenki.jp/forecast/3/16/4410/13103/3hours.html
...(略
Snipet集
# 管理者権限 PowerShell
# Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
# PowerShell Pathを出力/設定
# $ENV:Path.Split(";")
# $ENV:Path+=";C:\Windows\System32\"
# Google Chrome Web Driver Download
# https://googlechromelabs.github.io/chrome-for-testing/#stable
# $ENV:Path+=";$env:LOCALAPPDATA\Programs\GoogleChromeWebDriver\"
# venv環境削除
& cmd.exe /c "rmdir /s /q agentic_seek_env"
# venv作成
& "$env:LOCALAPPDATA\Programs\Python\Python310\python.exe" -m venv agentic_seek_env
# venv activate
.\agentic_seek_env\Scripts\activate
# .\agentic_seek_env\Scripts\deactivate.batは動かないのでターミナルごと落とす
# package install
python -m pip install --upgrade pip
pip install pyreadline3
pip install pyaudio
pip3 install -r requirements.txt
# docker/docker-compose install check
# dockerデスクトップをダウンロードしておく
# https://www.docker.com/ja-jp/get-started/
docker -v
# docker-composeはpip install
# pip install docker-compose
docker-compose -v
# docker compose up -d
start ./start_services.cmd
# backend serve
# .\agentic_seek_env\Scripts\activate
python -m uvicorn api:api --reload --host 0.0.0.0 --port 8000
# run ollama
# https://ollama.com/library/deepseek-r1
& "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" pull deepseek-r1:14b
# & "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" pull deepseek-r1:32b
& "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" list
& "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" ps
& "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" run deepseek-r1:14b
& "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" ps
# & "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" run deepseek-r1:32b
# & "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" stop deepseek-r1:14b
# & "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" stop deepseek-r1:32b
環境構築
Windows環境だとそのままだとエラーになるのでファイルを編集する
api.py
#!/usr/bin/env python3
import os, sys
import uvicorn
import aiofiles
import configparser
import asyncio
import time
from typing import List
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
import uuid
from sources.llm_provider import Provider
from sources.interaction import Interaction
from sources.agents import CasualAgent, CoderAgent, FileAgent, PlannerAgent, BrowserAgent
from sources.browser import Browser, create_driver
from sources.utility import pretty_print
from sources.logger import Logger
from sources.schemas import QueryRequest, QueryResponse
from celery import Celery
api = FastAPI(title="AgenticSeek API", version="0.1.0")
celery_app = Celery("tasks", broker="redis://127.0.0.1:6379/0", backend="redis://127.0.0.1:6379/0")
celery_app.conf.update(task_track_started=True)
logger = Logger("backend.log")
config = configparser.ConfigParser()
config.read('config.ini')
api.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
if not os.path.exists(".screenshots"):
os.makedirs(".screenshots")
api.mount("/screenshots", StaticFiles(directory=".screenshots"), name="screenshots")
def initialize_system():
stealth_mode = config.getboolean('BROWSER', 'stealth_mode')
personality_folder = "jarvis" if config.getboolean('MAIN', 'jarvis_personality') else "base"
languages = config["MAIN"]["languages"].split(' ')
provider = Provider(
provider_name=config["MAIN"]["provider_name"],
model=config["MAIN"]["provider_model"],
server_address=config["MAIN"]["provider_server_address"],
is_local=config.getboolean('MAIN', 'is_local')
)
logger.info(f"Provider initialized: {provider.provider_name} ({provider.model})")
browser = Browser(
create_driver(headless=config.getboolean('BROWSER', 'headless_browser'), stealth_mode=stealth_mode),
anticaptcha_manual_install=stealth_mode
)
logger.info("Browser initialized")
agents = [
CasualAgent(
name=config["MAIN"]["agent_name"],
prompt_path=f"prompts/{personality_folder}/casual_agent.txt",
provider=provider, verbose=False
),
CoderAgent(
name="coder",
prompt_path=f"prompts/{personality_folder}/coder_agent.txt",
provider=provider, verbose=False
),
FileAgent(
name="File Agent",
prompt_path=f"prompts/{personality_folder}/file_agent.txt",
provider=provider, verbose=False
),
BrowserAgent(
name="Browser",
prompt_path=f"prompts/{personality_folder}/browser_agent.txt",
provider=provider, verbose=False, browser=browser
),
PlannerAgent(
name="Planner",
prompt_path=f"prompts/{personality_folder}/planner_agent.txt",
provider=provider, verbose=False, browser=browser
)
]
logger.info("Agents initialized")
interaction = Interaction(
agents,
tts_enabled=config.getboolean('MAIN', 'speak'),
stt_enabled=config.getboolean('MAIN', 'listen'),
recover_last_session=config.getboolean('MAIN', 'recover_last_session'),
langs=languages
)
logger.info("Interaction initialized")
return interaction
interaction = initialize_system()
is_generating = False
query_resp_history = []
@api.get("/screenshot")
async def get_screenshot():
logger.info("Screenshot endpoint called")
screenshot_path = ".screenshots/updated_screen.png"
if os.path.exists(screenshot_path):
return FileResponse(screenshot_path)
logger.error("No screenshot available")
return JSONResponse(
status_code=404,
content={"error": "No screenshot available"}
)
@api.get("/health")
async def health_check():
logger.info("Health check endpoint called")
return {"status": "healthy", "version": "0.1.0"}
@api.get("/is_active")
async def is_active():
logger.info("Is active endpoint called")
return {"is_active": interaction.is_active}
@api.get("/latest_answer")
async def get_latest_answer():
global query_resp_history
if interaction.current_agent is None:
return JSONResponse(status_code=404, content={"error": "No agent available"})
uid = str(uuid.uuid4())
if not any(q["answer"] == interaction.current_agent.last_answer for q in query_resp_history):
query_resp = {
"done": "false",
"answer": interaction.current_agent.last_answer,
"agent_name": interaction.current_agent.agent_name if interaction.current_agent else "None",
"success": interaction.current_agent.success,
"blocks": {f'{i}': block.jsonify() for i, block in enumerate(interaction.get_last_blocks_result())} if interaction.current_agent else {},
"status": interaction.current_agent.get_status_message if interaction.current_agent else "No status available",
"uid": uid
}
interaction.current_agent.last_answer = ""
query_resp_history.append(query_resp)
return JSONResponse(status_code=200, content=query_resp)
if query_resp_history:
return JSONResponse(status_code=200, content=query_resp_history[-1])
return JSONResponse(status_code=404, content={"error": "No answer available"})
async def think_wrapper(interaction, query):
try:
interaction.last_query = query
logger.info("Agents request is being processed")
success = await interaction.think()
if not success:
interaction.last_answer = "Error: No answer from agent"
interaction.last_success = False
else:
interaction.last_success = True
pretty_print(interaction.last_answer)
interaction.speak_answer()
return success
except Exception as e:
logger.error(f"Error in think_wrapper: {str(e)}")
interaction.last_answer = f"Error: {str(e)}"
interaction.last_success = False
raise e
@api.post("/query", response_model=QueryResponse)
async def process_query(request: QueryRequest):
global is_generating, query_resp_history
logger.info(f"Processing query: {request.query}")
query_resp = QueryResponse(
done="false",
answer="",
agent_name="Unknown",
success="false",
blocks={},
status="Ready",
uid=str(uuid.uuid4())
)
if is_generating:
logger.warning("Another query is being processed, please wait.")
return JSONResponse(status_code=429, content=query_resp.jsonify())
try:
is_generating = True
success = await think_wrapper(interaction, request.query)
is_generating = False
if not success:
query_resp.answer = interaction.last_answer
return JSONResponse(status_code=400, content=query_resp.jsonify())
if interaction.current_agent:
blocks_json = {f'{i}': block.jsonify() for i, block in enumerate(interaction.current_agent.get_blocks_result())}
else:
logger.error("No current agent found")
blocks_json = {}
query_resp.answer = "Error: No current agent"
return JSONResponse(status_code=400, content=query_resp.jsonify())
logger.info(f"Answer: {interaction.last_answer}")
logger.info(f"Blocks: {blocks_json}")
query_resp.done = "true"
query_resp.answer = interaction.last_answer
query_resp.agent_name = interaction.current_agent.agent_name
query_resp.success = str(interaction.last_success)
query_resp.blocks = blocks_json
# Store the raw dictionary representation
query_resp_dict = {
"done": query_resp.done,
"answer": query_resp.answer,
"agent_name": query_resp.agent_name,
"success": query_resp.success,
"blocks": query_resp.blocks,
"status": query_resp.status,
"uid": query_resp.uid
}
query_resp_history.append(query_resp_dict)
logger.info("Query processed successfully")
return JSONResponse(status_code=200, content=query_resp.jsonify())
except Exception as e:
logger.error(f"An error occurred: {str(e)}")
sys.exit(1)
finally:
logger.info("Processing finished")
if config.getboolean('MAIN', 'save_session'):
interaction.save_session()
if __name__ == "__main__":
uvicorn.run(api, host="0.0.0.0", port=8000)
celery_app = Celery("tasks", broker="redis://127.0.0.1:6379/0", backend="redis://127.0.0.1:6379/0")
に変更
config.ini
[MAIN]
is_local = True
provider_name = ollama
# provider_model = deepseek-r1:32b
provider_model = deepseek-r1:14b
provider_server_address = 127.0.0.1:11434
agent_name = Name_of_your_AI
recover_last_session = False
save_session = False
speak = False
listen = False
work_dir = C:\<your-project-here>\agenticSeek
jarvis_personality = False
languages = en
[BROWSER]
headless_browser = True
stealth_mode = False
provider_model
を変更
work_dir
を変更
docker-compose.yml
services:
redis:
container_name: redis
image: docker.io/valkey/valkey:8-alpine
command: valkey-server --save 30 1 --loglevel warning
restart: unless-stopped
volumes:
- redis-data:/data
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
- DAC_OVERRIDE
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
networks:
- agentic-seek-net
searxng:
container_name: searxng
image: docker.io/searxng/searxng:latest
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./searxng:/etc/searxng:rw
environment:
- SEARXNG_BASE_URL=http://localhost:8080/
- SEARXNG_SECRET_KEY=<your-secret-key-here>
- UWSGI_WORKERS=4
- UWSGI_THREADS=4
cap_add:
- CHOWN
- SETGID
- SETUID
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
depends_on:
- redis
networks:
- agentic-seek-net
frontend:
container_name: frontend
build:
context: ./frontend
dockerfile: Dockerfile.frontend
ports:
- "3000:3000"
volumes:
- ./frontend/agentic-seek-front/src:/app/src
- ./screenshots:/app/screenshots
environment:
- NODE_ENV=development
- CHOKIDAR_USEPOLLING=true
- BACKEND_URL=http://backend:8000
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
- agentic-seek-net
# NOTE: backend service is not working yet due to issue with chromedriver on docker.
# Therefore backend is run on host machine.
# Open to pull requests to fix this.
#backend:
# container_name: backend
# build:
# context: ./
# dockerfile: Dockerfile.backend
# stdin_open: true
# tty: true
# shm_size: 8g
# ports:
# - "8000:8000"
# volumes:
# - ./:/app
# environment:
# - NODE_ENV=development
# - REDIS_URL=redis://redis:6379/0
# - SEARXNG_URL=http://searxng:8080
# - OLLAMA_URL=http://localhost:11434
# - LM_STUDIO_URL=http://localhost:1234
# extra_hosts:
# - "host.docker.internal:host-gateway"
# depends_on:
# - redis
# - searxng
# networks:
# - agentic-seek-net
volumes:
redis-data:
chrome_profiles:
networks:
agentic-seek-net:
driver: bridge
extra_hosts:
- "host.docker.internal:host-gateway"
を追加
version: '3'
を削除
requirements.txt
kokoro==0.9.4
certifi==2025.4.26
fastapi>=0.115.12
flask>=3.1.0
celery>=5.5.1
aiofiles>=24.1.0
uvicorn>=0.34.0
pydantic>=2.10.6
pydantic_core>=2.27.2
setuptools>=75.6.0
sacremoses>=0.0.53
requests>=2.31.0
numpy>=1.24.4
colorama>=0.4.6
python-dotenv>=1.0.0
soundfile>=0.13.1
transformers>=4.46.3
torch>=2.4.1
python-dotenv>=1.0.0
ollama>=0.4.7
scipy>=1.9.3
soundfile>=0.13.1
protobuf>=3.20.3
termcolor>=2.4.0
pypdf>=5.4.0
ipython>=8.13.0
pyaudio>=0.2.14
librosa>=0.10.2.post1
selenium>=4.27.1
markdownify>=1.1.0
text2emotion>=0.0.5
adaptive-classifier>=0.0.10
langid>=1.1.6
chromedriver-autoinstaller>=0.6.4
httpx>=0.27,<0.29
anyio>=3.5.0,<5
distro>=1.7.0,<2
jiter>=0.4.0,<1
fake_useragent>=2.1.0
selenium_stealth>=1.0.6
undetected-chromedriver>=3.5.5
sentencepiece>=0.2.0
tqdm>4
openai
sniffio
ordered_set
pypinyin
playsound>=1.3.0
を削除
start_services.cmd
@echo off
docker compose up
if %ERRORLEVEL% neq 0 (
echo Error: Failed to start containers. Check Docker logs with 'docker compose logs'.
echo Possible fixes: Ensure Docker Desktop is running or check if port 8080 is free.
exit /b 1
)
timeout /t 10 /nobreak >nul
docker compose up
に変更
app.js
import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import './App.css';
import { colors } from './colors';
function App() {
const [query, setQuery] = useState('');
const [messages, setMessages] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const [currentView, setCurrentView] = useState('blocks');
const [responseData, setResponseData] = useState(null);
const [isOnline, setIsOnline] = useState(false);
const [status, setStatus] = useState('Agents ready');
const messagesEndRef = useRef(null);
useEffect(() => {
const intervalId = setInterval(() => {
checkHealth();
fetchLatestAnswer();
fetchScreenshot();
}, 3000);
return () => clearInterval(intervalId);
}, [messages]);
const checkHealth = async () => {
try {
await axios.get('http://host.docker.internal:8000/health');
setIsOnline(true);
console.log('System is online');
} catch {
setIsOnline(false);
console.log('System is offline');
}
};
const fetchScreenshot = async () => {
try {
const timestamp = new Date().getTime();
const res = await axios.get(`http://host.docker.internal:8000/screenshots/updated_screen.png?timestamp=${timestamp}`, {
responseType: 'blob'
});
console.log('Screenshot fetched successfully');
const imageUrl = URL.createObjectURL(res.data);
setResponseData((prev) => {
if (prev?.screenshot && prev.screenshot !== 'placeholder.png') {
URL.revokeObjectURL(prev.screenshot);
}
return {
...prev,
screenshot: imageUrl,
screenshotTimestamp: new Date().getTime()
};
});
} catch (err) {
console.error('Error fetching screenshot:', err);
setResponseData((prev) => ({
...prev,
screenshot: 'placeholder.png',
screenshotTimestamp: new Date().getTime()
}));
}
};
const normalizeAnswer = (answer) => {
return answer
.trim()
.toLowerCase()
.replace(/\s+/g, ' ')
.replace(/[.,!?]/g, '')
};
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
const fetchLatestAnswer = async () => {
try {
const res = await axios.get('http://host.docker.internal:8000/latest_answer');
const data = res.data;
updateData(data);
if (!data.answer || data.answer.trim() === '') {
return;
}
const normalizedNewAnswer = normalizeAnswer(data.answer);
const answerExists = messages.some(
(msg) => normalizeAnswer(msg.content) === normalizedNewAnswer
);
if (!answerExists) {
setMessages((prev) => [
...prev,
{
type: 'agent',
content: data.answer,
agentName: data.agent_name,
status: data.status,
uid: data.uid,
},
]);
setStatus(data.status);
scrollToBottom();
} else {
console.log('Duplicate answer detected, skipping:', data.answer);
}
} catch (error) {
console.error('Error fetching latest answer:', error);
}
};
const updateData = (data) => {
setResponseData((prev) => ({
...prev,
blocks: data.blocks || prev.blocks || null,
done: data.done,
answer: data.answer,
agent_name: data.agent_name,
status: data.status,
uid: data.uid,
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
checkHealth();
if (!query.trim()) {
console.log('Empty query');
return;
}
setMessages((prev) => [...prev, { type: 'user', content: query }]);
setIsLoading(true);
setError(null);
try {
console.log('Sending query:', query);
setQuery('waiting for response...');
const res = await axios.post('http://host.docker.internal:8000/query', {
query,
tts_enabled: false
});
setQuery('Enter your query...');
console.log('Response:', res.data);
const data = res.data;
updateData(data);
} catch (err) {
console.error('Error:', err);
setError('Failed to process query.');
setMessages((prev) => [
...prev,
{ type: 'error', content: 'Error: Unable to get a response.' },
]);
} finally {
console.log('Query completed');
setIsLoading(false);
setQuery('');
}
};
const handleGetScreenshot = async () => {
try {
setCurrentView('screenshot');
} catch (err) {
setError('Browser not in use');
}
};
return (
<div className="app">
<header className="header">
<h1>AgenticSeek</h1>
</header>
<main className="main">
<div className="app-sections">
<div className="chat-section">
<h2>Chat Interface</h2>
<div className="messages">
{messages.length === 0 ? (
<p className="placeholder">No messages yet. Type below to start!</p>
) : (
messages.map((msg, index) => (
<div
key={index}
className={`message ${
msg.type === 'user'
? 'user-message'
: msg.type === 'agent'
? 'agent-message'
: 'error-message'
}`}
>
{msg.type === 'agent' && (
<span className="agent-name">{msg.agentName}</span>
)}
<p>{msg.content}</p>
</div>
))
)}
<div ref={messagesEndRef} />
</div>
{isOnline && <div className="loading-animation">{status}</div>}
{!isLoading && !isOnline && <p className="loading-animation">System offline. Deploy backend first.</p>}
<form onSubmit={handleSubmit} className="input-form">
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Type your query..."
disabled={isLoading}
/>
<button type="submit" disabled={isLoading}>
Send
</button>
</form>
</div>
<div className="computer-section">
<h2>Computer View</h2>
<div className="view-selector">
<button
className={currentView === 'blocks' ? 'active' : ''}
onClick={() => setCurrentView('blocks')}
>
Editor View
</button>
<button
className={currentView === 'screenshot' ? 'active' : ''}
onClick={responseData?.screenshot ? () => setCurrentView('screenshot') : handleGetScreenshot}
>
Browser View
</button>
</div>
<div className="content">
{error && <p className="error">{error}</p>}
{currentView === 'blocks' ? (
<div className="blocks">
{responseData && responseData.blocks && Object.values(responseData.blocks).length > 0 ? (
Object.values(responseData.blocks).map((block, index) => (
<div key={index} className="block">
<p className="block-tool">Tool: {block.tool_type}</p>
<pre>{block.block}</pre>
<p className="block-feedback">Feedback: {block.feedback}</p>
<p className="block-success">
Success: {block.success ? 'Yes' : 'No'}
</p>
</div>
))
) : (
<div className="block">
<p className="block-tool">Tool: No tool in use</p>
<pre>No file opened</pre>
</div>
)}
</div>
) : (
<div className="screenshot">
<img
src={responseData?.screenshot || 'placeholder.png'}
alt="Screenshot"
onError={(e) => {
e.target.src = 'placeholder.png';
console.error('Failed to load screenshot');
}}
key={responseData?.screenshotTimestamp || 'default'}
/>
</div>
)}
</div>
</div>
</div>
</main>
</div>
);
}
export default App;
await axios.get('http://host.docker.internal:8000/health');
に変更
const res = await axios.get(`http://host.docker.internal:8000/screenshots/updated_screen.png?timestamp=${timestamp}`, {
に変更
const res = await axios.get('http://host.docker.internal:8000/latest_answer');
に変更
const res = await axios.post('http://host.docker.internal:8000/query', {
に変更
余談
GWは色々捗りますね~