Files
free-ide-proxy/cmd/vision/main.go
T
renato97 0a4289cafc Initial commit: OpenCode Zen Proxy
Proxy translating OpenAI/Anthropic Messages API to OpenCode Zen's free models.
Pure stdlib Go 1.22, no external dependencies.

- OpenAI Chat Completions (/v1/chat/completions) with streaming
- Anthropic Messages API (/v1/messages) with streaming
- Model aliases for 5 free models
- Auth middleware support
- Session rotation (30min per user key)
2026-06-25 11:49:11 -03:00

144 lines
3.5 KiB
Go

package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
const defaultAPIKey = "opx-57ffcb013651f7acae558cd9ab094dbd719fdec980a6ad53"
type visionRequest struct {
Model string `json:"model"`
Messages []visionMessage `json:"messages"`
Stream bool `json:"stream"`
}
type visionMessage struct {
Role string `json:"role"`
Content interface{} `json:"content"`
}
type visionResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []visionChoice `json:"choices"`
}
type visionChoice struct {
Index int `json:"index"`
Message visionContent `json:"message"`
FinishReason string `json:"finish_reason"`
}
type visionContent struct {
Role string `json:"role"`
Content interface{} `json:"content"`
}
func main() {
if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, "Usage: vision <image-path> [prompt]\n")
fmt.Fprintf(os.Stderr, "Example: vision C:\\path\\to\\photo.jpg \"Describe this image\"\n")
os.Exit(1)
}
imagePath := os.Args[1]
prompt := "Describe esta imagen en detalle."
if len(os.Args) > 2 {
prompt = strings.Join(os.Args[2:], " ")
}
ext := strings.ToLower(filepath.Ext(imagePath))
var mediaType string
switch ext {
case ".jpg", ".jpeg":
mediaType = "image/jpeg"
case ".png":
mediaType = "image/png"
case ".webp":
mediaType = "image/webp"
default:
fmt.Fprintf(os.Stderr, "Unsupported image format: %s (supported: jpg, png, webp)\n", ext)
os.Exit(1)
}
data, err := os.ReadFile(imagePath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading file: %v\n", err)
os.Exit(1)
}
b64 := base64.StdEncoding.EncodeToString(data)
dataURL := fmt.Sprintf("data:%s;base64,%s", mediaType, b64)
reqBody := visionRequest{
Model: "mimo-v2.5-free",
Messages: []visionMessage{
{
Role: "user",
Content: []map[string]interface{}{
{"type": "text", "text": prompt},
{"type": "image_url", "image_url": map[string]string{"url": dataURL}},
},
},
},
}
body, _ := json.Marshal(reqBody)
httpReq, err := http.NewRequest("POST", "https://opencode.ai/zen/v1/chat/completions", bytes.NewReader(body))
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating request: %v\n", err)
os.Exit(1)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Authorization", "Bearer "+defaultAPIKey)
httpReq.Header.Set("User-Agent", "vision-tool/1.0")
httpReq.Header.Set("x-opencode-client", "cli")
httpReq.Header.Set("x-opencode-project", "vision")
httpReq.Header.Set("x-opencode-request", fmt.Sprintf("req_%d", time.Now().UnixNano()))
httpReq.Header.Set("x-opencode-session", fmt.Sprintf("ses_%d", time.Now().UnixNano()))
client := &http.Client{Timeout: 2 * time.Minute}
resp, err := client.Do(httpReq)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
respData, _ := io.ReadAll(resp.Body)
if resp.StatusCode != 200 {
fmt.Fprintf(os.Stderr, "API error %d: %s\n", resp.StatusCode, string(respData))
os.Exit(1)
}
var result visionResponse
if err := json.Unmarshal(respData, &result); err != nil {
fmt.Fprintf(os.Stderr, "Error parsing response: %v\n%s\n", err, string(respData))
os.Exit(1)
}
if len(result.Choices) > 0 {
switch c := result.Choices[0].Message.Content.(type) {
case string:
fmt.Println(c)
default:
b, _ := json.MarshalIndent(c, "", " ")
fmt.Println(string(b))
}
}
}