Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/andremaldonado_yt-answer-comments.json

1 line
10 KiB
JSON

{"repo": "andremaldonado/yt-answer-comments", "files": {"config.env.example": {"f375204aeb0ca24f0d8f49233426a16db016d977": {"t": 1785745157.0453408, "n": 1248, "h": "2b5eecf0eaccfed7", "c": "LLM_API_KEY=your_deepseek_api_key\nDATABASE_URL=postgres://postgres:SUASENHA@192.168.1.2:5432/roteiros_ab7?sslmode=disable\nCLIENT_SECRET_FILE=data/client_secret.json\nMEMBERS_CSV_FILE=data/members.csv\nDATABASE_FILE=data/comments.db\nTOKEN_FILE=data/token.json\n\n# LLM Configuration (DeepSeek)\nLLM_ANALYSIS_MODEL=deepseek-v4-flash\nLLM_GENERATION_MODEL=deepseek-v4-flash\n\n# LLM Prompts\n# Use {{COMMENT}}, {{TITLE}}, {{DESCRIPTION}}, {{TRANSCRIPT}}, {{HISTORY}}, {{CONSISTENCY}} as placeholders\nPROMPT_ANALYSIS=\"Você é um classificador de comentários feitos no youtube. ... Comentário que deve ser analisado: \\\"{{COMMENT}}\\\"\"\nPROMPT_POSITIVE_ANSWER=\"Você é o meu assistente e responde às mensagens que os inscritos do meu canal no Youtube me enviam. ... O comentário que você deve responder é este: \\\"{{COMMENT}}\\\" ... O título do vídeo: \\\"{{TITLE}}\\\" ... A descrição: \\\"{{DESCRIPTION}}\\\" {{TRANSCRIPT}} {{HISTORY}} {{CONSISTENCY}} {{MEMBER_NOTICE}}\"\nPROMPT_NEGATIVE_ANSWER=\"Você é o meu assistente e responde às mensagens que os inscritos do meu canal no Youtube me enviam. ... O comentário que você deve responder é este: \\\"{{COMMENT}}\\\" ... O título do vídeo: \\\"{{TITLE}}\\\" {{TRANSCRIPT}} {{DESCRIPTION}} {{HISTORY}} {{CONSISTENCY}} {{MEMBER_NOTICE}}\"\n"}, "9ea63126e1f9aafea981bfb3d56b4bf5f2ead7eb": {"t": 1785748281.2419086, "n": 1151, "h": "e3f572e26b60ea62", "c": "GEMINI_API_KEY=your_api_key_here\nCLIENT_SECRET_FILE=data/client_secret.json\nMEMBERS_CSV_FILE=data/members.csv\nDATABASE_FILE=data/comments.db\nTOKEN_FILE=data/token.json\n\n# LLM Configuration\nLLM_ANALYSIS_MODEL=gemini-2.0-flash-lite\nLLM_GENERATION_MODEL=gemini-2.0-flash\n\n# LLM Prompts\n# Use {{COMMENT}}, {{TITLE}}, {{DESCRIPTION}}, {{TRANSCRIPT}}, {{HISTORY}}, {{CONSISTENCY}} as placeholders\nPROMPT_ANALYSIS=\"Você é um classificador de comentários feitos no youtube. ... Comentário que deve ser analisado: \\\"{{COMMENT}}\\\"\"\nPROMPT_POSITIVE_ANSWER=\"Você é o meu assistente e responde às mensagens que os inscritos do meu canal no Youtube me enviam. ... O comentário que você deve responder é este: \\\"{{COMMENT}}\\\" ... O título do vídeo: \\\"{{TITLE}}\\\" ... A descrição: \\\"{{DESCRIPTION}}\\\" {{TRANSCRIPT}} {{HISTORY}} {{CONSISTENCY}} {{MEMBER_NOTICE}}\"\nPROMPT_NEGATIVE_ANSWER=\"Você é o meu assistente e responde às mensagens que os inscritos do meu canal no Youtube me enviam. ... O comentário que você deve responder é este: \\\"{{COMMENT}}\\\" ... O título do vídeo: \\\"{{TITLE}}\\\" {{TRANSCRIPT}} {{DESCRIPTION}} {{HISTORY}} {{CONSISTENCY}} {{MEMBER_NOTICE}}\"\n"}}, "internal/app/app.go": {"f375204aeb0ca24f0d8f49233426a16db016d977": {"t": 1785746060.1556714, "n": 3797, "h": "296d1d035f413bcf", "c": "package app\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"answer-comments/internal/database\"\n\t\"answer-comments/internal/ui\"\n\tyt \"answer-comments/internal/youtube\"\n\n\t\"github.com/joho/godotenv\"\n\t_ \"github.com/lib/pq\"\n\t\"github.com/openai/openai-go\"\n\topenaiopt \"github.com/openai/openai-go/option\"\n\t\"golang.org/x/oauth2/google\"\n\t\"google.golang.org/api/option\"\n\t\"google.golang.org/api/youtube/v3\"\n)\n\ntype Config struct {\n\tClientSecretFile string\n\tLLMAPIKey string\n\tMembersCSVFile string\n\tDatabaseFile string\n\tTokenFile string\n}\n\ntype App struct {\n\tConfig *Config\n\tYTService *youtube.Service\n\tLLMClient openai.Client\n\tChannelID string\n\tTranscriptionDB *sql.DB\n}\n\nfunc NewApp(ctx context.Context, transcriptionMode bool) (*App, error) {\n\t// Load config.env file\n\tif err := godotenv.Load(\"config.env\"); err != nil {\n\t\tlog.Printf(\"Aviso: Arquivo .env não encontrado. Usando variáveis de ambiente do sistema.\")\n\t}\n\n\tappConfig := &Config{\n\t\tClientSecretFile: getEnv(\"CLIENT_SECRET_FILE\", \"data/client_secret.json\"),\n\t\tLLMAPIKey: os.Getenv(\"LLM_API_KEY\"),\n\t\tMembersCSVFile: getEnv(\"MEMBERS_CSV_FILE\", \"data/members.csv\"),\n\t\tDatabaseFile: getEnv(\"DATABASE_FILE\", \"data/comments.db\"),\n\t\tTokenFile: getEnv(\"TOKEN_FILE\", \"data/token.json\"),\n\t}\n\n\tif appConfig.LLMAPIKey == \"\" {\n\t\treturn nil, fmt.Errorf(\"LLM_API_KEY não configurada\")\n\t}\n\n\t// Initialize database\n\tif err := database.InitDB(); err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao inicializar o banco de dados: %w\", err)\n\t}\n\n\t// YouTube Client\n\tb, err := os.ReadFile(appConfig.ClientSecretFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"não foi possível ler o arquivo %s: %w\", appConfig.ClientSecretFile, err)\n\t}\n\n\tscopes := []string{yt.YoutubeForceSslScope, yt.YoutubeChannelMembershipsCreatorScope}\n\tif transcriptionMode {\n\t\tscopes = append(scopes, youtube.YoutubeScope)\n\t}\n\toauthConfig, err := google.ConfigFromJSON(b, scopes...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"não foi possível analisar o arquivo de segredo do cliente: %w\", err)\n\t}\n\n\tclient, err := yt.GetYoutubeClient(oauthConfig)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao obter cliente do YouTube: %w\", err)\n\t}\n\n\tservice, err := youtube.NewService(ctx, option.WithHTTPClient(client))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao criar o serviço do YouTube: %w\", err)\n\t}\n\n\t// Get Channel ID\n\tchannelResponse, err := service.Channels.List([]string{\"id\"}).Mine(true).Do()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao obter o ID do canal: %w\", err)\n\t}\n\tif len(channelResponse.Items) == 0 {\n\t\treturn nil, fmt.Errorf(\"não foi possível encontrar o ID do canal do usuário autenticado\")\n\t}\n\tchannelID := channelResponse.Items[0].Id\n\n\t// LLM Client (DeepSeek)\n\tllmClient := openai.NewClient(\n\t\topenaiopt.WithAPIKey(appConfig.LLMAPIKey),\n\t\topenaiopt.WithBaseURL(\"https://api.deepseek.com/v1\"),\n\t)\n\n\tapp := &App{\n\t\tConfig: appConfig,\n\t\tYTService: service,\n\t\tLLMClient: llmClient,\n\t\tChannelID: channelID,\n\t}\n\n\t// Transcription DB (PostgreSQL, optional)\n\tif dbURL := os.Getenv(\"DATABASE_URL\"); dbURL != \"\" {\n\t\tpgDB, err := sql.Open(\"postgres\", dbURL)\n\t\tif err != nil {\n\t\t\tui.Warning(fmt.Sprintf(\"Não foi possível conectar ao banco de transcrições: %v\", err))\n\t\t} else if err := pgDB.Ping(); err != nil {\n\t\t\tui.Warning(fmt.Sprintf(\"Banco de transcrições inacessível: %v\", err))\n\t\t\tpgDB.Close()\n\t\t} else {\n\t\t\tapp.TranscriptionDB = pgDB\n\t\t}\n\t} else {\n\t\tui.Warning(\"DATABASE_URL não configurada — transcrições serão buscadas direto do YouTube.\")\n\t}\n\n\treturn app, nil\n}\n\nfunc (a *App) Close() {\n\tdatabase.CloseDB()\n\tif a.TranscriptionDB != nil {\n\t\ta.TranscriptionDB.Close()\n\t}\n}\n\nfunc getEnv(key, fallback string) string {\n\tif value, ok := os.LookupEnv(key); ok {\n\t\treturn value\n\t}\n\treturn fallback\n}\n"}, "9ea63126e1f9aafea981bfb3d56b4bf5f2ead7eb": {"t": 1785748279.8714883, "n": 3131, "h": "c4dfc2baa7eca87e", "c": "package app\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"answer-comments/internal/database\"\n\tyt \"answer-comments/internal/youtube\"\n\n\t\"github.com/joho/godotenv\"\n\t\"golang.org/x/oauth2/google\"\n\t\"google.golang.org/api/option\"\n\t\"google.golang.org/api/youtube/v3\"\n\t\"google.golang.org/genai\"\n)\n\ntype Config struct {\n\tClientSecretFile string\n\tGeminiAPIKey string\n\tMembersCSVFile string\n\tDatabaseFile string\n\tTokenFile string\n}\n\ntype App struct {\n\tConfig *Config\n\tYTService *youtube.Service\n\tGeminiClient *genai.Client\n\tChannelID string\n}\n\nfunc NewApp(ctx context.Context, transcriptionMode bool) (*App, error) {\n\t// Load config.env file\n\tif err := godotenv.Load(\"config.env\"); err != nil {\n\t\tlog.Printf(\"Aviso: Arquivo .env não encontrado. Usando variáveis de ambiente do sistema.\")\n\t}\n\n\tappConfig := &Config{\n\t\tClientSecretFile: getEnv(\"CLIENT_SECRET_FILE\", \"data/client_secret.json\"),\n\t\tGeminiAPIKey: os.Getenv(\"GEMINI_API_KEY\"),\n\t\tMembersCSVFile: getEnv(\"MEMBERS_CSV_FILE\", \"data/members.csv\"),\n\t\tDatabaseFile: getEnv(\"DATABASE_FILE\", \"data/comments.db\"),\n\t\tTokenFile: getEnv(\"TOKEN_FILE\", \"data/token.json\"),\n\t}\n\n\tif appConfig.GeminiAPIKey == \"\" {\n\t\treturn nil, fmt.Errorf(\"GEMINI_API_KEY não configurada\")\n\t}\n\n\t// Initialize database\n\tif err := database.InitDB(); err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao inicializar o banco de dados: %w\", err)\n\t}\n\n\t// YouTube Client\n\tb, err := os.ReadFile(appConfig.ClientSecretFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"não foi possível ler o arquivo %s: %w\", appConfig.ClientSecretFile, err)\n\t}\n\n\tscopes := []string{yt.YoutubeForceSslScope, yt.YoutubeChannelMembershipsCreatorScope}\n\tif transcriptionMode {\n\t\tscopes = append(scopes, youtube.YoutubeScope)\n\t}\n\toauthConfig, err := google.ConfigFromJSON(b, scopes...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"não foi possível analisar o arquivo de segredo do cliente: %w\", err)\n\t}\n\n\tclient, err := yt.GetYoutubeClient(oauthConfig)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao obter cliente do YouTube: %w\", err)\n\t}\n\n\tservice, err := youtube.NewService(ctx, option.WithHTTPClient(client))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao criar o serviço do YouTube: %w\", err)\n\t}\n\n\t// Get Channel ID\n\tchannelResponse, err := service.Channels.List([]string{\"id\"}).Mine(true).Do()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao obter o ID do canal: %w\", err)\n\t}\n\tif len(channelResponse.Items) == 0 {\n\t\treturn nil, fmt.Errorf(\"não foi possível encontrar o ID do canal do usuário autenticado\")\n\t}\n\tchannelID := channelResponse.Items[0].Id\n\n\t// Gemini Client\n\tgeminiClient, err := genai.NewClient(ctx, &genai.ClientConfig{\n\t\tAPIKey: appConfig.GeminiAPIKey,\n\t\tBackend: genai.BackendGeminiAPI,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"erro ao criar cliente Gemini: %w\", err)\n\t}\n\n\treturn &App{\n\t\tConfig: appConfig,\n\t\tYTService: service,\n\t\tGeminiClient: geminiClient,\n\t\tChannelID: channelID,\n\t}, nil\n}\n\nfunc (a *App) Close() {\n\tdatabase.CloseDB()\n}\n\nfunc getEnv(key, fallback string) string {\n\tif value, ok := os.LookupEnv(key); ok {\n\t\treturn value\n\t}\n\treturn fallback\n}\n"}}}}